summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorVladimir Glazounov <vg@openoffice.org>2006-09-08 07:39:15 +0000
committerVladimir Glazounov <vg@openoffice.org>2006-09-08 07:39:15 +0000
commit24c96ce397cbe00bc9e56571c98bd35b371dd5cc (patch)
tree4a3de38792feebc93da9831320960139a78319a4 /vcl
parentf31f3b2ad85d73ebd9e5be4e9f778bdc7b48075a (diff)
INTEGRATION: CWS pngperf (1.10.18); FILE MERGED
2006/08/18 14:41:34 hdu 1.10.18.27: #i67660# rename ambiguous mn*Depth members 2006/08/18 14:37:07 hdu 1.10.18.26: #i67660# fix 2bit palette import, adjust gamma constants 2006/08/18 09:52:02 hdu 1.10.18.25: #i54953# finish resync to SRC680m181, fix 16bit-alpha case 2006/08/16 14:43:45 hdu 1.10.18.24: RESYNC: remove double-merged code, nXpos==0 for nPass==7 2006/08/15 15:24:56 hdu 1.10.18.23: RESYNC: remove warning on wntmsci10.pro 2006/08/15 11:17:24 hdu 1.10.18.22: RESYNC: remove g++ 3.4.1 warnings after resync 2006/08/15 10:22:19 hdu 1.10.18.21: RESYNC: adjust to identifier renamings in HEAD fixes 2006/08/14 19:54:07 hdu 1.10.18.20: RESYNC: (1.13-1.17); FILE MERGED 2006/07/11 13:21:58 sj 1.10.18.19: #128377# removed chunk len fix which is no longer necessary 2006/02/23 10:31:46 hdu 1.10.18.18: ##128377# more sanity checks for chunk length 2005/12/14 17:57:13 radekdoulik 1.10.18.17: Issue number: #55174 Submitted by: radekdoulik Reviewed by: hdu - make it possible to request preview sizes of widthx0 or 0xheight, where the other parameter is computed using original size aspect ratio (in png reader) - fix preview of some interlaced png's (it is not possible to copy whole scanline when we are reading preview with width smaller than original width) 2005/12/01 12:17:47 hdu 1.10.18.16: #128377# chunk length is unsigned 2005/12/01 11:44:40 hdu 1.10.18.15: #128377# workaround bad chunk lengths crashing the memory allocator 2005/11/15 09:59:48 hdu 1.10.18.14: RESYNC: (1.10-1.12); FILE MERGED 2005/10/26 11:50:11 hdu 1.10.18.13: #i55174# set image source size 2005/10/14 11:32:35 hdu 1.10.18.12: #i55174# fix off by one for partially read files 2005/10/06 14:25:05 hdu 1.10.18.11: #i55174# no need to read an image stream after enough of the image has been read 2005/09/30 15:16:12 hdu 1.10.18.10: #i55174# 101 2005/09/30 13:24:02 hdu 1.10.18.9: #i55174# replace preview scaledown division by shift 2005/09/29 08:45:06 hdu 1.10.18.8: #i55174# for image preview allow skipping of passes for interlaced PNGs 2005/09/28 14:37:37 hdu 1.10.18.7: #i55174# starting PNG preview implementation 2005/09/27 08:27:43 hdu 1.10.18.6: #i54953# avoid transparency mask for opaque PNGs 2005/09/26 15:35:29 hdu 1.10.18.5: #i54953# prepare delayed transparency mask creation, get rid of full repaint on intermediate passes 2005/09/23 15:01:45 hdu 1.10.18.4: #i54953# split up Scanline filter method, fix progressive 2005/09/23 12:22:27 hdu 1.10.18.3: #i54953# more optimization for intermediate passes and inner scanline filter loops 2005/09/22 15:17:32 hdu 1.10.18.2: #i54953# skip bitmap buffer update in intermediate passes, more cleanup 2005/09/22 14:38:01 hdu 1.10.18.1: #i54953# first cleanup and reduce lifetime of vars
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/gdi/pngread.cxx1621
1 files changed, 775 insertions, 846 deletions
diff --git a/vcl/source/gdi/pngread.cxx b/vcl/source/gdi/pngread.cxx
index 92f85fb24425..a561fa18022a 100644
--- a/vcl/source/gdi/pngread.cxx
+++ b/vcl/source/gdi/pngread.cxx
@@ -4,9 +4,9 @@
*
* $RCSfile: pngread.cxx,v $
*
- * $Revision: 1.18 $
+ * $Revision: 1.19 $
*
- * last change: $Author: ihi $ $Date: 2006-08-22 13:51:19 $
+ * last change: $Author: vg $ $Date: 2006-09-08 08:39:15 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
@@ -69,10 +69,8 @@
#define PNGCHUNK_zTXt 0x7a545874
#define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
-#define PNG_TRANS_VAL 0x1
-
-#define VIEWING_GAMMA 2.5
-#define DISPLAY_GAMMA 1.25
+#define VIEWING_GAMMA 2.35
+#define DISPLAY_GAMMA 1.0
namespace vcl
{
@@ -80,18 +78,6 @@ namespace vcl
// - statics -
// -----------
-static const BYTE aBlockHeight[ 8 ] =
-{
- 0, 8, 8, 4, 4, 2, 2, 1
-};
-
-// ------------------------------------------------------------------------------
-
-static const BYTE aBlockWidth[ 8 ] =
-{
- 0, 8, 4, 4, 2, 2, 1, 1
-};
-
// ------------------------------------------------------------------------------
static const BYTE mpDefaultColorTable[ 256 ] =
@@ -113,73 +99,19 @@ static const BYTE mpDefaultColorTable[ 256 ] =
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
-/* ------------------------------------------------------------------------
- SJ: InitChunkSeq reads all PNG chunks. The rStm stream position will be at
- the end of the file afterwards.
-*/
-const sal_Bool InitChunkSeq( SvStream& rStm, std::vector< vcl::PNGReader::ChunkData >& rChunkSeq )
-{
- sal_Bool bRet = sal_True;
- sal_uInt16 nIStmOldMode = rStm.GetNumberFormatInt();
- rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
-
- // check PNG file header magic number
- sal_uInt32 nDummy[ 2 ] = {0, 0};
- rStm >> nDummy[0] >> nDummy[1];
- if( ( nDummy[0] != 0x89504e47 ) || ( nDummy[1] != 0x0d0a1a0a ) )
- bRet = sal_False;
- else
- {
- sal_uInt32 nChunkLen, nCRC32, nCheck, nType = 0;
- while( !rStm.IsEof() && ( rStm.GetError() == ERRCODE_NONE ) )
- {
- rChunkSeq.resize( rChunkSeq.size() + 1 );
- vcl::PNGReader::ChunkData& rChunkData = rChunkSeq.back();
- rStm >> nChunkLen
- >> nType;
-
- rChunkData.nType = nType;
- #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
- nType = SWAPLONG( nType );
- #endif
- nCRC32 = rtl_crc32( 0, &nType, 4 );
- if ( nChunkLen && !rStm.IsEof() )
- {
- rChunkData.aData.resize( nChunkLen );
- sal_uInt8* pPtr = &rChunkData.aData[ 0 ];
- rStm.Read( pPtr, nChunkLen );
- nCRC32 = rtl_crc32( nCRC32, pPtr, nChunkLen );
- }
- rStm >> nCheck;
-
- if ( rChunkData.nType == PNGCHUNK_IEND ) // SJ: not checking crc for the IEND chunk
- break; // because of I25246
-
- if ( nCRC32 != nCheck )
- {
- bRet = sal_False;
- break;
- }
- }
- if ( !rChunkSeq.size() || ( rChunkSeq[ 0 ].nType != PNGCHUNK_IHDR ) )
- bRet = sal_False;
- }
- rStm.SetNumberFormatInt( nIStmOldMode );
- return bRet;
-}
-
// -------------
// - PNGReaderImpl -
// -------------
class PNGReaderImpl
{
- friend class vcl::PNGReader;
+private:
+ SvStream& mrPNGStream;
+ sal_uInt16 mnOrigStreamMode;
std::vector< vcl::PNGReader::ChunkData > maChunkSeq;
+ std::vector< vcl::PNGReader::ChunkData >::iterator maChunkIter;
std::vector< sal_uInt8 >::iterator maDataIter;
- std::vector< sal_uInt8 >::iterator maDataEnd;
- sal_Int32 mnChunkLen;
Bitmap* mpBmp;
BitmapWriteAccess* mpAcc;
@@ -188,70 +120,83 @@ class PNGReaderImpl
BitmapWriteAccess* mpMaskAcc;
ZCodec* mpZCodec;
BYTE* mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
- BYTE* mpScanprior; // pointer to the latest scanline
- BYTE* mpTransTab; //
- BYTE* mpScan; // pointer in the current scanline
+ BYTE* mpScanPrior; // pointer to the latest scanline
+ BYTE* mpTransTab; // for transparency in images with palette colortype
+ BYTE* mpScanCurrent; // pointer into the current scanline
BYTE* mpColorTable; //
- sal_uInt32 mnChunkType; // Chunk which is currently open
- sal_uInt32 mnWidth;
- sal_uInt32 mnHeight;
- sal_uInt32 mnBBP; // number of bytes per pixel
+ sal_Size mnStreamSize; // estimate of PNG file size
+ sal_uInt32 mnChunkType; // Type of current PNG chunk
+ sal_uInt32 mnChunkLen; // Length of current PNG chunk
+ Size maOrigSize; // pixel size of the full image
+ Size maTargetSize; // pixel size of the result image
+ Size maPhysSize; // prefered size in MAP_100TH_MM units
+ sal_uInt32 mnBPP; // number of bytes per pixel
sal_uInt32 mnScansize; // max size of scanline
- sal_uInt32 mnPrefWidth; // preferred width in meter
- sal_uInt32 mnPrefHeight; // preferred Height in meter
- sal_uInt32 mnYpos; // latest y position;
+ sal_uInt32 mnYpos; // latest y position in full image
+ int mnPass; // if interlaced the latest pass ( 1..7 ) else 7
+ sal_uInt32 mnXStart; // the starting X for the current pass
+ sal_uInt32 mnXAdd; // the increment for input images X coords for the current pass
+ sal_uInt32 mnYAdd; // the increment for input images Y coords for the current pass
+ int mnPreviewShift; // shift to convert orig image coords into preview image coords
+ int mnPreviewMask; // == ((1 << mnPreviewShift) - 1)
USHORT mnIStmOldMode;
- USHORT mnDepth; // pixel depth
+ USHORT mnTargetDepth; // pixel depth of target bitmap
BYTE mnTransRed;
BYTE mnTransGreen;
BYTE mnTransBlue;
- BYTE mnBitDepth; // sample depth
+ BYTE mnPngDepth; // pixel depth of PNG data
BYTE mnColorType;
BYTE mnCompressionType;
BYTE mnFilterType;
BYTE mnInterlaceType;
- BYTE mnPass; // if interlaced the latest pass ( 1..7 ) else 7
- BYTE cTransIndex1;
- BYTE cNonTransIndex1;
- BOOL mbStatus;
+ BitmapColor mcTranspColor; // transparency mask's transparency "color"
+ BitmapColor mcOpaqueColor; // transparency mask's opaque "color"
BOOL mbTransparent; // graphic includes an tRNS Chunk or an alpha Channel
BOOL mbAlphaChannel; // is true for ColorType 4 and 6
BOOL mbRGBTriple;
BOOL mbPalette; // FALSE if we need a Palette
BOOL mbGrayScale;
BOOL mbzCodecInUse;
- BOOL mbIDAT; // TRUE if finished with the complete IDAT...
+ BOOL mbStatus;
+ BOOL mbIDAT; // TRUE if finished with enough IDAT chunks
BOOL mbGamma; // TRUE if Gamma Correction available
BOOL mbpHYs; // TRUE if pysical size of pixel available
- void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex );
+ bool ReadNextChunk();
+ void ReadRemainingChunks();
+ void SkipRemainingChunks();
+
void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
- void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, BOOL bTrans );
+ void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex );
+ void ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, BOOL bTrans );
void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex, BYTE nAlpha );
void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, BYTE nAlpha );
void ImplReadIDAT();
- void ImplResizeScanline();
- void ImplGetFilter( sal_uInt32 nXStart=0, sal_uInt32 nXAdd=1 );
- void ImplReadTransparent();
+ bool ImplPreparePass();
+ void ImplApplyFilter();
+ void ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
+ BOOL ImplReadTransparent();
void ImplGetGamma();
void ImplGetBackground();
BYTE ImplScaleColor();
- BOOL ImplReadHeader();
+ BOOL ImplReadHeader( const Size& rPreviewSizeHint );
BOOL ImplReadPalette();
void ImplGetGrayPalette( sal_uInt16 );
sal_uInt32 ImplReadsal_uInt32();
public:
- PNGReaderImpl( SvStream& rStm );
- ~PNGReaderImpl();
+ PNGReaderImpl( SvStream& );
+ ~PNGReaderImpl();
- BitmapEx Read();
+ BitmapEx GetBitmapEx( const Size& rPreviewSizeHint );
+ const std::vector< PNGReader::ChunkData >& GetAllChunks();
};
// ------------------------------------------------------------------------------
-PNGReaderImpl::PNGReaderImpl( SvStream& rPNG ) :
+PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
+: mrPNGStream( rPNGStream ),
mpBmp ( NULL ),
mpAcc ( NULL ),
mpMaskBmp ( NULL ),
@@ -259,56 +204,173 @@ PNGReaderImpl::PNGReaderImpl( SvStream& rPNG ) :
mpMaskAcc ( NULL ),
mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
mpInflateInBuf ( NULL ),
- mpScanprior ( NULL ),
+ mpScanPrior ( NULL ),
mpTransTab ( NULL ),
mpColorTable ( (sal_uInt8*) mpDefaultColorTable ),
mbzCodecInUse ( sal_False ),
+ mbStatus( TRUE),
+ mbIDAT( FALSE ),
mbGamma ( sal_False ),
mbpHYs ( sal_False )
{
- mbStatus = InitChunkSeq( rPNG, maChunkSeq );
+ // prepare the PNG data stream
+ mnOrigStreamMode = mrPNGStream.GetNumberFormatInt();
+ mrPNGStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
+
+ // prepare the chunk reader
+ maChunkSeq.reserve( 16 );
+ maChunkIter = maChunkSeq.begin();
+
+ // estimate PNG file size (to allow sanity checks)
+ const sal_Size nStreamPos = mrPNGStream.Tell();
+ mrPNGStream.Seek( STREAM_SEEK_TO_END );
+ mnStreamSize = mrPNGStream.Tell();
+ mrPNGStream.Seek( nStreamPos );
+
+ // check the PNG header magic
+ sal_uInt32 nDummy = 0;
+ mrPNGStream >> nDummy;
+ mbStatus = (nDummy == 0x89504e47);
+ mrPNGStream >> nDummy;
+ mbStatus &= (nDummy == 0x0d0a1a0a);
+
+ mnPreviewShift = 0;
+ mnPreviewMask = (1 << mnPreviewShift) - 1;
}
// ------------------------------------------------------------------------
PNGReaderImpl::~PNGReaderImpl()
{
+ mrPNGStream.SetNumberFormatInt( mnOrigStreamMode );
+
if ( mbzCodecInUse )
mpZCodec->EndCompression();
if( mpColorTable != mpDefaultColorTable )
delete[] mpColorTable;
- rtl_freeMemory( mpScanprior );
-
delete mpBmp;
delete mpAlphaMask;
delete mpMaskBmp;
delete[] mpTransTab;
delete[] mpInflateInBuf;
+ delete[] mpScanPrior;
delete mpZCodec;
}
// ------------------------------------------------------------------------
-BitmapEx PNGReaderImpl::Read()
+bool PNGReaderImpl::ReadNextChunk()
{
- BitmapEx aRet;
+ if( maChunkIter == maChunkSeq.end() )
+ {
+ // get the next chunk from the stream
+
+ // unless we are at the end of the PNG stream
+ if( mrPNGStream.IsEof() || (mrPNGStream.GetError() != ERRCODE_NONE) )
+ return false;
+ if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
+ return false;
+
+ PNGReader::ChunkData aDummyChunk;
+ maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
+ PNGReader::ChunkData& rChunkData = *maChunkIter;
+
+ // read the chunk header
+ mrPNGStream >> mnChunkLen >> mnChunkType;
+ rChunkData.nType = mnChunkType;
+
+ // #128377# sanity check for chunk length
+ const sal_Size nStreamPos = mrPNGStream.Tell();
+ if( nStreamPos + mnChunkLen >= mnStreamSize )
+ return false;
+
+ // calculate chunktype CRC (swap it back to original byte order)
+ sal_uInt32 nChunkType = mnChunkType;;
+ #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
+ nChunkType = SWAPLONG( nChunkType );
+ #endif
+ sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
+
+ // read the chunk data and check the CRC
+ if( mnChunkLen && !mrPNGStream.IsEof() )
+ {
+ rChunkData.aData.resize( mnChunkLen );
+ sal_uInt8* pPtr = &rChunkData.aData[ 0 ];
+ mrPNGStream.Read( pPtr, mnChunkLen );
+ nCRC32 = rtl_crc32( nCRC32, pPtr, mnChunkLen );
+ maDataIter = rChunkData.aData.begin();
+ }
+ sal_uInt32 nCheck;
+ mrPNGStream >> nCheck;
+ if( nCRC32 != nCheck )
+ return false;
+ }
+ else
+ {
+ // the next chunk was already read
+ mnChunkType = (*maChunkIter).nType;
+ mnChunkLen = (*maChunkIter).aData.size();
+ maDataIter = (*maChunkIter).aData.begin();
+ }
- std::vector< vcl::PNGReader::ChunkData >::iterator aIter( maChunkSeq.begin() );
- std::vector< vcl::PNGReader::ChunkData >::iterator aEnd ( maChunkSeq.end() );
+ ++maChunkIter;
+ if( mnChunkType == PNGCHUNK_IEND )
+ return false;
+ return true;
+}
+
+// ------------------------------------------------------------------------
- while( mbStatus && ( aIter != aEnd ) && ( aIter->nType != PNGCHUNK_IEND ) )
+// read the remaining chunks from mrPNGStream
+void PNGReaderImpl::ReadRemainingChunks()
+{
+ while( ReadNextChunk() );
+}
+
+// ------------------------------------------------------------------------
+
+// move position of mrPNGStream to the end of the file
+void PNGReaderImpl::SkipRemainingChunks()
+{
+ // nothing to skip if the last chunk was read
+ if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
+ return;
+
+ // read from the stream until the IEND chunk is found
+ while( !mrPNGStream.IsEof() && (mrPNGStream.GetError() == ERRCODE_NONE) )
{
- maDataIter = aIter->aData.begin();
- maDataEnd = aIter->aData.end();
- mnChunkLen = aIter->aData.size();
+ mrPNGStream >> mnChunkLen >> mnChunkType;
+ mrPNGStream.SeekRel( mnChunkLen + 4 ); // skip data + CRC
+ if( mnChunkType == PNGCHUNK_IEND )
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
+{
+ ReadRemainingChunks();
+ return maChunkSeq;
+}
- switch ( aIter->nType )
+// ------------------------------------------------------------------------
+
+BitmapEx PNGReaderImpl::GetBitmapEx( const Size& rPreviewSizeHint )
+{
+ // reset to the first chunk
+ maChunkIter = maChunkSeq.begin();
+
+ // parse the chunks
+ while( mbStatus && !mbIDAT && ReadNextChunk() )
+ {
+ switch( mnChunkType )
{
case PNGCHUNK_IHDR :
{
- mbStatus = ImplReadHeader();
+ mbStatus = ImplReadHeader( rPreviewSizeHint );
}
break;
@@ -329,7 +391,7 @@ BitmapEx PNGReaderImpl::Read()
case PNGCHUNK_tRNS :
{
if ( !mbIDAT ) // the tRNS chunk must precede the IDAT
- ImplReadTransparent();
+ mbStatus = ImplReadTransparent();
}
break;
@@ -351,19 +413,29 @@ BitmapEx PNGReaderImpl::Read()
{
if ( !mbIDAT && mnChunkLen == 9 )
{
- mnPrefWidth = ImplReadsal_uInt32();
- mnPrefHeight= ImplReadsal_uInt32();
+ sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
+ sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
sal_uInt8 nUnitSpecifier = *maDataIter++;
-
- if ( nUnitSpecifier == 1 )
+ if( (nUnitSpecifier == 1) && nXPixelPerMeter && nXPixelPerMeter )
+ {
mbpHYs = sal_True;
+
+ // convert into MAP_100TH_MM
+ maPhysSize.Width() = (sal_Int32)( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter );
+ maPhysSize.Height() = (sal_Int32)( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter );
+ }
}
}
break;
+
+ case PNGCHUNK_IEND:
+ mbStatus = mbIDAT; // there is a problem if the image is not complete yet
+ break;
}
- aIter++;
}
+
+ // release write access of the bitmaps
if ( mpAcc )
mpBmp->ReleaseAccess( mpAcc ), mpAcc = NULL;
@@ -377,7 +449,12 @@ BitmapEx PNGReaderImpl::Read()
mpMaskAcc = NULL;
}
- if ( mbStatus )
+ // return the resulting BitmapEx
+ BitmapEx aRet;
+
+ if( !mbStatus || !mbIDAT )
+ aRet.Clear();
+ else
{
if ( mpAlphaMask )
aRet = BitmapEx( *mpBmp, *mpAlphaMask );
@@ -386,69 +463,76 @@ BitmapEx PNGReaderImpl::Read()
else
aRet = *mpBmp;
- if ( mbpHYs && mnPrefWidth && mnPrefHeight )
+ if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
{
- sal_Int32 nPrefSizeX = (sal_Int32)( 100000.0 * ( (double)mnWidth / mnPrefWidth ) );
- sal_Int32 nPrefSizeY = (sal_Int32)( 100000.0 * ( (double)mnHeight / mnPrefHeight ) );
-
aRet.SetPrefMapMode( MAP_100TH_MM );
- aRet.SetPrefSize( Size( nPrefSizeX, nPrefSizeY ) );
+ aRet.SetPrefSize( maPhysSize );
}
+
+#if 0
+ // TODO: make sure nobody depends on the stream being after the IEND chunks
+ // => let them do ReadChunks before
+ ReadRemainingChunks();
+#endif
}
- if( !mbStatus )
- aRet.Clear();
return aRet;
}
// ------------------------------------------------------------------------
-BOOL PNGReaderImpl::ImplReadHeader()
+BOOL PNGReaderImpl::ImplReadHeader( const Size& rPreviewSizeHint )
{
- mnWidth = ImplReadsal_uInt32();
- mnHeight = ImplReadsal_uInt32();
+ maOrigSize.Width() = ImplReadsal_uInt32();
+ maOrigSize.Height() = ImplReadsal_uInt32();
- if ( ( mnWidth == 0 ) || ( mnHeight == 0 ) )
+ if ( !maOrigSize.Width() || !maOrigSize.Height() )
return FALSE;
- mnBitDepth = *maDataIter++;
- mnColorType = *maDataIter++;
+ mnPngDepth = *(maDataIter++);
+ mnColorType = *(maDataIter++);
- if ( (mnCompressionType = *maDataIter++) != 0 )
+ mnCompressionType = *(maDataIter++);
+ if( mnCompressionType != 0 ) // unknown compression type
return FALSE;
- if ( (mnFilterType = *maDataIter++) != 0 )
+ mnFilterType = *(maDataIter++);
+ if( mnFilterType != 0 ) // unknown filter type
return FALSE;
- switch ( mnInterlaceType = *maDataIter++ ) // filter type valid ?
+ mnInterlaceType = *(maDataIter++);
+ switch ( mnInterlaceType ) // filter type valid ?
{
- case 0 :
+ case 0 : // progressive image
mnPass = 7;
break;
- case 1 :
+ case 1 : // Adam7-interlaced image
mnPass = 0;
break;
default:
return FALSE;
}
- mnYpos = 0;
+
mbPalette = TRUE;
mbIDAT = mbAlphaChannel = mbTransparent = FALSE;
mbGrayScale = mbRGBTriple = FALSE;
- mnDepth = mnBitDepth;
- mnScansize = ( ( mnWidth * mnBitDepth ) + 7 ) >> 3;
+ mnTargetDepth = mnPngDepth;
+ mnScansize = ( ( maOrigSize.Width() * mnPngDepth ) + 7 ) >> 3;
// valid color types are 0,2,3,4 & 6
switch ( mnColorType )
{
case 0 : // each pixel is a grayscale
{
- switch ( mnBitDepth )
+ switch ( mnPngDepth )
{
- case 2 :
- mnDepth = 8; // we have to expand the bitmap
+ case 2 : // 2bit target not available -> use four bits
+ mnTargetDepth = 4; // we have to expand the bitmap
+ mbGrayScale = TRUE;
+ break;
case 16 :
- mnDepth >>= 1; // we have to reduce the bitmap
+ mnTargetDepth = 8; // we have to reduce the bitmap
+ // fall through
case 1 :
case 4 :
case 8 :
@@ -463,12 +547,12 @@ BOOL PNGReaderImpl::ImplReadHeader()
case 2 : // each pixel is an RGB triple
{
mbRGBTriple = TRUE;
- mnScansize*=3;
- switch ( mnBitDepth )
+ mnScansize *= 3;
+ switch ( mnPngDepth )
{
case 16 : // we have to reduce the bitmap
case 8 :
- mnDepth = 24;
+ mnTargetDepth = 24;
break;
default :
return FALSE;
@@ -478,10 +562,11 @@ BOOL PNGReaderImpl::ImplReadHeader()
case 3 : // each pixel is a palette index
{
- switch ( mnBitDepth )
+ switch ( mnPngDepth )
{
case 2 :
- mnDepth = 4; // we have to expand the bitmap
+ mnTargetDepth = 4; // we have to expand the bitmap
+ // fall through
case 1 :
case 4 :
case 8 :
@@ -495,12 +580,12 @@ BOOL PNGReaderImpl::ImplReadHeader()
case 4 : // each pixel is a grayscale sample followed by an alpha sample
{
- mnScansize <<= 1;
+ mnScansize *= 2;
mbAlphaChannel = TRUE;
- switch ( mnBitDepth )
+ switch ( mnPngDepth )
{
case 16 :
- mnDepth >>= 1; // we have to reduce the bitmap
+ mnTargetDepth = 8; // we have to reduce the bitmap
case 8 :
mbGrayScale = TRUE;
break;
@@ -513,13 +598,13 @@ BOOL PNGReaderImpl::ImplReadHeader()
case 6 : // each pixel is an RGB triple followed by an alpha sample
{
mbRGBTriple = TRUE;
- mnScansize*=4;
+ mnScansize *= 4;
mbAlphaChannel = TRUE;
- switch (mnBitDepth )
+ switch (mnPngDepth )
{
case 16 : // we have to reduce the bitmap
case 8 :
- mnDepth = 24;
+ mnTargetDepth = 24;
break;
default :
return FALSE;
@@ -530,33 +615,72 @@ BOOL PNGReaderImpl::ImplReadHeader()
default :
return FALSE;
}
- mnBBP = mnScansize / mnWidth;
- if ( !mnBBP )
- mnBBP = 1;
+ mnBPP = mnScansize / maOrigSize.Width();
+ if ( !mnBPP )
+ mnBPP = 1;
mnScansize++; // each scanline includes one filterbyte
- mpScan = mpInflateInBuf = new BYTE[ mnScansize ];
- mpScanprior = (sal_uInt8*)rtl_allocateZeroMemory( mnScansize );
- if ( mnInterlaceType )
- ImplResizeScanline();
+ // TODO: switch between both scanlines instead of copying
+ mpInflateInBuf = new BYTE[ mnScansize ];
+ mpScanCurrent = mpInflateInBuf;
+ mpScanPrior = new BYTE[ mnScansize ];
+
+ // calculate target size from original size and the preview hint
+ if( rPreviewSizeHint.Width() || rPreviewSizeHint.Height() )
+ {
+ Size aPreviewSize( rPreviewSizeHint.Width(), rPreviewSizeHint.Height() );
+ maTargetSize = maOrigSize;
+
+ if( aPreviewSize.Width() == 0 ) {
+ aPreviewSize.setWidth( ( maOrigSize.Width()*aPreviewSize.Height() )/maOrigSize.Height() );
+ if( aPreviewSize.Width() <= 0 )
+ aPreviewSize.setWidth( 1 );
+ } else if( aPreviewSize.Height() == 0 ) {
+ aPreviewSize.setHeight( ( maOrigSize.Height()*aPreviewSize.Width() )/maOrigSize.Width() );
+ if( aPreviewSize.Height() <= 0 )
+ aPreviewSize.setHeight( 1 );
+ }
+
+ if( aPreviewSize.Width() < maOrigSize.Width() && aPreviewSize.Height() < maOrigSize.Height() ) {
+ OSL_TRACE("preview size %dx%d", aPreviewSize.Width(), aPreviewSize.Height() );
+
+ for( int i = 1; i < 5; ++i )
+ {
+ if( (maTargetSize.Width() >> i) < aPreviewSize.Width() )
+ break;
+ if( (maTargetSize.Height() >> i) < aPreviewSize.Height() )
+ break;
+ mnPreviewShift = i;
+ }
+ mnPreviewMask = (1 << mnPreviewShift) - 1;
+ }
+ }
+
+ maTargetSize.Width() = (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift;
+ maTargetSize.Height() = (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift;
- mpBmp = new Bitmap( Size( mnWidth, mnHeight ), mnDepth);
+ mpBmp = new Bitmap( maTargetSize, mnTargetDepth );
mpAcc = mpBmp->AcquireWriteAccess();
- if ( !mpAcc )
+ if( !mpAcc )
return FALSE;
+ mpBmp->SetSourceSizePixel( maOrigSize );
+
if ( mbAlphaChannel )
{
- mpAlphaMask = new AlphaMask( Size( mnWidth, mnHeight ) );
+ mpAlphaMask = new AlphaMask( maTargetSize );
+ mpAlphaMask->Erase( 128 );
mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
- if ( !mpMaskAcc )
+ if( !mpMaskAcc )
return FALSE;
}
if ( mbGrayScale )
- ImplGetGrayPalette( mnBitDepth );
+ ImplGetGrayPalette( mnPngDepth );
+
+ ImplPreparePass();
return TRUE;
}
@@ -565,40 +689,19 @@ BOOL PNGReaderImpl::ImplReadHeader()
void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
{
- sal_uInt32 nAdd, nStart = 0;
- sal_uInt16 nPaletteEntryCount;
+ if( nBitDepth > 8 )
+ nBitDepth = 8;
- switch ( nBitDepth )
- {
- case 1 :
- {
- nPaletteEntryCount = 2;
- nAdd = 255;
- }
- break;
- case 2 :
- {
- nPaletteEntryCount = 16;
- nAdd = 85;
- }
- break;
- case 4 :
- {
- nPaletteEntryCount = 16;
- nAdd = 17;
- }
- break;
+ sal_uInt16 nPaletteEntryCount = 1 << nBitDepth;
+ sal_uInt32 nAdd = 256 / (nPaletteEntryCount - 1);
+
+ // no bitdepth==2 available
+ // but bitdepth==4 with two unused bits is close enough
+ if( nBitDepth == 2 )
+ nPaletteEntryCount = 16;
- default:
- case 8 :
- {
- nPaletteEntryCount = 256;
- nAdd = 1;
- }
- break;
- }
mpAcc->SetPaletteEntryCount( nPaletteEntryCount );
- for ( sal_uInt32 i = 0; nStart < 256; i++, nStart += nAdd )
+ for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
mpAcc->SetPaletteColor( (USHORT)i, BitmapColor( mpColorTable[ nStart ],
mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
}
@@ -607,20 +710,18 @@ void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
BOOL PNGReaderImpl::ImplReadPalette()
{
- sal_uInt32 nCount = mnChunkLen / 3;
+ sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mpAcc )
{
- BYTE nRed, nGreen, nBlue;
-
mbPalette = TRUE;
mpAcc->SetPaletteEntryCount( (USHORT) nCount );
- for ( USHORT i = 0; i < nCount; i++ )
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
{
- nRed = mpColorTable[ *maDataIter++ ];
- nGreen = mpColorTable[ *maDataIter++ ];
- nBlue = mpColorTable[ *maDataIter++ ];
+ BYTE nRed = mpColorTable[ *maDataIter++ ];
+ BYTE nGreen = mpColorTable[ *maDataIter++ ];
+ BYTE nBlue = mpColorTable[ *maDataIter++ ];
mpAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
}
}
@@ -632,8 +733,10 @@ BOOL PNGReaderImpl::ImplReadPalette()
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplReadTransparent()
+BOOL PNGReaderImpl::ImplReadTransparent()
{
+ bool bNeedAlpha = false;
+
if ( mpTransTab == NULL )
{
switch ( mnColorType )
@@ -648,11 +751,7 @@ void PNGReaderImpl::ImplReadTransparent()
// so the return value can be used as index
sal_uInt8 nIndex = ImplScaleColor();
mpTransTab[ nIndex ] = 0;
-
- mpAlphaMask = new AlphaMask( Size( mnWidth, mnHeight ) );
- mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
- if ( mpMaskAcc )
- mbTransparent = sal_True;
+ mbTransparent = true;
}
}
break;
@@ -664,18 +763,7 @@ void PNGReaderImpl::ImplReadTransparent()
mnTransRed = ImplScaleColor();
mnTransGreen = ImplScaleColor();
mnTransBlue = ImplScaleColor();
-
- mpMaskBmp = new Bitmap( Size( mnWidth, mnHeight ), 1 );
- mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
-
- if ( mpMaskAcc )
- {
- mbTransparent = mpMaskAcc != NULL;
-
- const Color aWhite( COL_WHITE );
- cTransIndex1 = (BYTE)mpMaskAcc->GetBestPaletteIndex( aWhite );
- cNonTransIndex1 = cTransIndex1 ? 0 : 1;
- }
+ mbTransparent = true;
}
}
break;
@@ -688,45 +776,32 @@ void PNGReaderImpl::ImplReadTransparent()
rtl_fillMemory( mpTransTab, 256, 0xff );
rtl_copyMemory( mpTransTab, &(*maDataIter), mnChunkLen );
maDataIter += mnChunkLen;
-
- const BYTE* pCurr = mpTransTab;
- const BYTE* const pEnd = mpTransTab+mnChunkLen;
- sal_Int32 nNumFF = 0, nNum00 = 0;
- while( pCurr != pEnd )
- {
- if( *pCurr == 0 )
- ++nNum00;
- else if( *pCurr == 0xFF )
- ++nNumFF;
- ++pCurr;
- }
-
- if( nNumFF + nNum00 == mnChunkLen )
- {
- mpMaskBmp = new Bitmap( Size( mnWidth, mnHeight ), 1 );
- mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
-
- const Color aWhite( COL_WHITE );
- if ( !mpMaskAcc->GetBestPaletteIndex( aWhite ) )
- {
- BYTE* pPtr = mpTransTab;
- while( pPtr != pEnd )
- *pPtr++ ^= 0xff;
- }
- }
- else
- {
- mpAlphaMask = new AlphaMask( Size( mnWidth, mnHeight ) );
- mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
- }
-
- if ( mpMaskAcc )
- mbTransparent = sal_True;
+ mbTransparent = true;
+ // need alpha transparency if not on/off masking
+ for( unsigned i = 0; i < mnChunkLen; ++i )
+ bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
}
}
break;
}
}
+
+ if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
+ {
+ if( bNeedAlpha)
+ mpAlphaMask = new AlphaMask( maTargetSize );
+ else
+ mpMaskBmp = new Bitmap( maTargetSize, 1 );
+ mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
+ mbTransparent = (mpMaskAcc != NULL);
+ if( !mbTransparent )
+ return FALSE;
+ mcOpaqueColor = BitmapColor( 0x00 );
+ mcTranspColor = BitmapColor( 0xFF );
+ mpMaskAcc->Erase( 0x00 );
+ }
+
+ return TRUE;
}
// ------------------------------------------------------------------------
@@ -748,7 +823,7 @@ void PNGReaderImpl::ImplGetGamma()
mpColorTable[ i ] = (sal_uInt8)(pow((double)i/255.0, fInvGamma) * 255.0 + 0.5);
if ( mbGrayScale )
- ImplGetGrayPalette( mnDepth );
+ ImplGetGrayPalette( mnPngDepth );
}
}
@@ -756,9 +831,6 @@ void PNGReaderImpl::ImplGetGamma()
void PNGReaderImpl::ImplGetBackground()
{
- Point aPoint;
- Rectangle aRectangle( aPoint, Size( mnWidth, mnHeight ) );
-
switch ( mnColorType )
{
case 3 :
@@ -768,8 +840,7 @@ void PNGReaderImpl::ImplGetBackground()
UINT16 nCol = *maDataIter++;
if ( nCol < mpAcc->GetPaletteEntryCount() )
{
- mpAcc->SetFillColor( (const Color&)mpAcc->GetPaletteColor( (BYTE)nCol ) );
- mpAcc->FillRect( aRectangle );
+ mpAcc->Erase( mpAcc->GetPaletteColor( (BYTE)nCol ) );
break;
}
}
@@ -784,8 +855,7 @@ void PNGReaderImpl::ImplGetBackground()
// the color type 0 and 4 is always greyscale,
// so the return value can be used as index
sal_uInt8 nIndex = ImplScaleColor();
- mpAcc->SetFillColor( (const Color&)mpAcc->GetPaletteColor( nIndex ) );
- mpAcc->FillRect( aRectangle );
+ mpAcc->Erase( mpAcc->GetPaletteColor( nIndex ) );
}
}
break;
@@ -798,8 +868,7 @@ void PNGReaderImpl::ImplGetBackground()
sal_uInt8 nRed = ImplScaleColor();
sal_uInt8 nGreen = ImplScaleColor();
sal_uInt8 nBlue = ImplScaleColor();
- mpAcc->SetFillColor( Color( nRed, nGreen, nBlue ) );
- mpAcc->FillRect( aRectangle );
+ mpAcc->Erase( Color( nRed, nGreen, nBlue ) );
}
}
break;
@@ -812,23 +881,22 @@ void PNGReaderImpl::ImplGetBackground()
// 2 and 6 (RGB) the return value is always the 8 bit color component
sal_uInt8 PNGReaderImpl::ImplScaleColor()
{
- sal_uInt32 nMask = ( ( 1 << mnBitDepth ) - 1 );
+ sal_uInt32 nMask = ( ( 1 << mnPngDepth ) - 1 );
sal_uInt16 nCol = ( *maDataIter++ << 8 );
nCol += *maDataIter++ & (sal_uInt16)nMask;
- if ( mnBitDepth > 8 ) // convert 16bit graphics to 8
+ if ( mnPngDepth > 8 ) // convert 16bit graphics to 8
nCol >>= 8;
return (sal_uInt8) nCol;
}
// ------------------------------------------------------------------------
-// ImplReadIDAT reads as much bitmap data as possible
+// ImplReadIDAT reads as much image data as needed
void PNGReaderImpl::ImplReadIDAT()
{
- sal_Int32 nToRead, nRead;
if ( mnChunkLen ) // Chunk empty ?
{
if ( mbzCodecInUse == FALSE )
@@ -842,733 +910,592 @@ void PNGReaderImpl::ImplReadIDAT()
while ( ( mpZCodec->GetBreak() ) )
{
// get bytes needed to fill the current scanline
- nToRead = mnScansize - ( mpScan - mpInflateInBuf );
-
- if ( ( nRead = mpZCodec->ReadAsynchron( aIStrm, mpScan, nToRead ) ) < 0 )
+ sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf);
+ sal_Int32 nRead = mpZCodec->ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
+ if ( nRead < 0 )
{
mbStatus = FALSE;
break;
}
if ( nRead < nToRead )
{
- mpScan += nRead; // ZStream is Broken
+ mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
break;
}
- else
+ else // this scanline is Finished
{
- mpScan = mpInflateInBuf; // this scanline is Finished
+ mpScanCurrent = mpInflateInBuf;
+ ImplApplyFilter();
- if ( mnInterlaceType == 0 )
- {
- ImplGetFilter ( 0, 1 );
- mnYpos++;
- }
- else
- {
- // interlace mode
- switch ( mnPass )
- {
- case 1 : // pass 1
- {
- ImplGetFilter ( 0, 8 );
- mnYpos += 8;
- }
- break;
-
- case 2 : // pass 2
- {
- ImplGetFilter ( 4, 8 );
- mnYpos += 8;
- }
- break;
-
- case 3 : // pass 3
- {
- if ( mnYpos >= 4 )
- {
- ImplGetFilter ( 0, 4 );
- }
- mnYpos += 8;
- }
- break;
-
- case 4 : // pass 4
- {
- ImplGetFilter ( 2, 4 );
- mnYpos += 4;
- }
- break;
-
- case 5 : // pass 5
- {
- if ( mnYpos >= 2 )
- {
- ImplGetFilter ( 0, 2 );
- }
- mnYpos += 4;
- }
- break;
-
- case 6 : // pass 6
- {
- ImplGetFilter ( 1, 2 );
- mnYpos += 2;
- }
- break;
-
- case 7 : // pass 7
- {
- if ( mnYpos >= 1 )
- {
- ImplGetFilter ( 0, 1 );
- }
- mnYpos += 2;
- }
- break;
- }
- }
+ ImplDrawScanline( mnXStart, mnXAdd );
+ mnYpos += mnYAdd;
}
- if ( mnYpos >= mnHeight )
+ if ( mnYpos >= (sal_uInt32)maOrigSize.Height() )
{
- if ( mnPass == 7 )
- break;
- else
- {
- ImplResizeScanline();
- }
+ if( (mnPass < 7) && mnInterlaceType )
+ if( ImplPreparePass() )
+ continue;
+ mbIDAT = true;
+ break;
}
}
}
- if ( ( mnPass >= 7 ) && ( mnYpos >= mnHeight ) )
+ if( mbIDAT )
{
mpZCodec->EndCompression();
mbzCodecInUse = FALSE;
- mbIDAT = TRUE;
}
}
// ---------------------------------------------------------------------------------------------------
-void PNGReaderImpl::ImplResizeScanline( void )
+bool PNGReaderImpl::ImplPreparePass()
{
- long nScansize;
-
- while ( mnPass < 7 )
+ struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
+ static const InterlaceParams aInterlaceParams[8] =
{
- sal_uInt32 nX = 0;
-
- mnYpos = 0;
- mnPass++;
-
- switch ( mnPass )
+ // non-interlaced
+ { 0, 0, 1, 1 },
+ // Adam7-interlaced
+ { 0, 0, 8, 8 }, // pass 1
+ { 4, 0, 8, 8 }, // pass 2
+ { 0, 4, 4, 8 }, // pass 3
+ { 2, 0, 4, 4 }, // pass 4
+ { 0, 2, 2, 4 }, // pass 5
+ { 1, 0, 2, 2 }, // pass 6
+ { 0, 1, 1, 2 } // pass 7
+ };
+
+ const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
+ if( mnInterlaceType )
+ {
+ while( ++mnPass <= 7 )
{
- case 1 :
- nScansize = ( mnWidth + 7 ) >> 3;
- break;
+ pParam = &aInterlaceParams[ mnPass ];
- case 2 :
- nX += 4;
- nScansize = ( mnWidth + 3 ) >> 3;
- break;
+ // skip this pass if the original image is too small for it
+ if( (pParam->mnXStart < maOrigSize.Width())
+ && (pParam->mnYStart < maOrigSize.Height()) )
+ break;
+ }
+ if( mnPass > 7 )
+ return false;
- case 3 :
- mnYpos += 4;
- nScansize = ( mnWidth + 3 ) >> 2;
- break;
+ // skip the last passes if possible (for scaled down target images)
+ if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
+ return false;
+ }
- case 4 :
- nX += 2;
- nScansize = ( mnWidth + 1) >> 2;
- break;
+ mnYpos = pParam->mnYStart;
+ mnXStart = pParam->mnXStart;
+ mnXAdd = pParam->mnXAdd;
+ mnYAdd = pParam->mnYAdd;
- case 5 :
- mnYpos += 2;
- nScansize = ( mnWidth + 1 ) >> 1;
- break;
+ // in Interlace mode the size of scanline is not constant
+ // so first we calculate the number of entrys
+ long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
+ mnScansize = nScanWidth;
- case 6 :
- nX++;
- nScansize = mnWidth >> 1;
- break;
+ if( mbRGBTriple )
+ mnScansize = 3 * nScanWidth;
- case 7 :
- mnYpos++;
- nScansize = mnWidth;
- break;
+ if( mbAlphaChannel )
+ mnScansize += nScanWidth;
- default:
- nScansize = 0;
- break;
- }
+ // convert to width in bytes
+ mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
- if ( ( mnYpos >= mnHeight ) || ( nX >= mnWidth ) ) // is pass to be skipped ?
- continue;
+ ++mnScansize; // scan size also needs room for the filtertype byte
+ rtl_zeroMemory( mpScanPrior, mnScansize );
- // in Interlace mode the size of scanline is not constant
- // so first we calculate the number of entrys
- mnScansize = nScansize * mnBitDepth;
+ return true;
+}
- if ( mbRGBTriple )
- mnScansize *= 3;
+// ----------------------------------------------------------------------------
+// ImplApplyFilter writes the complete Scanline (nY)
+// in interlace mode the parameter nXStart and nXAdd are non-zero
- // convert bitsize to byte
- mnScansize = ( mnScansize + 7 ) >> 3;
+void PNGReaderImpl::ImplApplyFilter()
+{
+ const BYTE* const pScanEnd = mpInflateInBuf + mnScansize;
- if ( mbAlphaChannel )
- mnScansize += ( ( nScansize * mnBitDepth ) >> 3 );
+ BYTE nFilterType = *mpInflateInBuf; // the filter type may change each scanline
+ switch ( nFilterType )
+ {
+ default: // unknown Scanline Filter Type
+ case 0: // Filter Type "None"
+ // we let the pixels pass and display the data unfiltered
+ break;
- rtl_zeroMemory( mpScanprior, ++mnScansize );
+ case 1: // Scanline Filter Type "Sub"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = p1;
+ p1 += mnBPP;
+
+ // use left pixels
+ do
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
+ while( ++p1 < pScanEnd );
+ }
break;
- }
-}
-// ---------------------------------------------------------------------------------------------------
-// ImplGetFilter writes the complete Scanline (nY) - in interlace mode the parameter nXStart and nXAdd
-// appends to the currently used pass
-// the complete size of scanline will be returned - in interlace mode zero is possible!
+ case 2: // Scanline Filter Type "Up"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
-void PNGReaderImpl::ImplGetFilter ( sal_uInt32 nXStart, sal_uInt32 nXAdd )
-{
- BYTE* pTmp = mpInflateInBuf;
- BYTE* p1;
- BYTE* p2;
- BYTE* p3;
- BYTE* p4;
- BYTE nFilterType;
- BYTE nCol = 0;
- sal_uInt32 nXIndex, nX, nY = mnYpos, n1, n2, na, nb, nc;
- sal_Int32 np, npa, npb, npc;
-
- sal_uInt32 nBBP = mnBBP;
-
- if ( nXStart < (sal_uInt32)mnWidth )
- {
- nFilterType = *pTmp++; // the filter type may change each scanline
+ // use pixels from prior line
+ do
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
+ while( ++p1 < pScanEnd );
+ }
+ break;
- switch ( nFilterType )
+ case 3: // Scanline Filter Type "Average"
{
- case 1 :
- {
- p1 = pTmp + nBBP;
- p2 = pTmp;
-
- for (; p1 < pTmp + mnScansize - 1; ++p1)
- *p1 = sal::static_int_cast<BYTE>(*p1 + ( *p2++ ));
- }
- break;
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
+ const BYTE* p3 = p1;
+
+ // use one pixel from prior line
+ for( int n = mnBPP; --n >= 0; ++p1, ++p2)
+ *p1 = static_cast<BYTE>( *p1 + (*p2 >> 1) );
+
+ // predict by averaging the left and prior line pixels
+ do
+ *p1 = static_cast<BYTE>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
+ while( ++p1 < pScanEnd );
+ }
+ break;
- case 2 :
- {
- p1 = pTmp;
- p2 = mpScanprior+1;
+ case 4: // Scanline Filter Type "PaethPredictor"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
+ const BYTE* p3 = p1;
+ const BYTE* p4 = p2;
- for (; p1 < pTmp + mnScansize - 1; ++p1)
- *p1 = sal::static_int_cast<BYTE>(*p1 + ( *p2++ ));
- }
- break;
+ // use one pixel from prior line
+ for( int n = mnBPP; --n >= 0; ++p1)
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
- case 3 :
+ // predict by using the left and the prior line pixels
+ do
{
- p1 = pTmp;
- p2 = mpScanprior + 1;
- p3 = pTmp-nBBP;
-
- for (; p1 < pTmp + mnScansize - 1; ++p1)
- {
- n1 = (BYTE)( *p2++ );
- n2 = ( p3 >= pTmp ) ? (BYTE)*p3 : 0;
- p3++;
- *p1 = sal::static_int_cast<BYTE>(*p1 + (BYTE)( ( n1 + n2 ) >> 1 ));
- }
+ int na = *(p2++);
+ int nb = *(p3++);
+ int nc = *(p4++);
+
+ int npa = nb - (int)nc;
+ int npb = na - (int)nc;
+ int npc = npa + npb;
+
+ if( npa < 0 )
+ npa =-npa;
+ if( npb < 0 )
+ npb =-npb;
+ if( npc < 0 )
+ npc =-npc;
+
+ if( npa > npb )
+ na = nb, npa = npb;
+ if( npa > npc )
+ na = nc;
+
+ *p1 = static_cast<BYTE>( *p1 + na );
}
- break;
+ while( ++p1 < pScanEnd );
+ }
+ break;
+ }
- case 4 :
- {
- p1 = pTmp;
- p2 = p1 - nBBP;
- p3 = mpScanprior + 1;
- p4 = p3 - nBBP;
+ rtl_copyMemory( mpScanPrior, mpInflateInBuf, mnScansize );
+}
- for (; p1 < pTmp + mnScansize - 1; ++p1)
- {
- nb = *p3++;
- if ( p2 >= pTmp )
- {
- na = *p2;
- nc = *p4;
- }
- else
- na = nc = 0;
-
- np = na + nb;
- np -= nc;
- npa = np - na;
- npb = np - nb;
- npc = np - nc;
-
- if ( npa < 0 )
- npa =-npa;
- if ( npb < 0 )
- npb =-npb;
- if ( npc < 0 )
- npc =-npc;
-
- if ( ( npa <= npb ) && ( npa <= npc ) )
- *p1 = sal::static_int_cast<BYTE>(*p1 + (BYTE)na);
- else if ( npb <= npc )
- *p1 = sal::static_int_cast<BYTE>(*p1 + (BYTE)nb);
- else
- *p1 = sal::static_int_cast<BYTE>(*p1 + (BYTE)nc);
+// ---------------------------------------------------------------------------------------------------
+// ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
+// In interlace mode the parameter nXStart and nXAdd append to the currently used pass
- p2++;
- p4++;
- }
- }
- break;
- // undefined FilterType -> we will let them pass and display the data unfiltered
- }
- if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
+void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
+{
+ // optimization for downscaling
+ if( mnYpos & mnPreviewMask )
+ return;
+ if( nXStart & mnPreviewMask )
+ return;
+
+ // convert nY to pixel units in the target image
+ // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
+ const sal_uInt32 nY = mnYpos >> mnPreviewShift;
+
+ const BYTE* pTmp = mpInflateInBuf + 1;
+ if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
+ {
+ switch ( mpAcc->GetBitCount() )
{
- switch ( mpAcc->GetBitCount() )
+ case 1 :
{
- case 1 :
+ if ( mbTransparent )
{
- if ( mbTransparent )
+ for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
{
- for ( nX = nXStart, nXIndex = 0; nX < (sal_uInt32)mnWidth; nX += nXAdd, nXIndex++ )
- {
- sal_uInt32 nShift = ( nXIndex & 7 ) ^ 7;
-
- if ( nShift == 0 )
- nCol = ( *pTmp++ ) & 1;
- else
- nCol = sal::static_int_cast<BYTE>(( *pTmp >> nShift ) & 1);
+ BYTE nCol;
+ nShift = (nShift - 1) & 7;
+ if ( nShift == 0 )
+ nCol = *(pTmp++);
+ else
+ nCol = static_cast<BYTE>( *pTmp >> nShift );
+ nCol &= 1;
- ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
- }
+ ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
}
- else
+ }
+ else
+ { // BMP_FORMAT_1BIT_MSB_PAL
+ for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
{
- for ( nX = nXStart, nXIndex = 0; nX < (sal_uInt32)mnWidth; nX += nXAdd, nXIndex++ )
- {
- sal_uInt32 nShift = ( nXIndex & 7 ) ^ 7;
+ nShift = (nShift - 1) & 7;
- if ( nShift == 0 )
- ImplSetPixel( nY, nX, ( *pTmp++ & 1 ) );
- else
- ImplSetPixel( nY, nX, sal::static_int_cast<BYTE>(( *pTmp >> nShift ) & 1) );
- }
+ BYTE nCol;
+ if ( nShift == 0 )
+ nCol = *(pTmp++);
+ else
+ nCol = static_cast<BYTE>( *pTmp >> nShift );
+ nCol &= 1;
+
+ ImplSetPixel( nY, nX, nCol );
}
}
- break;
+ }
+ break;
- case 4 :
+ case 4 :
+ {
+ if ( mbTransparent )
{
- if ( mbTransparent )
+ if ( mnPngDepth == 4 ) // check if source has a two bit pixel format
{
- if ( mnBitDepth == 4 ) // maybe the source is a two bit graphic
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
{
- for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++ )
+ if( nXIndex & 1 )
{
- if( nXIndex & 1 )
- {
- ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
- pTmp++;
- }
- else
- {
- ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
- }
+ ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
+ pTmp++;
}
- }
- else
- {
- for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++ )
+ else
{
- switch( nXIndex & 3 )
- {
- case 0 :
- nCol = *pTmp >> 6;
- break;
-
- case 1 :
- nCol = ( *pTmp >> 4 ) & 0x03 ;
- break;
-
- case 2 :
- nCol = ( *pTmp >> 2 ) & 0x03;
- break;
-
- case 3 :
- nCol = ( *pTmp++ ) & 0x03;
- break;
- }
-
- ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
+ ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
}
}
}
- else
+ else // if ( mnPngDepth == 2 )
{
- if ( mnBitDepth == 4 ) // maybe the source is a two bit graphic
- {
- for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++ )
- {
- if( nXIndex & 1 )
- ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
- else
- ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
- }
- }
- else
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
{
- for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++ )
+ BYTE nCol;
+ switch( nXIndex & 3 )
{
- switch( nXIndex & 3 )
- {
- case 0 :
- ImplSetPixel( nY, nX, *pTmp >> 6 );
- break;
+ case 0 :
+ nCol = *pTmp >> 6;
+ break;
- case 1 :
- ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
- break;
+ case 1 :
+ nCol = ( *pTmp >> 4 ) & 0x03 ;
+ break;
- case 2 :
- ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
- break;
+ case 2 :
+ nCol = ( *pTmp >> 2 ) & 0x03;
+ break;
+
+ case 3 :
+ nCol = ( *pTmp++ ) & 0x03;
+ break;
- case 3 :
- ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
+ default: // get rid of nCol uninitialized warning
+ nCol = 0;
break;
- }
}
+
+ ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
}
}
}
- break;
-
- case 8 :
+ else
{
- if ( mbAlphaChannel )
- {
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit grayscale
+ if ( mnPngDepth == 4 ) // maybe the source is a two bitmap graphic
+ { // BMP_FORMAT_4BIT_LSN_PAL
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 2 )
- ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
- }
- else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 4 )
- ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
+ if( nXIndex & 1 )
+ ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
+ else
+ ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
}
}
- else
+ else // if ( mnPngDepth == 2 )
{
- if ( mbTransparent )
- {
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit grayscale
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp++ )
- ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
- }
- else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 2 )
- ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
- }
- }
- else
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
{
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit grayscale
- {
- if ( mnPass == 7 ) // mnPass == 7 -> no interlace or whole scanline is available
- mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, mnScansize -1 );
- else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd )
- ImplSetPixel( nY, nX, *pTmp++ );
- }
- }
- else
+ switch( nXIndex & 3 )
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 2 )
- ImplSetPixel( nY, nX, *pTmp );
+ case 0 :
+ ImplSetPixel( nY, nX, *pTmp >> 6 );
+ break;
+
+ case 1 :
+ ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
+ break;
+
+ case 2 :
+ ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
+ break;
+
+ case 3 :
+ ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
+ break;
}
}
}
}
- break;
-
- default :
- mbStatus = FALSE;
- break;
}
- }
- else
- {
- if ( mbAlphaChannel || mbTransparent )
+ break;
+
+ case 8 :
{
if ( mbAlphaChannel )
{
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit each sample
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
{
- if ( mpColorTable != mpDefaultColorTable )
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 4 )
- ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 1 ] ],
- mpColorTable[ pTmp[ 2 ] ] ), pTmp[ 3 ] );
- }
- else
- {
-// if ( mnPass == 7 ) // mnPass == 7 -> no interlace or whole scanline is available
-// mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, mnScansize -1 );
-// else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 4 )
- ImplSetAlphaPixel( nY, nX, BitmapColor( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ] ), pTmp[ 3 ] );
- }
- }
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
}
else
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 8 )
- ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 2 ] ],
- mpColorTable[ pTmp[ 4 ] ] ), pTmp[6] );
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
}
}
- else // Transparency chunk
+ else if ( mbTransparent )
{
- sal_Bool bTransparent;
- sal_uInt8 nRed, nGreen, nBlue;
-
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit each sample
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 3 )
- {
- nRed = pTmp[ 0 ];
- nGreen = pTmp[ 1 ];
- nBlue = pTmp[ 2 ];
- bTransparent = ( ( nRed == mnTransRed )
- && ( nGreen == mnTransGreen )
- && ( nBlue == mnTransBlue ) );
-
- ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
- mpColorTable[ nGreen ],
- mpColorTable[ nBlue ] ), bTransparent );
- }
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
+ ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
}
else
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 6 )
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
+ }
+ }
+ else // neither alpha nor transparency
+ {
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
+ {
+ if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
+ {
+ int nLineBytes = maOrigSize.Width();
+ mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, nLineBytes );
+ pTmp += nLineBytes;
+ }
+ else
{
- nRed = pTmp[ 0 ];
- nGreen = pTmp[ 2 ];
- nBlue = pTmp[ 4 ];
- bTransparent = ( ( nRed == mnTransRed )
- && ( nGreen == mnTransGreen )
- && ( nBlue == mnTransBlue ) );
-
- ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
- mpColorTable[ nGreen ],
- mpColorTable[ nBlue ] ), bTransparent );
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
+ ImplSetPixel( nY, nX, *pTmp++ );
}
}
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetPixel( nY, nX, *pTmp );
+ }
+ }
+ }
+ break;
+
+ default :
+ mbStatus = FALSE;
+ break;
+ }
+ }
+ else // no palette => truecolor
+ {
+ if( mbAlphaChannel ) // has RGB + alpha
+ { // BMP_FORMAT_32BIT_TC_RGBA
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
+ {
+ if ( mpColorTable != mpDefaultColorTable )
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 1 ] ],
+ mpColorTable[ pTmp[ 2 ] ] ), pTmp[ 3 ] );
+ }
+ else
+ {
+// if ( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
+// {
+// int nLineBytes = 4 * maOrigSize.Width();
+// mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, nLineBytes );
+// pTmp += nLineBytes;
+// }
+// else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ), pTmp[3] );
+ }
}
}
else
+ { // BMP_FORMAT_64BIT_TC_RGBA
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 2 ] ],
+ mpColorTable[ pTmp[ 4 ] ] ), pTmp[6] );
+ }
+ }
+ else if( mbTransparent ) // has RGB + transparency
+ { // BMP_FORMAT_24BIT_TC_RGB
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
{
- if ( mnBitDepth == 8 ) // maybe the source is a 16 bit each sample
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
{
- if ( mpColorTable != mpDefaultColorTable )
+ sal_uInt8 nRed = pTmp[ 0 ];
+ sal_uInt8 nGreen = pTmp[ 1 ];
+ sal_uInt8 nBlue = pTmp[ 2 ];
+ sal_Bool bTransparent = ( ( nRed == mnTransRed )
+ && ( nGreen == mnTransGreen )
+ && ( nBlue == mnTransBlue ) );
+
+ ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
+ mpColorTable[ nGreen ],
+ mpColorTable[ nBlue ] ), bTransparent );
+ }
+ }
+ else
+ { // BMP_FORMAT_48BIT_TC_RGB
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
+ {
+ sal_uInt8 nRed = pTmp[ 0 ];
+ sal_uInt8 nGreen = pTmp[ 2 ];
+ sal_uInt8 nBlue = pTmp[ 4 ];
+ sal_Bool bTransparent = ( ( nRed == mnTransRed )
+ && ( nGreen == mnTransGreen )
+ && ( nBlue == mnTransBlue ) );
+
+ ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
+ mpColorTable[ nGreen ],
+ mpColorTable[ nBlue ] ), bTransparent );
+ }
+ }
+ }
+ else // has RGB but neither alpha nor transparency
+ { // BMP_FORMAT_24BIT_TC_RGB
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
+ {
+ if ( mpColorTable != mpDefaultColorTable )
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
+ ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 1 ] ],
+ mpColorTable[ pTmp[ 2 ] ] ) );
+ }
+ else
+ {
+ if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
{
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 3 )
- ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 1 ] ],
- mpColorTable[ pTmp[ 2 ] ] ) );
+ int nLineBytes = maOrigSize.Width() * 3;
+ mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_24BIT_TC_RGB, nLineBytes );
+ pTmp += nLineBytes;
}
else
{
- if ( mnPass == 7 ) // mnPass == 7 -> no interlace or whole scanline is available
- mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_24BIT_TC_RGB, mnScansize -1 );
- else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 3 )
- ImplSetPixel( nY, nX, BitmapColor( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ] ) );
- }
-
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
+ ImplSetPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ) );
}
}
- else
- {
- for ( nX = nXStart; nX < mnWidth; nX += nXAdd, pTmp += 6 )
- ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 2 ] ],
- mpColorTable[ pTmp[ 4 ] ] ) );
- }
+ }
+ else
+ { // BMP_FORMAT_48BIT_TC_RGB
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
+ ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 2 ] ],
+ mpColorTable[ pTmp[ 4 ] ] ) );
}
}
}
-
- rtl_copyMemory( mpScanprior, mpInflateInBuf, mnScansize );
}
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, BYTE nPalIndex )
+void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
{
- if ( mnPass == 7 )
- mpAcc->SetPixel( nY, nX, (BYTE)nPalIndex );
- else
- {
- sal_uInt32 nTX;
-
- for ( int nBHeight = 0; nBHeight < aBlockHeight[ mnPass ]; nBHeight++ )
- {
- nTX = nX;
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
- for ( int nBWidth = 0; nBWidth < aBlockWidth[ mnPass ]; nBWidth++ )
- {
- mpAcc->SetPixel( nY, nTX, (BYTE)nPalIndex );
- if ( ++nTX == mnWidth )
- break;
- }
- if ( ++nY == mnHeight )
- break;
- }
- }
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
}
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
+void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, BYTE nPalIndex )
{
- if ( mnPass == 7 )
- mpAcc->SetPixel( nY, nX, rBitmapColor );
- else
- {
- sal_uInt32 nTX;
-
- for ( int nBHeight = 0; nBHeight < aBlockHeight[ mnPass ]; nBHeight++ )
- {
- nTX = nX;
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
- for ( int nBWidth = 0; nBWidth < aBlockWidth[ mnPass ]; nBWidth++ )
- {
- mpAcc->SetPixel( nY, nTX, rBitmapColor );
- if ( ++nTX == mnWidth )
- break;
- }
- if ( ++nY == mnHeight )
- break;
- }
- }
+ mpAcc->SetPixel( nY, nX, nPalIndex );
}
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, BOOL bTrans )
+void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, BOOL bTrans )
{
- if ( mnPass == 7 )
- {
- mpAcc->SetPixel( nY, nX, rBitmapColor );
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
- if ( bTrans )
- mpMaskAcc->SetPixel( nY, nX, cTransIndex1 );
- else
- mpMaskAcc->SetPixel( nY, nX, cNonTransIndex1 );
- }
- else
- {
- sal_uInt32 nTX;
-
- for ( int nBHeight = 0; nBHeight < aBlockHeight[ mnPass ]; nBHeight++ )
- {
- nTX = nX;
-
- for ( int nBWidth = 0; nBWidth < aBlockWidth[ mnPass ]; nBWidth++ )
- {
- mpAcc->SetPixel( nY, nTX, rBitmapColor );
-
- if ( bTrans )
- mpMaskAcc->SetPixel( nY, nTX, cTransIndex1 );
- else
- mpMaskAcc->SetPixel( nY, nTX, cNonTransIndex1 );
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
- if ( ++nTX == mnWidth )
- break;
- }
-
- if ( ++nY == mnHeight )
- break;
- }
- }
+ if ( bTrans )
+ mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
+ else
+ mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
}
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX, BYTE nPalIndex, BYTE nAlpha )
+void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
+ BYTE nPalIndex, BYTE nAlpha )
{
- if ( mnPass == 7 )
- {
- mpAcc->SetPixel( nY, nX, (BYTE)nPalIndex );
- mpMaskAcc->SetPixel( nY, nX, 255 - nAlpha );
- }
- else
- {
- sal_uInt32 nTX;
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
- for ( int nBHeight = 0; nBHeight < aBlockHeight[ mnPass ]; nBHeight++ )
- {
- nTX = nX;
-
- for ( int nBWidth = 0; nBWidth < aBlockWidth[ mnPass ]; nBWidth++ )
- {
- mpAcc->SetPixel( nY, nTX, (BYTE)nPalIndex );
- mpMaskAcc->SetPixel( nY, nX, 255 - nAlpha );
- if ( ++nTX == mnWidth )
- break;
- }
- if ( ++nY == mnHeight )
- break;
- }
- }
+ mpAcc->SetPixel( nY, nX, nPalIndex );
+ mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
}
// ------------------------------------------------------------------------
-void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, BYTE nAlpha )
+void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
+ const BitmapColor& rBitmapColor, BYTE nAlpha )
{
- if ( mnPass == 7 )
- {
- mpAcc->SetPixel( nY, nX, rBitmapColor );
- mpMaskAcc->SetPixel( nY, nX, 255 - nAlpha );
- }
- else
- {
- sal_uInt32 nTX;
-
- for ( int nBHeight = 0; nBHeight < aBlockHeight[ mnPass ]; nBHeight++ )
- {
- nTX = nX;
-
- for ( int nBWidth = 0; nBWidth < aBlockWidth[ mnPass ]; nBWidth++ )
- {
- mpAcc->SetPixel( nY, nTX, rBitmapColor );
- mpMaskAcc->SetPixel( nY, nTX, 255 - nAlpha );
- if ( ++nTX == mnWidth )
- break;
- }
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
- if ( ++nY == mnHeight )
- break;
- }
- }
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
+ mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
}
// ------------------------------------------------------------------------
@@ -1606,16 +1533,18 @@ PNGReader::~PNGReader()
// ------------------------------------------------------------------------
+Size PNGReader::aPreviewSizeHint;
+
BitmapEx PNGReader::Read()
{
- return mpImpl->Read();
+ return mpImpl->GetBitmapEx( aPreviewSizeHint );
}
// ------------------------------------------------------------------------
const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
{
- return mpImpl->maChunkSeq;
+ return mpImpl->GetAllChunks();
}
} // namespace vcl