LCOV - code coverage report
Current view: top level - vcl/source/gdi - pngwrite.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 277 331 83.7 %
Date: 2014-11-03 Functions: 20 22 90.9 %
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             : #include <vcl/pngwrite.hxx>
      21             : 
      22             : #include <cmath>
      23             : #include <limits>
      24             : #include <rtl/crc.h>
      25             : #include <rtl/alloc.h>
      26             : #include <tools/zcodec.hxx>
      27             : #include <tools/stream.hxx>
      28             : #include <vcl/bmpacc.hxx>
      29             : #include <vcl/svapp.hxx>
      30             : #include <vcl/alpha.hxx>
      31             : #include <osl/endian.h>
      32             : #include <boost/scoped_array.hpp>
      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         198 : 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             : 
      53             :     bool    Write( SvStream& rOStm );
      54             : 
      55           0 :     std::vector< vcl::PNGWriter::ChunkData >&   GetChunks() { return maChunkSeq;}
      56             : 
      57             : private:
      58             : 
      59             :     std::vector< vcl::PNGWriter::ChunkData >    maChunkSeq;
      60             : 
      61             :     sal_Int32           mnCompLevel;
      62             :     sal_Int32           mnInterlaced;
      63             :     sal_uInt32          mnMaxChunkSize;
      64             :     bool                mbStatus;
      65             : 
      66             :     BitmapReadAccess*   mpAccess;
      67             :     BitmapReadAccess*   mpMaskAccess;
      68             :     ZCodec              mpZCodec;
      69             : 
      70             :     sal_uInt8*              mpDeflateInBuf;         // as big as the size of a scanline + alphachannel + 1
      71             :     sal_uInt8*              mpPreviousScan;         // as big as mpDeflateInBuf
      72             :     sal_uInt8*              mpCurrentScan;
      73             :     sal_uLong               mnDeflateInSize;
      74             : 
      75             :     sal_uLong               mnWidth, mnHeight;
      76             :     sal_uInt8               mnBitsPerPixel;
      77             :     sal_uInt8               mnFilterType;           // 0 oder 4;
      78             :     sal_uLong               mnBBP;                  // bytes per pixel ( needed for filtering )
      79             :     bool                mbTrueAlpha;
      80             :     sal_uLong               mnCRC;
      81             : 
      82             :     void                ImplWritepHYs( const BitmapEx& rBitmapEx );
      83             :     void                ImplWriteIDAT();
      84             :     sal_uLong               ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 );
      85             :     void                ImplClearFirstScanline();
      86             :     void                ImplWriteTransparent();
      87             :     bool                ImplWriteHeader();
      88             :     void                ImplWritePalette();
      89             :     void                ImplOpenChunk( sal_uLong nChunkType );
      90             :     void                ImplWriteChunk( sal_uInt8 nNumb );
      91             :     void                ImplWriteChunk( sal_uInt32 nNumb );
      92             :     void                ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize );
      93             :     void                ImplCloseChunk( void ) const;
      94             : };
      95             : 
      96         198 : PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
      97             :     const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData )
      98             :     : mnCompLevel(PNG_DEF_COMPRESSION)
      99             :     , mnInterlaced(0)
     100             :     , mnMaxChunkSize(0)
     101             :     , mbStatus(true)
     102             :     , mpAccess(NULL)
     103             :     , mpMaskAccess(NULL)
     104             :     , mpDeflateInBuf(NULL)
     105             :     , mpPreviousScan(NULL)
     106             :     , mpCurrentScan(NULL)
     107             :     , mnDeflateInSize(0)
     108             :     , mnWidth(0)
     109             :     , mnHeight(0)
     110             :     , mnBitsPerPixel(0)
     111             :     , mnFilterType(0)
     112             :     , mnBBP(0)
     113             :     , mbTrueAlpha(false)
     114         198 :     , mnCRC(0UL)
     115             : {
     116         198 :     if ( !rBmpEx.IsEmpty() )
     117             :     {
     118         198 :         Bitmap aBmp( rBmpEx.GetBitmap() );
     119             : 
     120         198 :         mnInterlaced = 0;   // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
     121             : 
     122             :         // #i67234# defaulting max chunk size to 256kb when using interlace mode
     123         198 :         mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000;
     124             : 
     125         198 :         if ( pFilterData )
     126             :         {
     127          70 :             sal_Int32 i = 0;
     128         144 :             for ( i = 0; i < pFilterData->getLength(); i++ )
     129             :             {
     130          74 :                 if ( (*pFilterData)[ i ].Name == "Compression" )
     131          70 :                     (*pFilterData)[ i ].Value >>= mnCompLevel;
     132           4 :                 else if ( (*pFilterData)[ i ].Name == "Interlaced" )
     133           2 :                     (*pFilterData)[ i ].Value >>= mnInterlaced;
     134           2 :                 else if ( (*pFilterData)[ i ].Name == "MaxChunkSize" )
     135             :                 {
     136           0 :                     sal_Int32 nVal = 0;
     137           0 :                     if ( (*pFilterData)[ i ].Value >>= nVal )
     138           0 :                         mnMaxChunkSize = (sal_uInt32)nVal;
     139             :                 }
     140             :             }
     141             :         }
     142         198 :         mnBitsPerPixel = (sal_uInt8)aBmp.GetBitCount();
     143             : 
     144         198 :         if( rBmpEx.IsTransparent() )
     145             :         {
     146          64 :             if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() )
     147             :             {
     148           0 :                 aBmp.Convert( BMP_CONVERSION_24BIT );
     149           0 :                 mnBitsPerPixel = 24;
     150             :             }
     151             : 
     152          64 :             if ( mnBitsPerPixel <= 8 )                  // transparent palette
     153             :             {
     154           2 :                 aBmp.Convert( BMP_CONVERSION_8BIT_TRANS );
     155           2 :                 aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS );
     156           2 :                 mnBitsPerPixel = 8;
     157           2 :                 mpAccess = aBmp.AcquireReadAccess();
     158           2 :                 if ( mpAccess )
     159             :                 {
     160           2 :                     if ( ImplWriteHeader() )
     161             :                     {
     162           2 :                         ImplWritepHYs( rBmpEx );
     163           2 :                         ImplWritePalette();
     164           2 :                         ImplWriteTransparent();
     165           2 :                         ImplWriteIDAT();
     166             :                     }
     167           2 :                     aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     168             :                 }
     169             :                 else
     170           0 :                     mbStatus = false;
     171             :             }
     172             :             else
     173             :             {
     174          62 :                 mpAccess = aBmp.AcquireReadAccess();    // true RGB with alphachannel
     175          62 :                 if( mpAccess )
     176             :                 {
     177          62 :                     if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) )
     178             :                     {
     179          44 :                         AlphaMask aMask( rBmpEx.GetAlpha() );
     180          44 :                         mpMaskAccess = aMask.AcquireReadAccess();
     181          44 :                         if ( mpMaskAccess )
     182             :                         {
     183          44 :                             if ( ImplWriteHeader() )
     184             :                             {
     185          44 :                                 ImplWritepHYs( rBmpEx );
     186          44 :                                 ImplWriteIDAT();
     187             :                             }
     188          44 :                             aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
     189             :                         }
     190             :                         else
     191           0 :                             mbStatus = false;
     192             :                     }
     193             :                     else
     194             :                     {
     195          18 :                         Bitmap aMask( rBmpEx.GetMask() );
     196          18 :                         mpMaskAccess = aMask.AcquireReadAccess();
     197          18 :                         if( mpMaskAccess )
     198             :                         {
     199          18 :                             if ( ImplWriteHeader() )
     200             :                             {
     201          18 :                                 ImplWritepHYs( rBmpEx );
     202          18 :                                 ImplWriteIDAT();
     203             :                             }
     204          18 :                             aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
     205             :                         }
     206             :                         else
     207           0 :                             mbStatus = false;
     208             :                     }
     209          62 :                     aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     210             :                 }
     211             :                 else
     212           0 :                     mbStatus = false;
     213             :             }
     214             :         }
     215             :         else
     216             :         {
     217         134 :             mpAccess = aBmp.AcquireReadAccess();        // palette + RGB without alphachannel
     218         134 :             if( mpAccess )
     219             :             {
     220         134 :                 if ( ImplWriteHeader() )
     221             :                 {
     222         134 :                     ImplWritepHYs( rBmpEx );
     223         134 :                     if( mpAccess->HasPalette() )
     224          70 :                         ImplWritePalette();
     225             : 
     226         134 :                     ImplWriteIDAT();
     227             :                 }
     228         134 :                 aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
     229             :             }
     230             :             else
     231           0 :                 mbStatus = false;
     232             :         }
     233         198 :         if ( mbStatus )
     234             :         {
     235         198 :             ImplOpenChunk( PNGCHUNK_IEND );     // create an IEND chunk
     236         198 :             ImplCloseChunk();
     237         198 :         }
     238             :     }
     239         198 : }
     240             : 
     241         198 : bool PNGWriterImpl::Write( SvStream& rOStm )
     242             : {
     243             :    /* png signature is always an array of 8 bytes */
     244         198 :     sal_uInt16 nOldMode = rOStm.GetNumberFormatInt();
     245         198 :     rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
     246         198 :     rOStm.WriteUInt32( 0x89504e47 );
     247         198 :     rOStm.WriteUInt32( 0x0d0a1a0a );
     248             : 
     249         198 :     std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() );
     250         198 :     std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() );
     251        1086 :     while( aBeg != aEnd )
     252             :     {
     253         690 :         sal_uInt32 nType = aBeg->nType;
     254             :     #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
     255         690 :         nType = OSL_SWAPDWORD( nType );
     256             :     #endif
     257         690 :         sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 );
     258         690 :         sal_uInt32 nDataSize = aBeg->aData.size();
     259         690 :         if ( nDataSize )
     260         492 :             nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize );
     261         690 :         rOStm.WriteUInt32( nDataSize )
     262        1380 :              .WriteUInt32( aBeg->nType );
     263         690 :         if ( nDataSize )
     264         492 :             rOStm.Write( &aBeg->aData[ 0 ], nDataSize );
     265         690 :         rOStm.WriteUInt32( nCRC );
     266         690 :         ++aBeg;
     267             :     }
     268         198 :     rOStm.SetNumberFormatInt( nOldMode );
     269         198 :     return mbStatus;
     270             : }
     271             : 
     272             : 
     273         198 : bool PNGWriterImpl::ImplWriteHeader()
     274             : {
     275         198 :     ImplOpenChunk(PNGCHUNK_IHDR);
     276         198 :     ImplWriteChunk( sal_uInt32( mnWidth =  mpAccess->Width() ) );
     277         198 :     ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) );
     278             : 
     279         198 :     if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus )
     280             :     {
     281         198 :         sal_uInt8 nBitDepth = mnBitsPerPixel;
     282         198 :         if ( mnBitsPerPixel <= 8 )
     283          72 :             mnFilterType = 0;
     284             :         else
     285         126 :             mnFilterType = 4;
     286             : 
     287         198 :         sal_uInt8 nColorType = 2;                   // colortype:
     288             :                                                 // bit 0 -> palette is used
     289         198 :         if ( mpAccess->HasPalette() )           // bit 1 -> color is used
     290          72 :             nColorType |= 1;                    // bit 2 -> alpha channel is used
     291             :         else
     292         126 :             nBitDepth /= 3;
     293             : 
     294         198 :         if ( mpMaskAccess )
     295          62 :             nColorType |= 4;
     296             : 
     297         198 :         ImplWriteChunk( nBitDepth );
     298         198 :         ImplWriteChunk( nColorType );           // colortype
     299         198 :         ImplWriteChunk((sal_uInt8) 0 );             // compression type
     300         198 :         ImplWriteChunk((sal_uInt8) 0 );             // filter type - is not supported in this version
     301         198 :         ImplWriteChunk((sal_uInt8) mnInterlaced );  // interlace type
     302         198 :         ImplCloseChunk();
     303             :     }
     304             :     else
     305           0 :         mbStatus = false;
     306         198 :     return mbStatus;
     307             : }
     308             : 
     309          72 : void PNGWriterImpl::ImplWritePalette()
     310             : {
     311          72 :     const sal_uLong nCount = mpAccess->GetPaletteEntryCount();
     312          72 :     boost::scoped_array<sal_uInt8> pTempBuf(new sal_uInt8[ nCount*3 ]);
     313          72 :     sal_uInt8*      pTmp = pTempBuf.get();
     314             : 
     315          72 :     ImplOpenChunk( PNGCHUNK_PLTE );
     316             : 
     317       18504 :     for ( sal_uInt16 i = 0; i < nCount; i++ )
     318             :     {
     319       18432 :         const BitmapColor& rColor = mpAccess->GetPaletteColor( i );
     320       18432 :         *pTmp++ = rColor.GetRed();
     321       18432 :         *pTmp++ = rColor.GetGreen();
     322       18432 :         *pTmp++ = rColor.GetBlue();
     323             :     }
     324          72 :     ImplWriteChunk( pTempBuf.get(), nCount*3 );
     325          72 :     ImplCloseChunk();
     326          72 : }
     327             : 
     328           2 : void PNGWriterImpl::ImplWriteTransparent ()
     329             : {
     330           2 :     const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex( BMP_COL_TRANS );
     331             : 
     332           2 :     ImplOpenChunk( PNGCHUNK_tRNS );
     333             : 
     334          58 :     for ( sal_uLong n = 0UL; n <= nTransIndex; n++ )
     335          56 :         ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff );
     336             : 
     337           2 :     ImplCloseChunk();
     338           2 : }
     339             : 
     340         198 : void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx )
     341             : {
     342         198 :     if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM )
     343             :     {
     344          22 :         Size aPrefSize( rBmpEx.GetPrefSize() );
     345          22 :         if ( aPrefSize.Width() && aPrefSize.Height() && mnWidth && mnHeight )
     346             :         {
     347          22 :             ImplOpenChunk( PNGCHUNK_pHYs );
     348          22 :             sal_uInt8 nMapUnit = 1;
     349          22 :             sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 );
     350          22 :             sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 );
     351          22 :             ImplWriteChunk( nPrefSizeX );
     352          22 :             ImplWriteChunk( nPrefSizeY );
     353          22 :             ImplWriteChunk( nMapUnit );
     354          22 :             ImplCloseChunk();
     355             :         }
     356             :     }
     357         198 : }
     358             : 
     359         198 : void PNGWriterImpl::ImplWriteIDAT ()
     360             : {
     361         198 :     mnDeflateInSize = mnBitsPerPixel;
     362             : 
     363         198 :     if( mpMaskAccess )
     364          62 :         mnDeflateInSize += 8;
     365             : 
     366         198 :     mnBBP = ( mnDeflateInSize + 7 ) >> 3;
     367             : 
     368         198 :     mnDeflateInSize = mnBBP * mnWidth + 1;
     369             : 
     370         198 :     mpDeflateInBuf = new sal_uInt8[ mnDeflateInSize ];
     371             : 
     372         198 :     if ( mnFilterType )         // using filter type 4 we need memory for the scanline 3 times
     373             :     {
     374         126 :         mpPreviousScan = new sal_uInt8[ mnDeflateInSize ];
     375         126 :         mpCurrentScan = new sal_uInt8[ mnDeflateInSize ];
     376         126 :         ImplClearFirstScanline();
     377             :     }
     378         198 :     mpZCodec.BeginCompression( mnCompLevel, true );
     379         198 :     mpZCodec.SetCRC( mnCRC );
     380         198 :     SvMemoryStream aOStm;
     381         198 :     if ( mnInterlaced == 0 )
     382             :     {
     383       22908 :         for ( sal_uLong nY = 0; nY < mnHeight; nY++ )
     384       22710 :             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         198 :     mpZCodec.EndCompression();
     427         198 :     mnCRC = mpZCodec.GetCRC();
     428             : 
     429         198 :     if ( mnFilterType )         // using filter type 4 we need memory for the scanline 3 times
     430             :     {
     431         126 :         delete[] mpCurrentScan;
     432         126 :         delete[] mpPreviousScan;
     433             :     }
     434         198 :     delete[] mpDeflateInBuf;
     435             : 
     436         198 :     sal_uInt32 nIDATSize = aOStm.Tell();
     437         198 :     sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
     438         594 :     while( nBytesToWrite )
     439             :     {
     440         198 :         nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
     441         198 :         ImplOpenChunk( PNGCHUNK_IDAT );
     442         198 :         ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes );
     443         198 :         ImplCloseChunk();
     444         198 :         nBytesToWrite -= nBytes;
     445         198 :     }
     446         198 : }
     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       22710 : sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd )
     453             : {
     454             :     sal_uInt8* pDest;
     455             : 
     456       22710 :     if ( mnFilterType )
     457        5444 :         pDest = mpCurrentScan;
     458             :     else
     459       17266 :         pDest = mpDeflateInBuf;
     460             : 
     461       22710 :     if ( nXStart < mnWidth )
     462             :     {
     463       22710 :         *pDest++ = mnFilterType;        // in this version the filter type is either 0 or 4
     464             : 
     465       22710 :         if ( mpAccess->HasPalette() )   // alphachannel is not allowed by pictures including palette entries
     466             :         {
     467       17266 :             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     3292636 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     503     3275370 :                         *pDest++ = mpAccess->GetPixelIndex( nY, nX );
     504             :                 }
     505       17266 :                 break;
     506             : 
     507             :                 default :
     508           0 :                     mbStatus = false;
     509           0 :                 break;
     510             :             }
     511             :         }
     512             :         else
     513             :         {
     514        5444 :             if ( mpMaskAccess )             // mpMaskAccess != NULL -> alphachannel is to create
     515             :             {
     516        3210 :                 if ( mbTrueAlpha )
     517             :                 {
     518      269406 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd )
     519             :                     {
     520      266396 :                         const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     521      266396 :                         *pDest++ = rColor.GetRed();
     522      266396 :                         *pDest++ = rColor.GetGreen();
     523      266396 :                         *pDest++ = rColor.GetBlue();
     524      266396 :                         *pDest++ = 255 - mpMaskAccess->GetPixelIndex( nY, nX );
     525      266396 :                     }
     526             :                 }
     527             :                 else
     528             :                 {
     529         200 :                     const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
     530             : 
     531       10392 :                     for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     532             :                     {
     533       10192 :                         const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     534       10192 :                         *pDest++ = rColor.GetRed();
     535       10192 :                         *pDest++ = rColor.GetGreen();
     536       10192 :                         *pDest++ = rColor.GetBlue();
     537             : 
     538       10192 :                         if( mpMaskAccess->GetPixel( nY, nX ) == aTrans )
     539        7784 :                             *pDest++ = 0;
     540             :                         else
     541        2408 :                             *pDest++ = 0xff;
     542       10392 :                     }
     543             :                 }
     544             :             }
     545             :             else
     546             :             {
     547      246402 :                 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
     548             :                 {
     549      244168 :                     const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
     550      244168 :                     *pDest++ = rColor.GetRed();
     551      244168 :                     *pDest++ = rColor.GetGreen();
     552      244168 :                     *pDest++ = rColor.GetBlue();
     553      244168 :                 }
     554             :             }
     555             :         }
     556             :     }
     557             :     // filter type4 ( PAETH ) will be used only for 24bit graphics
     558       22710 :     if ( mnFilterType )
     559             :     {
     560        5444 :         mnDeflateInSize = pDest - mpCurrentScan;
     561        5444 :         pDest = mpDeflateInBuf;
     562        5444 :         *pDest++ = 4;                                   // filter type
     563             : 
     564             :         sal_uLong na, nb, nc;
     565             :         long  np, npa, npb, npc;
     566             : 
     567        5444 :         sal_uInt8* p1 = mpCurrentScan + 1;                  // Current Pixel
     568        5444 :         sal_uInt8* p2 = p1 - mnBBP;                         // left pixel
     569        5444 :         sal_uInt8* p3 = mpPreviousScan;                     // upper pixel
     570        5444 :         sal_uInt8* p4 = p3 - mnBBP;                         // upperleft Pixel;
     571             : 
     572     1849744 :         while ( pDest < mpDeflateInBuf + mnDeflateInSize )
     573             :         {
     574     1838856 :             nb = *p3++;
     575     1838856 :             if ( p2 >= mpCurrentScan + 1 )
     576             :             {
     577     1819314 :                 na = *p2;
     578     1819314 :                 nc = *p4;
     579             :             }
     580             :             else
     581       19542 :                 na = nc = 0;
     582             : 
     583     1838856 :             np = na + nb;
     584     1838856 :             np -= nc;
     585     1838856 :             npa = np - na;
     586     1838856 :             npb = np - nb;
     587     1838856 :             npc = np - nc;
     588     1838856 :             if ( npa < 0 )
     589      213664 :                 npa =-npa;
     590     1838856 :             if ( npb < 0 )
     591      310298 :                 npb =-npb;
     592     1838856 :             if ( npc < 0 )
     593      343152 :                 npc =-npc;
     594     1838856 :             if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na;
     595      260158 :             else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb;
     596       32540 :             else *pDest++ = *p1++ - (sal_uInt8)nc;
     597     1838856 :             p4++;
     598     1838856 :             p2++;
     599             :         }
     600     1844300 :         for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ )
     601     1838856 :             mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ];
     602             :     }
     603             :     else
     604       17266 :         mnDeflateInSize = pDest - mpDeflateInBuf;
     605       22710 :     return ( mnDeflateInSize );
     606             : }
     607             : 
     608         126 : void PNGWriterImpl::ImplClearFirstScanline()
     609             : {
     610         126 :     if ( mnFilterType )
     611         126 :         memset( mpPreviousScan, 0, mnDeflateInSize );
     612         126 : }
     613             : 
     614         690 : void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType )
     615             : {
     616         690 :     maChunkSeq.resize( maChunkSeq.size() + 1 );
     617         690 :     maChunkSeq.back().nType = nChunkType;
     618         690 : }
     619             : 
     620        1068 : void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource )
     621             : {
     622        1068 :     maChunkSeq.back().aData.push_back( nSource );
     623        1068 : }
     624             : 
     625         440 : void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource )
     626             : {
     627         440 :     vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
     628         440 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) );
     629         440 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) );
     630         440 :     rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) );
     631         440 :     rChunkData.aData.push_back( (sal_uInt8)( nSource ) );
     632         440 : }
     633             : 
     634         270 : void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize )
     635             : {
     636         270 :     if ( nDatSize )
     637             :     {
     638         270 :         vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
     639         270 :         sal_uInt32 nSize = rChunkData.aData.size();
     640         270 :         rChunkData.aData.resize( nSize + nDatSize );
     641         270 :         memcpy( &rChunkData.aData[ nSize ], pSource, nDatSize );
     642             :     }
     643         270 : }
     644             : 
     645             : // nothing to do
     646         690 : void PNGWriterImpl::ImplCloseChunk ( void ) const
     647             : {
     648         690 : }
     649             : 
     650         198 : PNGWriter::PNGWriter( const BitmapEx& rBmpEx,
     651             :     const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
     652         198 :     mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) )
     653             : {
     654         198 : }
     655             : 
     656         198 : PNGWriter::~PNGWriter()
     657             : {
     658         198 :     delete mpImpl;
     659         198 : }
     660             : 
     661         198 : bool PNGWriter::Write( SvStream& rIStm )
     662             : {
     663         198 :     return mpImpl->Write( rIStm );
     664             : }
     665             : 
     666           0 : std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
     667             : {
     668           0 :     return mpImpl->GetChunks();
     669             : }
     670             : 
     671        1233 : } // namespace vcl
     672             : 
     673             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10