mmplugins/imagingplugins/codecs/PNGCodec/PngScanlineEncoder.cpp
branchRCL_3
changeset 50 948c7f65f6d4
parent 0 40261b775718
equal deleted inserted replaced
49:735348f59235 50:948c7f65f6d4
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "PngScanlineEncoder.h"
       
    17 
       
    18 // CPngWriteSubCodec
       
    19 CPngWriteSubCodec* CPngWriteSubCodec::NewL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
       
    20 	{
       
    21 	CPngWriteSubCodec* self = NULL;
       
    22 
       
    23 	switch (aInfo.iBitDepth)
       
    24 		{
       
    25 		case 1:
       
    26 			self = new(ELeave) CBitDepth1Encoder;
       
    27 			break;
       
    28 		case 2:
       
    29 			self = new(ELeave) CBitDepth2Encoder;
       
    30 			break;
       
    31 		case 4:
       
    32 			self = new(ELeave) CBitDepth4Encoder;
       
    33 			break;
       
    34 		case 8:
       
    35 			switch (aInfo.iColorType)
       
    36 				{
       
    37 				case TPngImageInformation::EGrayscale:
       
    38 				case TPngImageInformation::EIndexedColor:
       
    39 					self = new(ELeave) CBitDepth8Encoder;
       
    40 					break;
       
    41 				case TPngImageInformation::EDirectColor:
       
    42 					self = new(ELeave) CBitDepth8ColorType2Encoder;
       
    43 					break;
       
    44 				default:
       
    45 					User::Leave(KErrNotSupported);
       
    46 					break;
       
    47 				}
       
    48 			break;
       
    49 		default:
       
    50 			User::Leave(KErrNotSupported);
       
    51 			break;
       
    52 		}
       
    53 	ASSERT(self);
       
    54 	CleanupStack::PushL(self);
       
    55 	self->ConstructL(aInfo, aSource);
       
    56 	CleanupStack::Pop(self);
       
    57 	return self;
       
    58 	}
       
    59 
       
    60 CPngWriteSubCodec::CPngWriteSubCodec()
       
    61 	: iScanlineDes(NULL, 0)
       
    62 	{
       
    63 	}
       
    64 
       
    65 CPngWriteSubCodec::~CPngWriteSubCodec()
       
    66 	{
       
    67 	delete iScanlineBuffer;
       
    68 	delete iPalette;
       
    69 	}
       
    70 
       
    71 void CPngWriteSubCodec::ConstructL(const TPngImageInformation& aInfo, const CFbsBitmap* aSource)
       
    72 	{
       
    73 	iInfo = aInfo;
       
    74 	iSource = aSource;
       
    75 	iScanlineBufferSize = ScanlineBufferSize(iInfo.iSize.iWidth);
       
    76 	iScanlineBuffer = HBufC8::NewMaxL(iScanlineBufferSize);
       
    77 	iScanlineDes.Set(&(iScanlineBuffer->Des())[0], iScanlineBufferSize, iScanlineBufferSize);
       
    78 
       
    79 	// Init stuff specific to derived class
       
    80 	DoConstructL();
       
    81 	}
       
    82 
       
    83 void CPngWriteSubCodec::DoConstructL()
       
    84 	{
       
    85 	}
       
    86 
       
    87 TDes8& CPngWriteSubCodec::Buffer()
       
    88 	{
       
    89 	iScanlineDes.FillZ();
       
    90 	return iScanlineDes;
       
    91 	}
       
    92 
       
    93 TDes8& CPngWriteSubCodec::EncodeL(const TInt aScanline)
       
    94 	{
       
    95 	if (aScanline < iInfo.iSize.iHeight)
       
    96 		{
       
    97 		TUint8* dataPtr = const_cast<TUint8*>(iScanlineDes.Ptr());
       
    98 		const TUint8* dataPtrLimit = dataPtr + iScanlineBufferSize;
       
    99 
       
   100 		DoEncode(iSource, aScanline, dataPtr, dataPtrLimit);
       
   101 		}
       
   102 	else
       
   103 		{
       
   104 		iScanlineDes.Set(NULL, 0, 0);
       
   105 		}
       
   106 	return iScanlineDes;
       
   107 	}
       
   108 
       
   109 TUint8 CPngWriteSubCodec::ReverseBits(const TUint8 aValue) const
       
   110 	{
       
   111 	TUint value = aValue;
       
   112 	TUint reverseVal = 0;
       
   113 	for (TInt i = 0; i < 8; i++)
       
   114 		{
       
   115 		reverseVal <<= 1;
       
   116 		reverseVal |= value & 1;
       
   117 		value >>= 1;
       
   118 		}
       
   119 	return TUint8(reverseVal);
       
   120 	}
       
   121 
       
   122 void CPngWriteSubCodec::EncodePalettedScanline(TUint8* aDataPtr, const CFbsBitmap* aSource, const TInt aScanline,
       
   123 											   const TInt aPixelsPerByte, const TInt aShiftValue)
       
   124 	{
       
   125 	// Encode a single scanline with indexes into the current palette
       
   126 	ASSERT(iInfo.iPalettePresent);
       
   127 	TPoint pos(0, aScanline);
       
   128 	const TInt scanLength = iInfo.iSize.iWidth;
       
   129 	for (TInt i=0; i < scanLength; i += aPixelsPerByte)
       
   130 		{
       
   131 		// Pack each byte with 'aPixelsPerByte' index values
       
   132 		TUint8 pixels = 0;
       
   133 		for (TInt j=0; j < aPixelsPerByte; j++)
       
   134 			{
       
   135 			pixels <<= aShiftValue;
       
   136 			TRgb rgb;
       
   137 			aSource->GetPixel(rgb, pos);
       
   138 			pixels |= TUint8(iPalette->NearestIndex(rgb));
       
   139 			pos.iX++;
       
   140 			}
       
   141 		*aDataPtr = pixels;
       
   142 		aDataPtr++;
       
   143 		}
       
   144 	}
       
   145 
       
   146 // CBitDepth1Encoder
       
   147 void CBitDepth1Encoder::DoConstructL()
       
   148 	{
       
   149 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   150 		{
       
   151 		// Setup palette
       
   152 		iPalette = CPalette::NewL(2);
       
   153 		iPalette->SetEntry(0, KRgbBlack);
       
   154 		iPalette->SetEntry(1, KRgbWhite);
       
   155 		iInfo.iPalettePresent = ETrue;
       
   156 		}
       
   157 	}
       
   158 
       
   159 TInt CBitDepth1Encoder::ScanlineBufferSize(TInt aPixelLength)
       
   160 	{
       
   161 	// 8 pixels per byte
       
   162 	return ((aPixelLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte) + KPngScanlineFilterTypeLength;
       
   163 	}
       
   164 
       
   165 void CBitDepth1Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
       
   166 								 TUint8* aDataPtr, const TUint8* aDataPtrLimit)
       
   167 	{
       
   168 	// Filter method
       
   169 	PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
       
   170 	aDataPtr++;
       
   171 
       
   172 	// Pixel data
       
   173 	const TInt scanLength = iInfo.iSize.iWidth;
       
   174 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   175 		{
       
   176 		// Write palette indexes
       
   177 		EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth1PixelsPerByte, KPngDepth1ShiftValue);
       
   178 		}
       
   179 	else
       
   180 		{
       
   181 		// Write RGB data
       
   182 		TInt dataLength = (scanLength + KPngDepth1RoundUpValue) / KPngDepth1PixelsPerByte;
       
   183 		TPtr8 dataPtr(aDataPtr, dataLength, dataLength);
       
   184 
       
   185 		aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray2);
       
   186 
       
   187 		// Reverse the order of the bits
       
   188 		while (aDataPtr < aDataPtrLimit)
       
   189 			{
       
   190 			aDataPtr[0] = ReverseBits(aDataPtr[0]);
       
   191 			aDataPtr++;
       
   192 			}
       
   193 		}
       
   194 	}
       
   195 
       
   196 // CBitDepth2Encoder
       
   197 void CBitDepth2Encoder::DoConstructL()
       
   198 	{
       
   199 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   200 		{
       
   201 		// Setup palette entries
       
   202 		iPalette = CPalette::NewL(4);
       
   203 		iPalette->SetEntry(0, KRgbBlack);
       
   204 		iPalette->SetEntry(1, KRgbDarkGray);
       
   205 		iPalette->SetEntry(2, KRgbGray);
       
   206 		iPalette->SetEntry(3, KRgbWhite);
       
   207 		iInfo.iPalettePresent = ETrue;
       
   208 		}
       
   209 	}
       
   210 
       
   211 TInt CBitDepth2Encoder::ScanlineBufferSize(TInt aPixelLength)
       
   212 	{
       
   213 	return ((aPixelLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte) + KPngScanlineFilterTypeLength;
       
   214 	}
       
   215 
       
   216 void CBitDepth2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
       
   217 								 TUint8* aDataPtr, const TUint8* aDataPtrLimit)
       
   218 	{
       
   219 	// Filter method
       
   220 	PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
       
   221 	aDataPtr++;
       
   222 
       
   223 	// Pixel data
       
   224 	const TInt scanLength = iInfo.iSize.iWidth;
       
   225 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   226 		{
       
   227 		// Write palette indexes
       
   228 		EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth2PixelsPerByte, KPngDepth2ShiftValue);
       
   229 		}
       
   230 	else
       
   231 		{
       
   232 		// RGB values
       
   233 		TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth2RoundUpValue) / KPngDepth2PixelsPerByte);
       
   234 		aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray4);
       
   235 
       
   236 		// Reverse the order of the bits
       
   237 		while (aDataPtr < aDataPtrLimit)
       
   238 			{
       
   239 			TUint8 value = aDataPtr[0];
       
   240 			TUint8 reverse = 0;
       
   241 			for (TInt i=0; i < KPngDepth2PixelsPerByte; i++)
       
   242 				{
       
   243 				reverse <<= 2;	// advance the bits for the reverse value
       
   244 				reverse |= value & 0x3;	// mask off the 2 bits, then OR with existing reverse value
       
   245 				value >>= 2;	// advance the bits for the actual value
       
   246 				}
       
   247 			aDataPtr[0] = reverse;
       
   248 			aDataPtr++;
       
   249 			}
       
   250 		}
       
   251 	}
       
   252 
       
   253 // CBitDepth4Encoder
       
   254 void CBitDepth4Encoder::DoConstructL()
       
   255 	{
       
   256 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   257 		{
       
   258 		// Calculate palette for image
       
   259 		iPalette = CPalette::NewDefaultL(EColor16);
       
   260 		iInfo.iPalettePresent = ETrue;
       
   261 		}
       
   262 	}
       
   263 
       
   264 TInt CBitDepth4Encoder::ScanlineBufferSize(TInt aPixelLength)
       
   265 	{
       
   266 	return ((aPixelLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte) + KPngScanlineFilterTypeLength;
       
   267 	}
       
   268 
       
   269 void CBitDepth4Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
       
   270 								 TUint8* aDataPtr, const TUint8* aDataPtrLimit)
       
   271 	{
       
   272 	// Filter method
       
   273 	PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
       
   274 	aDataPtr++;
       
   275 
       
   276 	// Pixel data
       
   277 	const TInt scanLength = iInfo.iSize.iWidth;
       
   278 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   279 		{
       
   280 		// Write palette indexes
       
   281 		EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth4PixelsPerByte, KPngDepth4ShiftValue);
       
   282 		}
       
   283 	else
       
   284 		{
       
   285 		TPtr8 dataPtr(aDataPtr, (scanLength + KPngDepth4RoundUpValue) / KPngDepth4PixelsPerByte);
       
   286 		aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength,
       
   287 			(iInfo.iColorType == TPngImageInformation::EDirectColor) ? EColor16 : EGray16);
       
   288 
       
   289 		// Swap order of the low/high bits
       
   290 		while (aDataPtr < aDataPtrLimit)
       
   291 			{
       
   292 			TUint value = aDataPtr[0];
       
   293 			TUint low = value << KPngDepth4ShiftValue;
       
   294 			TUint high = value >> KPngDepth4ShiftValue;
       
   295 			aDataPtr[0] = TUint8(low | high);
       
   296 			aDataPtr++;
       
   297 			}
       
   298 		}
       
   299 	}
       
   300 
       
   301 // CBitDepth8ColorType2Encoder
       
   302 TInt CBitDepth8ColorType2Encoder::ScanlineBufferSize(TInt aPixelLength)
       
   303 	{
       
   304 	return (aPixelLength * KPngDepth8RgbBytesPerPixel) + KPngScanlineFilterTypeLength;
       
   305 	}
       
   306 
       
   307 void CBitDepth8ColorType2Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
       
   308 										   TUint8* aDataPtr, const TUint8* aDataPtrLimit)
       
   309 	{
       
   310 	// Filter method
       
   311 	PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
       
   312 	aDataPtr++;
       
   313 
       
   314 	// Pixel data
       
   315 	TPtr8 dataPtr(aDataPtr, iInfo.iSize.iWidth * KPngDepth8RgbBytesPerPixel);
       
   316 	aSource->GetScanLine(dataPtr, TPoint(0, aScanline), iInfo.iSize.iWidth, EColor16M);
       
   317 
       
   318 	while (aDataPtr < aDataPtrLimit)
       
   319 		{
       
   320 		// Swap the red and blue components of the image data
       
   321 		TUint8 temp = aDataPtr[0];	// temp = Red
       
   322 		aDataPtr[0] = aDataPtr[2];	// Red = Blue
       
   323 		aDataPtr[2] = temp;			// Blue = temp
       
   324 		aDataPtr += KPngDepth8RgbBytesPerPixel;
       
   325 		}
       
   326 	}
       
   327 
       
   328 // CBitDepth8Encoder
       
   329 void CBitDepth8Encoder::DoConstructL()
       
   330 	{
       
   331 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   332 		{
       
   333 		// Calculate palette for image
       
   334 		iPalette = CPalette::NewDefaultL(EColor256);
       
   335 		iInfo.iPalettePresent = ETrue;
       
   336 		}
       
   337 	}
       
   338 
       
   339 TInt CBitDepth8Encoder::ScanlineBufferSize(TInt aPixelLength)
       
   340 	{
       
   341 	return aPixelLength + KPngScanlineFilterTypeLength;
       
   342 	}
       
   343 
       
   344 void CBitDepth8Encoder::DoEncode(const CFbsBitmap* aSource, const TInt aScanline,
       
   345 								 TUint8* aDataPtr, const TUint8* /*aDataPtrLimit*/)
       
   346 	{
       
   347 	// Filter method
       
   348 	PtrWriteUtil::WriteInt8(aDataPtr, iInfo.iFilterMethod);
       
   349 	aDataPtr++;
       
   350 
       
   351 	const TInt scanLength = iInfo.iSize.iWidth;
       
   352 	if (iInfo.iColorType == TPngImageInformation::EIndexedColor)
       
   353 		{
       
   354 		// Write palette indexes
       
   355 		EncodePalettedScanline(aDataPtr, aSource, aScanline, KPngDepth8PixelsPerByte, KPngDepth8ShiftValue);
       
   356 		}
       
   357 	else
       
   358 		{
       
   359 		// Pixel data
       
   360 		TPtr8 dataPtr(aDataPtr, scanLength);
       
   361 		aSource->GetScanLine(dataPtr, TPoint(0, aScanline), scanLength, EGray256);
       
   362 		}
       
   363 	}