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

Generated by: LCOV version 1.10