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