LCOV - code coverage report
Current view: top level - vcl/source/gdi - pngwrite.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 182 335 54.3 %
Date: 2012-08-25 Functions: 16 20 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 114 402 28.4 %

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

Generated by: LCOV version 1.10