examples/Multimedia/ICL/ICLCodec/PNGCodec.cpp

00001 /*
00002 Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
00003 
00004 Redistribution and use in source and binary forms, with or without
00005 modification, are permitted provided that the following conditions are met:
00006 
00007 * Redistributions of source code must retain the above copyright notice, this
00008   list of conditions and the following disclaimer.
00009 * Redistributions in binary form must reproduce the above copyright notice,
00010   this list of conditions and the following disclaimer in the documentation
00011   and/or other materials provided with the distribution.
00012 * Neither the name of Nokia Corporation nor the names of its contributors
00013   may be used to endorse or promote products derived from this software
00014   without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00020 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00022 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00023 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00024 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00025 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027 Description:  
00028 */
00029 
00030 
00031 #include <fbs.h>
00032 
00033 #include "ImageUtils.h"
00034 #include "PNGCodec.h"
00035 
00036 // Constants.
00037 const TInt KTwipsPerMeter = 56693;
00038 
00039 // 
00040 // TPngImageInformation: PNG image information
00041 //
00042 
00043 // Initialise default PNG image information
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         // as an optimisation, we are going to set iPalette to all zeros, instead of setting
00056         // each element to KRgbBlack. This assumes that KRbgBlack is itself zero.
00057         ASSERT(sizeof(TRgb)==sizeof(TUint32)); // ie no new fields
00058         ASSERT(KRgbBlack.Value()==0); // ie the one value is zero
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 // CPngReadCodec: reads a PNG image
00075 //
00076 
00077 CPngReadCodec::~CPngReadCodec()
00078         {
00079         delete iDecoder;
00080         delete iDecompressor;
00081         }
00082 
00083 // Called by framework when a Convert operation begins
00084 void CPngReadCodec::InitFrameL(TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameImageData*/, 
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         // Use the supplied image processor
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         // If transparency is being used, create a bitmap mask as well
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                 // set mask to black so that unknown parts on streamed image are not drawn
00109                 ClearBitmapL(*aDestinationMask, KRgbBlack);
00110                 }
00111 
00112         // Create a helper to read the scan lines
00113         delete iDecoder;
00114         iDecoder = NULL;
00115         iDecoder = CPngReadSubCodec::NewL(imageProc,maskProc,iImageInfo);
00116 
00117         // And a unzipper to decompress image data
00118         if (!iDecompressor)
00119                 iDecompressor = CEZDecompressor::NewL(*this);
00120         else
00121                 iDecompressor->ResetL(*this);
00122 
00123         if (maskProc==NULL)
00124                 {
00125                 // if no mask, clear destination for sensible behaviour on streamed partial images
00126                 TRgb background = iImageInfo.iBackgroundPresent ? iImageInfo.iBackgroundColor : KRgbWhite;
00127                 ClearBitmapL(aDestination, background);
00128                 }
00129         }
00130 
00131 // Called by framework to initialise image frame header
00132 void CPngReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */)
00133         {
00134         ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
00135         iFrameInfo = &aFrameSettings;
00136         iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
00137         }
00138 
00139 // Called by framework to process a header for a frame
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         // Process the mandatory PNG header chunk: sets up iImageInfo
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         // Process any optional PNG header chunks
00166         TRAPD(err, DoProcessInfoL(dataPtr, dataPtrLimit));
00167         if (err != KErrNone)
00168                 {
00169                 if (err == KErrNotFound)
00170                         return EFrameComplete;
00171 
00172                 User::Leave(err); // A real error occured
00173                 }
00174 
00175         // Having read the header, can initialise the frame information
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 // Called by the framework to process frame data
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                 // If at the end of a PNG chunk
00256                 if (iChunkBytesRemaining == 0)
00257                         {
00258                         if (iChunkId == KPngIDATChunkId) // Need to skip IDAT chunk CRCs
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                 // Process an image data chunk
00276                 if (iChunkId == KPngIDATChunkId)
00277                         DoProcessDataL(const_cast<const TUint8*&>(dataPtr),dataPtrLimit);
00278                 // Process an END chunk -- frame is complete
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                 // Skip other chunks
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 // Process any optional PNG header chunks
00309 void CPngReadCodec::DoProcessInfoL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
00310         {
00311         FOREVER
00312                 {
00313                 if (aDataPtr + KPngChunkLengthSize + KPngChunkIdSize > aDataPtrLimit) // Check there is enough data to read the chunk length
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; // Rewind to start of chunkLength
00322                         break;
00323                         }
00324 
00325                 if (aDataPtr + KPngChunkIdSize + chunkLength + KPngChunkCRCSize > aDataPtrLimit) // Check there is enough data to read the whole chunk
00326                         {
00327                         aDataPtr -= KPngChunkLengthSize; // Rewind to start of chunkLength
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); // Skip crc value
00346                 }
00347         }
00348 
00349 // Process the mandatory PNG header chunk
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         // Check is one of the PNG formats we support
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 // Process a PNG PLTE (palette) chunk
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 // Process a PNG bKGD (background color) chunk
00391 void CPngReadCodec::DoProcessbKGDL(const TUint8* aDataPtr,TInt aChunkLength)
00392         {
00393         iImageInfo.iBackgroundPresent = ETrue;
00394 
00395         if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
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) // 0 & 4
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) // 2 & 6
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 // Process a PNG pHYs (Physical pixel dimensions) chunk
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 // Process a PNG tRNS (Transparency) chunk
00452 void CPngReadCodec::DoProcesstRNSL(const TUint8* aDataPtr,TInt aChunkLength)
00453         {
00454         iImageInfo.iTransparencyPresent = ETrue;
00455 
00456         if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor) // 3
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) // 0
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) // 2
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 // Process a PNG image data
00482 void CPngReadCodec::DoProcessDataL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
00483         {
00484         // Data is passed to the decompressor
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 // From MEZBufferManager: manage decompressor stream
00497 void CPngReadCodec::InitializeL(CEZZStream& aZStream)
00498         {
00499         aZStream.SetOutput(iDecoder->FirstBuffer());
00500         }
00501 
00502 void CPngReadCodec::NeedInputL(CEZZStream& /*aZStream*/)
00503         {
00504         }
00505 
00506 void CPngReadCodec::NeedOutputL(CEZZStream& aZStream)
00507         {
00508         aZStream.SetOutput(iDecoder->DecodeL());
00509         }
00510 
00511 void CPngReadCodec::FinalizeL(CEZZStream& /*aZStream*/)
00512         {
00513         iDecoder->DecodeL();
00514         }
00515 
00516 
00517 
00518 //
00519 // CPngWriteCodec: writes a PNG image
00520 //
00521 
00522 
00523 CPngWriteCodec::CPngWriteCodec(TInt aBpp, TBool aColor, TBool aPaletted, TInt aCompressionLevel)
00524         : iCompressionLevel(aCompressionLevel), iCompressorPtr(NULL, 0)
00525         {
00526         // Set bpp
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         // Set color type
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 // Called by framework at start of conversion operation
00563 void CPngWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
00564         {
00565         if (aDst.Length() == 0)
00566                 User::Leave(KErrArgument);      // Not enough length for anything
00567 
00568         SetSource(&aSource);
00569         iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
00570         iDestPtr = iDestStartPtr;
00571         iDestPtrLimit = iDestPtr + aDst.MaxLength();
00572 
00573         // Set image information
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                                 // Bit depths 1, 2 and 4 don't support RGB colour (color mode 2)
00585                                 // Must use paletted colour or greyscale
00586                                 User::Leave(KErrNotSupported);
00587                                 break;
00588                                 }
00589                         // fall through to case 8
00590                 case 8:
00591                         break;
00592                 default:
00593                         User::Leave(KErrNotSupported);  // unsupported bit depth
00594                         break;
00595                 }
00596 
00597         iImageInfo.iCompressionMethod = TPngImageInformation::EDeflateInflate32K;
00598         iImageInfo.iFilterMethod = TPngImageInformation::EAdaptiveFiltering;
00599         iImageInfo.iInterlaceMethod = TPngImageInformation::ENoInterlace;
00600 
00601         // Create encoder
00602         if (iEncoder)
00603                 {
00604                 delete iEncoder;
00605                 iEncoder = NULL;
00606                 }
00607         iEncoder = CPngWriteSubCodec::NewL(iImageInfo, &aSource);
00608 
00609         // Create compressor
00610         if (iCompressor)
00611                 {
00612                 delete iCompressor;
00613                 iCompressor = NULL;
00614                 }
00615         iCompressor = CEZCompressor::NewL(*this, iCompressionLevel);
00616 
00617         // Initial encoder state
00618         if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
00619                 iEncoderState = EPngWritePLTE;  
00620         else
00621                 iEncoderState = EPngDeflate;
00622         iCallAgain = ETrue;             // to make sure we call DeflateL
00623 
00624         // Write header
00625         User::LeaveIfError(WriteHeaderChunk(aDst));
00626         }
00627 
00628 // Called by the framework to process frame data
00629 TFrameState CPngWriteCodec::ProcessFrameL(TBufPtr8& aDst)
00630         {
00631         if (aDst.Length() == 0)
00632                 User::Leave(KErrArgument);      // Not enough length for anything
00633 
00634         TFrameState state = EFrameIncomplete;
00635         iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
00636         iDestPtr = iDestStartPtr;
00637         iDestPtrLimit = iDestPtr + aDst.MaxLength();
00638 
00639         // Set return buffer length to 0 initially
00640         aDst.SetLength(0);
00641 
00642         while (aDst.Length() == 0 && state != EFrameComplete)
00643                 {
00644                 // Loop round until we have some data to return or
00645                 // the image is encoded
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 // Write a compressed image data chunk
00673 void CPngWriteCodec::DeflateEncodedDataL(TBufPtr8& aDst, TFrameState& /*aState*/)
00674         {
00675         // Set ptr for compressed data
00676         const TInt dataLength = aDst.MaxLength() - KPngChunkLengthSize - KPngChunkIdSize - KPngChunkCRCSize;
00677         ASSERT(dataLength > 0);
00678         iCompressorPtr.Set(iDestPtr + KPngChunkIdSize + KPngChunkLengthSize, dataLength, dataLength);
00679 
00680         // Initialise input/output for compressor
00681         iCompressor->SetInput(iEncoder->EncodeL(iScanline));
00682         iScanline++;
00683         iCompressor->SetOutput(iCompressorPtr);
00684 
00685         while ((iEncoderState == EPngDeflate) && iCallAgain)
00686                 iCallAgain = iCompressor->DeflateL();
00687 
00688         // Write the IDAT chunk
00689         WriteIDATChunk(aDst);
00690         iEncoderState = EPngFlush;
00691         }
00692 
00693 void CPngWriteCodec::FlushCompressedDataL(TBufPtr8& aDst, TFrameState& /*aState*/)
00694         {
00695         if (iCallAgain)
00696                 {
00697                 iCallAgain = iCompressor->DeflateL();
00698                 WriteIDATChunk(aDst);
00699                 }
00700         else
00701                 {
00702                 iEncoderState = EPngEndChunk;
00703                 }
00704         }
00705 
00706 // Write a PLTE chunk
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)); // allowed color types for PLTE chunk
00713 
00714         // Get palette entries
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         // Write PLTE chunk
00732         WritePngChunk(iDestPtr, KPngPLTEChunkId, data, length);
00733         ASSERT(length % 3 == 0);        // length must be divisible by 3
00734         aDst.SetLength(length);
00735         iEncoderState = EPngDeflate;
00736         }
00737 
00738 // Write a data chunk
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                 // New output can write to the same compressor ptr
00749                 iCompressor->SetOutput(iCompressorPtr);
00750                 }
00751 
00752         if (iCallAgain)
00753                 iEncoderState = EPngFlush;
00754         }
00755 
00756 // Write an END chunk
00757 void CPngWriteCodec::WriteEndChunk(TBufPtr8& aDst)
00758         {
00759         // Write IEND chunk
00760         TInt length = 0;
00761         WritePngChunk(iDestPtr, KPngIENDChunkId, KNullDesC8, length);
00762         aDst.SetLength(length);
00763         }
00764 
00765 // Write a header chunk
00766 TInt CPngWriteCodec::WriteHeaderChunk(TBufPtr8& aDst)
00767         {
00768         // Write signature
00769         Mem::Copy(iDestPtr, &KPngSignature[0], KPngFileSignatureLength);
00770         iDestPtr += KPngFileSignatureLength;
00771 
00772         // Write IHDR chunk
00773         TBuf8<KPngIHDRChunkSize> buffer;
00774         TUint8* ptr = const_cast<TUint8*>(buffer.Ptr());
00775         // Set length of data
00776         buffer.SetLength(KPngIHDRChunkSize);
00777         // Chunk data
00778         // width (4 bytes)
00779         if ((iImageInfo.iSize.iWidth == 0) ||
00780                 (static_cast<TUint>(iImageInfo.iSize.iWidth) > KPngMaxImageSize))
00781                 {
00782                 return KErrArgument;    // invalid width
00783                 }
00784         PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iWidth);
00785         ptr += 4;
00786         // height (4 bytes)
00787         if ((iImageInfo.iSize.iHeight == 0) ||
00788                 (static_cast<TUint>(iImageInfo.iSize.iHeight) > KPngMaxImageSize))
00789                 {
00790                 return KErrArgument;    // invalid height
00791                 }
00792         PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iHeight);
00793         ptr += 4;
00794         // bit depth (1 byte)
00795         PtrWriteUtil::WriteInt8(ptr, iImageInfo.iBitDepth);
00796         ptr++;
00797         // colour type (1 byte)
00798         PtrWriteUtil::WriteInt8(ptr, iImageInfo.iColorType);
00799         ptr++;
00800         // compression method (1 byte)
00801         PtrWriteUtil::WriteInt8(ptr, iImageInfo.iCompressionMethod);
00802         ptr++;
00803         // filter method (1 byte)
00804         PtrWriteUtil::WriteInt8(ptr, iImageInfo.iFilterMethod);
00805         ptr++;
00806         // interlace method (1 byte)
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 // Chunk writing helper function
00818 void CPngWriteCodec::WritePngChunk(TUint8*& aDestPtr, const TDesC8& aChunkId, const TDesC8& aData, TInt& aLength)
00819         {
00820         // Chunk length (4 bytes)
00821         PtrWriteUtil::WriteBigEndianInt32(aDestPtr, aData.Length());
00822         aDestPtr += KPngChunkLengthSize;
00823         TUint8* crcPtr = aDestPtr;      // start position for calculating CRC
00824         // Chunk type (4 bytes)
00825         Mem::Copy(aDestPtr, aChunkId.Ptr(), KPngChunkIdSize);
00826         aDestPtr += KPngChunkIdSize;
00827         // Chunk data (0...n bytes)
00828         Mem::Copy(aDestPtr, aData.Ptr(), aData.Length());
00829         aDestPtr += aData.Length();
00830         // CRC (4 bytes)
00831         TUint32 crc = KPngCrcMask;
00832         GetCrc(crc, crcPtr, KPngChunkIdSize + aData.Length());
00833         crc ^= KPngCrcMask;
00834         PtrWriteUtil::WriteBigEndianInt32(aDestPtr, crc);
00835         aDestPtr += KPngChunkCRCSize;
00836         // Length of chunk
00837         aLength = KPngChunkLengthSize + KPngChunkIdSize + aData.Length() + KPngChunkCRCSize;
00838         }
00839 
00840 // from MEZBufferManager, manage data compressor
00841 void CPngWriteCodec::InitializeL(CEZZStream& /*aZStream*/)
00842         {
00843         }
00844 
00845 void CPngWriteCodec::NeedInputL(CEZZStream& aZStream)
00846         {
00847         // Give compressor more data from encoder
00848         aZStream.SetInput(iEncoder->EncodeL(iScanline));
00849         if (iCompressor->AvailIn() != 0)
00850                 iScanline++;
00851         }
00852 
00853 void CPngWriteCodec::NeedOutputL(CEZZStream& /*aZStream*/)
00854         {
00855         // Signal to write an IDAT chunk
00856         iEncoderState = EPngWriteIDAT;
00857         }
00858 
00859 void CPngWriteCodec::FinalizeL(CEZZStream& /*aZStream*/)
00860         {
00861         }
00862 
00863 // Calculate CRC for PNG chunks
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         }

Generated by  doxygen 1.6.2