00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <fbs.h>
00032
00033 #include "ImageUtils.h"
00034 #include "PNGCodec.h"
00035
00036
00037 const TInt KTwipsPerMeter = 56693;
00038
00039
00040
00041
00042
00043
00044 TPngImageInformation::TPngImageInformation()
00045 {
00046 iSize.SetSize(0,0);
00047 iBitDepth = 0;
00048 iColorType = EGrayscale;
00049 iCompressionMethod = EDeflateInflate32K;
00050 iFilterMethod = EAdaptiveFiltering;
00051 iInterlaceMethod = ENoInterlace;
00052 iPalettePresent = EFalse;
00053
00054 #if defined(_DEBUG)
00055
00056
00057 ASSERT(sizeof(TRgb)==sizeof(TUint32));
00058 ASSERT(KRgbBlack.Value()==0);
00059 #endif // defined(_DEBUG)
00060
00061 Mem::FillZ(iPalette, KPngMaxPLTESize*sizeof(TRgb));
00062
00063 iBackgroundPresent = EFalse;
00064 iBackgroundColor = KRgbWhite;
00065 iPhysicalPresent = EFalse;
00066 iPhysicalUnits = EUnknownUnits;
00067 iPhysicalSize.SetSize(0,0);
00068 iTransparencyPresent = EFalse;
00069 Mem::Fill(iTransparencyValue,KPngMaxPLTESize,0xff);
00070 }
00071
00072
00073
00074
00075
00076
00077 CPngReadCodec::~CPngReadCodec()
00078 {
00079 delete iDecoder;
00080 delete iDecompressor;
00081 }
00082
00083
00084 void CPngReadCodec::InitFrameL(TFrameInfo& , CFrameImageData& ,
00085 TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
00086 {
00087 CFbsBitmap& newFrame = aDestination;
00088
00089 TPoint& pos = Pos();
00090 pos.SetXY(0,0);
00091 iChunkBytesRemaining = 0;
00092
00093
00094 CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL(newFrame, iImageInfo.iSize, ERgb, aDisableErrorDiffusion);
00095 SetImageProcessor(imageProc);
00096 imageProc->PrepareL(newFrame,iImageInfo.iSize);
00097
00098 CImageProcessor* maskProc = NULL;
00099 SetMaskProcessor(NULL);
00100
00101
00102 if ((iImageInfo.iTransparencyPresent || (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed))
00103 && aDestinationMask)
00104 {
00105 maskProc = ImageProcessorUtility::NewImageProcessorL(*aDestinationMask, iImageInfo.iSize, ERgb, aDisableErrorDiffusion);
00106 SetMaskProcessor(maskProc);
00107 maskProc->PrepareL(*aDestinationMask,iImageInfo.iSize);
00108
00109 ClearBitmapL(*aDestinationMask, KRgbBlack);
00110 }
00111
00112
00113 delete iDecoder;
00114 iDecoder = NULL;
00115 iDecoder = CPngReadSubCodec::NewL(imageProc,maskProc,iImageInfo);
00116
00117
00118 if (!iDecompressor)
00119 iDecompressor = CEZDecompressor::NewL(*this);
00120 else
00121 iDecompressor->ResetL(*this);
00122
00123 if (maskProc==NULL)
00124 {
00125
00126 TRgb background = iImageInfo.iBackgroundPresent ? iImageInfo.iBackgroundColor : KRgbWhite;
00127 ClearBitmapL(aDestination, background);
00128 }
00129 }
00130
00131
00132 void CPngReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& )
00133 {
00134 ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
00135 iFrameInfo = &aFrameSettings;
00136 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
00137 }
00138
00139
00140 TFrameState CPngReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
00141 {
00142 const TUint8* startDataPtr = aData.Ptr();
00143 const TUint8* dataPtr = startDataPtr;
00144 const TUint8* dataPtrLimit = startDataPtr + aData.Length();
00145
00146
00147 if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
00148 {
00149 if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize + KPngIHDRChunkSize + KPngChunkCRCSize > dataPtrLimit)
00150 User::Leave(KErrUnderflow);
00151
00152 TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(dataPtr);
00153 TPtrC8 chunkId(dataPtr,KPngChunkIdSize);
00154
00155 if (chunkLength != KPngIHDRChunkSize || chunkId != KPngIHDRChunkId)
00156 User::Leave(KErrNotFound);
00157
00158 dataPtr += KPngChunkIdSize;
00159
00160 DoProcessIHDRL(dataPtr,chunkLength);
00161
00162 dataPtr += KPngIHDRChunkSize + KPngChunkCRCSize;
00163 }
00164
00165
00166 TRAPD(err, DoProcessInfoL(dataPtr, dataPtrLimit));
00167 if (err != KErrNone)
00168 {
00169 if (err == KErrNotFound)
00170 return EFrameComplete;
00171
00172 User::Leave(err);
00173 }
00174
00175
00176 aData.Shift(dataPtr - startDataPtr);
00177
00178 iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0),iImageInfo.iSize);
00179 iFrameInfo->iOverallSizeInPixels = iImageInfo.iSize;
00180 if (iImageInfo.iPhysicalPresent && iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
00181 iFrameInfo->iFrameSizeInTwips = iImageInfo.iPhysicalSize;
00182 else
00183 iFrameInfo->iFrameSizeInTwips.SetSize(0,0);
00184
00185 iFrameInfo->iBitsPerPixel = iImageInfo.iBitDepth;
00186 if (iImageInfo.iColorType & TPngImageInformation::EColorUsed)
00187 iFrameInfo->iBitsPerPixel *= 3;
00188
00189 iFrameInfo->iDelay = 0;
00190 iFrameInfo->iFlags = TFrameInfo::ECanDither;
00191
00192 if (iImageInfo.iColorType & (TPngImageInformation::EPaletteUsed | TPngImageInformation::EColorUsed))
00193 iFrameInfo->iFlags |= TFrameInfo::EColor;
00194
00195 if (iImageInfo.iColorType & TPngImageInformation::EAlphaChannelUsed)
00196 {
00197 iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
00198 iFrameInfo->iFlags |= TFrameInfo::EAlphaChannel;
00199 }
00200 else if (iImageInfo.iTransparencyPresent)
00201 iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
00202
00203 switch (iFrameInfo->iBitsPerPixel)
00204 {
00205 case 1:
00206 iFrameInfo->iFrameDisplayMode = EGray2;
00207 break;
00208
00209 case 2:
00210 iFrameInfo->iFrameDisplayMode = EGray4;
00211 break;
00212
00213 case 4:
00214 iFrameInfo->iFrameDisplayMode = (iFrameInfo->iFlags & TFrameInfo::EColor) ? EColor16 : EGray16;
00215 break;
00216
00217 case 8:
00218 iFrameInfo->iFrameDisplayMode = (iFrameInfo->iFlags & TFrameInfo::EColor) ? EColor256 : EGray256;
00219 break;
00220
00221 case 12:
00222 iFrameInfo->iFrameDisplayMode = EColor4K;
00223 break;
00224
00225 case 16:
00226 iFrameInfo->iFrameDisplayMode = EColor64K;
00227 break;
00228
00229 case 24:
00230 iFrameInfo->iFrameDisplayMode = EColor16M;
00231 break;
00232
00233 default:
00234 User::Leave(KErrCorrupt);
00235 }
00236
00237 if (iImageInfo.iBackgroundPresent)
00238 iFrameInfo->iBackgroundColor = iImageInfo.iBackgroundColor;
00239
00240 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
00241 return EFrameComplete;
00242 }
00243
00244
00245 TFrameState CPngReadCodec::ProcessFrameL(TBufPtr8& aSrc)
00246 {
00247 CImageProcessor*const imageProc = ImageProcessor();
00248 CImageProcessor*const maskProc = MaskProcessor();
00249
00250 TUint8* startDataPtr = const_cast<TUint8*>(aSrc.Ptr());
00251 TUint8* dataPtr = startDataPtr;
00252 const TUint8* dataPtrLimit = dataPtr + aSrc.Length();
00253 while (dataPtr < dataPtrLimit)
00254 {
00255
00256 if (iChunkBytesRemaining == 0)
00257 {
00258 if (iChunkId == KPngIDATChunkId)
00259 {
00260 if (dataPtr + KPngChunkCRCSize + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
00261 break;
00262
00263 dataPtr += KPngChunkCRCSize;
00264 }
00265 else
00266 {
00267 if (dataPtr + KPngChunkLengthSize + KPngChunkIdSize > dataPtrLimit)
00268 break;
00269 }
00270
00271 iChunkBytesRemaining = PtrReadUtil::ReadBigEndianUint32Inc(const_cast<const TUint8*&>(dataPtr));
00272 iChunkId = TPtr8(dataPtr,KPngChunkIdSize,KPngChunkIdSize);
00273 dataPtr += KPngChunkIdSize;
00274 }
00275
00276 if (iChunkId == KPngIDATChunkId)
00277 DoProcessDataL(const_cast<const TUint8*&>(dataPtr),dataPtrLimit);
00278
00279 else if (iChunkId == KPngIENDChunkId)
00280 {
00281 iDecompressor->InflateL();
00282 imageProc->FlushPixels();
00283 if (maskProc)
00284 maskProc->FlushPixels();
00285 return EFrameComplete;
00286 }
00287 else
00288
00289 {
00290 TInt bytesLeft = dataPtrLimit - dataPtr;
00291 if (bytesLeft >= iChunkBytesRemaining + KPngChunkCRCSize)
00292 {
00293 dataPtr += iChunkBytesRemaining + KPngChunkCRCSize;
00294 iChunkBytesRemaining = 0;
00295 }
00296 else
00297 {
00298 dataPtr += bytesLeft;
00299 iChunkBytesRemaining -= bytesLeft;
00300 }
00301 }
00302 }
00303
00304 aSrc.Shift(dataPtr - startDataPtr);
00305 return EFrameIncomplete;
00306 }
00307
00308
00309 void CPngReadCodec::DoProcessInfoL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
00310 {
00311 FOREVER
00312 {
00313 if (aDataPtr + KPngChunkLengthSize + KPngChunkIdSize > aDataPtrLimit)
00314 User::Leave(KErrUnderflow);
00315
00316 TInt chunkLength = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00317 TPtrC8 chunkId (&aDataPtr[0],KPngChunkIdSize);
00318
00319 if (chunkId == KPngIDATChunkId)
00320 {
00321 aDataPtr -= KPngChunkLengthSize;
00322 break;
00323 }
00324
00325 if (aDataPtr + KPngChunkIdSize + chunkLength + KPngChunkCRCSize > aDataPtrLimit)
00326 {
00327 aDataPtr -= KPngChunkLengthSize;
00328 User::Leave(KErrUnderflow);
00329 }
00330
00331 aDataPtr += KPngChunkIdSize;
00332
00333 if (chunkId == KPngPLTEChunkId)
00334 DoProcessPLTEL(aDataPtr,chunkLength);
00335 else if (chunkId == KPngbKGDChunkId)
00336 DoProcessbKGDL(aDataPtr,chunkLength);
00337 else if (chunkId == KPngpHYsChunkId)
00338 DoProcesspHYsL(aDataPtr,chunkLength);
00339 else if (chunkId == KPngtRNSChunkId)
00340 DoProcesstRNSL(aDataPtr,chunkLength);
00341 else if (chunkId == KPngIHDRChunkId || chunkId == KPngIENDChunkId)
00342 User::Leave(KErrCorrupt);
00343
00344 aDataPtr += chunkLength;
00345 PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00346 }
00347 }
00348
00349
00350 void CPngReadCodec::DoProcessIHDRL(const TUint8* aDataPtr,TInt aChunkLength)
00351 {
00352 if (aChunkLength != KPngIHDRChunkSize)
00353 User::Leave(KErrCorrupt);
00354
00355 iImageInfo.iSize.iWidth = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00356 iImageInfo.iSize.iHeight = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00357 iImageInfo.iBitDepth = aDataPtr[0];
00358 iImageInfo.iColorType = TPngImageInformation::TColorType(aDataPtr[1]);
00359 iImageInfo.iCompressionMethod = TPngImageInformation::TCompressionMethod(aDataPtr[2]);
00360 iImageInfo.iFilterMethod = TPngImageInformation::TFilterMethod(aDataPtr[3]);
00361 iImageInfo.iInterlaceMethod = TPngImageInformation::TInterlaceMethod(aDataPtr[4]);
00362
00363
00364 if (iImageInfo.iSize.iWidth < 1 || iImageInfo.iSize.iHeight < 1
00365 || iImageInfo.iCompressionMethod != TPngImageInformation::EDeflateInflate32K
00366 || iImageInfo.iFilterMethod != TPngImageInformation::EAdaptiveFiltering
00367 || (iImageInfo.iInterlaceMethod != TPngImageInformation::ENoInterlace &&
00368 iImageInfo.iInterlaceMethod != TPngImageInformation::EAdam7Interlace))
00369 User::Leave(KErrCorrupt);
00370 }
00371
00372
00373 void CPngReadCodec::DoProcessPLTEL(const TUint8* aDataPtr,TInt aChunkLength)
00374 {
00375 if (aChunkLength % 3 != 0)
00376 User::Leave(KErrCorrupt);
00377
00378 iImageInfo.iPalettePresent = ETrue;
00379
00380 const TUint8* dataPtrLimit = aDataPtr + aChunkLength;
00381 TRgb* palettePtr = iImageInfo.iPalette;
00382
00383 while (aDataPtr < dataPtrLimit)
00384 {
00385 *palettePtr++ = TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2]);
00386 aDataPtr += 3;
00387 }
00388 }
00389
00390
00391 void CPngReadCodec::DoProcessbKGDL(const TUint8* aDataPtr,TInt aChunkLength)
00392 {
00393 iImageInfo.iBackgroundPresent = ETrue;
00394
00395 if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
00396 {
00397 if (aChunkLength < 1)
00398 User::Leave(KErrCorrupt);
00399
00400 iImageInfo.iBackgroundColor = iImageInfo.iPalette[aDataPtr[0]];
00401 }
00402 else if (iImageInfo.iColorType & TPngImageInformation::EMonochrome)
00403 {
00404 if (aChunkLength < 2)
00405 User::Leave(KErrCorrupt);
00406
00407 TInt grayLevel = PtrReadUtil::ReadBigEndianInt16(aDataPtr);
00408 ASSERT(iImageInfo.iBitDepth<8);
00409 grayLevel <<= (7-iImageInfo.iBitDepth);
00410 iImageInfo.iBackgroundColor = TRgb::Gray256(grayLevel);
00411 }
00412 else if (iImageInfo.iColorType & TPngImageInformation::EColorUsed)
00413 {
00414 if (aChunkLength < 6)
00415 User::Leave(KErrCorrupt);
00416
00417 TInt red = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[0]);
00418 TInt green = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[2]);
00419 TInt blue = PtrReadUtil::ReadBigEndianInt16(&aDataPtr[4]);
00420 ASSERT (iImageInfo.iBitDepth<8);
00421 const TInt offset = 7-iImageInfo.iBitDepth;
00422 red <<= offset;
00423 green <<= offset;
00424 blue <<= offset;
00425 iImageInfo.iBackgroundColor = TRgb(red,green,blue);
00426 }
00427 }
00428
00429
00430 void CPngReadCodec::DoProcesspHYsL(const TUint8* aDataPtr,TInt aChunkLength)
00431 {
00432 if (aChunkLength != KPngpHYsChunkSize)
00433 User::Leave(KErrCorrupt);
00434
00435 iImageInfo.iPhysicalUnits = TPngImageInformation::TPhysicalUnits(aDataPtr[8]);
00436
00437 if (iImageInfo.iPhysicalUnits == TPngImageInformation::EMeters)
00438 {
00439 iImageInfo.iPhysicalPresent = ETrue;
00440
00441 TInt horzPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00442 TInt vertPixelsPerMeter = PtrReadUtil::ReadBigEndianUint32Inc(aDataPtr);
00443
00444 if (horzPixelsPerMeter > 0)
00445 iImageInfo.iPhysicalSize.iWidth = iImageInfo.iSize.iWidth * KTwipsPerMeter / horzPixelsPerMeter;
00446 if (vertPixelsPerMeter > 0)
00447 iImageInfo.iPhysicalSize.iHeight = iImageInfo.iSize.iHeight * KTwipsPerMeter / vertPixelsPerMeter;
00448 }
00449 }
00450
00451
00452 void CPngReadCodec::DoProcesstRNSL(const TUint8* aDataPtr,TInt aChunkLength)
00453 {
00454 iImageInfo.iTransparencyPresent = ETrue;
00455
00456 if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
00457 {
00458 if (aChunkLength < 1)
00459 User::Leave(KErrCorrupt);
00460
00461 Mem::Copy(iImageInfo.iTransparencyValue,aDataPtr,aChunkLength);
00462 }
00463 else if (iImageInfo.iColorType == TPngImageInformation::EGrayscale)
00464 {
00465 if (aChunkLength < 2)
00466 User::Leave(KErrCorrupt);
00467
00468 iImageInfo.iTransparentGray = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
00469 }
00470 else if (iImageInfo.iColorType == TPngImageInformation::EDirectColor)
00471 {
00472 if (aChunkLength < 6)
00473 User::Leave(KErrCorrupt);
00474
00475 iImageInfo.iTransparentRed = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
00476 iImageInfo.iTransparentGreen = TUint16((aDataPtr[2] << 8) | aDataPtr[3]);
00477 iImageInfo.iTransparentBlue = TUint16((aDataPtr[4] << 8) | aDataPtr[5]);
00478 }
00479 }
00480
00481
00482 void CPngReadCodec::DoProcessDataL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
00483 {
00484
00485 TInt bytesToProcess = Min(aDataPtrLimit - aDataPtr,iChunkBytesRemaining);
00486 iDataDes.Set(aDataPtr,bytesToProcess);
00487 iDecompressor->SetInput(iDataDes);
00488
00489 while (iDecompressor->AvailIn() > 0)
00490 iDecompressor->InflateL();
00491
00492 aDataPtr += bytesToProcess;
00493 iChunkBytesRemaining -= bytesToProcess;
00494 }
00495
00496
00497 void CPngReadCodec::InitializeL(CEZZStream& aZStream)
00498 {
00499 aZStream.SetOutput(iDecoder->FirstBuffer());
00500 }
00501
00502 void CPngReadCodec::NeedInputL(CEZZStream& )
00503 {
00504 }
00505
00506 void CPngReadCodec::NeedOutputL(CEZZStream& aZStream)
00507 {
00508 aZStream.SetOutput(iDecoder->DecodeL());
00509 }
00510
00511 void CPngReadCodec::FinalizeL(CEZZStream& )
00512 {
00513 iDecoder->DecodeL();
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523 CPngWriteCodec::CPngWriteCodec(TInt aBpp, TBool aColor, TBool aPaletted, TInt aCompressionLevel)
00524 : iCompressionLevel(aCompressionLevel), iCompressorPtr(NULL, 0)
00525 {
00526
00527 iImageInfo.iBitsPerPixel = aBpp;
00528 switch (aBpp)
00529 {
00530 case 1:
00531 iImageInfo.iBitDepth = 1;
00532 break;
00533 case 2:
00534 iImageInfo.iBitDepth = 2;
00535 break;
00536 case 4:
00537 iImageInfo.iBitDepth = 4;
00538 break;
00539 case 8:
00540 case 24:
00541 iImageInfo.iBitDepth = 8;
00542 break;
00543 default:
00544 break;
00545 }
00546
00547
00548 if (aColor && aPaletted)
00549 iImageInfo.iColorType = TPngImageInformation::EIndexedColor;
00550 else if (aColor)
00551 iImageInfo.iColorType = TPngImageInformation::EDirectColor;
00552 else
00553 iImageInfo.iColorType = TPngImageInformation::EGrayscale;
00554 }
00555
00556 CPngWriteCodec::~CPngWriteCodec()
00557 {
00558 delete iCompressor;
00559 delete iEncoder;
00560 }
00561
00562
00563 void CPngWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
00564 {
00565 if (aDst.Length() == 0)
00566 User::Leave(KErrArgument);
00567
00568 SetSource(&aSource);
00569 iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
00570 iDestPtr = iDestStartPtr;
00571 iDestPtrLimit = iDestPtr + aDst.MaxLength();
00572
00573
00574 const SEpocBitmapHeader& header = aSource.Header();
00575 iImageInfo.iSize = header.iSizeInPixels;
00576
00577 switch (iImageInfo.iBitDepth)
00578 {
00579 case 1:
00580 case 2:
00581 case 4:
00582 if (iImageInfo.iColorType == TPngImageInformation::EDirectColor)
00583 {
00584
00585
00586 User::Leave(KErrNotSupported);
00587 break;
00588 }
00589
00590 case 8:
00591 break;
00592 default:
00593 User::Leave(KErrNotSupported);
00594 break;
00595 }
00596
00597 iImageInfo.iCompressionMethod = TPngImageInformation::EDeflateInflate32K;
00598 iImageInfo.iFilterMethod = TPngImageInformation::EAdaptiveFiltering;
00599 iImageInfo.iInterlaceMethod = TPngImageInformation::ENoInterlace;
00600
00601
00602 if (iEncoder)
00603 {
00604 delete iEncoder;
00605 iEncoder = NULL;
00606 }
00607 iEncoder = CPngWriteSubCodec::NewL(iImageInfo, &aSource);
00608
00609
00610 if (iCompressor)
00611 {
00612 delete iCompressor;
00613 iCompressor = NULL;
00614 }
00615 iCompressor = CEZCompressor::NewL(*this, iCompressionLevel);
00616
00617
00618 if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
00619 iEncoderState = EPngWritePLTE;
00620 else
00621 iEncoderState = EPngDeflate;
00622 iCallAgain = ETrue;
00623
00624
00625 User::LeaveIfError(WriteHeaderChunk(aDst));
00626 }
00627
00628
00629 TFrameState CPngWriteCodec::ProcessFrameL(TBufPtr8& aDst)
00630 {
00631 if (aDst.Length() == 0)
00632 User::Leave(KErrArgument);
00633
00634 TFrameState state = EFrameIncomplete;
00635 iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
00636 iDestPtr = iDestStartPtr;
00637 iDestPtrLimit = iDestPtr + aDst.MaxLength();
00638
00639
00640 aDst.SetLength(0);
00641
00642 while (aDst.Length() == 0 && state != EFrameComplete)
00643 {
00644
00645
00646 switch (iEncoderState)
00647 {
00648 case EPngWritePLTE:
00649 WritePLTEChunk(aDst);
00650 break;
00651 case EPngDeflate:
00652 DeflateEncodedDataL(aDst, state);
00653 break;
00654 case EPngWriteIDAT:
00655 WriteIDATChunk(aDst);
00656 break;
00657 case EPngFlush:
00658 FlushCompressedDataL(aDst, state);
00659 break;
00660 case EPngEndChunk:
00661 WriteEndChunk(aDst);
00662 state = EFrameComplete;
00663 break;
00664 default:
00665 break;
00666 }
00667 }
00668
00669 return state;
00670 }
00671
00672
00673 void CPngWriteCodec::DeflateEncodedDataL(TBufPtr8& aDst, TFrameState& )
00674 {
00675
00676 const TInt dataLength = aDst.MaxLength() - KPngChunkLengthSize - KPngChunkIdSize - KPngChunkCRCSize;
00677 ASSERT(dataLength > 0);
00678 iCompressorPtr.Set(iDestPtr + KPngChunkIdSize + KPngChunkLengthSize, dataLength, dataLength);
00679
00680
00681 iCompressor->SetInput(iEncoder->EncodeL(iScanline));
00682 iScanline++;
00683 iCompressor->SetOutput(iCompressorPtr);
00684
00685 while ((iEncoderState == EPngDeflate) && iCallAgain)
00686 iCallAgain = iCompressor->DeflateL();
00687
00688
00689 WriteIDATChunk(aDst);
00690 iEncoderState = EPngFlush;
00691 }
00692
00693 void CPngWriteCodec::FlushCompressedDataL(TBufPtr8& aDst, TFrameState& )
00694 {
00695 if (iCallAgain)
00696 {
00697 iCallAgain = iCompressor->DeflateL();
00698 WriteIDATChunk(aDst);
00699 }
00700 else
00701 {
00702 iEncoderState = EPngEndChunk;
00703 }
00704 }
00705
00706
00707 void CPngWriteCodec::WritePLTEChunk(TBufPtr8& aDst)
00708 {
00709 ASSERT(iEncoder->Palette() &&
00710 (iImageInfo.iColorType == TPngImageInformation::EIndexedColor ||
00711 iImageInfo.iColorType == TPngImageInformation::EDirectColor ||
00712 iImageInfo.iColorType == TPngImageInformation::EAlphaDirectColor));
00713
00714
00715 CPalette* palette = iEncoder->Palette();
00716 ASSERT(palette);
00717 const TInt count = palette->Entries();
00718 TUint8* ptr = iDestPtr + KPngChunkIdSize + KPngChunkLengthSize;
00719 TInt length = count * 3;
00720 TPtr8 data(ptr, length, length);
00721 for (TInt i=0; i < count; i++)
00722 {
00723 TRgb rgb = palette->GetEntry(i);
00724 *ptr = TUint8(rgb.Red());
00725 ptr++;
00726 *ptr = TUint8(rgb.Green());
00727 ptr++;
00728 *ptr = TUint8(rgb.Blue());
00729 ptr++;
00730 }
00731
00732 WritePngChunk(iDestPtr, KPngPLTEChunkId, data, length);
00733 ASSERT(length % 3 == 0);
00734 aDst.SetLength(length);
00735 iEncoderState = EPngDeflate;
00736 }
00737
00738
00739 void CPngWriteCodec::WriteIDATChunk(TBufPtr8& aDst)
00740 {
00741 TPtrC8 ptr(iCompressor->OutputDescriptor());
00742 if (ptr.Length())
00743 {
00744 TInt length = 0;
00745 WritePngChunk(iDestPtr, KPngIDATChunkId, ptr, length);
00746 aDst.SetLength(length);
00747
00748
00749 iCompressor->SetOutput(iCompressorPtr);
00750 }
00751
00752 if (iCallAgain)
00753 iEncoderState = EPngFlush;
00754 }
00755
00756
00757 void CPngWriteCodec::WriteEndChunk(TBufPtr8& aDst)
00758 {
00759
00760 TInt length = 0;
00761 WritePngChunk(iDestPtr, KPngIENDChunkId, KNullDesC8, length);
00762 aDst.SetLength(length);
00763 }
00764
00765
00766 TInt CPngWriteCodec::WriteHeaderChunk(TBufPtr8& aDst)
00767 {
00768
00769 Mem::Copy(iDestPtr, &KPngSignature[0], KPngFileSignatureLength);
00770 iDestPtr += KPngFileSignatureLength;
00771
00772
00773 TBuf8<KPngIHDRChunkSize> buffer;
00774 TUint8* ptr = const_cast<TUint8*>(buffer.Ptr());
00775
00776 buffer.SetLength(KPngIHDRChunkSize);
00777
00778
00779 if ((iImageInfo.iSize.iWidth == 0) ||
00780 (static_cast<TUint>(iImageInfo.iSize.iWidth) > KPngMaxImageSize))
00781 {
00782 return KErrArgument;
00783 }
00784 PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iWidth);
00785 ptr += 4;
00786
00787 if ((iImageInfo.iSize.iHeight == 0) ||
00788 (static_cast<TUint>(iImageInfo.iSize.iHeight) > KPngMaxImageSize))
00789 {
00790 return KErrArgument;
00791 }
00792 PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iHeight);
00793 ptr += 4;
00794
00795 PtrWriteUtil::WriteInt8(ptr, iImageInfo.iBitDepth);
00796 ptr++;
00797
00798 PtrWriteUtil::WriteInt8(ptr, iImageInfo.iColorType);
00799 ptr++;
00800
00801 PtrWriteUtil::WriteInt8(ptr, iImageInfo.iCompressionMethod);
00802 ptr++;
00803
00804 PtrWriteUtil::WriteInt8(ptr, iImageInfo.iFilterMethod);
00805 ptr++;
00806
00807 PtrWriteUtil::WriteInt8(ptr, iImageInfo.iInterlaceMethod);
00808 ptr++;
00809
00810 TInt length = 0;
00811 WritePngChunk(iDestPtr, KPngIHDRChunkId, buffer, length);
00812 aDst.SetLength(KPngFileSignatureLength + length);
00813
00814 return KErrNone;
00815 }
00816
00817
00818 void CPngWriteCodec::WritePngChunk(TUint8*& aDestPtr, const TDesC8& aChunkId, const TDesC8& aData, TInt& aLength)
00819 {
00820
00821 PtrWriteUtil::WriteBigEndianInt32(aDestPtr, aData.Length());
00822 aDestPtr += KPngChunkLengthSize;
00823 TUint8* crcPtr = aDestPtr;
00824
00825 Mem::Copy(aDestPtr, aChunkId.Ptr(), KPngChunkIdSize);
00826 aDestPtr += KPngChunkIdSize;
00827
00828 Mem::Copy(aDestPtr, aData.Ptr(), aData.Length());
00829 aDestPtr += aData.Length();
00830
00831 TUint32 crc = KPngCrcMask;
00832 GetCrc(crc, crcPtr, KPngChunkIdSize + aData.Length());
00833 crc ^= KPngCrcMask;
00834 PtrWriteUtil::WriteBigEndianInt32(aDestPtr, crc);
00835 aDestPtr += KPngChunkCRCSize;
00836
00837 aLength = KPngChunkLengthSize + KPngChunkIdSize + aData.Length() + KPngChunkCRCSize;
00838 }
00839
00840
00841 void CPngWriteCodec::InitializeL(CEZZStream& )
00842 {
00843 }
00844
00845 void CPngWriteCodec::NeedInputL(CEZZStream& aZStream)
00846 {
00847
00848 aZStream.SetInput(iEncoder->EncodeL(iScanline));
00849 if (iCompressor->AvailIn() != 0)
00850 iScanline++;
00851 }
00852
00853 void CPngWriteCodec::NeedOutputL(CEZZStream& )
00854 {
00855
00856 iEncoderState = EPngWriteIDAT;
00857 }
00858
00859 void CPngWriteCodec::FinalizeL(CEZZStream& )
00860 {
00861 }
00862
00863
00864 void CPngWriteCodec::GetCrc(TUint32& aCrc, const TUint8* aPtr, const TInt aLength)
00865 {
00866 if (!iCrcTableCalculated)
00867 CalcCrcTable();
00868 TUint32 code = aCrc;
00869 for (TInt i=0; i < aLength; i++)
00870 code = iCrcTable[(code ^ aPtr[i]) & 0xff] ^ (code >> 8);
00871 aCrc = code;
00872 }
00873
00874 void CPngWriteCodec::CalcCrcTable()
00875 {
00876 for (TInt i=0; i < KPngCrcTableLength; i++)
00877 {
00878 TUint32 code = static_cast<TUint32>(i);
00879
00880 for (TInt j = 0; j < 8; j++)
00881 {
00882 if (code & 1)
00883 code = 0xedb88320 ^ (code >> 1);
00884 else
00885 code = code >> 1;
00886 }
00887 iCrcTable[i] = code;
00888 }
00889 iCrcTableCalculated = ETrue;
00890 }