mmplugins/imagingplugins/codecs/PNGCodec/PngScanlineEncoder.cpp
branchRCL_3
changeset 50 948c7f65f6d4
parent 0 40261b775718
--- /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);
+		}
+	}