⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pngcodec.cpp

📁 symbian 开SDK例子!!3RD 是学习的不错实例啊
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// PngCodec.CPP
//
// Copyright (c) 1999-2005 Symbian Software Ltd.  All rights reserved.
//

#include <fbs.h>

#include "ImageUtils.h"
#include "PngCodec.h"

// Constants.
const TInt KTwipsPerMeter = 56693;

// 
// TPngImageInformation: PNG image information
//

// Initialise default PNG image information
TPngImageInformation::TPngImageInformation()
	{
	iSize.SetSize(0,0);
	iBitDepth = 0;
	iColorType = EGrayscale;
	iCompressionMethod = EDeflateInflate32K;
	iFilterMethod = EAdaptiveFiltering;
	iInterlaceMethod = ENoInterlace;
	iPalettePresent = EFalse;

#if defined(_DEBUG)
	// as an optimisation, we are going to set iPalette to all zeros, instead of setting
	// each element to KRgbBlack. This assumes that KRbgBlack is itself zero.
	ASSERT(sizeof(TRgb)==sizeof(TUint32)); // ie no new fields
	ASSERT(KRgbBlack.Value()==0); // ie the one value is zero
#endif // defined(_DEBUG)

	Mem::FillZ(iPalette, KPngMaxPLTESize*sizeof(TRgb));

	iBackgroundPresent = EFalse;
	iBackgroundColor = KRgbWhite;
	iPhysicalPresent = EFalse;
	iPhysicalUnits = EUnknownUnits;
	iPhysicalSize.SetSize(0,0);
	iTransparencyPresent = EFalse;
	Mem::Fill(iTransparencyValue,KPngMaxPLTESize,0xff);
	}


//
// CPngReadCodec: reads a PNG image
//

CPngReadCodec::~CPngReadCodec()
	{
	delete iDecoder;
	delete iDecompressor;
	}

// Called by framework when a Convert operation begins
void CPngReadCodec::InitFrameL(TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameImageData*/, 
	TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
	{
	CFbsBitmap& newFrame = aDestination;

	TPoint& pos = Pos();
	pos.SetXY(0,0);
	iChunkBytesRemaining = 0;

	// Use the supplied image processor
	CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL(newFrame, iImageInfo.iSize, ERgb, aDisableErrorDiffusion);
	SetImageProcessor(imageProc);
	imageProc->PrepareL(newFrame,iImageInfo.iSize);

	CImageProcessor* maskProc = NULL;
	SetMaskProcessor(NULL);

	// If transparency is being used, create a bitmap mask as well
	if ((iImageInfo.iTransparencyPresent || (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed))
		&& aDestinationMask)
		{
		maskProc = ImageProcessorUtility::NewImageProcessorL(*aDestinationMask, iImageInfo.iSize, ERgb, aDisableErrorDiffusion);
		SetMaskProcessor(maskProc);
		maskProc->PrepareL(*aDestinationMask,iImageInfo.iSize);
		// set mask to black so that unknown parts on streamed image are not drawn
		ClearBitmapL(*aDestinationMask, KRgbBlack);
		}

	// Create a helper to read the scan lines
	delete iDecoder;
	iDecoder = NULL;
	iDecoder = CPngReadSubCodec::NewL(imageProc,maskProc,iImageInfo);

	// And a unzipper to decompress image data
	if (!iDecompressor)
		iDecompressor = CEZDecompressor::NewL(*this);
	else
		iDecompressor->ResetL(*this);

	if (maskProc==NULL)
		{
		// if no mask, clear destination for sensible behaviour on streamed partial images
		TRgb background = iImageInfo.iBackgroundPresent ? iImageInfo.iBackgroundColor : KRgbWhite;
		ClearBitmapL(aDestination, background);
		}
	}

// Called by framework to initialise image frame header
void CPngReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */)
	{
	ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
	iFrameInfo = &aFrameSettings;
	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
	}

