LCOV - code coverage report
Current view: top level - vcl/source/gdi - pngwrite.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 276 333 82.9 %
Date: 2015-06-13 12:38:46 Functions: 17 19 89.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11