mmplugins/imagingplugins/codecs/PNGCodec/PNGCodec.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <fbs.h>
       
    17 #include "ImageClientMain.h"
       
    18 #include "ImageUtils.h"
       
    19 #include "PNGCodec.h"
       
    20 
       
    21 // Constants.
       
    22 const TInt KTwipsPerMeter = 56693;
       
    23 
       
    24 
       
    25 // Helper classes.
       
    26 // TPngImageInformation
       
    27 TPngImageInformation::TPngImageInformation()
       
    28 	{
       
    29 	iSize.SetSize(0,0);
       
    30 	iBitDepth = 0;
       
    31 	iColorType = EGrayscale;
       
    32 	iCompressionMethod = EDeflateInflate32K;
       
    33 	iFilterMethod = EAdaptiveFiltering;
       
    34 	iInterlaceMethod = ENoInterlace;
       
    35 	iPalettePresent = EFalse;
       
    36 
       
    37 #if defined(_DEBUG)
       
    38 	ASSERT(sizeof(TRgb)==sizeof(TUint32)); // ie no new fields
       
    39 	ASSERT(KPngMaxPLTESize%4==0);
       
    40 #endif  // defined(_DEBUG)
       
    41 
       
    42 	TRgb* palette=iPalette;
       
    43 	TInt i=KPngMaxPLTESize>>2;
       
    44 	do 
       
    45 		{
       
    46 		*palette++ = KRgbBlack;
       
    47 		*palette++ = KRgbBlack;
       
    48 		*palette++ = KRgbBlack;
       
    49 		*palette++ = KRgbBlack;
       
    50 		} while (--i);
       
    51 
       
    52 	iBackgroundPresent = EFalse;
       
    53 	iBackgroundColor = KRgbWhite;
       
    54 	iPhysicalPresent = EFalse;
       
    55 	iPhysicalUnits = EUnknownUnits;
       
    56 	iPhysicalSize.SetSize(0,0);
       
    57 	iTransparencyPresent = EFalse;
       
    58 	Mem::Fill(iTransparencyValue,KPngMaxPLTESize,0xff);
       
    59 	}
       
    60 
       
    61 
       
    62 // CMdaPngReadCodec
       
    63 CPngReadCodec::~CPngReadCodec()
       
    64 	{
       
    65 	delete iDecoder;
       
    66 	delete iDecompressor;
       
    67 	if (iOwnsImageProcessor)
       
    68 		{
       
    69 		delete iImageProc;
       
    70 		}
       
    71 	if (iOwnsMaskProcessor)
       
    72 		{
       
    73 		delete iMaskProc;
       
    74 		}
       
    75 	if (iOwnsFastProcessor)
       
    76 		{
       
    77 		delete iFastProc;
       
    78 		}		
       
    79 	}
       
    80 
       
    81 CPngReadCodec* CPngReadCodec::NewL(MPngDecoder& aDecoderIFace)
       
    82 	{
       
    83 	CPngReadCodec* self = new(ELeave) CPngReadCodec(aDecoderIFace);
       
    84 	CleanupStack::PushL(self);
       
    85 	self->ConstructL();
       
    86 	CleanupStack::Pop(self); 
       
    87 	return self;
       
    88 	}
       
    89 
       
    90 
       
    91 CPngReadCodec::CPngReadCodec(MPngDecoder& aDecoderIFace):	
       
    92 	iDecoderIFace(aDecoderIFace), iNewPosition(0), iReadMore(EFalse)
       
    93 	{
       
    94 	}
       
    95 
       
    96 void CPngReadCodec::ConstructL()
       
    97 	{
       
    98 	CImageMaskProcessorReadCodec::ConstructL();
       
    99 	}
       
   100 
       
   101 void CPngReadCodec::InitFrameL(TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
       
   102 	{
       
   103 	CFbsBitmap& newFrame = aDestination;
       
   104 
       
   105 	iChunkBytesRemaining = 0;
       
   106 	iChunkId = KNullDesC8;
       
   107 	iPreviousChunkReadFailed = EFalse;
       
   108 	
       
   109 	const TSize destinationSize(newFrame.SizeInPixels());
       
   110 	TInt reductionFactor = ReductionFactor(iImageInfo.iSize, destinationSize);
       
   111 	
       
   112 	TBool fastProcessorMode = EFalse;
       
   113 	
       
   114 	CImageProcessor* imageProc = NULL;
       
   115 	SetImageProcessor(NULL);
       
   116 	
       
   117 	CImageProcessor* maskProc = NULL;
       
   118 	SetMaskProcessor(NULL);
       
   119 	
       
   120 	CFastProcessor* fastProc = NULL;
       
   121 	SetFastProcessor(NULL);
       
   122 	
       
   123 	if (!SkipImageProcessor(aDestination))
       
   124 		{
       
   125 		imageProc = ImageProcessorUtility::NewImageProcessorL(newFrame, reductionFactor, ERgb, aDisableErrorDiffusion);
       
   126 		SetImageProcessor(imageProc);
       
   127 		imageProc->PrepareL(newFrame,iImageInfo.iSize);
       
   128 
       
   129 		if ((iImageInfo.iTransparencyPresent || (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed))
       
   130 			&& aDestinationMask)
       
   131 			{
       
   132 			maskProc = ImageProcessorUtility::NewImageProcessorL(*aDestinationMask, iImageInfo.iSize, ERgb, aDisableErrorDiffusion);
       
   133 			SetMaskProcessor(maskProc);
       
   134 			maskProc->PrepareL(*aDestinationMask,iImageInfo.iSize);
       
   135 			// set mask to black so that unknown parts on streamed image are not drawn
       
   136 			ClearBitmapL(*aDestinationMask, KRgbBlack);
       
   137 			}
       
   138 		}
       
   139 	else
       
   140 		{
       
   141 		fastProc = CFastProcessor::NewL(iImageInfo, &aDestination, aDestinationMask, EFalse);
       
   142 		SetFastProcessor(fastProc);
       
   143 		fastProcessorMode = ETrue;
       
   144 		}
       
   145 
       
   146 	delete iDecoder;
       
   147 	iDecoder = NULL;
       
   148 	iDecoder = CPngReadSubCodec::NewL(imageProc,maskProc,iImageInfo, fastProc, fastProcessorMode);
       
   149 	
       
   150 	if (!iDecompressor)
       
   151 		{
       
   152 		iDecompressor = CEZDecompressor::NewL(*this);
       
   153 		}
       
   154 	else
       
   155 		{
       
   156 		iDecompressor->ResetL(*this);
       
   157 		}
       
   158 
       
   159 	if (!aDestinationMask)
       
   160 		{
       
   161 		// if no mask, clear destination for sensible behaviour on streamed partial images
       
   162 		TRgb background = iImageInfo.iBackgroundPresent ? iImageInfo.iBackgroundColor : KRgbWhite;
       
   163 		ClearBitmapL(aDestination, background);
       
   164 		
       
   165 		if (aDestination.DisplayMode() == EColor16MA && iFrameInfo->iFlags & TFrameInfo::ETransparencyPossible)
       
   166 			{
       
   167 			iDecoder->SetAlphaMode(ETrue);
       
   168 			}
       
   169 		}
       
   170 	}
       
   171 
       
   172 void CPngReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */)
       
   173 	{
       
   174 	ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
       
   175 	iFrameInfo = &aFrameSettings;
       
   176 	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
       
   177 	}
       
   178 
       
   179 TFrameState CPngReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
       
   180 	{
       
   181 	const TUint8* startDataPtr = aData.Ptr();
       
   182 	const TUint8* dataPtr = startDataPtr;
       
   183 	const TUint8* dataPtrLimit = startDataPtr + aData.Length();
       
   184 
       
   185 	
       
   186 	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
       
   187 		{
       
   188 		if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize + KPngIHDRChunkSize + KPngChunkCRCSize > dataPtrLimit)
       
   189 			User::Leave(KErrUnderflow);
       
   190 
       
   191 		TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(dataPtr);
       
   192 		TPtrC8 chunkId(dataPtr,KPngChunkIdSize);
       
   193 
       
   194 		if (chunkLength != KPngIHDRChunkSize || chunkId != KPngIHDRChunkId)
       
   195 			User::Leave(KErrNotFound);
       
   196 
       
   197 		dataPtr += KPngChunkIdSize;
       
   198 
       
   199 		DoProcessIHDRL(dataPtr,chunkLength);
       
   200 
       
   201 		dataPtr += KPngIHDRChunkSize + KPngChunkCRCSize;
       
   202 		}
       
   203 
       
   204 	//When there is not enough buffer to read the chunk length and chunk id,
       
   205 	//the input buffer is not increased, the decoder will not be able to read more data,
       
   206 	//the test will stuck in infinite loop.
       
   207 	//To break the infinite loop, here it checkes whether it's reading the same data as last time,
       
   208 	//if so, leaves.	
       
   209 	if ((iPreviousDataPos == iNewPosition) && (iPreviousDataLength == aData.Length()))
       
   210 		{
       
   211 		User::Leave(KErrUnderflow);
       
   212 		}
       
   213 	
       
   214 	TRAPD(err, DoProcessInfoL(dataPtr, dataPtrLimit));
       
   215 			
       
   216 	iPreviousDataPos = iNewPosition;
       
   217 	iPreviousDataLength = aData.Length();
       
   218 
       
   219 	if (err != KErrNone)
       
   220 		{
       
   221 		if (err == KErrNotFound)
       
   222 			return EFrameComplete;
       
   223 		User::Leave(err); // A real error occured
       
   224 		}
       
   225 	if(iReadMore)
       
   226 		{
       
   227 		iReadMore = EFalse;
       
   228 		iNewPosition += dataPtr - startDataPtr;
       
   229 		return EFrameIncompleteRepositionRequest;
       
   230 		}
       
   231 	aData.Shift(dataPtr - startDataPtr);
       
   232 
       
   233 	iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0),iImageInfo.iSize);
       
   234 	iFrameInfo->iOverallSizeInPixels = iImageInfo.iSize;
       
   235 	if (iImageInfo.iPhysicalPresent && iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
       
   236 		iFrameInfo->iFrameSizeInTwips = iImageInfo.iPhysicalSize;
       
   237 	else
       
   238 		iFrameInfo->iFrameSizeInTwips.SetSize(0,0);
       
   239 
       
   240 	iFrameInfo->iBitsPerPixel = iImageInfo.iBitDepth;
       
   241 	if (iImageInfo.iColorType & TPngImageInformation::EColorUsed 
       
   242 		 && iImageInfo.iColorType != TPngImageInformation::EIndexedColor)
       
   243 		iFrameInfo->iBitsPerPixel *= 3;
       
   244 	
       
   245 	iFrameInfo->iDelay = 0;
       
   246 	iFrameInfo->iFlags = TFrameInfo::ECanDither;
       
   247 	
       
   248 	if (iImageInfo.iColorType & (TPngImageInformation::EPaletteUsed | TPngImageInformation::EColorUsed))
       
   249 		iFrameInfo->iFlags |= TFrameInfo::EColor;
       
   250 	
       
   251 	if (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed)
       
   252 		{
       
   253 		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
       
   254 		iFrameInfo->iFlags |= TFrameInfo::EAlphaChannel;
       
   255 		}
       
   256 	else if (iImageInfo.iTransparencyPresent)
       
   257 		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
       
   258 
       
   259 	const TInt bitsPerPixel = iFrameInfo->iBitsPerPixel;
       
   260 	// the best mode for colour-indexed images is 16m
       
   261 	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   262 		iFrameInfo->iFrameDisplayMode = EColor16M;
       
   263 	else if(bitsPerPixel == 1)
       
   264 		iFrameInfo->iFrameDisplayMode = EGray2;
       
   265 	else if(bitsPerPixel == 2)
       
   266 		iFrameInfo->iFrameDisplayMode = EGray4;
       
   267 	else if((bitsPerPixel > 2)&&(bitsPerPixel <= 4))
       
   268 		iFrameInfo->iFrameDisplayMode = EGray16;
       
   269 	else if((bitsPerPixel > 4)&&(bitsPerPixel <= 8))
       
   270 		iFrameInfo->iFrameDisplayMode = EGray256;
       
   271 	else if((bitsPerPixel > 8)&&(bitsPerPixel <= 12))
       
   272 		iFrameInfo->iFrameDisplayMode = EColor4K;
       
   273 	else if((bitsPerPixel > 8) && (!(iFrameInfo->iFlags & TFrameInfo::EColor)))
       
   274 		iFrameInfo->iFrameDisplayMode = EGray256;
       
   275 	else if((bitsPerPixel > 12)&&(bitsPerPixel <= 16))
       
   276 		iFrameInfo->iFrameDisplayMode = EColor64K;
       
   277 	else if((bitsPerPixel > 16)&&(bitsPerPixel <= 48))
       
   278 		iFrameInfo->iFrameDisplayMode = EColor16M;
       
   279 	else
       
   280 		User::Leave(KErrCorrupt);
       
   281 
       
   282 
       
   283 	if (iImageInfo.iBackgroundPresent)
       
   284 		iFrameInfo->iBackgroundColor = iImageInfo.iBackgroundColor;
       
   285 
       
   286 	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
       
   287 	return EFrameComplete;
       
   288 	}
       
   289 
       
   290 TFrameState CPngReadCodec::ProcessFrameL(TBufPtr8& aSrc)
       
   291 	{
       
   292 	CImageProcessor*const imageProc = ImageProcessor();
       
   293 	CImageProcessor*const maskProc = MaskProcessor();
       
   294 
       
   295 	
       
   296 	TUint8* startDataPtr = CONST_CAST(TUint8*,aSrc.Ptr());
       
   297 	TUint8* dataPtr = startDataPtr;
       
   298 	const TUint8* dataPtrLimit = dataPtr + aSrc.Length();
       
   299 	TBool chunkReadFailed = EFalse;
       
   300 	while (dataPtr < dataPtrLimit)
       
   301 		{
       
   302 		if (iChunkBytesRemaining == 0)
       
   303 			{
       
   304 			if (iChunkId != KNullDesC8)
       
   305 				{
       
   306 				// this is not the first chunk - need to skip the previous chunk's CRC
       
   307 				// as well as reading this chunk's length and id
       
   308 				if (dataPtr + KPngChunkCRCSize + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
       
   309 					{
       
   310 					// not enough data
       
   311 					chunkReadFailed = ETrue;
       
   312 					break;
       
   313 					}
       
   314 
       
   315 				dataPtr += KPngChunkCRCSize;
       
   316 				}
       
   317 			else
       
   318 				{				
       
   319 				if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
       
   320 					{
       
   321 					// not enough data
       
   322 					break;
       
   323 					}
       
   324 				}
       
   325 
       
   326 			// read the current chunk's length and id
       
   327 			iChunkBytesRemaining = PtrReadUtil::ReadBigEndianUint32Inc(const_cast<const TUint8*&>(dataPtr));
       
   328 			
       
   329 			if(iChunkBytesRemaining < 0 )
       
   330 			    {
       
   331 			    User::Leave(KErrCorrupt);
       
   332 			    }
       
   333 			
       
   334 			iChunkId = TPtr8(dataPtr,KPngChunkIdSize,KPngChunkIdSize);
       
   335 			dataPtr += KPngChunkIdSize;
       
   336 			}
       
   337 
       
   338 		if (iChunkId == KPngIDATChunkId)
       
   339 			{
       
   340 			if(SetupProcessData(aSrc, dataPtr, const_cast<const TUint8*&>(dataPtr), dataPtrLimit))
       
   341 				iDecoderIFace.GoToProcessDataState();
       
   342 			break;
       
   343 			}
       
   344 		else if (iChunkId == KPngIENDChunkId)
       
   345 			{
       
   346 			iDecompressor->InflateL();
       
   347 			if (imageProc)
       
   348 				{
       
   349 				imageProc->FlushPixels();	
       
   350 				}
       
   351 			if (maskProc)
       
   352 				{
       
   353 				maskProc->FlushPixels();	
       
   354 				}
       
   355 			return EFrameComplete;
       
   356 			}
       
   357 		else // Skip other chunks
       
   358 			{
       
   359 			TInt bytesLeft = dataPtrLimit - dataPtr;
       
   360 			if (bytesLeft >= iChunkBytesRemaining)
       
   361 				{
       
   362 				dataPtr += iChunkBytesRemaining;
       
   363 				iChunkBytesRemaining = 0;
       
   364 				}
       
   365 			else
       
   366 				{
       
   367 				dataPtr += bytesLeft;
       
   368 				iChunkBytesRemaining -= bytesLeft;
       
   369 				}
       
   370 			}
       
   371 		}
       
   372 
       
   373 	// allow decode of png files with missing IEND chunks
       
   374 	if (!iMissingiENDChunkFail && chunkReadFailed && iPreviousChunkReadFailed)
       
   375 		{
       
   376 		// we're completely out of data but have finished a whole chunk
       
   377 		// try to decode the image
       
   378 		TBool moreDataNeeded = EFalse;
       
   379 		TRAPD(err, moreDataNeeded = iDecompressor->InflateL());
       
   380 		if ((err == KErrNone) && !moreDataNeeded)
       
   381 			{
       
   382 			if(imageProc)
       
   383 				{
       
   384 			 	imageProc->FlushPixels();
       
   385 				}			
       
   386 			if (maskProc)
       
   387 				{
       
   388 				maskProc->FlushPixels();
       
   389 				}
       
   390 
       
   391 			return EFrameComplete;
       
   392 			}
       
   393 		}
       
   394 	iPreviousChunkReadFailed = chunkReadFailed;
       
   395 	
       
   396 	aSrc.Shift(dataPtr - startDataPtr);
       
   397 	return EFrameIncomplete;
       
   398 	}
       
   399 
       
   400 void CPngReadCodec::DoProcessInfoL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
       
   401 	{
       
   402 	FOREVER
       
   403 		{
       
   404 		if (aDataPtr + KPngChunkLengthSize + KPngChunkIdSize > aDataPtrLimit) // Check there is enough data to read the chunk length
       
   405 			{
       
   406 			iNewPosition = 0 ;
       
   407 			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame);
       
   408 			iReadMore = ETrue;
       
   409 			return;
       
   410 			}
       
   411 		TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
       
   412 		TPtrC8 chunkId (&aDataPtr[0],KPngChunkIdSize);
       
   413 
       
   414 		if (chunkId == KPngIDATChunkId)
       
   415 			{
       
   416 			aDataPtr -= KPngChunkLengthSize; // Rewind to start of chunkLength
       
   417 			break;
       
   418 			}
       
   419 
       
   420 		if (aDataPtr + KPngChunkIdSize + chunkLength + KPngChunkCRCSize > aDataPtrLimit
       
   421 			 || chunkLength < 0) // Check there is enough data to read the whole chunk
       
   422 			{
       
   423 			if (	chunkId == KPngPLTEChunkId || chunkId == KPngbKGDChunkId ||
       
   424 					chunkId == KPngpHYsChunkId || chunkId == KPngtRNSChunkId )
       
   425 				{
       
   426 				aDataPtr -= KPngChunkLengthSize; // Rewind to start of chunkLength
       
   427 				User::Leave(chunkLength < 0 ? KErrCorrupt : KErrUnderflow);
       
   428 				}
       
   429 			iNewPosition = KPngChunkIdSize + chunkLength + KPngChunkCRCSize;
       
   430 			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame);
       
   431 			iReadMore = ETrue;
       
   432 			return;
       
   433 			}
       
   434 
       
   435 		aDataPtr += KPngChunkIdSize;
       
   436 
       
   437 		if (chunkId == KPngPLTEChunkId)
       
   438 			DoProcessPLTEL(aDataPtr,chunkLength);
       
   439 		else if (chunkId == KPngbKGDChunkId)
       
   440 			DoProcessbKGDL(aDataPtr,chunkLength);
       
   441 		else if (chunkId == KPngpHYsChunkId)
       
   442 			DoProcesspHYsL(aDataPtr,chunkLength);
       
   443 		else if (chunkId == KPngtRNSChunkId)
       
   444 			DoProcesstRNSL(aDataPtr,chunkLength);
       
   445 		else if (chunkId == KPngIHDRChunkId || chunkId == KPngIENDChunkId)
       
   446 			User::Leave(KErrCorrupt);
       
   447 
       
   448 		aDataPtr += chunkLength;
       
   449 		PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr); // Skip crc value
       
   450 		}
       
   451 	}
       
   452 
       
   453 void CPngReadCodec::DoProcessIHDRL(const TUint8* aDataPtr,TInt aChunkLength)
       
   454 	{
       
   455 	if (aChunkLength != KPngIHDRChunkSize)
       
   456 		User::Leave(KErrCorrupt);
       
   457 	
       
   458 	iImageInfo.iSize.iWidth = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
       
   459 	iImageInfo.iSize.iHeight = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
       
   460 	iImageInfo.iBitDepth = aDataPtr[0];
       
   461 	iImageInfo.iColorType = TPngImageInformation::TColorType(aDataPtr[1]);
       
   462 	iImageInfo.iCompressionMethod = TPngImageInformation::TCompressionMethod(aDataPtr[2]);
       
   463 	iImageInfo.iFilterMethod = TPngImageInformation::TFilterMethod(aDataPtr[3]);
       
   464 	iImageInfo.iInterlaceMethod = TPngImageInformation::TInterlaceMethod(aDataPtr[4]);
       
   465 	
       
   466 	// Check is one of the PNG formats we support
       
   467 	if (iImageInfo.iSize.iWidth < 1 || iImageInfo.iSize.iHeight < 1
       
   468 		|| iImageInfo.iCompressionMethod != TPngImageInformation::EDeflateInflate32K
       
   469 		|| iImageInfo.iFilterMethod != TPngImageInformation::EAdaptiveFiltering
       
   470 		|| (iImageInfo.iInterlaceMethod != TPngImageInformation::ENoInterlace &&
       
   471 		iImageInfo.iInterlaceMethod != TPngImageInformation::EAdam7Interlace))
       
   472 		User::Leave(KErrCorrupt);
       
   473 	
       
   474 	/*
       
   475 		Check if color type and bit depths are valid. 
       
   476 		PNG image type		Color type		Allowed bit depths
       
   477 		--------------      -----------     ------------------
       
   478 		Greyscale				0				1, 2, 4, 8, 16
       
   479 		Truecolour				2				8, 16
       
   480 		Indexed-colour			3				1, 2, 4, 8
       
   481 		Greyscale with alpha	4				8, 16
       
   482 		Truecolour with alpha	6				8, 16
       
   483 		
       
   484 		  (See http://www.w3.org/TR/PNG/#11IHDR)
       
   485 	*/
       
   486 	switch(iImageInfo.iColorType)
       
   487 		{
       
   488 		case TPngImageInformation::EGrayscale: // 0
       
   489 			{
       
   490 				if (! (iImageInfo.iBitDepth == 1 
       
   491 					|| iImageInfo.iBitDepth == 2 
       
   492 					|| iImageInfo.iBitDepth == 4
       
   493 					|| iImageInfo.iBitDepth == 8 
       
   494 					|| iImageInfo.iBitDepth == 16))
       
   495 				{
       
   496 					User::Leave(KErrCorrupt); // Invalid bit depth for color type 0
       
   497 				}
       
   498 			}
       
   499 			break;
       
   500 		case TPngImageInformation::EDirectColor: // 2
       
   501 		case TPngImageInformation::EAlphaGrayscale: // 4
       
   502 		case TPngImageInformation::EAlphaDirectColor: // 6
       
   503 			{
       
   504 				if (! (iImageInfo.iBitDepth == 8 
       
   505 					|| iImageInfo.iBitDepth == 16))
       
   506 				{
       
   507 					User::Leave(KErrCorrupt); // Invalid bit depth for color type 2 or 4 or 6
       
   508 				}
       
   509 			}
       
   510 			break;
       
   511 		case TPngImageInformation::EIndexedColor: //3
       
   512 			{
       
   513 				if (! (iImageInfo.iBitDepth == 1 
       
   514 					|| iImageInfo.iBitDepth == 2 
       
   515 					|| iImageInfo.iBitDepth == 4
       
   516 					|| iImageInfo.iBitDepth == 8))
       
   517 				{
       
   518 					User::Leave(KErrCorrupt); // Invalid bit depth for color type 3
       
   519 				}
       
   520 			}
       
   521 			break;
       
   522 		default: // Invalid color depth.
       
   523 			{
       
   524 				User::Leave(KErrCorrupt);
       
   525 			}
       
   526 		}
       
   527 	}
       
   528 
       
   529 void CPngReadCodec::DoProcessPLTEL(const TUint8* aDataPtr,TInt aChunkLength)
       
   530 	{
       
   531 	const TInt paletteEntries = aChunkLength / 3;
       
   532 
       
   533 	if ((aChunkLength % 3 != 0)||(paletteEntries > KPngMaxPLTESize))
       
   534 		User::Leave(KErrCorrupt);
       
   535 
       
   536 	iImageInfo.iPalettePresent = ETrue;
       
   537 
       
   538 	const TUint8* dataPtrLimit = aDataPtr + aChunkLength;
       
   539 	TRgb* palettePtr = iImageInfo.iPalette;
       
   540 
       
   541 	while (aDataPtr < dataPtrLimit)
       
   542 		{
       
   543 		*palettePtr++ = TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2]);
       
   544 		aDataPtr += 3;
       
   545 		}
       
   546 	}
       
   547 
       
   548 void CPngReadCodec::DoProcessbKGDL(const TUint8* aDataPtr,TInt aChunkLength)
       
   549 	{
       
   550 	iImageInfo.iBackgroundPresent = ETrue;
       
   551 	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
       
   552 		{
       
   553 		if (aChunkLength < 1)
       
   554 			User::Leave(KErrCorrupt);
       
   555 
       
   556 		iImageInfo.iBackgroundColor = iImageInfo.iPalette[aDataPtr[0]];
       
   557 		}
       
   558 	else if (iImageInfo.iColorType & TPngImageInformation::EColorUsed) // 2 & 6
       
   559 		{
       
   560 		if (aChunkLength < 6)
       
   561 			User::Leave(KErrCorrupt);
       
   562 
       
   563 		TInt red = PtrReadUtil::ReadBigEndianUint16(&aDataPtr[0]);
       
   564 		TInt green = PtrReadUtil::ReadBigEndianUint16(&aDataPtr[2]);
       
   565 		TInt blue = PtrReadUtil::ReadBigEndianUint16(&aDataPtr[4]);
       
   566 
       
   567 		//Allow negative shift on 48 bpp images
       
   568 		TInt offset = 8-iImageInfo.iBitDepth;
       
   569 		if(offset > 0)
       
   570 			{
       
   571 			red <<= offset;
       
   572 			green <<= offset;
       
   573 			blue <<= offset;
       
   574 			}
       
   575 		else
       
   576 			{
       
   577 			offset = -offset;
       
   578 			red >>= offset;
       
   579 			green >>= offset;
       
   580 			blue >>= offset;
       
   581 			}
       
   582 
       
   583 		iImageInfo.iBackgroundColor = TRgb(red,green,blue);
       
   584 		}
       
   585 	else
       
   586 		{
       
   587 		// Monochome images (iColorType 0 & 4)
       
   588 		ASSERT((iImageInfo.iColorType == TPngImageInformation::EGrayscale) || (iImageInfo.iColorType == TPngImageInformation::EAlphaGrayscale));
       
   589 		if (aChunkLength < 2)
       
   590 			User::Leave(KErrCorrupt);
       
   591 
       
   592 		TInt grayLevel = PtrReadUtil::ReadBigEndianUint16(aDataPtr);
       
   593 		switch (iImageInfo.iBitDepth)
       
   594 			{
       
   595 			case 16:
       
   596 				grayLevel >>= 8;
       
   597 				iImageInfo.iBackgroundColor = TRgb::Gray256(grayLevel);
       
   598 				break;
       
   599 
       
   600 			case 8:
       
   601 				iImageInfo.iBackgroundColor = TRgb::Gray256(grayLevel);
       
   602 				break;
       
   603 
       
   604 			case 4:
       
   605 				iImageInfo.iBackgroundColor = TRgb::Gray16(grayLevel);
       
   606 				break;
       
   607 
       
   608 			case 2:
       
   609 				iImageInfo.iBackgroundColor = TRgb::Gray4(grayLevel);
       
   610 				break;
       
   611 
       
   612 			case 1:
       
   613 				iImageInfo.iBackgroundColor = TRgb::Gray2(grayLevel);
       
   614 				break;
       
   615 
       
   616 			default:
       
   617 				ASSERT(0);
       
   618 			}
       
   619 		}
       
   620 	}
       
   621 
       
   622 void CPngReadCodec::DoProcesspHYsL(const TUint8* aDataPtr,TInt aChunkLength)
       
   623 	{
       
   624 	if (aChunkLength != KPngpHYsChunkSize)
       
   625 		User::Leave(KErrCorrupt);
       
   626 
       
   627 	iImageInfo.iPhysicalUnits = TPngImageInformation::TPhysicalUnits(aDataPtr[8]);
       
   628 
       
   629 	if (iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
       
   630 		{
       
   631 		iImageInfo.iPhysicalPresent = ETrue;
       
   632 
       
   633 		TInt horzPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
       
   634 		TInt vertPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
       
   635 
       
   636 		if (horzPixelsPerMeter > 0)
       
   637 			iImageInfo.iPhysicalSize.iWidth = iImageInfo.iSize.iWidth * KTwipsPerMeter / horzPixelsPerMeter;
       
   638 		if (vertPixelsPerMeter > 0)
       
   639 			iImageInfo.iPhysicalSize.iHeight = iImageInfo.iSize.iHeight * KTwipsPerMeter / vertPixelsPerMeter;
       
   640 		}
       
   641 	}
       
   642 
       
   643 void CPngReadCodec::DoProcesstRNSL(const TUint8* aDataPtr,TInt aChunkLength)
       
   644 	{
       
   645 	iImageInfo.iTransparencyPresent = ETrue;
       
   646 
       
   647 	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
       
   648 		{
       
   649 #if defined(_DEBUG)
       
   650 	ASSERT(sizeof(iImageInfo.iTransparencyValue)>sizeof(TAny*)); // ie it is not an allocated ptr.
       
   651 #endif  // defined
       
   652 		if (aChunkLength < 1 || TInt(sizeof(iImageInfo.iTransparencyValue)) < aChunkLength)
       
   653 			User::Leave(KErrCorrupt);
       
   654 
       
   655 		Mem::Copy(iImageInfo.iTransparencyValue,aDataPtr,aChunkLength);
       
   656 		}
       
   657 	else if (iImageInfo.iColorType == TPngImageInformation::EGrayscale) // 0
       
   658 		{
       
   659 		if (aChunkLength < 2)
       
   660 			User::Leave(KErrCorrupt);
       
   661 
       
   662 		iImageInfo.iTransparentGray = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
       
   663 		}
       
   664 	else if (iImageInfo.iColorType == TPngImageInformation::EDirectColor) // 2
       
   665 		{
       
   666 		if (aChunkLength < 6)
       
   667 			User::Leave(KErrCorrupt);
       
   668 
       
   669 		iImageInfo.iTransparentRed = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
       
   670 		iImageInfo.iTransparentGreen = TUint16((aDataPtr[2] << 8) | aDataPtr[3]);
       
   671 		iImageInfo.iTransparentBlue = TUint16((aDataPtr[4] << 8) | aDataPtr[5]);
       
   672 		}
       
   673 	}
       
   674 
       
   675 TBool CPngReadCodec::SetupProcessData(TBufPtr8& aSrc,
       
   676 									 TUint8* aStartDataPtr,
       
   677 									 const TUint8*& aDataPtr,
       
   678 									 const TUint8* aDataPtrLimit)
       
   679 	{
       
   680 	iSavedSrc = &aSrc;
       
   681 	iStartDataPtr = aStartDataPtr;
       
   682 	TInt bytesToProcess = Min(aDataPtrLimit - aDataPtr,iChunkBytesRemaining);
       
   683 	if(bytesToProcess<=0)
       
   684 		return EFalse;
       
   685 	iDataPtr = aDataPtr;
       
   686 	iDataDes.Set(aDataPtr,bytesToProcess);
       
   687 	iDecompressor->SetInput(iDataDes);
       
   688 	return ETrue;
       
   689 	}
       
   690 
       
   691 const TInt KInflateLimit=4; // max times we try to Inflate on each call
       
   692 
       
   693 TBool CPngReadCodec::DoProcessDataL()
       
   694 	{	
       
   695 	TInt bytesToProcess = iDataDes.Length(); // we stored this in SetupProcessData()
       
   696 	ASSERT(bytesToProcess>0);
       
   697 	TBool result = EFalse;
       
   698 	TBool callAgain = ETrue;
       
   699 	for (TInt count = 0; count < KInflateLimit &&
       
   700 						 callAgain &&
       
   701 						 iDecompressor->AvailIn() != 0; count++)
       
   702 		{
       
   703 		callAgain = iDecompressor->InflateL();
       
   704 		}
       
   705 
       
   706 	const TInt availData = iDecompressor->AvailIn();
       
   707 	if (!availData)
       
   708 		{
       
   709 		// Run out of data, get next buffer
       
   710 		iPreviousChunkReadFailed = ETrue;
       
   711 		result = ETrue;
       
   712 
       
   713 		// Advance the buffer
       
   714 		iDataPtr += bytesToProcess - availData;
       
   715 		iChunkBytesRemaining -= bytesToProcess - availData;
       
   716 		iSavedSrc->Shift(iDataPtr - iStartDataPtr);
       
   717 		}
       
   718 	return result;
       
   719 	}
       
   720 
       
   721 void CPngReadCodec::InitializeL(CEZZStream& aZStream)
       
   722 	{
       
   723 	aZStream.SetOutput(iDecoder->FirstBuffer());
       
   724 	}
       
   725 
       
   726 void CPngReadCodec::NeedInputL(CEZZStream& /*aZStream*/)
       
   727 	{
       
   728 	}
       
   729 
       
   730 void CPngReadCodec::NeedOutputL(CEZZStream& aZStream)
       
   731 	{
       
   732 	aZStream.SetOutput(iDecoder->DecodeL());
       
   733 	}
       
   734 
       
   735 void CPngReadCodec::FinalizeL(CEZZStream& aZStream)
       
   736 	{
       
   737 	TPtrC8 buffer(aZStream.OutputDescriptor());
       
   738 	if(buffer.Length())
       
   739 		iDecoder->DecodeL();
       
   740 	}
       
   741 void CPngReadCodec::GetNewDataPosition(TInt& aPosition, TInt&  /*aLength*/ )
       
   742 	{
       
   743 	aPosition += iNewPosition;
       
   744 	}
       
   745 
       
   746 void CPngReadCodec::SetMissingiENDChunkFail(TBool aValue)
       
   747 	{
       
   748 	iMissingiENDChunkFail = aValue;
       
   749 	}
       
   750 
       
   751 //Checks if Image processor is to be used or skipped. Returns ETrue if ImageProcessor is to be ignored.
       
   752 TBool CPngReadCodec::SkipImageProcessor(CFbsBitmap& aDestination)
       
   753 	{
       
   754 	TBool skipImgProc = EFalse;
       
   755 	
       
   756 	// If the image is interlaced, has transparency or is required to be scaled, then use the generic image processors
       
   757 	if(iImageInfo.iInterlaceMethod != TPngImageInformation::ENoInterlace || iImageInfo.iTransparencyPresent || aDestination.SizeInPixels().iWidth != iImageInfo.iSize.iWidth || aDestination.SizeInPixels().iHeight != iImageInfo.iSize.iHeight)
       
   758 		{
       
   759 		return EFalse;
       
   760 		}
       
   761 	
       
   762 	TDisplayMode mode = aDestination.DisplayMode();
       
   763 	// Skip ImageProcessor only when decoding 24 or 32 bpp images
       
   764 	switch (iImageInfo.iBitDepth)
       
   765 		{
       
   766 		case 8:
       
   767 			switch (iImageInfo.iColorType)
       
   768 				{
       
   769 				case TPngImageInformation::EDirectColor:
       
   770 					if(EColor16MAP == mode || EColor16MA == mode || EColor16MU == mode || EColor16M == mode)
       
   771 						{
       
   772 						skipImgProc = ETrue;	
       
   773 						}
       
   774 					break;
       
   775 				case TPngImageInformation::EAlphaDirectColor:
       
   776 					if(EColor16MAP == mode || EColor16MA == mode || EColor16MU == mode)
       
   777 						{
       
   778 						skipImgProc = ETrue;	
       
   779 						}
       
   780 					break;			
       
   781 				default:
       
   782 					break;
       
   783 				}
       
   784 			break;
       
   785 		default:
       
   786 			break;
       
   787 		}
       
   788 		
       
   789 	return skipImgProc;
       
   790 	}
       
   791 
       
   792 // CPngWriteCodec
       
   793 CPngWriteCodec::CPngWriteCodec(CPngEncoder& aPlugin, TInt aBpp, TBool aColor, TBool aPaletted, TInt aCompressionLevel):
       
   794 	iCompressionLevel(aCompressionLevel),
       
   795 	iCompressorPtr(NULL, 0),
       
   796 	iPlugin(aPlugin)
       
   797 	{
       
   798 	// Set bpp
       
   799 	iImageInfo.iBitsPerPixel = aBpp;
       
   800 	switch (aBpp)
       
   801 		{
       
   802 		case 1:
       
   803 			iImageInfo.iBitDepth = 1;
       
   804 			break;
       
   805 		case 2:
       
   806 			iImageInfo.iBitDepth = 2;
       
   807 			break;
       
   808 		case 4:
       
   809 			iImageInfo.iBitDepth = 4;
       
   810 			break;
       
   811 		case 8:
       
   812 		case 24:
       
   813 			iImageInfo.iBitDepth = 8;
       
   814 			break;
       
   815 		default:
       
   816 			break;
       
   817 		}
       
   818 
       
   819 	// Set color type
       
   820 	if (aColor && aPaletted)
       
   821 		iImageInfo.iColorType = TPngImageInformation::EIndexedColor;
       
   822 	else if (aColor)
       
   823 		iImageInfo.iColorType = TPngImageInformation::EDirectColor;
       
   824 	else
       
   825 		iImageInfo.iColorType = TPngImageInformation::EGrayscale;
       
   826 	}
       
   827 
       
   828 CPngWriteCodec::~CPngWriteCodec()
       
   829 	{
       
   830 	delete iCompressor;
       
   831 	delete iEncoder;
       
   832 	}
       
   833 
       
   834 CPngWriteCodec* CPngWriteCodec::NewL(CPngEncoder& aPlugin, TInt aBpp, TBool aColor, TBool aPaletted, TInt aCompressionLevel)
       
   835 {
       
   836 	CPngWriteCodec* self = new(ELeave) CPngWriteCodec(aPlugin, aBpp, aColor, aPaletted, aCompressionLevel);
       
   837 	CleanupStack::PushL(self);
       
   838 	self->ConstructL();
       
   839 	CleanupStack::Pop(self); 
       
   840 	return self;
       
   841 }
       
   842 
       
   843 
       
   844 
       
   845 // from CImageWriteCodec
       
   846 void CPngWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
       
   847 	{
       
   848 	if (aDst.Length() == 0)
       
   849 		User::Leave(KErrArgument);	// Not enough length for anything
       
   850 
       
   851 	SetSource(&aSource);
       
   852 	iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   853 	iDestPtr = iDestStartPtr;
       
   854 	iDestPtrLimit = iDestPtr + aDst.MaxLength();
       
   855 
       
   856 	// Set image information
       
   857 	const SEpocBitmapHeader& header = aSource.Header();
       
   858 	iImageInfo.iSize = header.iSizeInPixels;
       
   859 
       
   860 	switch (iImageInfo.iBitDepth)
       
   861 		{
       
   862 		case 1:
       
   863 		case 2:
       
   864 		case 4:
       
   865 			if (iImageInfo.iColorType == TPngImageInformation::EDirectColor)
       
   866 				{
       
   867 				// Bit depths 1, 2 and 4 don't support RGB colour (color mode 2)
       
   868 				// Must use paletted colour or greyscale
       
   869 				User::Leave(KErrNotSupported);
       
   870 				break;
       
   871 				}
       
   872 			// fall through to case 8
       
   873 		case 8:
       
   874 			break;
       
   875 		default:
       
   876 			User::Leave(KErrNotSupported);	// unsupported bit depth
       
   877 			break;
       
   878 		}
       
   879 
       
   880 	iImageInfo.iCompressionMethod = TPngImageInformation::EDeflateInflate32K;
       
   881 	iImageInfo.iFilterMethod = TPngImageInformation::EAdaptiveFiltering;
       
   882 	iImageInfo.iInterlaceMethod = TPngImageInformation::ENoInterlace;
       
   883 
       
   884 	// Create encoder
       
   885 	if (iEncoder)
       
   886 		{
       
   887 		delete iEncoder;
       
   888 		iEncoder = NULL;
       
   889 		}
       
   890 	iEncoder = CPngWriteSubCodec::NewL(iImageInfo, &aSource);
       
   891 
       
   892 	// Create compressor
       
   893 	if (iCompressor)
       
   894 		{
       
   895 		delete iCompressor;
       
   896 		iCompressor = NULL;
       
   897 		}
       
   898 	iCompressor = CEZCompressor::NewL(*this, iCompressionLevel);
       
   899 
       
   900 	// Initial encoder state
       
   901 	if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   902 		iEncoderState = EPngWritePLTE;	
       
   903 	else
       
   904 		iEncoderState = EPngInit;
       
   905 	iCallAgain = ETrue;		// to make sure we call DeflateL
       
   906 
       
   907 	// Write header
       
   908 	User::LeaveIfError(WriteHeaderChunk(aDst));
       
   909 	}
       
   910 
       
   911 TFrameState CPngWriteCodec::ProcessFrameL(TBufPtr8& aDst)
       
   912 	{
       
   913 	if (aDst.MaxLength() == 0)
       
   914 		User::Leave(KErrArgument);	// Not enough length for anything
       
   915 
       
   916 	TFrameState state = EFrameIncomplete;
       
   917 	iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   918 	iDestPtr = iDestStartPtr;
       
   919 	iDestPtrLimit = iDestPtr + aDst.MaxLength();
       
   920 
       
   921 	// Set return buffer length to 0 initially
       
   922 	aDst.SetLength(0);
       
   923 
       
   924 	while (aDst.Length() == 0 && state != EFrameComplete)
       
   925 		{
       
   926 		// Loop round until we have some data to return or
       
   927 		// the image is encoded
       
   928 		switch (iEncoderState)
       
   929 			{
       
   930 			case EPngWritePLTE:
       
   931 				WritePLTEChunk(aDst);
       
   932 				break;
       
   933 			case EPngInit:
       
   934 				InitializeCompressorL(aDst);
       
   935 				ASSERT(iEncoderState==EPngDeflate);
       
   936 				break;
       
   937 			case EPngDeflate:
       
   938 			    SetCompressorOutputL(aDst);
       
   939 				iPlugin.GoToProcessDataState();
       
   940 				return state;
       
   941 			case EPngWriteIDAT:
       
   942 				WriteIDATChunk(aDst);
       
   943 				ASSERT(iEncoderState==EPngDeflate || iEncoderState==EPngEndChunk);
       
   944 				break;
       
   945 			case EPngEndChunk:
       
   946 				WriteEndChunk(aDst);
       
   947 				state = EFrameComplete;
       
   948 				break;
       
   949 			default:
       
   950 				ASSERT(EFalse);
       
   951 				break;
       
   952 			}
       
   953 		}
       
   954 
       
   955 	return state;
       
   956 	}
       
   957 
       
   958 void CPngWriteCodec::SetCompressorOutputL(TBufPtr8& aDst)
       
   959     {
       
   960 	// Set ptr for compressed data
       
   961 	const TInt dataLength = aDst.MaxLength() - KPngChunkLengthSize - KPngChunkIdSize - KPngChunkCRCSize;
       
   962 
       
   963 	if(dataLength <= 0)
       
   964 	    {
       
   965 	    // this effectively means that framework is broken
       
   966 	    // and can't provide encoder with sufficiently big buffer
       
   967 	    ASSERT( EFalse );
       
   968 	    User::Leave(KErrArgument);
       
   969 	    }
       
   970 
       
   971 	iCompressorPtr.Set(iDestPtr + KPngChunkIdSize + KPngChunkLengthSize, dataLength, dataLength);    
       
   972 	iCompressor->SetOutput(iCompressorPtr);
       
   973     }
       
   974 
       
   975 void CPngWriteCodec::InitializeCompressorL(TBufPtr8& aDst)
       
   976 	{
       
   977 	// Initialise input/output for compressor
       
   978 	iCompressor->SetInput(iEncoder->EncodeL(iScanline));
       
   979 	
       
   980 	SetCompressorOutputL(aDst);
       
   981     iScanline++;
       
   982 	iEncoderState = EPngDeflate;
       
   983 	}
       
   984 
       
   985 TBool CPngWriteCodec::DeflateEncodedDataL()
       
   986 	{
       
   987 	ASSERT(iCallAgain);
       
   988 	iCallAgain = iCompressor->DeflateL();
       
   989 	//finished when NeedOutputL() or FinalizeL() change the state to EPngWriteIDAT
       
   990 	ASSERT(iEncoderState==EPngDeflate || iEncoderState==EPngWriteIDAT);
       
   991 	return(iEncoderState!=EPngDeflate);
       
   992 	}
       
   993 
       
   994 void CPngWriteCodec::WritePLTEChunk(TBufPtr8& aDst)
       
   995 	{
       
   996 	ASSERT(iEncoder->Palette() &&
       
   997 		   (iImageInfo.iColorType == TPngImageInformation::EIndexedColor ||
       
   998 		    iImageInfo.iColorType == TPngImageInformation::EDirectColor ||
       
   999 		    iImageInfo.iColorType == TPngImageInformation::EAlphaDirectColor));	// allowed color types for PLTE chunk
       
  1000 
       
  1001 	// Get palette entries
       
  1002 	CPalette* palette = iEncoder->Palette();
       
  1003 	ASSERT(palette);
       
  1004 	const TInt count = palette->Entries();
       
  1005 	TUint8* ptr = iDestPtr + KPngChunkIdSize + KPngChunkLengthSize;
       
  1006 	TInt length = count * 3;
       
  1007 	TPtr8 data(ptr, length, length);
       
  1008 	for (TInt i=0; i < count; i++)
       
  1009 		{
       
  1010 		TRgb rgb = palette->GetEntry(i);
       
  1011 		*ptr = TUint8(rgb.Red());
       
  1012 		ptr++;
       
  1013 		*ptr = TUint8(rgb.Green());
       
  1014 		ptr++;
       
  1015 		*ptr = TUint8(rgb.Blue());
       
  1016 		ptr++;
       
  1017 		}
       
  1018 	// Write PLTE chunk
       
  1019 	WritePngChunk(iDestPtr, KPngPLTEChunkId, data, length);
       
  1020 	ASSERT(length % 3 == 0);	// length must be divisible by 3
       
  1021 	aDst.SetLength(length);
       
  1022 	iEncoderState = EPngInit;
       
  1023 	}
       
  1024 
       
  1025 void CPngWriteCodec::WriteIDATChunk(TBufPtr8& aDst)
       
  1026 	{
       
  1027 	TPtrC8 ptr(iCompressor->OutputDescriptor());
       
  1028 	if (ptr.Length())
       
  1029 		{
       
  1030 		TInt length = 0;
       
  1031 		WritePngChunk(iDestPtr, KPngIDATChunkId, ptr, length);
       
  1032 		aDst.SetLength(length);
       
  1033 
       
  1034 		// New output can write to the same compressor ptr
       
  1035 		iCompressor->SetOutput(iCompressorPtr);
       
  1036 		}
       
  1037 
       
  1038 	if (iCallAgain)
       
  1039 		iEncoderState = EPngDeflate;
       
  1040 	else
       
  1041 		iEncoderState = EPngEndChunk;
       
  1042 	}
       
  1043 
       
  1044 void CPngWriteCodec::WriteEndChunk(TBufPtr8& aDst)
       
  1045 	{
       
  1046 	// Write IEND chunk
       
  1047 	TInt length = 0;
       
  1048 	WritePngChunk(iDestPtr, KPngIENDChunkId, KNullDesC8, length);
       
  1049 	aDst.SetLength(length);
       
  1050 	}
       
  1051 
       
  1052 TInt CPngWriteCodec::WriteHeaderChunk(TBufPtr8& aDst)
       
  1053 	{
       
  1054 	// Write signature
       
  1055 	Mem::Copy(iDestPtr, &KPngSignature[0], KPngFileSignatureLength);
       
  1056 	iDestPtr += KPngFileSignatureLength;
       
  1057 
       
  1058 	// Write IHDR chunk
       
  1059 	TBuf8<KPngIHDRChunkSize> buffer;
       
  1060 	TUint8* ptr = const_cast<TUint8*>(buffer.Ptr());
       
  1061 	// Set length of data
       
  1062 	buffer.SetLength(KPngIHDRChunkSize);
       
  1063 	// Chunk data
       
  1064 	// width (4 bytes)
       
  1065 	if ((iImageInfo.iSize.iWidth == 0) ||
       
  1066 		(static_cast<TUint>(iImageInfo.iSize.iWidth) > KPngMaxImageSize))
       
  1067 		{
       
  1068 		return KErrArgument;	// invalid width
       
  1069 		}
       
  1070 	PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iWidth);
       
  1071 	ptr += 4;
       
  1072 	// height (4 bytes)
       
  1073 	if ((iImageInfo.iSize.iHeight == 0) ||
       
  1074 		(static_cast<TUint>(iImageInfo.iSize.iHeight) > KPngMaxImageSize))
       
  1075 		{
       
  1076 		return KErrArgument;	// invalid height
       
  1077 		}
       
  1078 	PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iHeight);
       
  1079 	ptr += 4;
       
  1080 	// bit depth (1 byte)
       
  1081 	PtrWriteUtil::WriteInt8(ptr, iImageInfo.iBitDepth);
       
  1082 	ptr++;
       
  1083 	// colour type (1 byte)
       
  1084 	PtrWriteUtil::WriteInt8(ptr, iImageInfo.iColorType);
       
  1085 	ptr++;
       
  1086 	// compression method (1 byte)
       
  1087 	PtrWriteUtil::WriteInt8(ptr, iImageInfo.iCompressionMethod);
       
  1088 	ptr++;
       
  1089 	// filter method (1 byte)
       
  1090 	PtrWriteUtil::WriteInt8(ptr, iImageInfo.iFilterMethod);
       
  1091 	ptr++;
       
  1092 	// interlace method (1 byte)
       
  1093 	PtrWriteUtil::WriteInt8(ptr, iImageInfo.iInterlaceMethod);
       
  1094 	ptr++;
       
  1095 
       
  1096 	TInt length = 0;
       
  1097 	WritePngChunk(iDestPtr, KPngIHDRChunkId, buffer, length);
       
  1098 	aDst.SetLength(KPngFileSignatureLength + length);
       
  1099 
       
  1100 	return KErrNone;
       
  1101 	}
       
  1102 
       
  1103 void CPngWriteCodec::WritePngChunk(TUint8*& aDestPtr, const TDesC8& aChunkId, const TDesC8& aData, TInt& aLength)
       
  1104 	{
       
  1105 	// Chunk length (4 bytes)
       
  1106 	PtrWriteUtil::WriteBigEndianInt32(aDestPtr, aData.Length());
       
  1107 	aDestPtr += KPngChunkLengthSize;
       
  1108 	TUint8* crcPtr = aDestPtr;	// start position for calculating CRC
       
  1109 	// Chunk type (4 bytes)
       
  1110 	Mem::Copy(aDestPtr, aChunkId.Ptr(), KPngChunkIdSize);
       
  1111 	aDestPtr += KPngChunkIdSize;
       
  1112 	// Chunk data (0...n bytes)
       
  1113 	Mem::Copy(aDestPtr, aData.Ptr(), aData.Length());
       
  1114 	aDestPtr += aData.Length();
       
  1115 	// CRC (4 bytes)
       
  1116 	TUint32 crc = KPngCrcMask;
       
  1117 	GetCrc(crc, crcPtr, KPngChunkIdSize + aData.Length());
       
  1118 	crc ^= KPngCrcMask;
       
  1119 	PtrWriteUtil::WriteBigEndianInt32(aDestPtr, crc);
       
  1120 	aDestPtr += KPngChunkCRCSize;
       
  1121 	// Length of chunk
       
  1122 	aLength = KPngChunkLengthSize + KPngChunkIdSize + aData.Length() + KPngChunkCRCSize;
       
  1123 	}
       
  1124 
       
  1125 // from MEZBufferManager
       
  1126 void CPngWriteCodec::InitializeL(CEZZStream& /*aZStream*/)
       
  1127 	{
       
  1128 	}
       
  1129 
       
  1130 void CPngWriteCodec::NeedInputL(CEZZStream& aZStream)
       
  1131 	{
       
  1132 	// Give compressor more data from encoder
       
  1133 	aZStream.SetInput(iEncoder->EncodeL(iScanline));
       
  1134 	if (iCompressor->AvailIn() != 0)
       
  1135 		iScanline++;
       
  1136 	}
       
  1137 
       
  1138 void CPngWriteCodec::NeedOutputL(CEZZStream& /*aZStream*/)
       
  1139 	{
       
  1140 	// Signal to write an IDAT chunk
       
  1141 	iEncoderState = EPngWriteIDAT;
       
  1142 	}
       
  1143 
       
  1144 void CPngWriteCodec::FinalizeL(CEZZStream& /*aZStream*/)
       
  1145 	{
       
  1146 	// Signal to write an IDAT chunk
       
  1147 	iEncoderState = EPngWriteIDAT;
       
  1148 	}
       
  1149 
       
  1150 // New functions
       
  1151 void CPngWriteCodec::GetCrc(TUint32& aCrc, const TUint8* aPtr, const TInt aLength)
       
  1152 	{
       
  1153 	if (!iCrcTableCalculated)
       
  1154 		CalcCrcTable();
       
  1155 	TUint32 code = aCrc;
       
  1156 	for (TInt i=0; i < aLength; i++)
       
  1157 		code = iCrcTable[(code ^ aPtr[i]) & 0xff] ^ (code >> 8);
       
  1158 	aCrc = code;
       
  1159 	}
       
  1160 
       
  1161 void CPngWriteCodec::CalcCrcTable()
       
  1162 	{
       
  1163 	for (TInt i=0; i < KPngCrcTableLength; i++)
       
  1164 		{
       
  1165 		TUint32 code = static_cast<TUint32>(i);
       
  1166 
       
  1167 		for (TInt j = 0; j < 8; j++)
       
  1168 			{
       
  1169 			if (code & 1)
       
  1170 				code = 0xedb88320 ^ (code >> 1);
       
  1171 			else
       
  1172 				code = code >> 1;
       
  1173 			}
       
  1174 		iCrcTable[i] = code;
       
  1175 		}
       
  1176 	iCrcTableCalculated = ETrue;
       
  1177 	}