examples/Multimedia/ICL/ICLCodec/PngScanlineEncoder.cpp

00001 // PngScanlineEncoder.cpp
00002 //
00003 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
00004 // All rights reserved.
00005 // This component and the accompanying materials are made available
00006 // under the terms of "Eclipse Public License v1.0"
00007 // which accompanies this distribution, and is available
00008 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00009 //
00010 // Initial Contributors:
00011 // Nokia Corporation - initial contribution.
00012 //
00013 // Contributors:
00014 //
00015 // Description:
00016 //
00017 //
00018 
00019 #include "PngScanlineEncoder.h"
00020 
00021 //
00022 // CPngWriteSubCodec: base class for writing PNG scanlines
00023 //
00024 
00025 // Factory function
00026 CPngWriteSubCodec* CPngWriteSubCodec::NewL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
00027         {
00028         CPngWriteSubCodec* self = NULL;
00029 
00030         switch (aInfo.iBitDepth)
00031                 {
00032                 case 1:
00033                         self = new(ELeave) CBitDepth1Encoder;
00034                         break;
00035                 case 2:
00036                         self = new(ELeave) CBitDepth2Encoder;
00037                         break;
00038                 case 4:
00039                         self = new(ELeave) CBitDepth4Encoder;
00040                         break;
00041                 case 8:
00042                         switch (aInfo.iColorType)
00043                                 {
00044                                 case TPngImageInformation::EGrayscale:
00045                                 case TPngImageInformation::EIndexedColor:
00046                                         self = new(ELeave) CBitDepth8Encoder;
00047                                         break;
00048                                 case TPngImageInformation::EDirectColor:
00049                                         self = new(ELeave) CBitDepth8ColorType2Encoder;
00050                                         break;
00051                                 default:
00052                                         User::Leave(KErrNotSupported);
00053                                         break;
00054                                 }
00055                         break;
00056                 default:
00057                         User::Leave(KErrNotSupported);
00058                         break;
00059                 }
00060         ASSERT(self);
00061         CleanupStack::PushL(self);
00062         self->ConstructL(aInfo, aSource);
00063         CleanupStack::Pop(self);
00064         return self;
00065         }
00066 
00067 CPngWriteSubCodec::CPngWriteSubCodec()
00068         : iScanlineDes(NULL, 0)
00069         {
00070         }
00071 
00072 CPngWriteSubCodec::~CPngWriteSubCodec()
00073         {
00074         delete iScanlineBuffer;
00075         delete iPalette;
00076         }
00077 
00078 void CPngWriteSubCodec::ConstructL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
00079         {
00080         iInfo = aInfo;
00081         iSource = aSource;
00082         iScanlineBufferSize = ScanlineBufferSize(iInfo.iSize.iWidth);
00083         iScanlineBuffer = HBufC8::NewMaxL(iScanlineBufferSize);
00084         iScanlineDes.Set(&(iScanlineBuffer->Des())[0], iScanlineBufferSize, iScanlineBufferSize);
00085 
00086         // Init stuff specific to derived class
00087         DoConstructL();
00088         }
00089 
00090 void CPngWriteSubCodec::DoConstructL()
00091         {
00092         }
00093 
00094 TDes8& CPngWriteSubCodec::Buffer()
00095         {
00096         iScanlineDes.FillZ();
00097         return iScanlineDes;
00098         }
00099 
00100 TDes8& CPngWriteSubCodec::EncodeL(const TInt aScanline)
00101         {
00102         if (aScanline < iInfo.iSize.iHeight)
00103                 {
00104                 TUint8* dataPtr = const_cast<TUint8*>(iScanlineDes.Ptr());
00105                 const TUint8* dataPtrLimit = dataPtr + iScanlineBufferSize;
00106 
00107                 DoEncode(iSource, aScanline, dataPtr, dataPtrLimit);
00108                 }
00109         else
00110                 {
00111                 iScanlineDes.Set(NULL, 0, 0);
00112                 }
00113         return iScanlineDes;
00114         }
00115 
00116 TUint8 CPngWriteSubCodec::ReverseBits(const TUint8 aValue) const
00117         {
00118         TUint value = aValue;
00119         TUint reverseVal = 0;
00120         for (TInt i = 0; i < 8; i++)
00121                 {
00122                 reverseVal <<= 1;
00123                 reverseVal |= value & 1;
00124                 value >>= 1;
00125                 }
00126         return TUint8(reverseVal);
00127         }
00128 
00129 void CPngWriteSubCodec::EncodePalettedScanline(TUint8* aDataPtr, const CFbsBitmap* aSource, const TInt aScanline,
00130                                                                                            const TInt aPixelsPerByte, const TInt aShiftValue)
00131         {
00132         // Encode a single scanline with indexes into the current palette
00133         ASSERT(iInfo.iPalettePresent);
00134         TPoint pos(0, aScanline);
00135         const TInt scanLength = iInfo.iSize.iWidth;
00136         for (TInt i=0; i < scanLength; i += aPixelsPerByte)
00137                 {
00138                 // Pack each byte with 'aPixelsPerByte' index values
00139                 TUint8 pixels = 0;
00140                 for (TInt j=0; j < aPixelsPerByte; j++)
00141                         {
00142                         pixels <<= aShiftValue;
00143                         TRgb rgb;
00144                         aSource->GetPixel(rgb, pos);
00145                         pixels |= TUint8(iPalette->NearestIndex(rgb));
00146                         pos.iX++;
00147                         }
00148                 *aDataPtr = pixels;
00149                 aDataPtr++;
00150                 }
00151         }
00152 
00153 //
00154 // These classes specialise the PNG writer to write
00155 // scanlines with different bitmap depths/colour types
00156 //
00157 
00158 //
00159 // CBitDepth1Encoder
00160 //
00161 
00162 void CBitDepth1Encoder::DoConstructL()
00163         {
00164         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00165                 {
00166                 // Setup palette
00167                 iPalette = CPalette::NewL(2);
00168                 iPalette->SetEntry(0, KRgbBlack);
00169                 iPalette->SetEntry(1, KRgbWhite);
00170                 iInfo.iPalettePresent = ETrue;
00171                 }
00172         }
00173 
00174 TInt CBitDepth1Encoder::ScanlineBufferSize(TInt aPixelLength)
00175         {
00176         // 8 pixels per byte
00177         return ((aPixelLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte) + KPngScanlineFilterTypeLength;
00178         }
00179 
00180 void CBitDepth1Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
00181                                                                  TUint8* aDataPtr, const TUint8* aDataPtrLimit)
00182         {
00183         // Filter method
00184         PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
00185         aDataPtr++;
00186 
00187         // Pixel data
00188         const TInt scanLength = iInfo.iSize.iWidth;
00189         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00190                 {
00191                 // Write palette indexes
00192                 EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth1PixelsPerByte, KPngDepth1ShiftValue);
00193                 }
00194         else
00195                 {
00196                 // Write RGB data
00197                 TInt dataLength = (scanLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte;
00198                 TPtr8 dataPtr(aDataPtr, dataLength, dataLength);
00199 
00200                 aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray2);
00201 
00202                 // Reverse the order of the bits
00203                 while (aDataPtr < aDataPtrLimit)
00204                         {
00205                         aDataPtr[0] = ReverseBits(aDataPtr[0]);
00206                         aDataPtr++;
00207                         }
00208                 }
00209         }
00210 
00211 //
00212 // CBitDepth2Encoder
00213 //
00214 
00215 void CBitDepth2Encoder::DoConstructL()
00216         {
00217         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00218                 {
00219                 // Setup palette entries
00220                 iPalette = CPalette::NewL(4);
00221                 iPalette->SetEntry(0, KRgbBlack);
00222                 iPalette->SetEntry(1, KRgbDarkGray);
00223                 iPalette->SetEntry(2, KRgbGray);
00224                 iPalette->SetEntry(3, KRgbWhite);
00225                 iInfo.iPalettePresent = ETrue;
00226                 }
00227         }
00228 
00229 TInt CBitDepth2Encoder::ScanlineBufferSize(TInt aPixelLength)
00230         {
00231         return ((aPixelLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte) + KPngScanlineFilterTypeLength;
00232         }
00233 
00234 void CBitDepth2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
00235                                                                  TUint8* aDataPtr, const TUint8* aDataPtrLimit)
00236         {
00237         // Filter method
00238         PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
00239         aDataPtr++;
00240 
00241         // Pixel data
00242         const TInt scanLength = iInfo.iSize.iWidth;
00243         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00244                 {
00245                 // Write palette indexes
00246                 EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth2PixelsPerByte, KPngDepth2ShiftValue);
00247                 }
00248         else
00249                 {
00250                 // RGB values
00251                 TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte);
00252                 aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray4);
00253 
00254                 // Reverse the order of the bits
00255                 while (aDataPtr < aDataPtrLimit)
00256                         {
00257                         TUint8 value = aDataPtr[0];
00258                         TUint8 reverse = 0;
00259                         for (TInt i=0; i < KPngDepth2PixelsPerByte; i++)
00260                                 {
00261                                 reverse <<= 2;  // advance the bits for the reverse value
00262                                 reverse |= value & 0x3; // mask off the 2 bits, then OR with existing reverse value
00263                                 value >>= 2;    // advance the bits for the actual value
00264                                 }
00265                         aDataPtr[0] = reverse;
00266                         aDataPtr++;
00267                         }
00268                 }
00269         }
00270 
00271 //
00272 // CBitDepth4Encoder
00273 //
00274 
00275 void CBitDepth4Encoder::DoConstructL()
00276         {
00277         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00278                 {
00279                 // Calculate palette for image
00280                 iPalette = CPalette::NewDefaultL(EColor16);
00281                 iInfo.iPalettePresent = ETrue;
00282                 }
00283         }
00284 
00285 TInt CBitDepth4Encoder::ScanlineBufferSize(TInt aPixelLength)
00286         {
00287         return ((aPixelLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte) + KPngScanlineFilterTypeLength;
00288         }
00289 
00290 void CBitDepth4Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
00291                                                                  TUint8* aDataPtr, const TUint8* aDataPtrLimit)
00292         {
00293         // Filter method
00294         PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
00295         aDataPtr++;
00296 
00297         // Pixel data
00298         const TInt scanLength = iInfo.iSize.iWidth;
00299         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00300                 {
00301                 // Write palette indexes
00302                 EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth4PixelsPerByte, KPngDepth4ShiftValue);
00303                 }
00304         else
00305                 {
00306                 TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte);
00307                 aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength,
00308                         (iInfo.iColorType == TPngImageInformation::EDirectColor) ? EColor16 : EGray16);
00309 
00310                 // Swap order of the low/high bits
00311                 while (aDataPtr < aDataPtrLimit)
00312                         {
00313                         TUint value = aDataPtr[0];
00314                         TUint low = value << KPngDepth4ShiftValue;
00315                         TUint high = value >> KPngDepth4ShiftValue;
00316                         aDataPtr[0] = TUint8(low | high);
00317                         aDataPtr++;
00318                         }
00319                 }
00320         }
00321 
00322 //
00323 // CBitDepth8ColorType2Encoder
00324 //
00325 
00326 TInt CBitDepth8ColorType2Encoder::ScanlineBufferSize(TInt aPixelLength)
00327         {
00328         return (aPixelLength * KPngDepth8RgbBytesPerPixel) + KPngScanlineFilterTypeLength;
00329         }
00330 
00331 void CBitDepth8ColorType2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
00332                                                                                    TUint8* aDataPtr, const TUint8* aDataPtrLimit)
00333         {
00334         // Filter method
00335         PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
00336         aDataPtr++;
00337 
00338         // Pixel data
00339         TPtr8 dataPtr(aDataPtr, iInfo.iSize.iWidth * KPngDepth8RgbBytesPerPixel);
00340         aSource->GetScanLine(dataPtr, TPoint(0, aScanline), iInfo.iSize.iWidth, EColor16M);
00341 
00342         while (aDataPtr < aDataPtrLimit)
00343                 {
00344                 // Swap the red and blue components of the image data
00345                 TUint8 temp = aDataPtr[0];      // temp = Red
00346                 aDataPtr[0] = aDataPtr[2];      // Red = Blue
00347                 aDataPtr[2] = temp;                     // Blue = temp
00348                 aDataPtr += KPngDepth8RgbBytesPerPixel;
00349                 }
00350         }
00351 
00352 //
00353 // CBitDepth8Encoder
00354 //
00355 
00356 void CBitDepth8Encoder::DoConstructL()
00357         {
00358         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00359                 {
00360                 // Calculate palette for image
00361                 iPalette = CPalette::NewDefaultL(EColor256);
00362                 iInfo.iPalettePresent = ETrue;
00363                 }
00364         }
00365 
00366 TInt CBitDepth8Encoder::ScanlineBufferSize(TInt aPixelLength)
00367         {
00368         return aPixelLength + KPngScanlineFilterTypeLength;
00369         }
00370 
00371 void CBitDepth8Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
00372                                                                  TUint8* aDataPtr, const TUint8* /*aDataPtrLimit*/)
00373         {
00374         // Filter method
00375         PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
00376         aDataPtr++;
00377 
00378         const TInt scanLength = iInfo.iSize.iWidth;
00379         if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
00380                 {
00381                 // Write palette indexes
00382                 EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth8PixelsPerByte, KPngDepth8ShiftValue);
00383                 }
00384         else
00385                 {
00386                 // Pixel data
00387                 TPtr8 dataPtr(aDataPtr, scanLength);
00388                 aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray256);
00389                 }
00390         }

Generated by  doxygen 1.6.2