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 }
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.