LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - pngwrite.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 226 336 67.3 %
Date: 2013-07-09 Functions: 18 22 81.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <vcl/pngwrite.hxx>
      22             : 
      23             : #include <cmath>
      24             : #include <limits>
      25             : #include <rtl/crc.h>
      26             : #include <rtl/alloc.h>
      27             : #include <tools/zcodec.hxx>
      28             : #include <tools/stream.hxx>
      29             : #include <vcl/bmpacc.hxx>
      30             : #include <vcl/svapp.hxx>
      31             : #include <vcl/alpha.hxx>
      32             : #include <osl/endian.h>
      33             : 
      34             : #define PNG_DEF_COMPRESSION 6
      35             : 
      36             : #define PNGCHUNK_IHDR 0x49484452
      37             : #define PNGCHUNK_PLTE 0x504c5445
      38             : #define PNGCHUNK_IDAT 0x49444154
      39             : #define PNGCHUNK_IEND 0x49454e44
      40             : #define PNGCHUNK_pHYs 0x70485973
      41             : #define PNGCHUNK_tRNS 0x74524e53
      42             : 
      43             : namespace vcl
      44             : {
      45             : 
      46             : class PNGWriterImpl
      47             : {
      48             : public:
      49             : 
      50             :                 PNGWriterImpl( const BitmapEx& BmpEx,
      51             :                     const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
      52             :                 ~PNGWriterImpl();
      53             : 
      54             :     sal_Bool    Write( SvStream& rOStm );
      55             : 
      56             :     std::vector< vcl::PNGWriter::ChunkData >&   GetChunks();
      57             : 
      58             : private:
      59             : 
      60             :     std::vector< vcl::PNGWriter::ChunkData >    maChunkSeq;
      61             : 
      62             :     sal_Int32           mnCompLevel;
      63             :     sal_Int32           mnInterlaced;
      64             :     sal_uInt32          mnMaxChunkSize;
      65             :     sal_Bool                mbStatus;
      66             : 
      67             :     BitmapReadAccess*   mpAccess;
      68             :     BitmapReadAccess*   mpMaskAccess;
      69             :     ZCodec*             mpZCodec;
      70             : 
      71             :     sal_uInt8*              mpDeflateInBuf;         // as big as the size of a scanline + alphachannel + 1
      72             :     sal_uInt8*              mpPreviousScan;         // as big as mpDeflateInBuf
      73             :     sal_uInt8*              mpCurrentScan;
      74             :     sal_uLong               mnDeflateInSize;
      75             : 
      76             :     sal_uLong               mnWidth, mnHeight;
      77             :     sal_uInt8               mnBitsPerPixel;
      78             :     sal_uInt8               mnFilterType;           // 0 oder 4;
      79             :     sal_uLong               mnBBP;                  // bytes per pixel ( needed for filtering )
      80             :     sal_Bool                mbTrueAlpha;
      81             :     sal_uLong               mnCRC;
      82             : 
      83             :     void                ImplWritepHYs( const BitmapEx& rBitmapEx );
      84             :     void                ImplWriteIDAT();
      85             :     sal_uLong               ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 );
      86             :     void                ImplClearFirstScanline();
      87             :     void                ImplWriteTransparent();
      88             :     sal_Bool                ImplWriteHeader();
      89             :     void                ImplWritePalette();
      90             :     void                ImplOpenChunk( sal_uLong nChunkType );
      91             :     void                ImplWriteChunk( sal_uInt8 nNumb );
      92             :     void                ImplWriteChunk( sal_uInt32 nNumb );
      93             :     void                ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize );
      94             :     void                ImplCloseChunk( void ) const;
      95             : };
      96             : 
      97          55 : PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
      98             :     const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
      99             :         mnCompLevel     ( PNG_DEF_COMPRESSION ),
     100             :         mbStatus        ( sal_True ),
     101             :         mpAccess        ( NULL ),
     102             :         mpMaskAccess    ( NULL ),
     103          55 :         mpZCodec        ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
     104         110 :         mnCRC(0UL)
     105             : {
     106          55 :     if ( !rBmpEx.IsEmpty() )
     107             :     {
     108          55 :         Bitmap aBmp( rBmpEx.GetBitmap() );
     109             : 
     110          55 :         mnInterlaced = 0;   // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
     111             : 
     112             :         // #i67234# defaulting max chunk size to 256kb when using interlace mode
     113          55 :         mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000;
     114             : 
     115          55 :         if ( pFilterData )
     116             :         {
     117           1 :             sal_Int32 i = 0;
     118           4 :             for ( i = 0; i < pFilterData->getLength(); i++ )
     119             :             {
     120           3 :                 if ( (*pFilterData)[ i ].Name == "Compression" )
     121           1 :                     (*pFilterData)[ i ].Value >>= mnCompLevel;
     122           2 :                 else if ( (*pFilterData)[ i ].Name == "Interlaced" )
     123           1 :                     (*pFilterData)[ i ].Value >>= mnInterlaced;
     124           1 :                 else if ( (*pFilterData)[ i ].Name == "MaxChunkSize" )
     125             :                 {
     126           0 :                     sal_Int32 nVal = 0;
     127           0 :                     if ( (*pFilterData)[ i ].Value >>= nVal )
     128           0 :                         mnMaxChunkSize = (sal_uInt32)nVal;
     129             :                 }
     130             :             }
     131             :         }
     132          55 :         mnBitsPerPixel = (sal_uInt8)aBmp.GetBitCount();
     133             : 
     134          55 :         if( rBmpEx.IsTransparent() )
     135             :         {
     136           2 :             if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() )
     137             :             {
     138           0 :                 aBmp.Convert( BMP_CONVERSION_24BIT );
     139           0 :                 mnBitsPerPixel = 24;
     140             :             }
     141             : 
     142           2 :             if ( mnBitsPerPixel <= 8 )                  // transparent palette
     143             :             {
     144           0 :                 aBmp.Convert( BMP_CONVERSION_8BIT_TRANS );
     145           0 :                 aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS );
     146           0 :                 mnBitsPerPixel = 8;
     147           0 :                 mpAccess = aBmp.AcquireReadAccess();
     148           0 :                 if ( mpAccess )
     149             :                 {
     150           0 :                     if ( ImplWriteHeader() )
     151             :                     {
     152           0 :                         ImplWritepHYs( rBmpEx );
     153           0 :                         ImplWritePalette();
     154           0 :                         ImplWriteTransparent();
     155           0 :                         ImplWriteIDAT();
     156             :                     }
     157           0 :                     aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     158             :                 }
     159             :                 else
     160           0 :                     mbStatus = sal_False;
     161             :             }
     162             :             else
     163             :             {
     164           2 :                 mpAccess = aBmp.AcquireReadAccess();    // sal_True RGB with alphachannel
     165           2 :                 if( mpAccess )
     166             :                 {
     167           2 :                     if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) != sal_False )
     168             :                     {
     169           0 :                         AlphaMask aMask( rBmpEx.GetAlpha() );
     170           0 :                         mpMaskAccess = aMask.AcquireReadAccess();
     171           0 :                         if ( mpMaskAccess )
     172             :                         {
     173           0 :                             if ( ImplWriteHeader() )
     174             :                             {
     175           0 :                                 ImplWritepHYs( rBmpEx );
     176           0 :                                 ImplWriteIDAT();
     177             :                             }
     178           0 :                             aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
     179             :                         }
     180             :                         else
     181           0 :                             mbStatus = sal_False;
     182             :                     }
     183             :                     else
     184             :                     {
     185           2 :                         Bitmap aMask( rBmpEx.GetMask() );
     186           2 :                         mpMaskAccess = aMask.AcquireReadAccess();
     187           2 :                         if( mpMaskAccess )
     188             :                         {
     189           2 :                             if ( ImplWriteHeader() )
     190             :                             {
     191           2 :                                 ImplWritepHYs( rBmpEx );
     192           2 :                                 ImplWriteIDAT();
     193             :                             }
     194           2 :                             aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
     195             :                         }
     196             :                         else
     197           0 :                             mbStatus = sal_False;
     198             :                     }
     199           2 :                     aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     200             :                 }
     201             :                 else
     202           0 :                     mbStatus = sal_False;
     203             :             }
     204             :         }
     205             :         else
     206             :         {
     207          53 :             mpAccess = aBmp.AcquireReadAccess();        // palette + RGB without alphachannel
     208          53 :             if( mpAccess )
     209             :             {
     210          53 :                 if ( ImplWriteHeader() )
     211             :                 {
     212          53 :                     ImplWritepHYs( rBmpEx );
     213          53 :                     if( mpAccess->HasPalette() )
     214           0 :                         ImplWritePalette();
     215             : 
     216          53 :                     ImplWriteIDAT();
     217             :                 }
     218          53 :                 aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     219             :             }
     220             :             else
     221           0 :                 mbStatus = sal_False;
     222             :         }
     223          55 :         if ( mbStatus )
     224             :         {
     225          55 :             ImplOpenChunk( PNGCHUNK_IEND );     // create an IEND chunk
     226          55 :             ImplCloseChunk();
     227          55 :         }
     228             :     }
     229          55 : }
     230             : 
     231         110 : PNGWriterImpl::~PNGWriterImpl()
     232             : {
     233          55 :     delete mpZCodec;
     234          55 : }
     235             : 
     236          55 : sal_Bool PNGWriterImpl::Write( SvStream& rOStm )
     237             : {
     238             :    /* png signature is always an array of 8 bytes */
     239          55 :     sal_uInt16 nOldMode = rOStm.GetNumberFormatInt();
     240          55 :     rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
     241          55 :     rOStm << static_cast<sal_uInt32>(0x89504e47);
     242          55 :     rOStm << static_cast<sal_uInt32>(0x0d0a1a0a);
     243             : 
     244          55 :     std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() );
     245          55 :     std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() );
     246         277 :     while( aBeg != aEnd )
     247             :     {
     248         167 :         sal_uInt32 nType = aBeg->nType;
     249             :     #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
     250         167 :         nType = OSL_SWAPDWORD( nType );
     251             :     #endif
     252         167 :         sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 );
     253         167 :         sal_uInt32 nDataSize = aBeg->aData.size();
     254         167 :         if ( nDataSize )
     255         112 :             nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize );
     256         167 :         rOStm << nDataSize
     257         334 :               << aBeg->nType;
     258         167 :         if ( nDataSize )
     259         112 :             rOStm.Write( &aBeg->aData[ 0 ], nDataSize );
     260         167 :         rOStm << nCRC;
     261         167 :         ++aBeg;
     262             :     }
     263          55 :     rOStm.SetNumberFormatInt( nOldMode );
     264          55 :     return mbStatus;
     265             : }
     266             : 
     267           0 : std::vector< vcl::PNGWriter::ChunkData >& PNGWriterImpl::GetChunks()
     268             : {
     269           0 :     return maChunkSeq;
     270             : }
     271             : 
     272          55 : sal_Bool PNGWriterImpl::ImplWriteHeader()
     273             : {
     274          55 :     ImplOpenChunk(PNGCHUNK_IHDR);
     275          55 :     ImplWriteChunk( sal_uInt32( mnWidth =  mpAccess->Width() ) );
     276          55 :     ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) );
     277             : 
     278          55 :     if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus )
     279             :     {
     280          55 :         sal_uInt8 nBitDepth = mnBitsPerPixel;
     281          55 :         if ( mnBitsPerPixel <= 8 )
     282           0 :             mnFilterType = 0;
     283             :         else
     284          55 :             mnFilterType = 4;
     285             : 
     286          55 :         sal_uInt8 nColorType = 2;                   // colortype:
     287             :                                                 // bit 0 -> palette is used
     288          55 :         if ( mpAccess->HasPalette() )           // bit 1 -> color is used
     289           0 :             nColorType |= 1;                    // bit 2 -> alpha channel is used
     290             :         else
     291          55 :             nBitDepth /= 3;
     292             : 
     293          55 :         if ( mpMaskAccess )
     294           2 :             nColorType |= 4;
     295             : 
     296          55 :         ImplWriteChunk( nBitDepth );
     297          55 :         ImplWriteChunk( nColorType );           // colortype
     298          55 :         ImplWriteChunk((sal_uInt8) 0 );             // compression type
     299          55 :         ImplWriteChunk((sal_uInt8) 0 );             // filter type - is not supported in this version
     300          55 :         ImplWriteChunk((sal_uInt8) mnInterlaced );  // interlace type
     301          55 :         ImplCloseChunk();
     302             :     }
     303             :     else
     304           0 :         mbStatus = sal_False;
     305          55 :     return mbStatus;
     306             : }
     307             : 
     308           0 : void PNGWriterImpl::ImplWritePalette()
     309             : {
     310           0 :     const sal_uLong nCount = mpAccess->GetPaletteEntryCount();
     311           0 :     sal_uInt8*      pTempBuf = new sal_uInt8[ nCount*3 ];
     312           0 :     sal_uInt8*      pTmp = pTempBuf;
     313             : 
     314           0 :     ImplOpenChunk( PNGCHUNK_PLTE );
     315             : 
     316           0 :     for ( sal_uInt16 i = 0; i < nCount; i++ )
     317             :     {
     318           0 :         const BitmapColor& rColor = mpAccess->GetPaletteColor( i );
     319           0 :         *pTmp++ = rColor.GetRed();
     320           0 :         *pTmp++ = rColor.GetGreen();
     321           0 :         *pTmp++ = rColor.GetBlue();
     322             :     }
     323           0 :     ImplWriteChunk( pTempBuf, nCount*3 );
     324           0 :     ImplCloseChunk();
     325           0 :     delete[] pTempBuf;
     326           0 : }
     327             : 
     328           0 : void PNGWriterImpl::ImplWriteTransparent ()
     329             : {
     330           0 :     const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex( BMP_COL_TRANS );
     331             : 
     332           0 :     ImplOpenChunk( PNGCHUNK_tRNS );
     333             : 
     334           0 :     for ( sal_uLong n = 0UL; n <= nTransIndex; n++ )
     335           0 :         ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff );
     336             : 
     337           0 :     ImplCloseChunk();
     338           0 : }
     339             : 
     340          55 : void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx )
     341             : {
     342          55 :     if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM )
     343             :     {
     344           2 :         Size aPrefSize( rBmpEx.GetPrefSize() );
     345           2 :         if ( aPrefSize.Width() && aPrefSize.Height() )
     346             :         {
     347           2 :             ImplOpenChunk( PNGCHUNK_pHYs );
     348           2 :             sal_uInt8 nMapUnit = 1;
     349           2 :             sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 );
     350           2 :             sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 );
     351           2 :             ImplWriteChunk( nPrefSizeX );
     352           2 :             ImplWriteChunk( nPrefSizeY );
     353           2 :             ImplWriteChunk( nMapUnit );
     354           2 :             ImplCloseChunk();
     355             :         }
     356             :     }
     357          55 : }
     358             : 
     359          55 : void PNGWriterImpl::ImplWriteIDAT ()
     360             : {
     361          55 :     mnDeflateInSize = mnBitsPerPixel;
     362             : 
     363          55 :     if( mpMaskAccess )
     364           2 :         mnDeflateInSize += 8;
     365             : 
     366          55 :     mnBBP = ( mnDeflateInSize + 7 ) >> 3;
     367             : 
     368          55 :     mnDeflateInSize = mnBBP * mnWidth + 1;
     369             : 
     370          55 :     mpDeflateInBuf = new sal_uInt8[ mnDeflateInSize ];
     371             : 
     372          55 :     if ( mnFilterType )         // using filter type 4 we need memory for the scanline 3 times
     373             :     {
     374          55 :         mpPreviousScan = new sal_uInt8[ mnDeflateInSize ];
     375          55 :         mpCurrentScan = new sal_uInt8[ mnDeflateInSize ];
     376          55 :         ImplClearFirstScanline();
     377             :     }
     378          55 :     mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT + mnCompLevel );
     379          55 :     mpZCodec->SetCRC( mnCRC );
     380          55 :     SvMemoryStream aOStm;
     381          55 :     if ( mnInterlaced == 0 )
     382             :     {
     383        6552 :         for ( sal_uLong nY = 0; nY < mnHeight; nY++ )
     384        6497 :             mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) );
     385             :     }
     386             :     else
     387             :     {
     388             :         // interlace mode
     389             :         sal_uLong nY;
     390           0 :         for ( nY = 0; nY < mnHeight; nY+=8 )                                                // pass 1
     391           0 :             mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) );
     392           0 :         ImplClearFirstScanline();
     393             : 
     394           0 :         for ( nY = 0; nY < mnHeight; nY+=8 )                                                // pass 2
     395           0 :             mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) );
     396           0 :         ImplClearFirstScanline();
     397             : 
     398           0 :         if ( mnHeight >= 5 )                                                                // pass 3
     399             :         {
     400           0 :             for ( nY = 4; nY < mnHeight; nY+=8 )
     401           0 :                 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) );
     402           0 :             ImplClearFirstScanline();
     403             :         }
     404             : 
     405           0 :         for ( nY = 0; nY < mnHeight; nY+=4 )                                                // pass 4
     406           0 :             mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) );
     407           0 :         ImplClearFirstScanline();
     408             : 
     409           0 :         if ( mnHeight >= 3 )                                                                // pass 5
     410             :         {
     411           0 :             for ( nY = 2; nY < mnHeight; nY+=4 )
     412           0 :                 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) );
     413           0 :             ImplClearFirstScanline();
     414             :         }
     415             : 
     416           0 :         for ( nY = 0; nY < mnHeight; nY+=2 )                                                // pass 6
     417           0 :             mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) );
     418           0 :         ImplClearFirstScanline();
     419             : 
     420           0 :         if ( mnHeight >= 2 )                                                                // pass 7
     421             :         {
     422           0 :             for ( nY = 1; nY < mnHeight; nY+=2 )
     423           0 :                 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) );
     424             :         }
     425             :     }
     426          55 :     mpZCodec->EndCompression();
     427          55 :     mnCRC = mpZCodec->GetCRC();
     428             : 
     429          55 :     if ( mnFilterType )         // using filter type 4 we need memory for the scanline 3 times
     430             :     {
     431          55 :         delete[] mpCurrentScan;
     432          55 :         delete[] mpPreviousScan;
     433             :     }
     434          55 :     delete[] mpDeflateInBuf;
     435             : 
     436          55 :     sal_uInt32 nIDATSize = aOStm.Tell();
     437          55 :     sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
     438         165 :     while( nBytesToWrite )
     439             :     {
     440          55 :         nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
     441          55 :         ImplOpenChunk( PNGCHUNK_IDAT );
     442          55 :         ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes );
     443          55 :         ImplCloseChunk();
     444          55 :         nBytesToWrite -= nBytes;
     445          55 :     }
     446          55 : }
     447             : 
     448             : // ImplGetFilter writes the complete Scanline (nY) - in interlace mode the parameter nXStart and nXAdd
     449             : // appends to the currently used pass
     450             : // the complete size of scanline will be returned - in interlace mode zero is possible!
     451             : 
     452        6497 : sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd )
     453             : {
     454             :     sal_uInt8* pDest;
     455             : 
     456        6497 :     if ( mnFilterType )
     457        6497 :         pDest = mpCurrentScan;
     458             :     else
     459           0 :         pDest = mpDeflateInBuf;
     460             : 
     461        6497 :     if ( nXStart < mnWidth )
     462             :     {
     463        6497 :         *pDest++ = mnFilterType;        // in this version the filter type is either 0 or 4
     464             : 
     465        6497 :         if ( mpAccess->HasPalette() )   // alphachannel is not allowed by pictures including palette entries
     466             :         {
     467           0 :             switch ( mnBitsPerPixel )
     468             :             {
     469             :                 case( 1 ):
     470             :                 {
     471             :                     sal_uLong nX, nXIndex;
     472           0 :                     for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+=nXAdd, nXIndex++ )
     473             :                     {
     474           0 :                         sal_uLong nShift = ( nXIndex & 7 ) ^ 7;
     475           0 :                         if ( nShift == 7)
     476           0 :                             *pDest = mpAccess->GetPixelIndex( nY, nX ) << nShift;
     477           0 :                         else if  ( nShift == 0 )
     478           0 :                             *pDest++ |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
     479             :                         else
     480           0 :                             *pDest |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
     481             :                     }
     482           0 :                     if ( ( nXIndex & 7 ) != 0 ) pDest++;    // byte is not completely used, so the
     483             :                 }                                           // bufferpointer is to correct
     484           0 :                 break;
     485             : 
     486             :                 case( 4 ):
     487             :                 {
     488             :                     sal_uLong nX, nXIndex;
     489           0 :                     for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+= nXAdd, nXIndex++ )
     490             :                     {
     491           0 :                         if( nXIndex & 1 )
     492           0 :                             *pDest++ |= mpAccess->GetPixelIndex( nY, nX );
     493             :                         else
     494           0 :                             *pDest = mpAccess->GetPixelIndex( nY, nX ) << 4;
     495             :                     }
     496           0 :                     if ( nXIndex & 1 ) pDest++;
     497             :                 }
     498           0 :                 break;
     499             : 
     500             :                 case( 8 ):
     501             :                 {
     502           0 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     503           0 :                         *pDest++ = mpAccess->GetPixelIndex( nY, nX );
     504             :                 }
     505           0 :                 break;
     506             : 
     507             :                 default :
     508           0 :                     mbStatus = sal_False;
     509           0 :                 break;
     510             :             }
     511             :         }
     512             :         else
     513             :         {
     514        6497 :             if ( mpMaskAccess )             // mpMaskAccess != NULL -> alphachannel is to create
     515             :             {
     516          11 :                 if ( mbTrueAlpha )
     517             :                 {
     518           0 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd )
     519             :                     {
     520           0 :                         const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     521           0 :                         *pDest++ = rColor.GetRed();
     522           0 :                         *pDest++ = rColor.GetGreen();
     523           0 :                         *pDest++ = rColor.GetBlue();
     524           0 :                         *pDest++ = 255 - mpMaskAccess->GetPixelIndex( nY, nX );
     525           0 :                     }
     526             :                 }
     527             :                 else
     528             :                 {
     529          11 :                     const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
     530             : 
     531          96 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     532             :                     {
     533          85 :                         const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     534          85 :                         *pDest++ = rColor.GetRed();
     535          85 :                         *pDest++ = rColor.GetGreen();
     536          85 :                         *pDest++ = rColor.GetBlue();
     537             : 
     538          85 :                         if( mpMaskAccess->GetPixel( nY, nX ) == aTrans )
     539          33 :                             *pDest++ = 0;
     540             :                         else
     541          52 :                             *pDest++ = 0xff;
     542          96 :                     }
     543             :                 }
     544             :             }
     545             :             else
     546             :             {
     547     1164422 :                 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     548             :                 {
     549     1157936 :                     const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     550     1157936 :                     *pDest++ = rColor.GetRed();
     551     1157936 :                     *pDest++ = rColor.GetGreen();
     552     1157936 :                     *pDest++ = rColor.GetBlue();
     553     1157936 :                 }
     554             :             }
     555             :         }
     556             :     }
     557             :     // filter type4 ( PAETH ) will be used only for 24bit graphics
     558        6497 :     if ( mnFilterType )
     559             :     {
     560        6497 :         mnDeflateInSize = pDest - mpCurrentScan;
     561        6497 :         pDest = mpDeflateInBuf;
     562        6497 :         *pDest++ = 4;                                   // filter type
     563             : 
     564             :         sal_uLong na, nb, nc;
     565             :         long  np, npa, npb, npc;
     566             : 
     567        6497 :         sal_uInt8* p1 = mpCurrentScan + 1;                  // Current Pixel
     568        6497 :         sal_uInt8* p2 = p1 - mnBBP;                         // left pixel
     569        6497 :         sal_uInt8* p3 = mpPreviousScan;                     // upper pixel
     570        6497 :         sal_uInt8* p4 = p3 - mnBBP;                         // upperleft Pixel;
     571             : 
     572     3487142 :         while ( pDest < mpDeflateInBuf + mnDeflateInSize )
     573             :         {
     574     3474148 :             nb = *p3++;
     575     3474148 :             if ( p2 >= mpCurrentScan + 1 )
     576             :             {
     577     3454646 :                 na = *p2;
     578     3454646 :                 nc = *p4;
     579             :             }
     580             :             else
     581       19502 :                 na = nc = 0;
     582             : 
     583     3474148 :             np = na + nb;
     584     3474148 :             np -= nc;
     585     3474148 :             npa = np - na;
     586     3474148 :             npb = np - nb;
     587     3474148 :             npc = np - nc;
     588     3474148 :             if ( npa < 0 )
     589       61888 :                 npa =-npa;
     590     3474148 :             if ( npb < 0 )
     591       77370 :                 npb =-npb;
     592     3474148 :             if ( npc < 0 )
     593       97776 :                 npc =-npc;
     594     3474148 :             if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na;
     595       94489 :             else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb;
     596       11396 :             else *pDest++ = *p1++ - (sal_uInt8)nc;
     597     3474148 :             p4++;
     598     3474148 :             p2++;
     599             :         }
     600     3480645 :         for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ )
     601     3474148 :             mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ];
     602             :     }
     603             :     else
     604           0 :         mnDeflateInSize = pDest - mpDeflateInBuf;
     605        6497 :     return ( mnDeflateInSize );
     606             : }
     607             : 
     608          55 : void PNGWriterImpl::ImplClearFirstScanline()
     609             : {
     610          55 :     if ( mnFilterType )
     611          55 :         memset( mpPreviousScan, 0, mnDeflateInSize );
     612          55 : }
     613             : 
     614         167 : void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType )
     615             : {
     616         167 :     maChunkSeq.resize( maChunkSeq.size() + 1 );
     617         167 :     maChunkSeq.back().nType = nChunkType;
     618         167 : }
     619             : 
     620         277 : void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource )
     621             : {
     622         277 :     maChunkSeq.back().aData.push_back( nSource );
     623         277 : }
     624             : 
     625         114 : void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource )
     626             : {
     627         114 :     vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
     628         114 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) );
     629         114 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) );
     630         114 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) );
     631         114 :     rChunkData.aData.push_back( (sal_uInt8)( nSource ) );
     632         114 : }
     633             : 
     634          55 : void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize )
     635             : {
     636          55 :     if ( nDatSize )
     637             :     {
     638          55 :         vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
     639          55 :         sal_uInt32 nSize = rChunkData.aData.size();
     640          55 :         rChunkData.aData.resize( nSize + nDatSize );
     641          55 :         memcpy( &rChunkData.aData[ nSize ], pSource, nDatSize );
     642             :     }
     643          55 : }
     644             : 
     645             : // nothing to do
     646         167 : void PNGWriterImpl::ImplCloseChunk ( void ) const
     647             : {
     648         167 : }
     649             : 
     650          55 : PNGWriter::PNGWriter( const BitmapEx& rBmpEx,
     651             :     const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
     652          55 :     mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) )
     653             : {
     654          55 : }
     655             : 
     656          55 : PNGWriter::~PNGWriter()
     657             : {
     658          55 :     delete mpImpl;
     659          55 : }
     660             : 
     661          55 : sal_Bool PNGWriter::Write( SvStream& rIStm )
     662             : {
     663          55 :     return mpImpl->Write( rIStm );
     664             : }
     665             : 
     666           0 : std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
     667             : {
     668           0 :     return mpImpl->GetChunks();
     669             : }
     670             : 
     671         465 : } // namespace vcl
     672             : 
     673             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10