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

Generated by  doxygen 1.6.2