diff -r 000000000000 -r 40261b775718 mmplugins/imagingplugins/codecs/PNGCodec/PngScanlineEncoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/imagingplugins/codecs/PNGCodec/PngScanlineEncoder.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -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(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); + } + }