diff -r 000000000000 -r 5752a19fdefe imaging/imagingplugins/codecs/PNGCodec/PngScanlineDecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imaging/imagingplugins/codecs/PNGCodec/PngScanlineDecoder.cpp Wed Aug 25 12:29:52 2010 +0300 @@ -0,0 +1,1722 @@ +// 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 "PNGCodec.h" +#include "ImageUtils.h" + +const TInt KPngScanlineFilterTypeLength = 1; + +const TInt KColStart[KPngNumInterlacedPasses] = { 0, 4, 0, 2, 0, 1, 0, 0 }; +const TInt KRowStart[KPngNumInterlacedPasses] = { 0, 0, 4, 0, 2, 0, 1, 0 }; +const TInt KColIncrement[KPngNumInterlacedPasses] = { 8, 8, 4, 4, 2, 2, 1, 0 }; +const TInt KRowIncrement[KPngNumInterlacedPasses] = { 8, 8, 8, 4, 4, 2, 2, 0 }; +const TInt KBlockWidth[KPngNumInterlacedPasses] = { 8, 4, 4, 2, 2, 1, 1, 0 }; +const TInt KBlockHeight[KPngNumInterlacedPasses] = { 8, 8, 4, 4, 2, 2, 1, 0 }; + +const TInt KPngDepth1BytesPerPixel = 1; +const TInt KPngDepth3BytesPerPixel = 3; +const TInt KPngDepth4BytesPerPixel = 4; + +// CFastProcessor16MAto16MA +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of 24bpp + 8bpp alpha to EColor16MA display mode. +*/ +class CFastProcessor16MAto16MA: public CFastProcessor + { +public: + CFastProcessor16MAto16MA(CFbsBitmap* aDestination, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +// CFastProcessor16MAto16MAP +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of 24bpp + 8bpp alpha to EColor16MAP display mode. +*/ +class CFastProcessor16MAto16MAP: public CFastProcessor + { +public: + CFastProcessor16MAto16MAP(CFbsBitmap* aDestination, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +// CFastProcessor16MtoM +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of 24bpp to EColor16M display mode. +*/ +class CFastProcessor16Mto16M: public CFastProcessor + { +public: + CFastProcessor16Mto16M(CFbsBitmap* aDestination, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +// CFastProcessor16MtoMA +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of 24bpp to EColor16MU, EColor16MA or EColor16MAP display mode. +*/ +class CFastProcessor16Mto16MA: public CFastProcessor + { +public: + CFastProcessor16Mto16MA(CFbsBitmap* aDestination, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +// CFastProcessor16MAto16MU +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of a 24bpp + 8bpp alpha source to a EColor16MU (setting alpha as 0xFF). +*/ +class CFastProcessor16MAto16MU: public CFastProcessor + { +public: + CFastProcessor16MAto16MU(CFbsBitmap* aDestination, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +// CFastProcessor32bitTo32bitAndMask +/**This class is a specific implementation of CFastProcessor. +It provides a conversion of a 24bpp + 8bpp alpha source to an opaque 32 bit destination bitmap (i.e. +setting the alpha channel to 0xFF) and EGray256 mask (which contains the alpha channel of the source). +*/ +class CFastProcessor32bitTo32bitAndMask: public CFastProcessor + { +public: + CFastProcessor32bitTo32bitAndMask(CFbsBitmap* aDestination, CFbsBitmap* aMask, TBool aRgbaMode); + void SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos); + }; + +/** +Constructs a new FastProcessor based on the conversion type. + +@param aImageInfo + A reference to TPngImageInformation for the FastProcessor to use. +@param aDestination + A reference to the destination bitmap. +@param aRgbaMode + This flag indicates that MNG frames are being processed. +*/ +CFastProcessor* CFastProcessor::NewL(const TPngImageInformation& aImageInfo, CFbsBitmap* aDestination, CFbsBitmap* aMask, TBool aRgbaMode) + { + CFastProcessor* self = NULL; + + if (aRgbaMode) //if MNG + { + if (aImageInfo.iColorType == TPngImageInformation::EDirectColor) + { + self = new (ELeave) CFastProcessor16Mto16MA(aDestination, aRgbaMode); + } + else if(aImageInfo.iColorType == TPngImageInformation::EAlphaDirectColor) + { + self = new (ELeave) CFastProcessor16MAto16MA(aDestination, aRgbaMode); + } + else + { + User::Leave(KErrNotSupported); + } + } + else + { + TDisplayMode mode = aDestination->DisplayMode(); + + switch (aImageInfo.iColorType) + { + case TPngImageInformation::EDirectColor: + if(EColor16M == mode) + { + self = new (ELeave) CFastProcessor16Mto16M(aDestination, aRgbaMode); + } + else if(EColor16MAP == mode || EColor16MA == mode || EColor16MU == mode) + { + self = new (ELeave) CFastProcessor16Mto16MA(aDestination, aRgbaMode); + } + break; + + case TPngImageInformation::EAlphaDirectColor: + if(aMask && (EColor16MA == mode || EColor16MU == mode || EColor16MAP == mode)) + { + self = new (ELeave) CFastProcessor32bitTo32bitAndMask(aDestination, aMask, aRgbaMode); + } + else if(EColor16MA == mode) + { + self = new (ELeave) CFastProcessor16MAto16MA(aDestination, aRgbaMode); + } + else if(EColor16MAP == mode) + { + self = new (ELeave) CFastProcessor16MAto16MAP(aDestination, aRgbaMode); + } + else if(EColor16MU == mode) + { + self = new (ELeave) CFastProcessor16MAto16MU(aDestination, aRgbaMode); + } + else + { + User::Leave(KErrNotSupported); + } + break; + + default: + User::Leave(KErrNotSupported); + break; + } + } + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Destructor for this class. +Releases the lock for the current bitmap. +*/ +CFastProcessor::~CFastProcessor() + { + } + +/** +Second phase constructor. +Requests a lock for the current bitmap. +*/ +void CFastProcessor::ConstructL() + { + // NO-OP - reserved for changes at a later stage. + } + +/** +Default constructor +*/ +CFastProcessor::CFastProcessor(CFbsBitmap* aDestination, CFbsBitmap* aMask, TBool aRgbaMode) + { + iRgbaMode = aRgbaMode; + + if (!aRgbaMode) + { + iBitmap = aDestination; + iBitmapSize = iBitmap->SizeInPixels(); + if (aMask) + { + ASSERT(aMask->SizeInPixels() == iBitmapSize); + iMask = aMask; + } + } + } + +/** +Requests a lock for the current bitmap from the font & bitmap server and +sets the current position in the bitmap to the first pixel. +*/ +void CFastProcessor::Begin() + { + if (!iRgbaMode) + { + if (iBitmapBuffer==NULL) + { + iBitmapBuffer = reinterpret_cast( iBitmap->DataAddress() ); + if (iMask) + { + iMaskBuffer = reinterpret_cast( iMask->DataAddress() ); + } + } + } + } + +/** +Releases a lock previously acquired using CFastProcessor::Begin(). +*/ +void CFastProcessor::End() + { + if (!iRgbaMode) + { + if (iBitmapBuffer) + { + iBitmapBuffer = NULL; + } + if (iMaskBuffer) + { + iMaskBuffer = NULL; + } + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor16Mto16M::CFastProcessor16Mto16M(CFbsBitmap* aDestination, TBool aRgbaMode): + CFastProcessor(aDestination, NULL, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +*/ +void CFastProcessor16Mto16M::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* /*aLineCache*/, TPoint& /*aPos*/) + { + TUint8* scanLinePtr = (iBitmapBuffer + KPngDepth3BytesPerPixel * ( iPos.iX + iPos.iY * (( (iBitmapSize.iWidth + 3)>>2)<<2))); //aligns the specified value onto a 4-byte boundary. + + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth3BytesPerPixel; + + while (aDataPtr < aDataPtrLimit) + { + scanLinePtr[0] = aDataPtr[2]; + scanLinePtr[1] = aDataPtr[1]; + scanLinePtr[2] = aDataPtr[0]; + + scanLinePtr += KPngDepth3BytesPerPixel; + aDataPtr += KPngDepth3BytesPerPixel; + } + + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor16Mto16MA::CFastProcessor16Mto16MA(CFbsBitmap* aDestination, TBool aRgbaMode): + CFastProcessor(aDestination, NULL, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +//used only if RgbaMode i.e MNG processing +@param aLineCache + A pointer to current scanline buffer. +@param aPos + Current pixel position. +*/ +void CFastProcessor16Mto16MA::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos) + { + TUint32* scanLinePtr; + + if (!iRgbaMode) + { + scanLinePtr = (TUint32*)(iBitmapBuffer + (KPngDepth3BytesPerPixel + 1) * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth3BytesPerPixel; + } + else + { + scanLinePtr = reinterpret_cast(aLineCache); + aPos.iX = TUint(aDataPtrLimit - aDataPtr) / KPngDepth3BytesPerPixel; + } + + while (aDataPtr < aDataPtrLimit) + { + *scanLinePtr++ = ((TUint32)0xFF << 24) | ((TUint32)aDataPtr[0] << 16) | ((TUint32)aDataPtr[1] << 8) | aDataPtr[2]; + + aDataPtr += KPngDepth3BytesPerPixel; + } + + if (!iRgbaMode) + { + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor16MAto16MA::CFastProcessor16MAto16MA(CFbsBitmap* aDestination, TBool aRgbaMode): + CFastProcessor(aDestination, NULL, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +//used only if RgbaMode i.e MNG processing +@param aLineCache + A pointer to current scanline buffer. +@param aPos + Current pixel position. +*/ +void CFastProcessor16MAto16MA::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos) + { + TUint32* scanLinePtr; + + if (!iRgbaMode) + { + scanLinePtr = (TUint32*)(iBitmapBuffer + KPngDepth4BytesPerPixel * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + else + { + scanLinePtr = reinterpret_cast(aLineCache); + aPos.iX = TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + + while (aDataPtr + sizeof(TUint32) < aDataPtrLimit) + { + TUint32 pixel1 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + TUint32 pixel2 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + + pixel1 = (pixel1 & 0xFF00FF00) | ((pixel1 & 0xFF)<<16) | ((pixel1>>16) & 0xFF); + pixel2 = (pixel2 & 0xFF00FF00) | ((pixel2 & 0xFF)<<16) | ((pixel2>>16) & 0xFF); + + *scanLinePtr++ = pixel1; + *scanLinePtr++ = pixel2; + } + + if (aDataPtr + sizeof(TUint32) == aDataPtrLimit) + { + TUint32 pixel1 = *(TUint32*) aDataPtr; + + *scanLinePtr = (pixel1 & 0xFF00FF00) | ((pixel1 & 0xFF)<<16) | ((pixel1>>16) & 0xFF); + } + + if (!iRgbaMode) + { + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor16MAto16MAP::CFastProcessor16MAto16MAP(CFbsBitmap* aDestination, TBool aRgbaMode): + CFastProcessor(aDestination, NULL, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +//used only if RgbaMode i.e MNG processing +@param aLineCache + A pointer to current scanline buffer. +@param aPos + Current pixel position. +*/ + +// function to convert PNG pixel to 16MAP pixel + +static TUint32 PngTo16Map(TUint32 aPngPixel) + { + TUint8 const alpha = TUint8( aPngPixel >> 24 ); + + if (alpha == 0) + { + aPngPixel = 0; + } + else + { + // PNG bytes position in TUint32 are ABGR and must be coverted to ARGB in our case + + if (alpha == 0xff) + { + aPngPixel = (aPngPixel & 0xFF00FF00) | ((aPngPixel & 0xFF) << 16) | ((aPngPixel >> 16) & 0xFF); + } + else + { + // Use a bias value of 128 rather than 255, but also add 1/256 of the numerator + // before dividing the sum by 256. + + TUint32 scaledRB = (aPngPixel & KRBMask) * alpha + KRBBias; + scaledRB = (scaledRB + ( (scaledRB >> 8) & KRBMask) ) >> 8; + // swap now the R & B channels + scaledRB = (scaledRB << 16) | (scaledRB >> 16); + + TUint32 scaledG = (aPngPixel & KGMask) * alpha + KGBias; + scaledG = (scaledG + (scaledG >> 8)) >> 8; + + // compose the new pixel swapping R with B as we premultiplied alpha on a PNG pixel + + aPngPixel = (aPngPixel & KAMask) | (scaledRB & KRBMask) | (scaledG & KGMask); + } + } + + return aPngPixel; + } + +void CFastProcessor16MAto16MAP::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos) + { + TUint32* scanLinePtr; + + if (!iRgbaMode) + { + scanLinePtr = (TUint32*)(iBitmapBuffer + KPngDepth4BytesPerPixel * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + else + { + scanLinePtr = reinterpret_cast(aLineCache); + aPos.iX = TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + + // perform a direct conversion PNG -> Pixel 16MAP + + while (aDataPtr + sizeof(TUint32) < aDataPtrLimit) + { + TUint32 pixel1 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + TUint32 pixel2 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + + pixel1 = PngTo16Map(pixel1); + pixel2 = PngTo16Map(pixel2); + + *scanLinePtr++ = pixel1; + *scanLinePtr++ = pixel2; + } + + if (aDataPtr + sizeof(TUint32) == aDataPtrLimit) + { + *scanLinePtr = PngTo16Map(*(TUint32*) aDataPtr); + } + + if (!iRgbaMode) + { + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor32bitTo32bitAndMask::CFastProcessor32bitTo32bitAndMask(CFbsBitmap* aDestination, CFbsBitmap* aMask, TBool aRgbaMode) +: CFastProcessor(aDestination, aMask, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +//used only if RgbaMode i.e MNG processing +@param aLineCache + A pointer to current scanline buffer. +@param aPos + Current pixel position. +*/ +void CFastProcessor32bitTo32bitAndMask::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* /*aLineCache*/, TPoint& /*aPos*/) + { + ASSERT(!iRgbaMode); // Not configured for MNG use + + TUint32* scanLinePtr; // alpha channel set to fully opaque + TUint8* maskScanLinePtr; // set alpha channel in mask + + scanLinePtr = (TUint32*)(iBitmapBuffer + KPngDepth4BytesPerPixel * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + maskScanLinePtr = (TUint8*)(iMaskBuffer + KPngDepth1BytesPerPixel * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + + if (iBitmap->DisplayMode() == EColor16MAP) + { + while (aDataPtr + sizeof(TUint32) < aDataPtrLimit) + { + TUint32 pixel1 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + TUint32 pixel2 = *(TUint32*) aDataPtr; + aDataPtr += KPngDepth4BytesPerPixel; + + pixel1 = PngTo16Map(pixel1); + pixel2 = PngTo16Map(pixel2); + + *scanLinePtr++ = 0xFF000000 | pixel1; + *maskScanLinePtr++ = (pixel1 & 0xFF000000) >> 24; + + *scanLinePtr++ = 0xFF000000 | pixel2; + *maskScanLinePtr++ = (pixel2 & 0xFF000000) >> 24; + } + + if (aDataPtr + sizeof(TUint32) == aDataPtrLimit) + { + TUint32 oddPixel = *(TUint32*) aDataPtr; + + oddPixel = PngTo16Map(oddPixel); + + *scanLinePtr++ = 0xFF000000 | oddPixel; + *maskScanLinePtr++ = (oddPixel & 0xFF000000) >> 24; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + *scanLinePtr++ = 0xFF000000 | (aDataPtr[0] << 16) | (aDataPtr[1] << 8) | aDataPtr[2]; + *maskScanLinePtr++ = (aDataPtr[3]); + + aDataPtr += KPngDepth4BytesPerPixel; + } + } + + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + +/** +Default constructor for this class. +*/ +CFastProcessor16MAto16MU::CFastProcessor16MAto16MU(CFbsBitmap* aDestination, TBool aRgbaMode) +: CFastProcessor(aDestination, NULL, aRgbaMode) + {} + +/** +Sets an array of pixel values, starting at the current bitmap position using the +values supplied in aDataPtr. + +@param aDataPtr + A pointer to the first element in the array. +@param aDataPtrLimit + A pointer to the last element in the array. +//used only if RgbaMode i.e MNG processing +@param aLineCache + A pointer to current scanline buffer. +@param aPos + Current pixel position. +*/ +void CFastProcessor16MAto16MU::SetPixels(const TUint8* aDataPtr, const TUint8* aDataPtrLimit, TRgb* aLineCache, TPoint& aPos) + { + TUint32* scanLinePtr; + + if (!iRgbaMode) + { + scanLinePtr = (TUint32*)(iBitmapBuffer + KPngDepth4BytesPerPixel * ( iPos.iX + iPos.iY * iBitmapSize.iWidth)); + iPos.iX += TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + else + { + scanLinePtr = reinterpret_cast(aLineCache); + aPos.iX = TUint(aDataPtrLimit - aDataPtr) / KPngDepth4BytesPerPixel; + } + + while (aDataPtr < aDataPtrLimit) + { + *scanLinePtr++ = 0xFF000000 | (aDataPtr[0] << 16) | (aDataPtr[1] << 8) | aDataPtr[2]; + + aDataPtr += KPngDepth4BytesPerPixel; + } + + if (!iRgbaMode) + { + while (iPos.iX >= iBitmapSize.iWidth) + { + iPos.iY++; + iPos.iX -= iBitmapSize.iWidth; + } + } + } + +class CBitDepth1Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth2Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth4Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth8Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth8ColorType2Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth8ColorType4Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth8ColorType6Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth16ColorType0Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth16ColorType2Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth16ColorType4Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +class CBitDepth16ColorType6Decoder : public CPngReadSubCodec + { +private: + virtual void DoConstructL(); + virtual TInt ScanlineBufferSize(TInt aPixelLength); + virtual void DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit); + }; + +// CPngReadSubCodec +CPngReadSubCodec* CPngReadSubCodec::NewL(CImageProcessor* aImageProc,CImageProcessor* aMaskProc,const TPngImageInformation& aInfo, CFastProcessor* aFastProc, TBool aFastProcessorMode) + { + CPngReadSubCodec* self = NULL; + + switch (aInfo.iBitDepth) + { + case 1: + self = new(ELeave) CBitDepth1Decoder; + break; + case 2: + self = new(ELeave) CBitDepth2Decoder; + break; + case 4: + self = new(ELeave) CBitDepth4Decoder; + break; + case 8: + switch (aInfo.iColorType) + { + case TPngImageInformation::EGrayscale: + case TPngImageInformation::EIndexedColor: + self = new(ELeave) CBitDepth8Decoder; + break; + case TPngImageInformation::EDirectColor: + self = new(ELeave) CBitDepth8ColorType2Decoder; + break; + case TPngImageInformation::EAlphaGrayscale: + self = new(ELeave) CBitDepth8ColorType4Decoder; + break; + case TPngImageInformation::EAlphaDirectColor: + self = new(ELeave) CBitDepth8ColorType6Decoder; + break; + default: + User::Leave(KErrNotSupported); + break; + } + break; + case 16: + switch (aInfo.iColorType) + { + case TPngImageInformation::EGrayscale: + self = new(ELeave) CBitDepth16ColorType0Decoder; + break; + case TPngImageInformation::EDirectColor: + self = new(ELeave) CBitDepth16ColorType2Decoder; + break; + case TPngImageInformation::EAlphaGrayscale: + self = new(ELeave) CBitDepth16ColorType4Decoder; + break; + case TPngImageInformation::EAlphaDirectColor: + self = new(ELeave) CBitDepth16ColorType6Decoder; + break; + case TPngImageInformation::EIndexedColor: + default: + User::Leave(KErrNotSupported); + break; + } + break; + default: + User::Leave(KErrNotSupported); + break; + } + + CleanupStack::PushL(self); + self->ConstructL(aImageProc,aMaskProc,aInfo, aFastProc, aFastProcessorMode); + CleanupStack::Pop(self); + return self; + } + +CPngReadSubCodec::CPngReadSubCodec(): + iScanlineDes1(NULL,0), + iScanlineDes2(NULL,0) + {} + +CPngReadSubCodec::~CPngReadSubCodec() + { + delete iScanlineBuffer1; + delete iScanlineBuffer2; + delete [] iLineCache; + } + +void CPngReadSubCodec::ConstructL(CImageProcessor* aImageProc,CImageProcessor* aMaskProc,const TPngImageInformation& aInfo, CFastProcessor* aFastProc, TBool aFastProcessorMode) + { + iImageProc = aImageProc; + iMaskProc = aMaskProc; + iFastProc = aFastProc; + + iInfo = aInfo; + + SetFastProcessorMode(aFastProcessorMode); + + iScanlineBufferSize = ScanlineBufferSize(iInfo.iSize.iWidth); + + DoConstructL(); + if (iInfo.iInterlaceMethod != TPngImageInformation::EAdam7Interlace) + { + iLineCache = new (ELeave) TRgb [iInfo.iSize.iWidth + 8]; // +8 to be sure we won't exceed buffer for padded images (up to 8 pixels padding) + } + + iScanlineBuffer1 = HBufC8::NewMaxL(iScanlineBufferSize + 7); + iScanlineBuffer2 = HBufC8::NewMaxL(iScanlineBufferSize + 7); + + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + iInterlacedScanlineBufferSize[0] = ScanlineBufferSize((iInfo.iSize.iWidth + 7) >> 3); + iInterlacedScanlineBufferSize[1] = ScanlineBufferSize((iInfo.iSize.iWidth + 3) >> 3); + iInterlacedScanlineBufferSize[2] = ScanlineBufferSize((iInfo.iSize.iWidth + 3) >> 2); + iInterlacedScanlineBufferSize[3] = ScanlineBufferSize((iInfo.iSize.iWidth + 1) >> 2); + iInterlacedScanlineBufferSize[4] = ScanlineBufferSize((iInfo.iSize.iWidth + 1) >> 1); + iInterlacedScanlineBufferSize[5] = ScanlineBufferSize(iInfo.iSize.iWidth >> 1); + iInterlacedScanlineBufferSize[6] = iScanlineBufferSize; + iInterlacedScanlineBufferSize[7] = 0; + iPass = 0; + + iScanlineDes1.Set(&(iScanlineBuffer1->Des())[0],iInterlacedScanlineBufferSize[0],iInterlacedScanlineBufferSize[0]); + iScanlineDes2.Set(&(iScanlineBuffer2->Des())[0],iInterlacedScanlineBufferSize[0],iInterlacedScanlineBufferSize[0]); + + if(iImageProc) + { + const TInt lineRepeat = ClampValue(KBlockHeight[iPass]-1,0,iInfo.iSize.iHeight-iPos.iY-2); + iImageProc->SetLineRepeat(lineRepeat); + } + } + else + { + // to align actual data per word boudary + iScanlineDes1.Set(&(iScanlineBuffer1->Des())[3],iScanlineBufferSize,iScanlineBufferSize); + iScanlineDes2.Set(&(iScanlineBuffer2->Des())[3],iScanlineBufferSize,iScanlineBufferSize); + } + } + +void CPngReadCodec::SetImageProcessor(CImageProcessor* aImageProc, TBool aOwnsProcessor) + { + if (iOwnsImageProcessor) + delete iImageProc; + iImageProc = aImageProc; + iOwnsImageProcessor = aOwnsProcessor; + } + +void CPngReadCodec::SetMaskProcessor(CImageProcessor* aMaskProc, TBool aOwnsProcessor) + { + if (iOwnsMaskProcessor) + delete iMaskProc; + iMaskProc = aMaskProc; + iOwnsMaskProcessor = aOwnsProcessor; + } + +void CPngReadCodec::SetFastProcessor(CFastProcessor* aFastProc, TBool aOwnsProcessor) + { + if (iOwnsFastProcessor) + delete iFastProc; + iFastProc = aFastProc; + iOwnsFastProcessor = aOwnsProcessor; + } + +void CPngReadSubCodec::SetFastProcessorMode(TBool aMode) + { + iFastProcessorMode = aMode; + } + +void CPngReadSubCodec::ResetL() + { + iPos.SetXY(0,0); + iPass = 0; + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + iScanlineDes1.Set(&(iScanlineBuffer1->Des())[0],iInterlacedScanlineBufferSize[0],iInterlacedScanlineBufferSize[0]); + iScanlineDes2.Set(&(iScanlineBuffer2->Des())[0],iInterlacedScanlineBufferSize[0],iInterlacedScanlineBufferSize[0]); + + if(iImageProc) + { + const TInt lineRepeat = ClampValue(KBlockHeight[iPass]-1,0,iInfo.iSize.iHeight-iPos.iY-2); + iImageProc->SetLineRepeat(lineRepeat); + } + } + } + +TDes8& CPngReadSubCodec::FirstBuffer() + { + iScanlineDes1.FillZ(); + iCurrentScanlineBuffer = 2; + return iScanlineDes2; + } + +TDes8& CPngReadSubCodec::DecodeL() + { + TUint8* dataPtr = (iCurrentScanlineBuffer == 1) ? &iScanlineDes1[1] : &iScanlineDes2[1]; + const TUint8* dataPtrLimit = dataPtr + iScanlineDes1.Length() - 1; + + FilterScanlineDataL(dataPtr,dataPtrLimit); + + if (iFastProcessorMode) + { + iFastProc->Begin(); + } + + DoDecode(dataPtr,dataPtrLimit); + + if (iFastProcessorMode) + { + iFastProc->End(); + } + + UpdatePos(); + + if (iCurrentScanlineBuffer == 1) + { + iCurrentScanlineBuffer = 2; + return iScanlineDes2; + } + else + { + iCurrentScanlineBuffer = 1; + return iScanlineDes1; + } + } + +void CPngReadSubCodec::FilterScanlineDataL(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + TInt filterType = (iCurrentScanlineBuffer == 1) ? iScanlineDes1[0] : iScanlineDes2[0]; + + switch (filterType) + { + case 0: // None + break; + case 1: // Sub + { + aDataPtr += iBytesPerPixel; + + while (aDataPtr < aDataPtrLimit) + { + aDataPtr[0] = TUint8(aDataPtr[0] + aDataPtr[-iBytesPerPixel]); + aDataPtr++; + } + } + break; + case 2: // Up + { + TUint8* altDataPtr = (iCurrentScanlineBuffer == 1) ? &iScanlineDes2[1] : &iScanlineDes1[1]; + + while (aDataPtr < aDataPtrLimit) + { + *aDataPtr = TUint8(*aDataPtr + *altDataPtr); + aDataPtr++; + altDataPtr++; + } + } + break; + case 3: // Average + { + const TUint8* tempDataPtrLimit = Min(aDataPtr + iBytesPerPixel,aDataPtrLimit); + TUint8* altDataPtr = (iCurrentScanlineBuffer == 1) ? &iScanlineDes2[1] : &iScanlineDes1[1]; + + while (aDataPtr < tempDataPtrLimit) + { + aDataPtr[0] = TUint8(aDataPtr[0] + (altDataPtr[0] / 2)); + aDataPtr++; + altDataPtr++; + } + + while (aDataPtr < aDataPtrLimit) + { + aDataPtr[0] = TUint8(aDataPtr[0] + ((altDataPtr[0] + aDataPtr[-iBytesPerPixel]) / 2)); + aDataPtr++; + altDataPtr++; + } + } + break; + case 4: // Paeth + { + const TUint8* tempDataPtrLimit = Min(aDataPtr + iBytesPerPixel,aDataPtrLimit); + TUint8* altDataPtr = (iCurrentScanlineBuffer == 1) ? &iScanlineDes2[1] : &iScanlineDes1[1]; + + while (aDataPtr < tempDataPtrLimit) + { + aDataPtr[0] = TUint8(aDataPtr[0] + altDataPtr[0]); + aDataPtr++; + altDataPtr++; + } + + while (aDataPtr < aDataPtrLimit) + { + aDataPtr[0] = TUint8(aDataPtr[0] + PaethPredictor(aDataPtr[-iBytesPerPixel],altDataPtr[0],altDataPtr[-iBytesPerPixel])); + aDataPtr++; + altDataPtr++; + } + } + break; + + case 64: // support for additional MNG-defined filter (Adaptive filtering with five basic types and intrapixel differencing) + { + const TInt plusAlpha=(0 != (iInfo.iColorType & TPngImageInformation::EAlphaChannelUsed)); + if ( iInfo.iBitDepth == 16) + { + const TUint KBytesPerPixel=2*(3+plusAlpha); + aDataPtrLimit-=KBytesPerPixel; + while(aDataPtr < aDataPtrLimit) + { + const TUint32 s0 = (aDataPtr[0] << 8) | aDataPtr[1]; + const TUint32 s1 = 0x10000u + (aDataPtr[2] << 8) | aDataPtr[3]; + const TUint32 s2 = (aDataPtr[4] << 8) | aDataPtr[5]; + const TUint32 red = ((s0+s1) & 0xffffu); + const TUint32 blue = ((s2+s1) & 0xffffu); + aDataPtr[0] = TUint8((red >> 8) & 0xff); + aDataPtr[1] = TUint8(red & 0xff); + aDataPtr[4] = TUint8((blue >> 8) & 0xff); + aDataPtr[5] = TUint8(blue & 0xff); + aDataPtr+=KBytesPerPixel; + } + } + else if (iInfo.iBitDepth == 8) + { + const TUint KBytesPerPixel=3+plusAlpha; + aDataPtrLimit-=KBytesPerPixel; + while(aDataPtr < aDataPtrLimit) + { + aDataPtr[0] = TUint8((0x100u + aDataPtr[0] + aDataPtr[1])&0xffu); + aDataPtr[1] = TUint8((0x100u + aDataPtr[2] + aDataPtr[1])&0xffu); + aDataPtr +=KBytesPerPixel; + } + } + } + break; + + default: // Error + User::Leave(KErrCorrupt); + break; + } + } + +TInt CPngReadSubCodec::PaethPredictor(TInt aLeft,TInt aAbove,TInt aAboveLeft) + { + TInt p = aLeft + aAbove - aAboveLeft; + TInt pa = Abs(p - aLeft); + TInt pb = Abs(p - aAbove); + TInt pc = Abs(p - aAboveLeft); + + if (pa <= pb && pa <= pc) + return aLeft; + else if (pb <= pc) + return aAbove; + else + return aAboveLeft; + } + +void CPngReadSubCodec::WritePixel(TRgb aPixelColor) + { + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + const TInt width = ClampValue(KBlockWidth[iPass],0,iInfo.iSize.iWidth - iPos.iX); + TPoint pos(iPos); + iImageProc->SetPos(pos); + iImageProc->SetPixelRun(aPixelColor,width); + iPos.iX += KColIncrement[iPass]; + } + else + { + if (iRgbaMode) + { + iLineCache[iPos.iX++]=aPixelColor; + } + else + { + iImageProc->SetPixel(aPixelColor); + } + } + } + +void CPngReadSubCodec::WritePixel(TRgb aPixelColor,TUint8 aAlphaValue) + { + if(iAlphaMode || iRgbaMode) + { + TRgb RgbaColour( aPixelColor.Internal()&0xFFFFFF, (TUint32(aAlphaValue)) ); + + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + iImageProc->SetPos(iPos); + iImageProc->SetPixel(RgbaColour); + iPos.iX += KColIncrement[iPass]; + } + else + { + iRgbaMode ? iLineCache[iPos.iX++]=RgbaColour : iImageProc->SetPixel(RgbaColour); + } + } + else + { + ASSERT(iMaskProc); + { + TRgb maskColor(TRgb::Gray256(aAlphaValue)); + + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + iImageProc->SetPos(iPos); + iMaskProc->SetPos(iPos); + iImageProc->SetPixel(aPixelColor); + iMaskProc->SetPixel(maskColor); + + iPos.iX += KColIncrement[iPass]; + } + else + { + iImageProc->SetPixel(aPixelColor); + iMaskProc->SetPixel(maskColor); + } + } + } + } + +void CPngReadSubCodec::UpdatePos() + { + if (iInfo.iInterlaceMethod == TPngImageInformation::EAdam7Interlace) + { + ASSERT(iPass <= 7); + + iPos.iX = KColStart[iPass]; + iPos.iY += KRowIncrement[iPass]; + + while (iPos.iX >= iInfo.iSize.iWidth || iPos.iY >= iInfo.iSize.iHeight) + { + iPass++; + + /* Coverity may flag this up as an overrun of KColStart and KRowStart. This is a false + positive because both arrays have a 'safety entry' at index [7], which is 0. Thus, + iPos.iX and iPos.iY will be be 0, and so never equal to the image width/height as we + won't decode images with these dimensions. Therefore, this loop will never be entered.*/ + + iPos.iX = KColStart[iPass]; + iPos.iY = KRowStart[iPass]; + iScanlineDes1.Set(&(iScanlineBuffer1->Des())[0],iInterlacedScanlineBufferSize[iPass],iInterlacedScanlineBufferSize[iPass]); + iScanlineDes2.Set(&(iScanlineBuffer2->Des())[0],iInterlacedScanlineBufferSize[iPass],iInterlacedScanlineBufferSize[iPass]); + iScanlineDes1.FillZ(); + iScanlineDes2.FillZ(); + } + + if(iImageProc) + { + const TInt lineRepeat = ClampValue(KBlockHeight[iPass]-1,0,iInfo.iSize.iHeight-iPos.iY-2); + iImageProc->SetLineRepeat(lineRepeat); + } + } + else + { + if (iRgbaMode) + { + iImageProc->SetPixels(iLineCache, iPos.iX); + } + iPos.iX=0; + } + } + + +// CBitDepth1Decoder +void CBitDepth1Decoder::DoConstructL() + { + if (!(iInfo.iColorType & TPngImageInformation::EPaletteUsed)) + { // Set up palette to be grayscale values + iInfo.iPalette[0] = KRgbBlack; + iInfo.iPalette[1] = KRgbWhite; + + + if (iInfo.iTransparencyPresent) + { + if (iInfo.iTransparentGray <= 1) + iInfo.iTransparencyValue[iInfo.iTransparentGray] = 0; + } + } + + // Replicate values to avoid shifts when decoding + iInfo.iPalette[2] = iInfo.iPalette[1]; + iInfo.iPalette[4] = iInfo.iPalette[1]; + iInfo.iPalette[8] = iInfo.iPalette[1]; + iInfo.iPalette[16] = iInfo.iPalette[1]; + iInfo.iPalette[32] = iInfo.iPalette[1]; + iInfo.iPalette[64] = iInfo.iPalette[1]; + iInfo.iPalette[128] = iInfo.iPalette[1]; + + if (iInfo.iTransparencyPresent && iInfo.iTransparencyValue[1] != 255) + { + iInfo.iTransparencyValue[2] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[4] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[8] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[16] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[32] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[64] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[128] = iInfo.iTransparencyValue[1]; + } + + iBytesPerPixel = 1; + if (iInfo.iInterlaceMethod == TPngImageInformation::ENoInterlace) + { + TInt pixelPadding = ((iInfo.iSize.iWidth + 7) & ~7) - iInfo.iSize.iWidth; + if(iImageProc) + { + iImageProc->SetPixelPadding(pixelPadding); + } + if (iMaskProc) + { + iMaskProc->SetPixelPadding(pixelPadding); + } + } + } + +TInt CBitDepth1Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return ((aPixelLength + 7) / 8) + KPngScanlineFilterTypeLength; + } + +void CBitDepth1Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + for (TUint mask=0x80; mask!=0; mask>>=1) // iterate with 0x80, 0x40 .. 0x01 + WritePixel(iInfo.iPalette[dataValue & mask],iInfo.iTransparencyValue[dataValue & mask]); + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + for (TUint mask=0x80; mask!=0; mask>>=1) // iterate with 0x80, 0x40 .. 0x01 + WritePixel(iInfo.iPalette[dataValue & mask]); + } + } + } + + +// CBitDepth2Decoder +void CBitDepth2Decoder::DoConstructL() + { + if (!(iInfo.iColorType & TPngImageInformation::EPaletteUsed)) + { // Set up palette to be grayscale values + iInfo.iPalette[0] = KRgbBlack; + iInfo.iPalette[1] = KRgbDarkGray; + iInfo.iPalette[2] = KRgbGray; + iInfo.iPalette[3] = KRgbWhite; + + if (iInfo.iTransparencyPresent) + { + if (iInfo.iTransparentGray <= 3) + iInfo.iTransparencyValue[iInfo.iTransparentGray] = 0; + } + } + + // Replicate values to avoid shifts when decoding + iInfo.iPalette[4] = iInfo.iPalette[1]; + iInfo.iPalette[8] = iInfo.iPalette[2]; + iInfo.iPalette[12] = iInfo.iPalette[3]; + + iInfo.iPalette[16] = iInfo.iPalette[1]; + iInfo.iPalette[32] = iInfo.iPalette[2]; + iInfo.iPalette[48] = iInfo.iPalette[3]; + + iInfo.iPalette[64] = iInfo.iPalette[1]; + iInfo.iPalette[128] = iInfo.iPalette[2]; + iInfo.iPalette[192] = iInfo.iPalette[3]; + + if (iInfo.iTransparencyPresent) + { + iInfo.iTransparencyValue[4] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[8] = iInfo.iTransparencyValue[2]; + iInfo.iTransparencyValue[12] = iInfo.iTransparencyValue[3]; + + iInfo.iTransparencyValue[16] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[32] = iInfo.iTransparencyValue[2]; + iInfo.iTransparencyValue[48] = iInfo.iTransparencyValue[3]; + + iInfo.iTransparencyValue[64] = iInfo.iTransparencyValue[1]; + iInfo.iTransparencyValue[128] = iInfo.iTransparencyValue[2]; + iInfo.iTransparencyValue[192] = iInfo.iTransparencyValue[3]; + } + + iBytesPerPixel = 1; + if (iInfo.iInterlaceMethod == TPngImageInformation::ENoInterlace) + { + TInt pixelPadding = ((iInfo.iSize.iWidth + 3) & ~3) - iInfo.iSize.iWidth; + if(iImageProc) + { + iImageProc->SetPixelPadding(pixelPadding); + } + if (iMaskProc) + { + iMaskProc->SetPixelPadding(pixelPadding); + } + } + } + +TInt CBitDepth2Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return ((aPixelLength + 3) / 4) + KPngScanlineFilterTypeLength; + } + +void CBitDepth2Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + for (TInt mask=0xc0; mask!=0; mask>>=2) // iterate through 0xc0, 0x30, 0x0c and 0x03 + WritePixel(iInfo.iPalette[dataValue & mask],iInfo.iTransparencyValue[dataValue & mask]); + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + for (TInt mask=0xc0; mask!=0; mask>>=2) // iterate through 0xc0, 0x30, 0x0c and 0x03 + WritePixel(iInfo.iPalette[dataValue & mask]); + } + } + } + + +// CBitDepth4Decoder +void CBitDepth4Decoder::DoConstructL() + { + if (!(iInfo.iColorType & TPngImageInformation::EPaletteUsed)) + { // Set up palette to be grayscale values + for (TInt index = 0; index < 16; index++) + iInfo.iPalette[index] = TRgb::Gray16(index); + + if (iInfo.iTransparencyPresent) + { + if (iInfo.iTransparentGray <= 15) + iInfo.iTransparencyValue[iInfo.iTransparentGray] = 0; + } + } + + iBytesPerPixel = 1; + if (iInfo.iInterlaceMethod == TPngImageInformation::ENoInterlace) + { + TInt pixelPadding = ((iInfo.iSize.iWidth + 1) & ~1) - iInfo.iSize.iWidth; + if(iImageProc) + { + iImageProc->SetPixelPadding(pixelPadding); + } + if (iMaskProc) + { + iMaskProc->SetPixelPadding(pixelPadding); + } + } + } + +TInt CBitDepth4Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return ((aPixelLength + 1) / 2) + KPngScanlineFilterTypeLength; + } + +void CBitDepth4Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + WritePixel(iInfo.iPalette[dataValue >> 4],iInfo.iTransparencyValue[dataValue >> 4]); + WritePixel(iInfo.iPalette[dataValue & 0x0f],iInfo.iTransparencyValue[dataValue & 0x0f]); + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + TInt dataValue = *aDataPtr++; + + WritePixel(iInfo.iPalette[dataValue >> 4]); + WritePixel(iInfo.iPalette[dataValue & 0x0f]); + } + } + } + + +// CBitDepth8Decoder +void CBitDepth8Decoder::DoConstructL() + { + if (!(iInfo.iColorType & TPngImageInformation::EPaletteUsed)) + { // Set up palette to be grayscale values + for (TInt index = 0; index < 256; index++) + iInfo.iPalette[index] = TRgb::Gray256(index); + + if (iInfo.iTransparencyPresent) + { + if (iInfo.iTransparentGray <= 255) + iInfo.iTransparencyValue[iInfo.iTransparentGray] = 0; + } + } + + iBytesPerPixel = 1; + } + +TInt CBitDepth8Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return aPixelLength + KPngScanlineFilterTypeLength; + } + +void CBitDepth8Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(iInfo.iPalette[aDataPtr[0]],iInfo.iTransparencyValue[aDataPtr[0]]); + aDataPtr++; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + WritePixel(iInfo.iPalette[*aDataPtr++]); + } + } + + +// CBitDepth8ColorType2Decoder +void CBitDepth8ColorType2Decoder::DoConstructL() + { + iBytesPerPixel = 3; + } + +TInt CBitDepth8ColorType2Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 3) + KPngScanlineFilterTypeLength; + } + +void CBitDepth8ColorType2Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (!iFastProcessorMode) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt red = aDataPtr[0]; + TInt green = aDataPtr[1]; + TInt blue = aDataPtr[2]; + TRgb pixelColor(red,green,blue); + if (red == iInfo.iTransparentRed && green == iInfo.iTransparentGreen && blue == iInfo.iTransparentBlue) + { + WritePixel(pixelColor,0); + } + else + { + WritePixel(pixelColor,255); + } + aDataPtr += 3; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2])); + aDataPtr += 3; + } + } + } + else + { + iFastProc->SetPixels(aDataPtr, aDataPtrLimit, iLineCache, iPos); + } + } + + +// CBitDepth8ColorType4Decoder +void CBitDepth8ColorType4Decoder::DoConstructL() + { + iBytesPerPixel = 2; + } + +TInt CBitDepth8ColorType4Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 2) + KPngScanlineFilterTypeLength; + } + +void CBitDepth8ColorType4Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iMaskProc || iAlphaMode) + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb::Gray256(aDataPtr[0]),aDataPtr[1]); + aDataPtr += 2; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb::Gray256(aDataPtr[0])); + aDataPtr += 2; + } + } + } + + +// CBitDepth8ColorType6Decoder +void CBitDepth8ColorType6Decoder::DoConstructL() + { + iBytesPerPixel = 4; + } + +TInt CBitDepth8ColorType6Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 4) + KPngScanlineFilterTypeLength; + } + +void CBitDepth8ColorType6Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (!iFastProcessorMode) + { + if (iMaskProc || iAlphaMode) + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2]),aDataPtr[3]); + aDataPtr += 4; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2])); + aDataPtr += 4; + } + } + } + else + { + iFastProc->SetPixels(aDataPtr, aDataPtrLimit, iLineCache, iPos); + } + } + + +// CBitDepth16ColorType0Decoder +void CBitDepth16ColorType0Decoder::DoConstructL() + { + iBytesPerPixel = 2; + } + +TInt CBitDepth16ColorType0Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 2) + KPngScanlineFilterTypeLength; + } + +void CBitDepth16ColorType0Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt gray = (aDataPtr[0] << 8) | aDataPtr[1]; + TRgb pixelColor(TRgb::Gray256(aDataPtr[0])); + if (gray == iInfo.iTransparentGray) + WritePixel(pixelColor,0); + else + WritePixel(pixelColor,255); + aDataPtr += 2; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb::Gray256(aDataPtr[0])); + aDataPtr += 2; + } + } + } + + +// CBitDepth16ColorType2Decoder +void CBitDepth16ColorType2Decoder::DoConstructL() + { + iBytesPerPixel = 6; + } + +TInt CBitDepth16ColorType2Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 6) + KPngScanlineFilterTypeLength; + } + +void CBitDepth16ColorType2Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iInfo.iTransparencyPresent && (iMaskProc || iAlphaMode) ) + { + while (aDataPtr < aDataPtrLimit) + { + TInt red = (aDataPtr[0] << 8) | aDataPtr[1]; + TInt green = (aDataPtr[2] << 8) | aDataPtr[3]; + TInt blue = (aDataPtr[4] << 8) | aDataPtr[5]; + TRgb pixelColor(aDataPtr[0],aDataPtr[2],aDataPtr[4]); + if (red == iInfo.iTransparentRed && green == iInfo.iTransparentGreen && blue == iInfo.iTransparentBlue) + WritePixel(pixelColor,0); + else + WritePixel(pixelColor,255); + aDataPtr += 6; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[2],aDataPtr[4])); + aDataPtr += 6; + } + } + } + + +// CBitDepth16ColorType4Decoder +void CBitDepth16ColorType4Decoder::DoConstructL() + { + iBytesPerPixel = 4; + } + +TInt CBitDepth16ColorType4Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 4) + KPngScanlineFilterTypeLength; + } + +void CBitDepth16ColorType4Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iMaskProc || iAlphaMode) + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb::Gray256(aDataPtr[0]),aDataPtr[2]); + aDataPtr += 4; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb::Gray256(aDataPtr[0])); + aDataPtr += 4; + } + } + } + + +// CBitDepth16ColorType6Decoder +void CBitDepth16ColorType6Decoder::DoConstructL() + { + iBytesPerPixel = 8; + } + +TInt CBitDepth16ColorType6Decoder::ScanlineBufferSize(TInt aPixelLength) + { + return (aPixelLength * 8) + KPngScanlineFilterTypeLength; + } + +void CBitDepth16ColorType6Decoder::DoDecode(TUint8* aDataPtr,const TUint8* aDataPtrLimit) + { + if (iMaskProc || iAlphaMode) + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[2],aDataPtr[4]),aDataPtr[6]); + aDataPtr += 8; + } + } + else + { + while (aDataPtr < aDataPtrLimit) + { + WritePixel(TRgb(aDataPtr[0],aDataPtr[2],aDataPtr[4])); + aDataPtr += 8; + } + } + }