// Called by framework to process a header for a frame
TFrameState CPngReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
	{
	const TUint8* startDataPtr = aData.Ptr();
	const TUint8* dataPtr = startDataPtr;
	const TUint8* dataPtrLimit = startDataPtr + aData.Length();

	// Process the mandatory PNG header chunk: sets up iImageInfo
	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
		{
		if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize + KPngIHDRChunkSize + KPngChunkCRCSize > dataPtrLimit)
			User::Leave(KErrUnderflow);

		TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(dataPtr);
		TPtrC8 chunkId(dataPtr,KPngChunkIdSize);

		if (chunkLength != KPngIHDRChunkSize || chunkId != KPngIHDRChunkId)
			User::Leave(KErrNotFound);

		dataPtr += KPngChunkIdSize;

		DoProcessIHDRL(dataPtr,chunkLength);

		dataPtr += KPngIHDRChunkSize + KPngChunkCRCSize;
		}

	// Process any optional PNG header chunks
	TRAPD(err, DoProcessInfoL(dataPtr, dataPtrLimit));
	if (err != KErrNone)
		{
		if (err == KErrNotFound)
			return EFrameComplete;

		User::Leave(err); // A real error occured
		}

	// Having read the header, can initialise the frame information
	aData.Shift(dataPtr - startDataPtr);

	iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0),iImageInfo.iSize);
	iFrameInfo->iOverallSizeInPixels = iImageInfo.iSize;
	if (iImageInfo.iPhysicalPresent && iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
		iFrameInfo->iFrameSizeInTwips = iImageInfo.iPhysicalSize;
	else
		iFrameInfo->iFrameSizeInTwips.SetSize(0,0);

	iFrameInfo->iBitsPerPixel = iImageInfo.iBitDepth;
	if (iImageInfo.iColorType & TPngImageInformation::EColorUsed)
		iFrameInfo->iBitsPerPixel *= 3;
	
	iFrameInfo->iDelay = 0;
	iFrameInfo->iFlags = TFrameInfo::ECanDither;
	
	if (iImageInfo.iColorType & (TPngImageInformation::EPaletteUsed | TPngImageInformation::EColorUsed))
		iFrameInfo->iFlags |= TFrameInfo::EColor;
	
	if (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed)
		{
		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
		iFrameInfo->iFlags |= TFrameInfo::EAlphaChannel;
		}
	else if (iImageInfo.iTransparencyPresent)
		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;

	switch (iFrameInfo->iBitsPerPixel)
		{
	case 1:
		iFrameInfo->iFrameDisplayMode = EGray2;
		break;

	case 2:
		iFrameInfo->iFrameDisplayMode = EGray4;
		break;

	case 4:
		iFrameInfo->iFrameDisplayMode = (iFrameInfo->iFlags & TFrameInfo::EColor) ? EColor16 : EGray16;
		break;

	case 8:
		iFrameInfo->iFrameDisplayMode = (iFrameInfo->iFlags & TFrameInfo::EColor) ? EColor256 : EGray256;
		break;

	case 12:
		iFrameInfo->iFrameDisplayMode = EColor4K;
		break;

	case 16:
		iFrameInfo->iFrameDisplayMode = EColor64K;
		break;

	case 24:
		iFrameInfo->iFrameDisplayMode = EColor16M;
		break;

	default:
		User::Leave(KErrCorrupt);
		}

	if (iImageInfo.iBackgroundPresent)
		iFrameInfo->iBackgroundColor = iImageInfo.iBackgroundColor;

	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
	return EFrameComplete;
	}

