Kaydet (Commit) 389bf9e1 authored tarafından Tomaž Vajngerl's avatar Tomaž Vajngerl

cleanup pngwrite, use const std::unique_ptr for pImpl

Change-Id: I7c9941731789be3553d473d64716484bfceaf8b4
üst 4dfa19d6
......@@ -26,33 +26,28 @@
#include <vcl/bitmapex.hxx>
#include <vector>
// - PNGWriter -
namespace vcl
{
class PNGWriterImpl;
class VCL_DLLPUBLIC PNGWriter
{
PNGWriterImpl* mpImpl;
const std::unique_ptr<PNGWriterImpl> mpImpl;
public:
explicit PNGWriter( const BitmapEx&,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
explicit PNGWriter(const BitmapEx&, const css::uno::Sequence<css::beans::PropertyValue>* pFilterData = NULL);
~PNGWriter();
bool Write( SvStream& rStm );
bool Write(SvStream& rStream);
// additional method to be able to modify all chunk before they are stored
struct ChunkData
{
sal_uInt32 nType;
std::vector< sal_uInt8 > aData;
std::vector<sal_uInt8> aData;
};
std::vector< vcl::PNGWriter::ChunkData >& GetChunks();
std::vector<vcl::PNGWriter::ChunkData>& GetChunks();
};
}
......
......@@ -47,53 +47,57 @@ class PNGWriterImpl
{
public:
PNGWriterImpl( const BitmapEx& BmpEx,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
PNGWriterImpl(const BitmapEx& BmpEx,
const css::uno::Sequence<css::beans::PropertyValue>* pFilterData = NULL);
bool Write( SvStream& rOStm );
bool Write(SvStream& rOutStream);
std::vector< vcl::PNGWriter::ChunkData >& GetChunks() { return maChunkSeq;}
std::vector<vcl::PNGWriter::ChunkData>& GetChunks()
{
return maChunkSeq;
}
private:
std::vector< vcl::PNGWriter::ChunkData > maChunkSeq;
sal_Int32 mnCompLevel;
sal_Int32 mnInterlaced;
sal_uInt32 mnMaxChunkSize;
bool mbStatus;
BitmapReadAccess* mpAccess;
BitmapReadAccess* mpMaskAccess;
ZCodec mpZCodec;
sal_uInt8* mpDeflateInBuf; // as big as the size of a scanline + alphachannel + 1
sal_uInt8* mpPreviousScan; // as big as mpDeflateInBuf
sal_uInt8* mpCurrentScan;
sal_uLong mnDeflateInSize;
sal_uLong mnWidth, mnHeight;
sal_uInt8 mnBitsPerPixel;
sal_uInt8 mnFilterType; // 0 oder 4;
sal_uLong mnBBP; // bytes per pixel ( needed for filtering )
bool mbTrueAlpha;
sal_uLong mnCRC;
void ImplWritepHYs( const BitmapEx& rBitmapEx );
void ImplWriteIDAT();
sal_uLong ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 );
void ImplClearFirstScanline();
void ImplWriteTransparent();
bool ImplWriteHeader();
void ImplWritePalette();
void ImplOpenChunk( sal_uLong nChunkType );
void ImplWriteChunk( sal_uInt8 nNumb );
void ImplWriteChunk( sal_uInt32 nNumb );
void ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize );
std::vector<vcl::PNGWriter::ChunkData> maChunkSeq;
sal_Int32 mnCompLevel;
sal_Int32 mnInterlaced;
sal_uInt32 mnMaxChunkSize;
bool mbStatus;
BitmapReadAccess* mpAccess;
BitmapReadAccess* mpMaskAccess;
ZCodec mpZCodec;
sal_uInt8* mpDeflateInBuf; // as big as the size of a scanline + alphachannel + 1
sal_uInt8* mpPreviousScan; // as big as mpDeflateInBuf
sal_uInt8* mpCurrentScan;
sal_uLong mnDeflateInSize;
sal_uLong mnWidth;
sal_uLong mnHeight;
sal_uInt8 mnBitsPerPixel;
sal_uInt8 mnFilterType; // 0 oder 4;
sal_uLong mnBBP; // bytes per pixel ( needed for filtering )
bool mbTrueAlpha;
sal_uLong mnCRC;
void ImplWritepHYs(const BitmapEx& rBitmapEx);
void ImplWriteIDAT();
sal_uLong ImplGetFilter(sal_uLong nY, sal_uLong nXStart = 0, sal_uLong nXAdd = 1);
void ImplClearFirstScanline();
void ImplWriteTransparent();
bool ImplWriteHeader();
void ImplWritePalette();
void ImplOpenChunk(sal_uLong nChunkType);
void ImplWriteChunk(sal_uInt8 nNumb);
void ImplWriteChunk(sal_uInt32 nNumb);
void ImplWriteChunk(unsigned char* pSource, sal_uInt32 nDatSize);
};
PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData )
const css::uno::Sequence<css::beans::PropertyValue>* pFilterData )
: mnCompLevel(PNG_DEF_COMPRESSION)
, mnInterlaced(0)
, mnMaxChunkSize(0)
......@@ -112,158 +116,174 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
, mbTrueAlpha(false)
, mnCRC(0UL)
{
if ( !rBmpEx.IsEmpty() )
if (!rBmpEx.IsEmpty())
{
Bitmap aBmp( rBmpEx.GetBitmap() );
Bitmap aBmp(rBmpEx.GetBitmap());
mnInterlaced = 0; // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
mnInterlaced = 0; // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
// #i67234# defaulting max chunk size to 256kb when using interlace mode
mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000;
mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits<sal_uInt32>::max() : 0x40000;
if ( pFilterData )
if (pFilterData)
{
sal_Int32 i = 0;
for ( i = 0; i < pFilterData->getLength(); i++ )
for (i = 0; i < pFilterData->getLength(); i++)
{
if ( (*pFilterData)[ i ].Name == "Compression" )
(*pFilterData)[ i ].Value >>= mnCompLevel;
else if ( (*pFilterData)[ i ].Name == "Interlaced" )
(*pFilterData)[ i ].Value >>= mnInterlaced;
else if ( (*pFilterData)[ i ].Name == "MaxChunkSize" )
if ((*pFilterData)[i].Name == "Compression")
(*pFilterData)[i].Value >>= mnCompLevel;
else if ((*pFilterData)[i].Name == "Interlaced")
(*pFilterData)[i].Value >>= mnInterlaced;
else if ((*pFilterData)[i].Name == "MaxChunkSize")
{
sal_Int32 nVal = 0;
if ( (*pFilterData)[ i ].Value >>= nVal )
mnMaxChunkSize = (sal_uInt32)nVal;
if ((*pFilterData)[i].Value >>= nVal)
mnMaxChunkSize = static_cast<sal_uInt32>(nVal);
}
}
}
mnBitsPerPixel = (sal_uInt8)aBmp.GetBitCount();
mnBitsPerPixel = static_cast<sal_uInt8>(aBmp.GetBitCount());
if( rBmpEx.IsTransparent() )
if (rBmpEx.IsTransparent())
{
if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() )
if (mnBitsPerPixel <= 8 && rBmpEx.IsAlpha())
{
aBmp.Convert( BMP_CONVERSION_24BIT );
mnBitsPerPixel = 24;
}
if ( mnBitsPerPixel <= 8 ) // transparent palette
if (mnBitsPerPixel <= 8) // transparent palette
{
aBmp.Convert( BMP_CONVERSION_8BIT_TRANS );
aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS );
aBmp.Convert(BMP_CONVERSION_8BIT_TRANS);
aBmp.Replace(rBmpEx.GetMask(), BMP_COL_TRANS);
mnBitsPerPixel = 8;
mpAccess = aBmp.AcquireReadAccess();
if ( mpAccess )
if (mpAccess)
{
if ( ImplWriteHeader() )
if (ImplWriteHeader())
{
ImplWritepHYs( rBmpEx );
ImplWritepHYs(rBmpEx);
ImplWritePalette();
ImplWriteTransparent();
ImplWriteIDAT();
}
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
}
else
{
mbStatus = false;
}
}
else
{
mpAccess = aBmp.AcquireReadAccess(); // true RGB with alphachannel
if( mpAccess )
mpAccess = aBmp.AcquireReadAccess(); // true RGB with alphachannel
if (mpAccess)
{
if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) )
if ((mbTrueAlpha = rBmpEx.IsAlpha()))
{
AlphaMask aMask( rBmpEx.GetAlpha() );
AlphaMask aMask(rBmpEx.GetAlpha());
mpMaskAccess = aMask.AcquireReadAccess();
if ( mpMaskAccess )
if (mpMaskAccess)
{
if ( ImplWriteHeader() )
if (ImplWriteHeader())
{
ImplWritepHYs( rBmpEx );
ImplWritepHYs(rBmpEx);
ImplWriteIDAT();
}
aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
aMask.ReleaseAccess(mpMaskAccess);
mpMaskAccess = NULL;
}
else
{
mbStatus = false;
}
}
else
{
Bitmap aMask( rBmpEx.GetMask() );
Bitmap aMask(rBmpEx.GetMask());
mpMaskAccess = aMask.AcquireReadAccess();
if( mpMaskAccess )
if (mpMaskAccess)
{
if ( ImplWriteHeader() )
if (ImplWriteHeader())
{
ImplWritepHYs( rBmpEx );
ImplWritepHYs(rBmpEx);
ImplWriteIDAT();
}
aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
aMask.ReleaseAccess(mpMaskAccess);
mpMaskAccess = NULL;
}
else
{
mbStatus = false;
}
}
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
}
else
{
mbStatus = false;
}
}
}
else
{
mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel
if( mpAccess )
mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel
if (mpAccess)
{
if ( ImplWriteHeader() )
if (ImplWriteHeader())
{
ImplWritepHYs( rBmpEx );
if( mpAccess->HasPalette() )
ImplWritepHYs(rBmpEx);
if (mpAccess->HasPalette())
ImplWritePalette();
ImplWriteIDAT();
}
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
}
else
{
mbStatus = false;
}
}
if ( mbStatus )
if (mbStatus)
{
ImplOpenChunk( PNGCHUNK_IEND ); // create an IEND chunk
ImplOpenChunk(PNGCHUNK_IEND); // create an IEND chunk
}
}
}
bool PNGWriterImpl::Write( SvStream& rOStm )
bool PNGWriterImpl::Write(SvStream& rOStm)
{
/* png signature is always an array of 8 bytes */
SvStreamEndian nOldMode = rOStm.GetEndian();
rOStm.SetEndian( SvStreamEndian::BIG );
rOStm.WriteUInt32( 0x89504e47 );
rOStm.WriteUInt32( 0x0d0a1a0a );
rOStm.SetEndian(SvStreamEndian::BIG);
rOStm.WriteUInt32(0x89504e47);
rOStm.WriteUInt32(0x0d0a1a0a);
std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() );
std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() );
while( aBeg != aEnd )
std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg(maChunkSeq.begin());
std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd(maChunkSeq.end());
while (aBeg != aEnd)
{
sal_uInt32 nType = aBeg->nType;
#if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
nType = OSL_SWAPDWORD( nType );
nType = OSL_SWAPDWORD(nType);
#endif
sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 );
sal_uInt32 nCRC = rtl_crc32(0, &nType, 4);
sal_uInt32 nDataSize = aBeg->aData.size();
if ( nDataSize )
nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize );
rOStm.WriteUInt32( nDataSize )
.WriteUInt32( aBeg->nType );
if ( nDataSize )
rOStm.Write( &aBeg->aData[ 0 ], nDataSize );
rOStm.WriteUInt32( nCRC );
if (nDataSize)
nCRC = rtl_crc32(nCRC, &aBeg->aData[0], nDataSize);
rOStm.WriteUInt32(nDataSize);
rOStm.WriteUInt32(aBeg->nType);
if (nDataSize)
rOStm.Write(&aBeg->aData[0], nDataSize);
rOStm.WriteUInt32(nCRC);
++aBeg;
}
rOStm.SetEndian( nOldMode );
rOStm.SetEndian(nOldMode);
return mbStatus;
}
......@@ -271,155 +291,177 @@ bool PNGWriterImpl::Write( SvStream& rOStm )
bool PNGWriterImpl::ImplWriteHeader()
{
ImplOpenChunk(PNGCHUNK_IHDR);
ImplWriteChunk( sal_uInt32( mnWidth = mpAccess->Width() ) );
ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) );
ImplWriteChunk(sal_uInt32(mnWidth = mpAccess->Width()));
ImplWriteChunk(sal_uInt32(mnHeight = mpAccess->Height()));
if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus )
if (mnWidth && mnHeight && mnBitsPerPixel && mbStatus)
{
sal_uInt8 nBitDepth = mnBitsPerPixel;
if ( mnBitsPerPixel <= 8 )
if (mnBitsPerPixel <= 8)
mnFilterType = 0;
else
mnFilterType = 4;
sal_uInt8 nColorType = 2; // colortype:
// bit 0 -> palette is used
if ( mpAccess->HasPalette() ) // bit 1 -> color is used
nColorType |= 1; // bit 2 -> alpha channel is used
sal_uInt8 nColorType = 2; // colortype:
// bit 0 -> palette is used
if (mpAccess->HasPalette()) // bit 1 -> color is used
nColorType |= 1; // bit 2 -> alpha channel is used
else
nBitDepth /= 3;
if ( mpMaskAccess )
if (mpMaskAccess)
nColorType |= 4;
ImplWriteChunk( nBitDepth );
ImplWriteChunk( nColorType ); // colortype
ImplWriteChunk((sal_uInt8) 0 ); // compression type
ImplWriteChunk((sal_uInt8) 0 ); // filter type - is not supported in this version
ImplWriteChunk((sal_uInt8) mnInterlaced ); // interlace type
ImplWriteChunk(nBitDepth);
ImplWriteChunk(nColorType); // colortype
ImplWriteChunk(static_cast<sal_uInt8>(0)); // compression type
ImplWriteChunk(static_cast<sal_uInt8>(0)); // filter type - is not supported in this version
ImplWriteChunk(static_cast<sal_uInt8>(mnInterlaced)); // interlace type
}
else
{
mbStatus = false;
}
return mbStatus;
}
void PNGWriterImpl::ImplWritePalette()
{
const sal_uLong nCount = mpAccess->GetPaletteEntryCount();
boost::scoped_array<sal_uInt8> pTempBuf(new sal_uInt8[ nCount*3 ]);
sal_uInt8* pTmp = pTempBuf.get();
boost::scoped_array<sal_uInt8> pTempBuf(new sal_uInt8[nCount * 3]);
sal_uInt8* pTmp = pTempBuf.get();
ImplOpenChunk( PNGCHUNK_PLTE );
ImplOpenChunk(PNGCHUNK_PLTE);
for ( sal_uInt16 i = 0; i < nCount; i++ )
{
const BitmapColor& rColor = mpAccess->GetPaletteColor( i );
const BitmapColor& rColor = mpAccess->GetPaletteColor(i);
*pTmp++ = rColor.GetRed();
*pTmp++ = rColor.GetGreen();
*pTmp++ = rColor.GetBlue();
}
ImplWriteChunk( pTempBuf.get(), nCount*3 );
ImplWriteChunk(pTempBuf.get(), nCount * 3);
}
void PNGWriterImpl::ImplWriteTransparent ()
void PNGWriterImpl::ImplWriteTransparent()
{
const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex( BMP_COL_TRANS );
const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex(BMP_COL_TRANS);
ImplOpenChunk( PNGCHUNK_tRNS );
ImplOpenChunk(PNGCHUNK_tRNS);
for ( sal_uLong n = 0UL; n <= nTransIndex; n++ )
ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff );
for (sal_uLong n = 0UL; n <= nTransIndex; n++)
{
ImplWriteChunk((nTransIndex == n) ? static_cast<sal_uInt8>(0x0) : static_cast<sal_uInt8>(0xff));
}
}
void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx )
void PNGWriterImpl::ImplWritepHYs(const BitmapEx& rBmpEx)
{
if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM )
if (rBmpEx.GetPrefMapMode() == MAP_100TH_MM)
{
Size aPrefSize( rBmpEx.GetPrefSize() );
if ( aPrefSize.Width() && aPrefSize.Height() && mnWidth && mnHeight )
Size aPrefSize(rBmpEx.GetPrefSize());
if (aPrefSize.Width() && aPrefSize.Height() && mnWidth && mnHeight)
{
ImplOpenChunk( PNGCHUNK_pHYs );
ImplOpenChunk(PNGCHUNK_pHYs);
sal_uInt8 nMapUnit = 1;
sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 );
sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 );
ImplWriteChunk( nPrefSizeX );
ImplWriteChunk( nPrefSizeY );
ImplWriteChunk( nMapUnit );
sal_uInt32 nPrefSizeX = static_cast<sal_uInt32>(100000.0 / (static_cast<double>(aPrefSize.Width()) / mnWidth) + 0.5);
sal_uInt32 nPrefSizeY = static_cast<sal_uInt32>(100000.0 / (static_cast<double>(aPrefSize.Height()) / mnHeight) + 0.5);
ImplWriteChunk(nPrefSizeX);
ImplWriteChunk(nPrefSizeY);
ImplWriteChunk(nMapUnit);
}
}
}
void PNGWriterImpl::ImplWriteIDAT ()
void PNGWriterImpl::ImplWriteIDAT()
{
mnDeflateInSize = mnBitsPerPixel;
if( mpMaskAccess )
if (mpMaskAccess)
mnDeflateInSize += 8;
mnBBP = ( mnDeflateInSize + 7 ) >> 3;
mnBBP = (mnDeflateInSize + 7) >> 3;
mnDeflateInSize = mnBBP * mnWidth + 1;
mpDeflateInBuf = new sal_uInt8[ mnDeflateInSize ];
mpDeflateInBuf = new sal_uInt8[mnDeflateInSize];
if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
if (mnFilterType) // using filter type 4 we need memory for the scanline 3 times
{
mpPreviousScan = new sal_uInt8[ mnDeflateInSize ];
mpCurrentScan = new sal_uInt8[ mnDeflateInSize ];
mpPreviousScan = new sal_uInt8[mnDeflateInSize];
mpCurrentScan = new sal_uInt8[mnDeflateInSize];
ImplClearFirstScanline();
}
mpZCodec.BeginCompression( mnCompLevel, true );
mpZCodec.SetCRC( mnCRC );
mpZCodec.BeginCompression(mnCompLevel, true);
mpZCodec.SetCRC(mnCRC);
SvMemoryStream aOStm;
if ( mnInterlaced == 0 )
if (mnInterlaced == 0)
{
for ( sal_uLong nY = 0; nY < mnHeight; nY++ )
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) );
for (sal_uLong nY = 0; nY < mnHeight; nY++)
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY));
}
}
else
{
// interlace mode
sal_uLong nY;
for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 1
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) );
for (nY = 0; nY < mnHeight; nY += 8) // pass 1
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 8));
}
ImplClearFirstScanline();
for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 2
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) );
for (nY = 0; nY < mnHeight; nY += 8) // pass 2
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 4, 8));
}
ImplClearFirstScanline();
if ( mnHeight >= 5 ) // pass 3
if (mnHeight >= 5) // pass 3
{
for ( nY = 4; nY < mnHeight; nY+=8 )
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) );
for (nY = 4; nY < mnHeight; nY += 8)
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 4));
}
ImplClearFirstScanline();
}
for ( nY = 0; nY < mnHeight; nY+=4 ) // pass 4
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) );
for (nY = 0; nY < mnHeight; nY += 4) // pass 4
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 2, 4));
}
ImplClearFirstScanline();
if ( mnHeight >= 3 ) // pass 5
if (mnHeight >= 3) // pass 5
{
for ( nY = 2; nY < mnHeight; nY+=4 )
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) );
for (nY = 2; nY < mnHeight; nY += 4)
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 2));
}
ImplClearFirstScanline();
}
for ( nY = 0; nY < mnHeight; nY+=2 ) // pass 6
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) );
for (nY = 0; nY < mnHeight; nY += 2) // pass 6
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 1, 2));
}
ImplClearFirstScanline();
if ( mnHeight >= 2 ) // pass 7
if (mnHeight >= 2) // pass 7
{
for ( nY = 1; nY < mnHeight; nY+=2 )
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) );
for (nY = 1; nY < mnHeight; nY += 2)
{
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter (nY, 0, 1));
}
}
}
mpZCodec.EndCompression();
mnCRC = mpZCodec.GetCRC();
if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
if (mnFilterType) // using filter type 4 we need memory for the scanline 3 times
{
delete[] mpCurrentScan;
delete[] mpPreviousScan;
......@@ -428,11 +470,11 @@ void PNGWriterImpl::ImplWriteIDAT ()
sal_uInt32 nIDATSize = aOStm.Tell();
sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
while( nBytesToWrite )
while(nBytesToWrite)
{
nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
ImplOpenChunk( PNGCHUNK_IDAT );
ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes );
ImplOpenChunk(PNGCHUNK_IDAT);
ImplWriteChunk((unsigned char*)aOStm.GetData() + (nIDATSize - nBytesToWrite), nBytes);
nBytesToWrite -= nBytes;
}
}
......@@ -441,58 +483,62 @@ void PNGWriterImpl::ImplWriteIDAT ()
// appends to the currently used pass
// the complete size of scanline will be returned - in interlace mode zero is possible!
sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd )
sal_uLong PNGWriterImpl::ImplGetFilter (sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd)
{
sal_uInt8* pDest;
if ( mnFilterType )
if (mnFilterType)
pDest = mpCurrentScan;
else
pDest = mpDeflateInBuf;
if ( nXStart < mnWidth )
if (nXStart < mnWidth)
{
*pDest++ = mnFilterType; // in this version the filter type is either 0 or 4
*pDest++ = mnFilterType; // in this version the filter type is either 0 or 4
if ( mpAccess->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
if (mpAccess->HasPalette()) // alphachannel is not allowed by pictures including palette entries
{
switch ( mnBitsPerPixel )
switch (mnBitsPerPixel)
{
case( 1 ):
case 1:
{
sal_uLong nX, nXIndex;
for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+=nXAdd, nXIndex++ )
for (nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++)
{
sal_uLong nShift = ( nXIndex & 7 ) ^ 7;
if ( nShift == 7)
*pDest = mpAccess->GetPixelIndex( nY, nX ) << nShift;
else if ( nShift == 0 )
*pDest++ |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
sal_uLong nShift = (nXIndex & 7) ^ 7;
if (nShift == 7)
*pDest = mpAccess->GetPixelIndex(nY, nX) << nShift;
else if (nShift == 0)
*pDest++ |= mpAccess->GetPixelIndex(nY, nX) << nShift;
else
*pDest |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
*pDest |= mpAccess->GetPixelIndex(nY, nX) << nShift;
}
if ( ( nXIndex & 7 ) != 0 ) pDest++; // byte is not completely used, so the
} // bufferpointer is to correct
if ( (nXIndex & 7) != 0 )
pDest++; // byte is not completely used, so the bufferpointer is to correct
}
break;
case( 4 ):
case 4:
{
sal_uLong nX, nXIndex;
for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+= nXAdd, nXIndex++ )
for (nX = nXStart, nXIndex = 0; nX < mnWidth; nX += nXAdd, nXIndex++)
{
if( nXIndex & 1 )
*pDest++ |= mpAccess->GetPixelIndex( nY, nX );
if(nXIndex & 1)
*pDest++ |= mpAccess->GetPixelIndex(nY, nX);
else
*pDest = mpAccess->GetPixelIndex( nY, nX ) << 4;
*pDest = mpAccess->GetPixelIndex(nY, nX) << 4;
}
if ( nXIndex & 1 ) pDest++;
if (nXIndex & 1)
pDest++;
}
break;
case( 8 ):
case 8:
{
for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
for (sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd)
{
*pDest++ = mpAccess->GetPixelIndex( nY, nX );
}
}
break;
......@@ -503,31 +549,31 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
}
else
{
if ( mpMaskAccess ) // mpMaskAccess != NULL -> alphachannel is to create
if (mpMaskAccess) // mpMaskAccess != NULL -> alphachannel is to create
{
if ( mbTrueAlpha )
if (mbTrueAlpha)
{
for ( sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd )
for (sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd)
{
const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
const BitmapColor& rColor = mpAccess->GetPixel(nY, nX);
*pDest++ = rColor.GetRed();
*pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue();
*pDest++ = 255 - mpMaskAccess->GetPixelIndex( nY, nX );
*pDest++ = 255 - mpMaskAccess->GetPixelIndex(nY, nX);
}
}
else
{
const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
const BitmapColor aTrans(mpMaskAccess->GetBestMatchingColor(Color(COL_WHITE)));
for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
for (sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd)
{
const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
const BitmapColor& rColor = mpAccess->GetPixel(nY, nX);
*pDest++ = rColor.GetRed();
*pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue();
if( mpMaskAccess->GetPixel( nY, nX ) == aTrans )
if(mpMaskAccess->GetPixel(nY, nX) == aTrans)
*pDest++ = 0;
else
*pDest++ = 0xff;
......@@ -536,9 +582,9 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
}
else
{
for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
for (sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd)
{
const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
const BitmapColor& rColor = mpAccess->GetPixel(nY, nX);
*pDest++ = rColor.GetRed();
*pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue();
......@@ -547,110 +593,121 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
}
}
// filter type4 ( PAETH ) will be used only for 24bit graphics
if ( mnFilterType )
if (mnFilterType)
{
mnDeflateInSize = pDest - mpCurrentScan;
pDest = mpDeflateInBuf;
*pDest++ = 4; // filter type
*pDest++ = 4; // filter type
sal_uLong na, nb, nc;
long np, npa, npb, npc;
sal_uInt8* p1 = mpCurrentScan + 1; // Current Pixel
sal_uInt8* p2 = p1 - mnBBP; // left pixel
sal_uInt8* p3 = mpPreviousScan; // upper pixel
sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel;
sal_uInt8* p1 = mpCurrentScan + 1; // Current Pixel
sal_uInt8* p2 = p1 - mnBBP; // left pixel
sal_uInt8* p3 = mpPreviousScan; // upper pixel
sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel;
while ( pDest < mpDeflateInBuf + mnDeflateInSize )
while (pDest < mpDeflateInBuf + mnDeflateInSize)
{
nb = *p3++;
if ( p2 >= mpCurrentScan + 1 )
if (p2 >= mpCurrentScan + 1)
{
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 )
if (npa < 0)
npa =-npa;
if ( npb < 0 )
if (npb < 0)
npb =-npb;
if ( npc < 0 )
if (npc < 0)
npc =-npc;
if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na;
else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb;
else *pDest++ = *p1++ - (sal_uInt8)nc;
if (npa <= npb && npa <= npc)
*pDest++ = *p1++ - static_cast<sal_uInt8>(na);
else if ( npb <= npc )
*pDest++ = *p1++ - static_cast<sal_uInt8>(nb);
else
*pDest++ = *p1++ - static_cast<sal_uInt8>(nc);
p4++;
p2++;
}
for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ )
mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ];
for (long i = 0; i < static_cast<long>(mnDeflateInSize - 1); i++)
{
mpPreviousScan[i] = mpCurrentScan[i + 1];
}
}
else
{
mnDeflateInSize = pDest - mpDeflateInBuf;
}
return mnDeflateInSize;
}
void PNGWriterImpl::ImplClearFirstScanline()
{
if ( mnFilterType )
memset( mpPreviousScan, 0, mnDeflateInSize );
if (mnFilterType)
memset(mpPreviousScan, 0, mnDeflateInSize);
}
void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType )
void PNGWriterImpl::ImplOpenChunk (sal_uLong nChunkType)
{
maChunkSeq.resize( maChunkSeq.size() + 1 );
maChunkSeq.resize(maChunkSeq.size() + 1);
maChunkSeq.back().nType = nChunkType;
}
void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource )
void PNGWriterImpl::ImplWriteChunk (sal_uInt8 nSource)
{
maChunkSeq.back().aData.push_back( nSource );
maChunkSeq.back().aData.push_back(nSource);
}
void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource )
void PNGWriterImpl::ImplWriteChunk (sal_uInt32 nSource)
{
vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) );
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) );
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) );
rChunkData.aData.push_back( (sal_uInt8)( nSource ) );
rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 24));
rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 16));
rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 8));
rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource));
}
void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize )
void PNGWriterImpl::ImplWriteChunk (unsigned char* pSource, sal_uInt32 nDatSize)
{
if ( nDatSize )
if (nDatSize)
{
vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
sal_uInt32 nSize = rChunkData.aData.size();
rChunkData.aData.resize( nSize + nDatSize );
memcpy( &rChunkData.aData[ nSize ], pSource, nDatSize );
rChunkData.aData.resize(nSize + nDatSize);
memcpy(&rChunkData.aData[nSize], pSource, nDatSize);
}
}
PNGWriter::PNGWriter( const BitmapEx& rBmpEx,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) )
PNGWriter::PNGWriter(const BitmapEx& rBmpEx,
const css::uno::Sequence<css::beans::PropertyValue>* pFilterData)
: mpImpl(new vcl::PNGWriterImpl(rBmpEx, pFilterData))
{
}
PNGWriter::~PNGWriter()
{
delete mpImpl;
}
bool PNGWriter::Write( SvStream& rIStm )
bool PNGWriter::Write(SvStream& rStream)
{
return mpImpl->Write( rIStm );
return mpImpl->Write(rStream);
}
std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
std::vector<vcl::PNGWriter::ChunkData>& PNGWriter::GetChunks()
{
return mpImpl->GetChunks();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment