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 @@ ...@@ -26,33 +26,28 @@
#include <vcl/bitmapex.hxx> #include <vcl/bitmapex.hxx>
#include <vector> #include <vector>
// - PNGWriter -
namespace vcl namespace vcl
{ {
class PNGWriterImpl; class PNGWriterImpl;
class VCL_DLLPUBLIC PNGWriter class VCL_DLLPUBLIC PNGWriter
{ {
PNGWriterImpl* mpImpl; const std::unique_ptr<PNGWriterImpl> mpImpl;
public: public:
explicit PNGWriter( const BitmapEx&, explicit PNGWriter(const BitmapEx&, const css::uno::Sequence<css::beans::PropertyValue>* pFilterData = NULL);
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
~PNGWriter(); ~PNGWriter();
bool Write( SvStream& rStm ); bool Write(SvStream& rStream);
// additional method to be able to modify all chunk before they are stored // additional method to be able to modify all chunk before they are stored
struct ChunkData struct ChunkData
{ {
sal_uInt32 nType; 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,16 +47,19 @@ class PNGWriterImpl ...@@ -47,16 +47,19 @@ class PNGWriterImpl
{ {
public: public:
PNGWriterImpl( const BitmapEx& BmpEx, PNGWriterImpl(const BitmapEx& BmpEx,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL ); 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: private:
std::vector< vcl::PNGWriter::ChunkData > maChunkSeq; std::vector<vcl::PNGWriter::ChunkData> maChunkSeq;
sal_Int32 mnCompLevel; sal_Int32 mnCompLevel;
sal_Int32 mnInterlaced; sal_Int32 mnInterlaced;
...@@ -72,28 +75,29 @@ private: ...@@ -72,28 +75,29 @@ private:
sal_uInt8* mpCurrentScan; sal_uInt8* mpCurrentScan;
sal_uLong mnDeflateInSize; sal_uLong mnDeflateInSize;
sal_uLong mnWidth, mnHeight; sal_uLong mnWidth;
sal_uLong mnHeight;
sal_uInt8 mnBitsPerPixel; sal_uInt8 mnBitsPerPixel;
sal_uInt8 mnFilterType; // 0 oder 4; sal_uInt8 mnFilterType; // 0 oder 4;
sal_uLong mnBBP; // bytes per pixel ( needed for filtering ) sal_uLong mnBBP; // bytes per pixel ( needed for filtering )
bool mbTrueAlpha; bool mbTrueAlpha;
sal_uLong mnCRC; sal_uLong mnCRC;
void ImplWritepHYs( const BitmapEx& rBitmapEx ); void ImplWritepHYs(const BitmapEx& rBitmapEx);
void ImplWriteIDAT(); void ImplWriteIDAT();
sal_uLong ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 ); sal_uLong ImplGetFilter(sal_uLong nY, sal_uLong nXStart = 0, sal_uLong nXAdd = 1);
void ImplClearFirstScanline(); void ImplClearFirstScanline();
void ImplWriteTransparent(); void ImplWriteTransparent();
bool ImplWriteHeader(); bool ImplWriteHeader();
void ImplWritePalette(); void ImplWritePalette();
void ImplOpenChunk( sal_uLong nChunkType ); void ImplOpenChunk(sal_uLong nChunkType);
void ImplWriteChunk( sal_uInt8 nNumb ); void ImplWriteChunk(sal_uInt8 nNumb);
void ImplWriteChunk( sal_uInt32 nNumb ); void ImplWriteChunk(sal_uInt32 nNumb);
void ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize ); void ImplWriteChunk(unsigned char* pSource, sal_uInt32 nDatSize);
}; };
PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx, 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) : mnCompLevel(PNG_DEF_COMPRESSION)
, mnInterlaced(0) , mnInterlaced(0)
, mnMaxChunkSize(0) , mnMaxChunkSize(0)
...@@ -112,158 +116,174 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx, ...@@ -112,158 +116,174 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
, mbTrueAlpha(false) , mbTrueAlpha(false)
, mnCRC(0UL) , 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 // #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; sal_Int32 i = 0;
for ( i = 0; i < pFilterData->getLength(); i++ ) for (i = 0; i < pFilterData->getLength(); i++)
{ {
if ( (*pFilterData)[ i ].Name == "Compression" ) if ((*pFilterData)[i].Name == "Compression")
(*pFilterData)[ i ].Value >>= mnCompLevel; (*pFilterData)[i].Value >>= mnCompLevel;
else if ( (*pFilterData)[ i ].Name == "Interlaced" ) else if ((*pFilterData)[i].Name == "Interlaced")
(*pFilterData)[ i ].Value >>= mnInterlaced; (*pFilterData)[i].Value >>= mnInterlaced;
else if ( (*pFilterData)[ i ].Name == "MaxChunkSize" ) else if ((*pFilterData)[i].Name == "MaxChunkSize")
{ {
sal_Int32 nVal = 0; sal_Int32 nVal = 0;
if ( (*pFilterData)[ i ].Value >>= nVal ) if ((*pFilterData)[i].Value >>= nVal)
mnMaxChunkSize = (sal_uInt32)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 ); aBmp.Convert( BMP_CONVERSION_24BIT );
mnBitsPerPixel = 24; mnBitsPerPixel = 24;
} }
if ( mnBitsPerPixel <= 8 ) // transparent palette if (mnBitsPerPixel <= 8) // transparent palette
{ {
aBmp.Convert( BMP_CONVERSION_8BIT_TRANS ); aBmp.Convert(BMP_CONVERSION_8BIT_TRANS);
aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS ); aBmp.Replace(rBmpEx.GetMask(), BMP_COL_TRANS);
mnBitsPerPixel = 8; mnBitsPerPixel = 8;
mpAccess = aBmp.AcquireReadAccess(); mpAccess = aBmp.AcquireReadAccess();
if ( mpAccess ) if (mpAccess)
{ {
if ( ImplWriteHeader() ) if (ImplWriteHeader())
{ {
ImplWritepHYs( rBmpEx ); ImplWritepHYs(rBmpEx);
ImplWritePalette(); ImplWritePalette();
ImplWriteTransparent(); ImplWriteTransparent();
ImplWriteIDAT(); ImplWriteIDAT();
} }
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0; aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
} }
else else
{
mbStatus = false; mbStatus = false;
} }
}
else else
{ {
mpAccess = aBmp.AcquireReadAccess(); // true RGB with alphachannel mpAccess = aBmp.AcquireReadAccess(); // true RGB with alphachannel
if( mpAccess ) if (mpAccess)
{ {
if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) ) if ((mbTrueAlpha = rBmpEx.IsAlpha()))
{ {
AlphaMask aMask( rBmpEx.GetAlpha() ); AlphaMask aMask(rBmpEx.GetAlpha());
mpMaskAccess = aMask.AcquireReadAccess(); mpMaskAccess = aMask.AcquireReadAccess();
if ( mpMaskAccess ) if (mpMaskAccess)
{ {
if ( ImplWriteHeader() ) if (ImplWriteHeader())
{ {
ImplWritepHYs( rBmpEx ); ImplWritepHYs(rBmpEx);
ImplWriteIDAT(); ImplWriteIDAT();
} }
aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0; aMask.ReleaseAccess(mpMaskAccess);
mpMaskAccess = NULL;
} }
else else
{
mbStatus = false; mbStatus = false;
} }
}
else else
{ {
Bitmap aMask( rBmpEx.GetMask() ); Bitmap aMask(rBmpEx.GetMask());
mpMaskAccess = aMask.AcquireReadAccess(); mpMaskAccess = aMask.AcquireReadAccess();
if( mpMaskAccess ) if (mpMaskAccess)
{ {
if ( ImplWriteHeader() ) if (ImplWriteHeader())
{ {
ImplWritepHYs( rBmpEx ); ImplWritepHYs(rBmpEx);
ImplWriteIDAT(); ImplWriteIDAT();
} }
aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0; aMask.ReleaseAccess(mpMaskAccess);
mpMaskAccess = NULL;
} }
else else
{
mbStatus = false; mbStatus = false;
} }
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0; }
aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
} }
else else
{
mbStatus = false; mbStatus = false;
} }
} }
}
else else
{ {
mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel
if( mpAccess ) if (mpAccess)
{ {
if ( ImplWriteHeader() ) if (ImplWriteHeader())
{ {
ImplWritepHYs( rBmpEx ); ImplWritepHYs(rBmpEx);
if( mpAccess->HasPalette() ) if (mpAccess->HasPalette())
ImplWritePalette(); ImplWritePalette();
ImplWriteIDAT(); ImplWriteIDAT();
} }
aBmp.ReleaseAccess( mpAccess ), mpAccess = 0; aBmp.ReleaseAccess(mpAccess);
mpAccess = NULL;
} }
else else
{
mbStatus = false; 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 */ /* png signature is always an array of 8 bytes */
SvStreamEndian nOldMode = rOStm.GetEndian(); SvStreamEndian nOldMode = rOStm.GetEndian();
rOStm.SetEndian( SvStreamEndian::BIG ); rOStm.SetEndian(SvStreamEndian::BIG);
rOStm.WriteUInt32( 0x89504e47 ); rOStm.WriteUInt32(0x89504e47);
rOStm.WriteUInt32( 0x0d0a1a0a ); rOStm.WriteUInt32(0x0d0a1a0a);
std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() ); std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg(maChunkSeq.begin());
std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() ); std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd(maChunkSeq.end());
while( aBeg != aEnd ) while (aBeg != aEnd)
{ {
sal_uInt32 nType = aBeg->nType; sal_uInt32 nType = aBeg->nType;
#if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN) #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
nType = OSL_SWAPDWORD( nType ); nType = OSL_SWAPDWORD(nType);
#endif #endif
sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 ); sal_uInt32 nCRC = rtl_crc32(0, &nType, 4);
sal_uInt32 nDataSize = aBeg->aData.size(); sal_uInt32 nDataSize = aBeg->aData.size();
if ( nDataSize ) if (nDataSize)
nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize ); nCRC = rtl_crc32(nCRC, &aBeg->aData[0], nDataSize);
rOStm.WriteUInt32( nDataSize ) rOStm.WriteUInt32(nDataSize);
.WriteUInt32( aBeg->nType ); rOStm.WriteUInt32(aBeg->nType);
if ( nDataSize ) if (nDataSize)
rOStm.Write( &aBeg->aData[ 0 ], nDataSize ); rOStm.Write(&aBeg->aData[0], nDataSize);
rOStm.WriteUInt32( nCRC ); rOStm.WriteUInt32(nCRC);
++aBeg; ++aBeg;
} }
rOStm.SetEndian( nOldMode ); rOStm.SetEndian(nOldMode);
return mbStatus; return mbStatus;
} }
...@@ -271,155 +291,177 @@ bool PNGWriterImpl::Write( SvStream& rOStm ) ...@@ -271,155 +291,177 @@ bool PNGWriterImpl::Write( SvStream& rOStm )
bool PNGWriterImpl::ImplWriteHeader() bool PNGWriterImpl::ImplWriteHeader()
{ {
ImplOpenChunk(PNGCHUNK_IHDR); ImplOpenChunk(PNGCHUNK_IHDR);
ImplWriteChunk( sal_uInt32( mnWidth = mpAccess->Width() ) ); ImplWriteChunk(sal_uInt32(mnWidth = mpAccess->Width()));
ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) ); ImplWriteChunk(sal_uInt32(mnHeight = mpAccess->Height()));
if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus ) if (mnWidth && mnHeight && mnBitsPerPixel && mbStatus)
{ {
sal_uInt8 nBitDepth = mnBitsPerPixel; sal_uInt8 nBitDepth = mnBitsPerPixel;
if ( mnBitsPerPixel <= 8 ) if (mnBitsPerPixel <= 8)
mnFilterType = 0; mnFilterType = 0;
else else
mnFilterType = 4; mnFilterType = 4;
sal_uInt8 nColorType = 2; // colortype: sal_uInt8 nColorType = 2; // colortype:
// bit 0 -> palette is used // bit 0 -> palette is used
if ( mpAccess->HasPalette() ) // bit 1 -> color is used if (mpAccess->HasPalette()) // bit 1 -> color is used
nColorType |= 1; // bit 2 -> alpha channel is used nColorType |= 1; // bit 2 -> alpha channel is used
else else
nBitDepth /= 3; nBitDepth /= 3;
if ( mpMaskAccess ) if (mpMaskAccess)
nColorType |= 4; nColorType |= 4;
ImplWriteChunk( nBitDepth ); ImplWriteChunk(nBitDepth);
ImplWriteChunk( nColorType ); // colortype ImplWriteChunk(nColorType); // colortype
ImplWriteChunk((sal_uInt8) 0 ); // compression type ImplWriteChunk(static_cast<sal_uInt8>(0)); // compression type
ImplWriteChunk((sal_uInt8) 0 ); // filter type - is not supported in this version ImplWriteChunk(static_cast<sal_uInt8>(0)); // filter type - is not supported in this version
ImplWriteChunk((sal_uInt8) mnInterlaced ); // interlace type ImplWriteChunk(static_cast<sal_uInt8>(mnInterlaced)); // interlace type
} }
else else
{
mbStatus = false; mbStatus = false;
}
return mbStatus; return mbStatus;
} }
void PNGWriterImpl::ImplWritePalette() void PNGWriterImpl::ImplWritePalette()
{ {
const sal_uLong nCount = mpAccess->GetPaletteEntryCount(); const sal_uLong nCount = mpAccess->GetPaletteEntryCount();
boost::scoped_array<sal_uInt8> pTempBuf(new sal_uInt8[ nCount*3 ]); boost::scoped_array<sal_uInt8> pTempBuf(new sal_uInt8[nCount * 3]);
sal_uInt8* pTmp = pTempBuf.get(); sal_uInt8* pTmp = pTempBuf.get();
ImplOpenChunk( PNGCHUNK_PLTE ); ImplOpenChunk(PNGCHUNK_PLTE);
for ( sal_uInt16 i = 0; i < nCount; i++ ) 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.GetRed();
*pTmp++ = rColor.GetGreen(); *pTmp++ = rColor.GetGreen();
*pTmp++ = rColor.GetBlue(); *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++ ) for (sal_uLong n = 0UL; n <= nTransIndex; n++)
ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff ); {
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() ); Size aPrefSize(rBmpEx.GetPrefSize());
if ( aPrefSize.Width() && aPrefSize.Height() && mnWidth && mnHeight )
if (aPrefSize.Width() && aPrefSize.Height() && mnWidth && mnHeight)
{ {
ImplOpenChunk( PNGCHUNK_pHYs ); ImplOpenChunk(PNGCHUNK_pHYs);
sal_uInt8 nMapUnit = 1; sal_uInt8 nMapUnit = 1;
sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 ); sal_uInt32 nPrefSizeX = static_cast<sal_uInt32>(100000.0 / (static_cast<double>(aPrefSize.Width()) / mnWidth) + 0.5);
sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 ); sal_uInt32 nPrefSizeY = static_cast<sal_uInt32>(100000.0 / (static_cast<double>(aPrefSize.Height()) / mnHeight) + 0.5);
ImplWriteChunk( nPrefSizeX ); ImplWriteChunk(nPrefSizeX);
ImplWriteChunk( nPrefSizeY ); ImplWriteChunk(nPrefSizeY);
ImplWriteChunk( nMapUnit ); ImplWriteChunk(nMapUnit);
} }
} }
} }
void PNGWriterImpl::ImplWriteIDAT () void PNGWriterImpl::ImplWriteIDAT()
{ {
mnDeflateInSize = mnBitsPerPixel; mnDeflateInSize = mnBitsPerPixel;
if( mpMaskAccess ) if (mpMaskAccess)
mnDeflateInSize += 8; mnDeflateInSize += 8;
mnBBP = ( mnDeflateInSize + 7 ) >> 3; mnBBP = (mnDeflateInSize + 7) >> 3;
mnDeflateInSize = mnBBP * mnWidth + 1; 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 ]; mpPreviousScan = new sal_uInt8[mnDeflateInSize];
mpCurrentScan = new sal_uInt8[ mnDeflateInSize ]; mpCurrentScan = new sal_uInt8[mnDeflateInSize];
ImplClearFirstScanline(); ImplClearFirstScanline();
} }
mpZCodec.BeginCompression( mnCompLevel, true ); mpZCodec.BeginCompression(mnCompLevel, true);
mpZCodec.SetCRC( mnCRC ); mpZCodec.SetCRC(mnCRC);
SvMemoryStream aOStm; SvMemoryStream aOStm;
if ( mnInterlaced == 0 ) if (mnInterlaced == 0)
{
for (sal_uLong nY = 0; nY < mnHeight; nY++)
{ {
for ( sal_uLong nY = 0; nY < mnHeight; nY++ ) mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY));
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) ); }
} }
else else
{ {
// interlace mode // interlace mode
sal_uLong nY; sal_uLong nY;
for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 1 for (nY = 0; nY < mnHeight; nY += 8) // pass 1
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) ); {
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 8));
}
ImplClearFirstScanline(); ImplClearFirstScanline();
for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 2 for (nY = 0; nY < mnHeight; nY += 8) // pass 2
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) ); {
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 4, 8));
}
ImplClearFirstScanline(); ImplClearFirstScanline();
if ( mnHeight >= 5 ) // pass 3 if (mnHeight >= 5) // pass 3
{
for (nY = 4; nY < mnHeight; nY += 8)
{ {
for ( nY = 4; nY < mnHeight; nY+=8 ) mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 4));
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) ); }
ImplClearFirstScanline(); ImplClearFirstScanline();
} }
for ( nY = 0; nY < mnHeight; nY+=4 ) // pass 4 for (nY = 0; nY < mnHeight; nY += 4) // pass 4
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) ); {
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 2, 4));
}
ImplClearFirstScanline(); ImplClearFirstScanline();
if ( mnHeight >= 3 ) // pass 5 if (mnHeight >= 3) // pass 5
{
for (nY = 2; nY < mnHeight; nY += 4)
{ {
for ( nY = 2; nY < mnHeight; nY+=4 ) mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 0, 2));
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) ); }
ImplClearFirstScanline(); ImplClearFirstScanline();
} }
for ( nY = 0; nY < mnHeight; nY+=2 ) // pass 6 for (nY = 0; nY < mnHeight; nY += 2) // pass 6
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) ); {
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter(nY, 1, 2));
}
ImplClearFirstScanline(); ImplClearFirstScanline();
if ( mnHeight >= 2 ) // pass 7 if (mnHeight >= 2) // pass 7
{ {
for ( nY = 1; nY < mnHeight; nY+=2 ) for (nY = 1; nY < mnHeight; nY += 2)
mpZCodec.Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) ); {
mpZCodec.Write(aOStm, mpDeflateInBuf, ImplGetFilter (nY, 0, 1));
}
} }
} }
mpZCodec.EndCompression(); mpZCodec.EndCompression();
mnCRC = mpZCodec.GetCRC(); 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[] mpCurrentScan;
delete[] mpPreviousScan; delete[] mpPreviousScan;
...@@ -428,11 +470,11 @@ void PNGWriterImpl::ImplWriteIDAT () ...@@ -428,11 +470,11 @@ void PNGWriterImpl::ImplWriteIDAT ()
sal_uInt32 nIDATSize = aOStm.Tell(); sal_uInt32 nIDATSize = aOStm.Tell();
sal_uInt32 nBytes, nBytesToWrite = nIDATSize; sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
while( nBytesToWrite ) while(nBytesToWrite)
{ {
nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize; nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
ImplOpenChunk( PNGCHUNK_IDAT ); ImplOpenChunk(PNGCHUNK_IDAT);
ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes ); ImplWriteChunk((unsigned char*)aOStm.GetData() + (nIDATSize - nBytesToWrite), nBytes);
nBytesToWrite -= nBytes; nBytesToWrite -= nBytes;
} }
} }
...@@ -441,59 +483,63 @@ void PNGWriterImpl::ImplWriteIDAT () ...@@ -441,59 +483,63 @@ void PNGWriterImpl::ImplWriteIDAT ()
// appends to the currently used pass // appends to the currently used pass
// the complete size of scanline will be returned - in interlace mode zero is possible! // 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; sal_uInt8* pDest;
if ( mnFilterType ) if (mnFilterType)
pDest = mpCurrentScan; pDest = mpCurrentScan;
else else
pDest = mpDeflateInBuf; 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; 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; sal_uLong nShift = (nXIndex & 7) ^ 7;
if ( nShift == 7) if (nShift == 7)
*pDest = mpAccess->GetPixelIndex( nY, nX ) << nShift; *pDest = mpAccess->GetPixelIndex(nY, nX) << nShift;
else if ( nShift == 0 ) else if (nShift == 0)
*pDest++ |= mpAccess->GetPixelIndex( nY, nX ) << nShift; *pDest++ |= mpAccess->GetPixelIndex(nY, nX) << nShift;
else 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; break;
case( 4 ): case 4:
{ {
sal_uLong nX, nXIndex; 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 ) if(nXIndex & 1)
*pDest++ |= mpAccess->GetPixelIndex( nY, nX ); *pDest++ |= mpAccess->GetPixelIndex(nY, nX);
else else
*pDest = mpAccess->GetPixelIndex( nY, nX ) << 4; *pDest = mpAccess->GetPixelIndex(nY, nX) << 4;
} }
if ( nXIndex & 1 ) pDest++; if (nXIndex & 1)
pDest++;
} }
break; 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 ); *pDest++ = mpAccess->GetPixelIndex( nY, nX );
} }
}
break; break;
default : default :
...@@ -503,31 +549,31 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL ...@@ -503,31 +549,31 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
} }
else 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.GetRed();
*pDest++ = rColor.GetGreen(); *pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue(); *pDest++ = rColor.GetBlue();
*pDest++ = 255 - mpMaskAccess->GetPixelIndex( nY, nX ); *pDest++ = 255 - mpMaskAccess->GetPixelIndex(nY, nX);
} }
} }
else 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.GetRed();
*pDest++ = rColor.GetGreen(); *pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue(); *pDest++ = rColor.GetBlue();
if( mpMaskAccess->GetPixel( nY, nX ) == aTrans ) if(mpMaskAccess->GetPixel(nY, nX) == aTrans)
*pDest++ = 0; *pDest++ = 0;
else else
*pDest++ = 0xff; *pDest++ = 0xff;
...@@ -536,9 +582,9 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL ...@@ -536,9 +582,9 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
} }
else 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.GetRed();
*pDest++ = rColor.GetGreen(); *pDest++ = rColor.GetGreen();
*pDest++ = rColor.GetBlue(); *pDest++ = rColor.GetBlue();
...@@ -547,7 +593,7 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL ...@@ -547,7 +593,7 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
} }
} }
// filter type4 ( PAETH ) will be used only for 24bit graphics // filter type4 ( PAETH ) will be used only for 24bit graphics
if ( mnFilterType ) if (mnFilterType)
{ {
mnDeflateInSize = pDest - mpCurrentScan; mnDeflateInSize = pDest - mpCurrentScan;
pDest = mpDeflateInBuf; pDest = mpDeflateInBuf;
...@@ -561,96 +607,107 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL ...@@ -561,96 +607,107 @@ sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uL
sal_uInt8* p3 = mpPreviousScan; // upper pixel sal_uInt8* p3 = mpPreviousScan; // upper pixel
sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel; sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel;
while ( pDest < mpDeflateInBuf + mnDeflateInSize ) while (pDest < mpDeflateInBuf + mnDeflateInSize)
{ {
nb = *p3++; nb = *p3++;
if ( p2 >= mpCurrentScan + 1 ) if (p2 >= mpCurrentScan + 1)
{ {
na = *p2; na = *p2;
nc = *p4; nc = *p4;
} }
else else
{
na = nc = 0; na = nc = 0;
}
np = na + nb; np = na + nb;
np -= nc; np -= nc;
npa = np - na; npa = np - na;
npb = np - nb; npb = np - nb;
npc = np - nc; npc = np - nc;
if ( npa < 0 )
if (npa < 0)
npa =-npa; npa =-npa;
if ( npb < 0 ) if (npb < 0)
npb =-npb; npb =-npb;
if ( npc < 0 ) if (npc < 0)
npc =-npc; npc =-npc;
if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na;
else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb; if (npa <= npb && npa <= npc)
else *pDest++ = *p1++ - (sal_uInt8)nc; *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++; p4++;
p2++; p2++;
} }
for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ ) for (long i = 0; i < static_cast<long>(mnDeflateInSize - 1); i++)
mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ]; {
mpPreviousScan[i] = mpCurrentScan[i + 1];
}
} }
else else
{
mnDeflateInSize = pDest - mpDeflateInBuf; mnDeflateInSize = pDest - mpDeflateInBuf;
}
return mnDeflateInSize; return mnDeflateInSize;
} }
void PNGWriterImpl::ImplClearFirstScanline() void PNGWriterImpl::ImplClearFirstScanline()
{ {
if ( mnFilterType ) if (mnFilterType)
memset( mpPreviousScan, 0, mnDeflateInSize ); 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; 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(); vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) ); rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 24));
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) ); rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 16));
rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) ); rChunkData.aData.push_back(static_cast<sal_uInt8>(nSource >> 8));
rChunkData.aData.push_back( (sal_uInt8)( nSource ) ); 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(); vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
sal_uInt32 nSize = rChunkData.aData.size(); sal_uInt32 nSize = rChunkData.aData.size();
rChunkData.aData.resize( nSize + nDatSize ); rChunkData.aData.resize(nSize + nDatSize);
memcpy( &rChunkData.aData[ nSize ], pSource, nDatSize ); memcpy(&rChunkData.aData[nSize], pSource, nDatSize);
} }
} }
PNGWriter::PNGWriter( const BitmapEx& rBmpEx, PNGWriter::PNGWriter(const BitmapEx& rBmpEx,
const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) : const css::uno::Sequence<css::beans::PropertyValue>* pFilterData)
mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) ) : mpImpl(new vcl::PNGWriterImpl(rBmpEx, pFilterData))
{ {
} }
PNGWriter::~PNGWriter() 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(); 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