// Called by the framework to process frame data
TFrameState CPngReadCodec::ProcessFrameL(TBufPtr8& aSrc)
	{
	CImageProcessor*const imageProc = ImageProcessor();
	CImageProcessor*const maskProc = MaskProcessor();

	TUint8* startDataPtr = const_cast<TUint8*>(aSrc.Ptr());
	TUint8* dataPtr = startDataPtr;
	const TUint8* dataPtrLimit = dataPtr + aSrc.Length();
	while (dataPtr < dataPtrLimit)
		{
		// If at the end of a PNG chunk
		if (iChunkBytesRemaining == 0)
			{
			if (iChunkId == KPngIDATChunkId) // Need to skip IDAT chunk CRCs
				{
				if (dataPtr + KPngChunkCRCSize + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
					break;

				dataPtr += KPngChunkCRCSize;
				}
			else
				{
				if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
					break;
				}

			iChunkBytesRemaining = PtrReadUtil::ReadBigEndianUint32Inc(const_cast<const TUint8*&>(dataPtr));
			iChunkId = TPtr8(dataPtr,KPngChunkIdSize,KPngChunkIdSize);
			dataPtr += KPngChunkIdSize;
			}
		// Process an image data chunk
		if (iChunkId == KPngIDATChunkId)
			DoProcessDataL(const_cast<const TUint8*&>(dataPtr),dataPtrLimit);
		// Process an END chunk -- frame is complete
		else if (iChunkId == KPngIENDChunkId)
			{
			iDecompressor->InflateL();
			imageProc->FlushPixels();
			if (maskProc)
				maskProc->FlushPixels();
			return EFrameComplete;
			}
		else 
		// Skip other chunks
			{
			TInt bytesLeft = dataPtrLimit - dataPtr;
			if (bytesLeft >= iChunkBytesRemaining + KPngChunkCRCSize)
				{
				dataPtr += iChunkBytesRemaining + KPngChunkCRCSize;
				iChunkBytesRemaining = 0;
				}
			else
				{
				dataPtr += bytesLeft;
				iChunkBytesRemaining -= bytesLeft;
				}
			}
		}

	aSrc.Shift(dataPtr - startDataPtr);
	return EFrameIncomplete;
	}

// Process any optional PNG header chunks
void CPngReadCodec::DoProcessInfoL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
	{
	FOREVER
		{
		if (aDataPtr + KPngChunkLengthSize + KPngChunkIdSize > aDataPtrLimit) // Check there is enough data to read the chunk length
			User::Leave(KErrUnderflow);

		TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
		TPtrC8 chunkId (&aDataPtr[0],KPngChunkIdSize);

		if (chunkId == KPngIDATChunkId)
			{
			aDataPtr -= KPngChunkLengthSize; // Rewind to start of chunkLength
			break;
			}

		if (aDataPtr + KPngChunkIdSize + chunkLength + KPngChunkCRCSize > aDataPtrLimit) // Check there is enough data to read the whole chunk
			{
			aDataPtr -= KPngChunkLengthSize; // Rewind to start of chunkLength
			User::Leave(KErrUnderflow);
			}

		aDataPtr += KPngChunkIdSize;

		if (chunkId == KPngPLTEChunkId)
			DoProcessPLTEL(aDataPtr,chunkLength);
		else if (chunkId == KPngbKGDChunkId)
			DoProcessbKGDL(aDataPtr,chunkLength);
		else if (chunkId == KPngpHYsChunkId)
			DoProcesspHYsL(aDataPtr,chunkLength);
		else if (chunkId == KPngtRNSChunkId)
			DoProcesstRNSL(aDataPtr,chunkLength);
		else if (chunkId == KPngIHDRChunkId || chunkId == KPngIENDChunkId)
			User::Leave(KErrCorrupt);

		aDataPtr += chunkLength;
		PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr); // Skip crc value
		}
	}

// Process the mandatory PNG header chunk
void CPngReadCodec::DoProcessIHDRL(const TUint8* aDataPtr,TInt aChunkLength)
	{
	if (aChunkLength != KPngIHDRChunkSize)
		User::Leave(KErrCorrupt);

	iImageInfo.iSize.iWidth = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
	iImageInfo.iSize.iHeight = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
	iImageInfo.iBitDepth = aDataPtr[0];
	iImageInfo.iColorType = TPngImageInformation::TColorType(aDataPtr[1]);
	iImageInfo.iCompressionMethod = TPngImageInformation::TCompressionMethod(aDataPtr[2]);
	iImageInfo.iFilterMethod = TPngImageInformation::TFilterMethod(aDataPtr[3]);
	iImageInfo.iInterlaceMethod = TPngImageInformation::TInterlaceMethod(aDataPtr[4]);

	// Check is one of the PNG formats we support
	if (iImageInfo.iSize.iWidth < 1 || iImageInfo.iSize.iHeight < 1
		|| iImageInfo.iCompressionMethod != TPngImageInformation::EDeflateInflate32K
		|| iImageInfo.iFilterMethod != TPngImageInformation::EAdaptiveFiltering
		|| (iImageInfo.iInterlaceMethod != TPngImageInformation::ENoInterlace &&
			iImageInfo.iInterlaceMethod != TPngImageInformation::EAdam7Interlace))
		User::Leave(KErrCorrupt);
	}

