LCOV - code coverage report
Current view: top level - libreoffice/sdext/source/pdfimport/xpdfwrapper - pnghelper.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 178 0.0 %
Date: 2012-12-27 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "pnghelper.hxx"
      21             : #include <sal/macros.h>
      22             : 
      23             : #ifdef SYSTEM_ZLIB
      24             : #include "zlib.h"
      25             : #else
      26             : #define ZLIB_INTERNAL 1
      27             : #include <zlib/zlib.h>
      28             : #endif
      29             : 
      30             : using namespace pdfi;
      31             : 
      32             : // checksum helpers, courtesy of libpng.org
      33             : 
      34             : /* Table of CRCs of all 8-bit messages. */
      35             : sal_uInt32 PngHelper::crc_table[256];
      36             : 
      37             : /* Flag: has the table been computed? Initially false. */
      38             : bool PngHelper::bCRCTableInit = true;
      39             : 
      40             : /* Make the table for a fast CRC. */
      41           0 : void PngHelper::initCRCTable()
      42             : {
      43           0 :     for (sal_uInt32 n = 0; n < 256; n++)
      44             :     {
      45           0 :         sal_uInt32 c = n;
      46           0 :         for (int k = 0; k < 8; k++)
      47             :         {
      48           0 :             if (c & 1)
      49           0 :                 c = 0xedb88320L ^ (c >> 1);
      50             :             else
      51           0 :                 c = c >> 1;
      52             :         }
      53           0 :         crc_table[n] = c;
      54             :     }
      55           0 :     bCRCTableInit = false;
      56           0 : }
      57             : 
      58             : /* Update a running CRC with the bytes buf[0..len-1]--the CRC
      59             :   should be initialized to all 1's, and the transmitted value
      60             :   is the 1's complement of the final running CRC (see the
      61             :   crc() routine below)). */
      62             : 
      63           0 : void PngHelper::updateCRC( sal_uInt32& io_rCRC, const sal_uInt8* i_pBuf, size_t i_nLen )
      64             : {
      65           0 :     if( bCRCTableInit )
      66           0 :         initCRCTable();
      67             : 
      68           0 :     sal_uInt32 nCRC = io_rCRC;
      69           0 :     for( size_t n = 0; n < i_nLen; n++ )
      70           0 :         nCRC = crc_table[(nCRC ^ i_pBuf[n]) & 0xff] ^ (nCRC >> 8);
      71           0 :     io_rCRC = nCRC;
      72           0 : }
      73             : 
      74           0 : sal_uInt32 PngHelper::getCRC( const sal_uInt8* i_pBuf, size_t i_nLen )
      75             : {
      76           0 :     sal_uInt32 nCRC = 0xffffffff;
      77           0 :     updateCRC( nCRC, i_pBuf, i_nLen );
      78           0 :     return nCRC ^ 0xffffffff;
      79             : }
      80             : 
      81           0 : sal_uInt32 PngHelper::deflateBuffer( const Output_t* i_pBuf, size_t i_nLen, OutputBuffer& o_rOut )
      82             : {
      83           0 :     size_t nOrigSize = o_rOut.size();
      84             : 
      85             :     // prepare z stream
      86             :     z_stream aStream;
      87           0 :     aStream.zalloc  = Z_NULL;
      88           0 :     aStream.zfree   = Z_NULL;
      89           0 :     aStream.opaque  = Z_NULL;
      90           0 :     deflateInit( &aStream, Z_BEST_COMPRESSION );
      91           0 :     aStream.avail_in = uInt(i_nLen);
      92           0 :     aStream.next_in = (Bytef*)i_pBuf;
      93             : 
      94             :     sal_uInt8 aOutBuf[ 32768 ];
      95           0 :     do
      96             :     {
      97           0 :         aStream.avail_out = sizeof( aOutBuf );
      98           0 :         aStream.next_out = aOutBuf;
      99             : 
     100           0 :         if( deflate( &aStream, Z_FINISH ) == Z_STREAM_ERROR )
     101             :         {
     102           0 :             deflateEnd( &aStream );
     103             :             // scrao the data of this broken stream
     104           0 :             o_rOut.resize( nOrigSize );
     105           0 :             return 0;
     106             :         }
     107             : 
     108             :         // append compressed bytes
     109           0 :         sal_uInt32 nCompressedBytes = sizeof( aOutBuf ) - aStream.avail_out;
     110           0 :         if( nCompressedBytes )
     111           0 :             o_rOut.insert( o_rOut.end(), aOutBuf, aOutBuf+nCompressedBytes );
     112             : 
     113             :     } while( aStream.avail_out == 0 );
     114             : 
     115             :     // cleanup
     116           0 :     deflateEnd( &aStream );
     117             : 
     118           0 :     return sal_uInt32( o_rOut.size() - nOrigSize );
     119             : }
     120             : 
     121           0 : void PngHelper::appendFileHeader( OutputBuffer& o_rOutputBuf )
     122             : {
     123             :     static const unsigned char aHeader[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
     124             : 
     125           0 :     o_rOutputBuf.insert( o_rOutputBuf.end(), aHeader, aHeader + SAL_N_ELEMENTS(aHeader) );
     126           0 : }
     127             : 
     128           0 : size_t PngHelper::startChunk( const char* pChunkName, OutputBuffer& o_rOutputBuf )
     129             : {
     130           0 :     size_t nIndex = sal_uInt32( o_rOutputBuf.size() );
     131           0 :     o_rOutputBuf.insert( o_rOutputBuf.end(), 4, (Output_t)0 );
     132           0 :     o_rOutputBuf.push_back( pChunkName[0] );
     133           0 :     o_rOutputBuf.push_back( pChunkName[1] );
     134           0 :     o_rOutputBuf.push_back( pChunkName[2] );
     135           0 :     o_rOutputBuf.push_back( pChunkName[3] );
     136           0 :     return nIndex;
     137             : }
     138             : 
     139           0 : void PngHelper::set( sal_uInt32 i_nValue, OutputBuffer& o_rOutputBuf, size_t i_nIndex )
     140             : {
     141           0 :     o_rOutputBuf[ i_nIndex   ] = (i_nValue & 0xff000000) >> 24;
     142           0 :     o_rOutputBuf[ i_nIndex+1 ] = (i_nValue & 0x00ff0000) >> 16;
     143           0 :     o_rOutputBuf[ i_nIndex+2 ] = (i_nValue & 0x0000ff00) >> 8;
     144           0 :     o_rOutputBuf[ i_nIndex+3 ] = (i_nValue & 0x000000ff);
     145           0 : }
     146             : 
     147           0 : void PngHelper::endChunk( size_t nStart, OutputBuffer& o_rOutputBuf )
     148             : {
     149           0 :     if( nStart+8 > o_rOutputBuf.size() )
     150           0 :         return; // something broken is going on
     151             : 
     152             :     // update chunk length
     153           0 :     size_t nLen = o_rOutputBuf.size() - nStart;
     154           0 :     sal_uInt32 nDataLen = sal_uInt32(nLen)-8;
     155           0 :     set( nDataLen, o_rOutputBuf, nStart );
     156             : 
     157             :     // append chunk crc
     158           0 :     sal_uInt32 nChunkCRC = getCRC( (sal_uInt8*)&o_rOutputBuf[nStart+4], nLen-4 );
     159           0 :     append( nChunkCRC, o_rOutputBuf );
     160             : }
     161             : 
     162           0 : void PngHelper::appendIHDR( OutputBuffer& o_rOutputBuf, int width, int height, int depth, int colortype )
     163             : {
     164           0 :     size_t nStart = startChunk( "IHDR", o_rOutputBuf );
     165           0 :     append( width, o_rOutputBuf );
     166           0 :     append( height, o_rOutputBuf );
     167           0 :     o_rOutputBuf.push_back( Output_t(depth) );
     168           0 :     o_rOutputBuf.push_back( Output_t(colortype) );
     169           0 :     o_rOutputBuf.push_back( 0 ); // compression method deflate
     170           0 :     o_rOutputBuf.push_back( 0 ); // filtering method 0 (default)
     171           0 :     o_rOutputBuf.push_back( 0 ); // no interlacing
     172           0 :     endChunk( nStart, o_rOutputBuf );
     173           0 : }
     174             : 
     175           0 : void PngHelper::appendIEND( OutputBuffer& o_rOutputBuf )
     176             : {
     177           0 :     size_t nStart = startChunk( "IEND", o_rOutputBuf );
     178           0 :     endChunk( nStart, o_rOutputBuf );
     179           0 : }
     180             : 
     181           0 : void PngHelper::createPng( OutputBuffer&     o_rOutputBuf,
     182             :                            Stream*           str,
     183             :                            int               width,
     184             :                            int               height,
     185             :                            GfxRGB&           zeroColor,
     186             :                            GfxRGB&           oneColor,
     187             :                            bool              bIsMask
     188             :                            )
     189             : {
     190           0 :     appendFileHeader( o_rOutputBuf );
     191           0 :     appendIHDR( o_rOutputBuf, width, height, 1, 3 );
     192             : 
     193             :     // write palette
     194           0 :     size_t nIdx = startChunk( "PLTE", o_rOutputBuf );
     195             :     // write colors 0 and 1
     196           0 :     o_rOutputBuf.push_back(colToByte(zeroColor.r));
     197           0 :     o_rOutputBuf.push_back(colToByte(zeroColor.g));
     198           0 :     o_rOutputBuf.push_back(colToByte(zeroColor.b));
     199           0 :     o_rOutputBuf.push_back(colToByte(oneColor.r));
     200           0 :     o_rOutputBuf.push_back(colToByte(oneColor.g));
     201           0 :     o_rOutputBuf.push_back(colToByte(oneColor.b));
     202             :     // end PLTE chunk
     203           0 :     endChunk( nIdx, o_rOutputBuf );
     204             : 
     205           0 :     if( bIsMask )
     206             :     {
     207             :         // write tRNS chunk
     208           0 :         nIdx = startChunk( "tRNS", o_rOutputBuf );
     209           0 :         o_rOutputBuf.push_back( 0xff );
     210           0 :         o_rOutputBuf.push_back( 0 );
     211             :         // end tRNS chunk
     212           0 :         endChunk( nIdx, o_rOutputBuf );
     213             :     }
     214             : 
     215             :     // create scan line data buffer
     216           0 :     OutputBuffer aScanlines;
     217           0 :     int nLineSize = (width + 7)/8;
     218           0 :     aScanlines.reserve( nLineSize * height + height );
     219             : 
     220           0 :     str->reset();
     221           0 :     for( int y = 0; y < height; y++ )
     222             :     {
     223             :         // determine filter type (none) for this scanline
     224           0 :         aScanlines.push_back( 0 );
     225           0 :         for( int x = 0; x < nLineSize; x++ )
     226           0 :             aScanlines.push_back( str->getChar() );
     227             :     }
     228             : 
     229             :     // begin IDAT chunk for scanline data
     230           0 :     nIdx = startChunk( "IDAT", o_rOutputBuf );
     231             :     // compress scanlines
     232           0 :     deflateBuffer( &aScanlines[0], aScanlines.size(), o_rOutputBuf );
     233             :     // end IDAT chunk
     234           0 :     endChunk( nIdx, o_rOutputBuf );
     235             : 
     236             :     // output IEND
     237           0 :     appendIEND( o_rOutputBuf );
     238           0 : }
     239             : 
     240           0 : void PngHelper::createPng( OutputBuffer& o_rOutputBuf,
     241             :                            Stream* str,
     242             :                            int width, int height, GfxImageColorMap* colorMap,
     243             :                            Stream* maskStr,
     244             :                            int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap )
     245             : {
     246           0 :     appendFileHeader( o_rOutputBuf );
     247           0 :     appendIHDR( o_rOutputBuf, width, height, 8, 6 ); // RGBA image
     248             : 
     249             :     // initialize stream
     250             :     Guchar *p, *pm;
     251             :     GfxRGB rgb;
     252             :     GfxGray alpha;
     253             :     ImageStream* imgStr =
     254             :         new ImageStream(str,
     255             :                         width,
     256             :                         colorMap->getNumPixelComps(),
     257           0 :                         colorMap->getBits());
     258           0 :     imgStr->reset();
     259             : 
     260             :     // create scan line data buffer
     261           0 :     OutputBuffer aScanlines;
     262           0 :     aScanlines.reserve( width*height*4 + height );
     263             : 
     264           0 :     for( int y=0; y<height; ++y)
     265             :     {
     266           0 :         aScanlines.push_back( 0 );
     267           0 :         p = imgStr->getLine();
     268           0 :         for( int x=0; x<width; ++x)
     269             :         {
     270           0 :             colorMap->getRGB(p, &rgb);
     271           0 :             aScanlines.push_back(colToByte(rgb.r));
     272           0 :             aScanlines.push_back(colToByte(rgb.g));
     273           0 :             aScanlines.push_back(colToByte(rgb.b));
     274           0 :             aScanlines.push_back( 0xff );
     275             : 
     276           0 :             p +=colorMap->getNumPixelComps();
     277             :         }
     278             :     }
     279             : 
     280             : 
     281             :     // now fill in the mask data
     282             : 
     283             :     // CAUTION: originally this was done in one single loop
     284             :     // it caused merry chaos; the reason is that maskStr and str are
     285             :     // not independent streams, it happens that reading one advances
     286             :     // the other, too. Hence the two passes are imperative !
     287             : 
     288             :     // initialize mask stream
     289             :     ImageStream* imgStrMask =
     290             :         new ImageStream(maskStr,
     291             :                         maskWidth,
     292             :                         maskColorMap->getNumPixelComps(),
     293           0 :                         maskColorMap->getBits());
     294             : 
     295           0 :     imgStrMask->reset();
     296           0 :     for( int y = 0; y < maskHeight; ++y )
     297             :     {
     298           0 :         pm = imgStrMask->getLine();
     299           0 :         for( int x = 0; x < maskWidth; ++x )
     300             :         {
     301           0 :             maskColorMap->getGray(pm,&alpha);
     302           0 :             pm += maskColorMap->getNumPixelComps();
     303             :             int nIndex = (y*height/maskHeight) * (width*4+1) + // mapped line
     304           0 :                          (x*width/maskWidth)*4 + 1  + 3        // mapped column
     305             :                          ;
     306           0 :             aScanlines[ nIndex ] = colToByte(alpha);
     307             :         }
     308             :     }
     309             : 
     310           0 :     delete imgStr;
     311           0 :     delete imgStrMask;
     312             : 
     313             :     // begind IDAT chunk for scanline data
     314           0 :     size_t nIdx = startChunk( "IDAT", o_rOutputBuf );
     315             :     // compress scanlines
     316           0 :     deflateBuffer( &aScanlines[0], aScanlines.size(), o_rOutputBuf );
     317             :     // end IDAT chunk
     318           0 :     endChunk( nIdx, o_rOutputBuf );
     319             :     // output IEND
     320           0 :     appendIEND( o_rOutputBuf );
     321           0 : }
     322             : 
     323             : // one bit mask; 0 bits opaque
     324           0 : void PngHelper::createPng( OutputBuffer& o_rOutputBuf,
     325             :                            Stream* str,
     326             :                            int width, int height, GfxImageColorMap* colorMap,
     327             :                            Stream* maskStr,
     328             :                            int maskWidth, int maskHeight,
     329             :                            bool maskInvert
     330             :                           )
     331             : {
     332           0 :     appendFileHeader( o_rOutputBuf );
     333           0 :     appendIHDR( o_rOutputBuf, width, height, 8, 6 ); // RGBA image
     334             : 
     335             :     // initialize stream
     336             :     Guchar *p;
     337             :     GfxRGB rgb;
     338             :     ImageStream* imgStr =
     339             :         new ImageStream(str,
     340             :                         width,
     341             :                         colorMap->getNumPixelComps(),
     342           0 :                         colorMap->getBits());
     343           0 :     imgStr->reset();
     344             : 
     345             :     // create scan line data buffer
     346           0 :     OutputBuffer aScanlines;
     347           0 :     aScanlines.reserve( width*height*4 + height );
     348             : 
     349           0 :     for( int y=0; y<height; ++y)
     350             :     {
     351           0 :         aScanlines.push_back( 0 );
     352           0 :         p = imgStr->getLine();
     353           0 :         for( int x=0; x<width; ++x)
     354             :         {
     355           0 :             colorMap->getRGB(p, &rgb);
     356           0 :             aScanlines.push_back(colToByte(rgb.r));
     357           0 :             aScanlines.push_back(colToByte(rgb.g));
     358           0 :             aScanlines.push_back(colToByte(rgb.b));
     359           0 :             aScanlines.push_back( 0xff );
     360             : 
     361           0 :             p +=colorMap->getNumPixelComps();
     362             :         }
     363             :     }
     364             : 
     365             : 
     366             :     // now fill in the mask data
     367             : 
     368             :     // CAUTION: originally this was done in one single loop
     369             :     // it caused merry chaos; the reason is that maskStr and str are
     370             :     // not independent streams, it happens that reading one advances
     371             :     // the other, too. Hence the two passes are imperative !
     372             : 
     373             :     // initialize mask stream
     374             :     ImageStream* imgStrMask =
     375           0 :         new ImageStream(maskStr, maskWidth, 1, 1);
     376             : 
     377           0 :     imgStrMask->reset();
     378           0 :     for( int y = 0; y < maskHeight; ++y )
     379             :     {
     380           0 :         for( int x = 0; x < maskWidth; ++x )
     381             :         {
     382           0 :             Guchar aPixel = 0;
     383           0 :             imgStrMask->getPixel( &aPixel );
     384             :             int nIndex = (y*height/maskHeight) * (width*4+1) + // mapped line
     385           0 :                          (x*width/maskWidth)*4 + 1  + 3        // mapped column
     386             :                          ;
     387           0 :             if( maskInvert )
     388           0 :                 aScanlines[ nIndex ] = aPixel ? 0xff : 0x00;
     389             :             else
     390           0 :                 aScanlines[ nIndex ] = aPixel ? 0x00 : 0xff;
     391             :         }
     392             :     }
     393             : 
     394           0 :     delete imgStr;
     395           0 :     delete imgStrMask;
     396             : 
     397             :     // begind IDAT chunk for scanline data
     398           0 :     size_t nIdx = startChunk( "IDAT", o_rOutputBuf );
     399             :     // compress scanlines
     400           0 :     deflateBuffer( &aScanlines[0], aScanlines.size(), o_rOutputBuf );
     401             :     // end IDAT chunk
     402           0 :     endChunk( nIdx, o_rOutputBuf );
     403             :     // output IEND
     404           0 :     appendIEND( o_rOutputBuf );
     405           0 : }
     406             : 
     407             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10