--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/PNGCodec/PngScanlineEncoder.cpp Wed Sep 01 12:38:50 2010 +0100
@@ -0,0 +1,363 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "PngScanlineEncoder.h"
+
+// CPngWriteSubCodec
+CPngWriteSubCodec* CPngWriteSubCodec::NewL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
+ {
+ CPngWriteSubCodec* self = NULL;
+
+ switch (aInfo.iBitDepth)
+ {
+ case 1:
+ self = new(ELeave) CBitDepth1Encoder;
+ break;
+ case 2:
+ self = new(ELeave) CBitDepth2Encoder;
+ break;
+ case 4:
+ self = new(ELeave) CBitDepth4Encoder;
+ break;
+ case 8:
+ switch (aInfo.iColorType)
+ {
+ case TPngImageInformation::EGrayscale:
+ case TPngImageInformation::EIndexedColor:
+ self = new(ELeave) CBitDepth8Encoder;
+ break;
+ case TPngImageInformation::EDirectColor:
+ self = new(ELeave) CBitDepth8ColorType2Encoder;
+ break;
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+ break;
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+ ASSERT(self);
+ CleanupStack::PushL(self);
+ self->ConstructL(aInfo, aSource);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CPngWriteSubCodec::CPngWriteSubCodec()
+ : iScanlineDes(NULL, 0)
+ {
+ }
+
+CPngWriteSubCodec::~CPngWriteSubCodec()
+ {
+ delete iScanlineBuffer;
+ delete iPalette;
+ }
+
+void CPngWriteSubCodec::ConstructL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
+ {
+ iInfo = aInfo;
+ iSource = aSource;
+ iScanlineBufferSize = ScanlineBufferSize(iInfo.iSize.iWidth);
+ iScanlineBuffer = HBufC8::NewMaxL(iScanlineBufferSize);
+ iScanlineDes.Set(&(iScanlineBuffer->Des())[0], iScanlineBufferSize, iScanlineBufferSize);
+
+ // Init stuff specific to derived class
+ DoConstructL();
+ }
+
+void CPngWriteSubCodec::DoConstructL()
+ {
+ }
+
+TDes8& CPngWriteSubCodec::Buffer()
+ {
+ iScanlineDes.FillZ();
+ return iScanlineDes;
+ }
+
+TDes8& CPngWriteSubCodec::EncodeL(const TInt aScanline)
+ {
+ if (aScanline < iInfo.iSize.iHeight)
+ {
+ TUint8* dataPtr = const_cast<TUint8*>(iScanlineDes.Ptr());
+ const TUint8* dataPtrLimit = dataPtr + iScanlineBufferSize;
+
+ DoEncode(iSource, aScanline, dataPtr, dataPtrLimit);
+ }
+ else
+ {
+ iScanlineDes.Set(NULL, 0, 0);
+ }
+ return iScanlineDes;
+ }
+
+TUint8 CPngWriteSubCodec::ReverseBits(const TUint8 aValue) const
+ {
+ TUint value = aValue;
+ TUint reverseVal = 0;
+ for (TInt i = 0; i < 8; i++)
+ {
+ reverseVal <<= 1;
+ reverseVal |= value & 1;
+ value >>= 1;
+ }
+ return TUint8(reverseVal);
+ }
+
+void CPngWriteSubCodec::EncodePalettedScanline(TUint8* aDataPtr, const CFbsBitmap* aSource, const TInt aScanline,
+ const TInt aPixelsPerByte, const TInt aShiftValue)
+ {
+ // Encode a single scanline with indexes into the current palette
+ ASSERT(iInfo.iPalettePresent);
+ TPoint pos(0, aScanline);
+ const TInt scanLength = iInfo.iSize.iWidth;
+ for (TInt i=0; i < scanLength; i += aPixelsPerByte)
+ {
+ // Pack each byte with 'aPixelsPerByte' index values
+ TUint8 pixels = 0;
+ for (TInt j=0; j < aPixelsPerByte; j++)
+ {
+ pixels <<= aShiftValue;
+ TRgb rgb;
+ aSource->GetPixel(rgb, pos);
+ pixels |= TUint8(iPalette->NearestIndex(rgb));
+ pos.iX++;
+ }
+ *aDataPtr = pixels;
+ aDataPtr++;
+ }
+ }
+
+// CBitDepth1Encoder
+void CBitDepth1Encoder::DoConstructL()
+ {
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Setup palette
+ iPalette = CPalette::NewL(2);
+ iPalette->SetEntry(0, KRgbBlack);
+ iPalette->SetEntry(1, KRgbWhite);
+ iInfo.iPalettePresent = ETrue;
+ }
+ }
+
+TInt CBitDepth1Encoder::ScanlineBufferSize(TInt aPixelLength)
+ {
+ // 8 pixels per byte
+ return ((aPixelLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte) + KPngScanlineFilterTypeLength;
+ }
+
+void CBitDepth1Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
+ TUint8* aDataPtr, const TUint8* aDataPtrLimit)
+ {
+ // Filter method
+ PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
+ aDataPtr++;
+
+ // Pixel data
+ const TInt scanLength = iInfo.iSize.iWidth;
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Write palette indexes
+ EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth1PixelsPerByte, KPngDepth1ShiftValue);
+ }
+ else
+ {
+ // Write RGB data
+ TInt dataLength = (scanLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte;
+ TPtr8 dataPtr(aDataPtr, dataLength, dataLength);
+
+ aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray2);
+
+ // Reverse the order of the bits
+ while (aDataPtr < aDataPtrLimit)
+ {
+ aDataPtr[0] = ReverseBits(aDataPtr[0]);
+ aDataPtr++;
+ }
+ }
+ }
+
+// CBitDepth2Encoder
+void CBitDepth2Encoder::DoConstructL()
+ {
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Setup palette entries
+ iPalette = CPalette::NewL(4);
+ iPalette->SetEntry(0, KRgbBlack);
+ iPalette->SetEntry(1, KRgbDarkGray);
+ iPalette->SetEntry(2, KRgbGray);
+ iPalette->SetEntry(3, KRgbWhite);
+ iInfo.iPalettePresent = ETrue;
+ }
+ }
+
+TInt CBitDepth2Encoder::ScanlineBufferSize(TInt aPixelLength)
+ {
+ return ((aPixelLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte) + KPngScanlineFilterTypeLength;
+ }
+
+void CBitDepth2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
+ TUint8* aDataPtr, const TUint8* aDataPtrLimit)
+ {
+ // Filter method
+ PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
+ aDataPtr++;
+
+ // Pixel data
+ const TInt scanLength = iInfo.iSize.iWidth;
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Write palette indexes
+ EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth2PixelsPerByte, KPngDepth2ShiftValue);
+ }
+ else
+ {
+ // RGB values
+ TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte);
+ aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray4);
+
+ // Reverse the order of the bits
+ while (aDataPtr < aDataPtrLimit)
+ {
+ TUint8 value = aDataPtr[0];
+ TUint8 reverse = 0;
+ for (TInt i=0; i < KPngDepth2PixelsPerByte; i++)
+ {
+ reverse <<= 2; // advance the bits for the reverse value
+ reverse |= value & 0x3; // mask off the 2 bits, then OR with existing reverse value
+ value >>= 2; // advance the bits for the actual value
+ }
+ aDataPtr[0] = reverse;
+ aDataPtr++;
+ }
+ }
+ }
+
+// CBitDepth4Encoder
+void CBitDepth4Encoder::DoConstructL()
+ {
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Calculate palette for image
+ iPalette = CPalette::NewDefaultL(EColor16);
+ iInfo.iPalettePresent = ETrue;
+ }
+ }
+
+TInt CBitDepth4Encoder::ScanlineBufferSize(TInt aPixelLength)
+ {
+ return ((aPixelLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte) + KPngScanlineFilterTypeLength;
+ }
+
+void CBitDepth4Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
+ TUint8* aDataPtr, const TUint8* aDataPtrLimit)
+ {
+ // Filter method
+ PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
+ aDataPtr++;
+
+ // Pixel data
+ const TInt scanLength = iInfo.iSize.iWidth;
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Write palette indexes
+ EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth4PixelsPerByte, KPngDepth4ShiftValue);
+ }
+ else
+ {
+ TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte);
+ aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength,
+ (iInfo.iColorType == TPngImageInformation::EDirectColor) ? EColor16 : EGray16);
+
+ // Swap order of the low/high bits
+ while (aDataPtr < aDataPtrLimit)
+ {
+ TUint value = aDataPtr[0];
+ TUint low = value << KPngDepth4ShiftValue;
+ TUint high = value >> KPngDepth4ShiftValue;
+ aDataPtr[0] = TUint8(low | high);
+ aDataPtr++;
+ }
+ }
+ }
+
+// CBitDepth8ColorType2Encoder
+TInt CBitDepth8ColorType2Encoder::ScanlineBufferSize(TInt aPixelLength)
+ {
+ return (aPixelLength * KPngDepth8RgbBytesPerPixel) + KPngScanlineFilterTypeLength;
+ }
+
+void CBitDepth8ColorType2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
+ TUint8* aDataPtr, const TUint8* aDataPtrLimit)
+ {
+ // Filter method
+ PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
+ aDataPtr++;
+
+ // Pixel data
+ TPtr8 dataPtr(aDataPtr, iInfo.iSize.iWidth * KPngDepth8RgbBytesPerPixel);
+ aSource->GetScanLine(dataPtr, TPoint(0, aScanline), iInfo.iSize.iWidth, EColor16M);
+
+ while (aDataPtr < aDataPtrLimit)
+ {
+ // Swap the red and blue components of the image data
+ TUint8 temp = aDataPtr[0]; // temp = Red
+ aDataPtr[0] = aDataPtr[2]; // Red = Blue
+ aDataPtr[2] = temp; // Blue = temp
+ aDataPtr += KPngDepth8RgbBytesPerPixel;
+ }
+ }
+
+// CBitDepth8Encoder
+void CBitDepth8Encoder::DoConstructL()
+ {
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Calculate palette for image
+ iPalette = CPalette::NewDefaultL(EColor256);
+ iInfo.iPalettePresent = ETrue;
+ }
+ }
+
+TInt CBitDepth8Encoder::ScanlineBufferSize(TInt aPixelLength)
+ {
+ return aPixelLength + KPngScanlineFilterTypeLength;
+ }
+
+void CBitDepth8Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
+ TUint8* aDataPtr, const TUint8* /*aDataPtrLimit*/)
+ {
+ // Filter method
+ PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
+ aDataPtr++;
+
+ const TInt scanLength = iInfo.iSize.iWidth;
+ if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
+ {
+ // Write palette indexes
+ EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth8PixelsPerByte, KPngDepth8ShiftValue);
+ }
+ else
+ {
+ // Pixel data
+ TPtr8 dataPtr(aDataPtr, scanLength);
+ aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray256);
+ }
+ }