// Process a PNG PLTE (palette) chunk
void CPngReadCodec::DoProcessPLTEL(const TUint8* aDataPtr,TInt aChunkLength)
	{
	if (aChunkLength % 3 != 0)
		User::Leave(KErrCorrupt);

	iImageInfo.iPalettePresent = ETrue;

	const TUint8* dataPtrLimit = aDataPtr + aChunkLength;
	TRgb* palettePtr = iImageInfo.iPalette;

	while (aDataPtr < dataPtrLimit)
		{
		*palettePtr++ = TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2]);
		aDataPtr += 3;
		}
	}

// Process a PNG bKGD (background color) chunk
void CPngReadCodec::DoProcessbKGDL(const TUint8* aDataPtr,TInt aChunkLength)
	{
	iImageInfo.iBackgroundPresent = ETrue;

	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
		{
		if (aChunkLength < 1)
			User::Leave(KErrCorrupt);

		iImageInfo.iBackgroundColor = iImageInfo.iPalette[aDataPtr[0]];
		}
	else if (iImageInfo.iColorType & TPngImageInformation::EMonochrome) // 0 & 4
		{
		if (aChunkLength < 2)
			User::Leave(KErrCorrupt);

		TInt grayLevel = PtrReadUtil::ReadBigEndianInt16(aDataPtr);
		ASSERT(iImageInfo.iBitDepth<8);
		grayLevel <<= (7-iImageInfo.iBitDepth);
		iImageInfo.iBackgroundColor = TRgb::Gray256(grayLevel);
		}
	else if (iImageInfo.iColorType & TPngImageInformation::EColorUsed) // 2 & 6
		{
		if (aChunkLength < 6)
			User::Leave(KErrCorrupt);

		TInt red = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[0]);
		TInt green = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[2]);
		TInt blue = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[4]);
		ASSERT (iImageInfo.iBitDepth<8);
		const TInt offset = 7-iImageInfo.iBitDepth;
		red <<= offset;
		green <<= offset;
		blue <<= offset;
		iImageInfo.iBackgroundColor = TRgb(red,green,blue);
		}
	}

// Process a PNG pHYs (Physical pixel dimensions) chunk
void CPngReadCodec::DoProcesspHYsL(const TUint8* aDataPtr,TInt aChunkLength)
	{
	if (aChunkLength != KPngpHYsChunkSize)
		User::Leave(KErrCorrupt);

	iImageInfo.iPhysicalUnits = TPngImageInformation::TPhysicalUnits(aDataPtr[8]);

	if (iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
		{
		iImageInfo.iPhysicalPresent = ETrue;

		TInt horzPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
		TInt vertPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);

		if (horzPixelsPerMeter > 0)
			iImageInfo.iPhysicalSize.iWidth = iImageInfo.iSize.iWidth * KTwipsPerMeter / horzPixelsPerMeter;
		if (vertPixelsPerMeter > 0)
			iImageInfo.iPhysicalSize.iHeight = iImageInfo.iSize.iHeight * KTwipsPerMeter / vertPixelsPerMeter;
		}
	}

// Process a PNG tRNS (Transparency) chunk
void CPngReadCodec::DoProcesstRNSL(const TUint8* aDataPtr,TInt aChunkLength)
	{
	iImageInfo.iTransparencyPresent = ETrue;

	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
		{
		if (aChunkLength < 1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -