mmplugins/imagingplugins/codecs/BMPCodec/BMPConvert.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/BMPCodec/BMPConvert.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,654 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <gdi.h>
+#include <barsc.h>
+#include <barsread.h>
+#include <bautils.h>
+#include <imageconversion.h>
+#include "ImageClientMain.h"
+#include "ImageUtils.h"
+#include <101F45AE_extra.rsg>
+#include "BMPConvert.h"
+#include "icl/ICL_UIDS.hrh"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <icl/icl_uids_const.hrh>
+#include <icl/icl_uids_def.hrh>
+#include <icl/imagecodecdef.h>
+#endif
+
+_LIT(KBMPPanicCategory, "BMPConvertPlugin");
+
+// Global panic function
+GLDEF_C void Panic(TIclPanic aError)
+	{
+	User::Panic(KBMPPanicCategory, aError);
+	}
+
+void WriteTUint32(TUint8*& aPtr, TUint32 aValue)
+	{
+	Mem::Copy(aPtr, &aValue, 4);
+	aPtr += 4;
+	}
+
+CBmpDecoder* CBmpDecoder::NewL()
+	{
+	return new(ELeave) CBmpDecoder;
+	}
+
+void CBmpDecoder::ImageType(TInt aFrameNumber, TUid& aImageType, TUid& aImageSubType) const
+	{
+	__ASSERT_ALWAYS(aFrameNumber == 0, Panic(EFrameNumberOutOfRange));
+	aImageType = KImageTypeBMPUid;
+	aImageSubType = KNullUid;
+	}
+
+CBmpDecoder::CBmpDecoder()
+	{
+	}
+
+CBmpDecoder::~CBmpDecoder()
+	{
+	Cleanup();
+	}
+
+void CBmpDecoder::ScanDataL()
+	{
+	ReadFormatL();
+
+	ASSERT(ImageReadCodec() == NULL);
+
+	TSize size = iBitmapHeader.iSizeInPixels;
+	TRgb* const palette = &(iPalette[0]);
+
+	CBmpReadCodec* imageReadCodec = NULL;
+
+
+	const TFrameInfo& imageInfo = ImageInfo();
+	switch(imageInfo.iFrameDisplayMode)
+		{
+	case EGray2:
+		imageReadCodec = CBmp1BppReadCodec::NewL(size, palette);
+		break;
+	case EColor16:
+		if (iBitmapHeader.iCompression == TBmpHeader::EFourBppRLE)
+			imageReadCodec = CBmpRLE4ReadCodec::NewL(size, palette);
+		else
+			imageReadCodec = CBmpNoComp4BppReadCodec::NewL(size, palette);
+		break;
+	case EColor256:
+		if (iBitmapHeader.iCompression == TBmpHeader::EEightBppRLE)
+			imageReadCodec = CBmpRLE8ReadCodec::NewL(size, palette);
+		else
+			imageReadCodec = CBmpNoComp8BppReadCodec::NewL(size, palette);
+		break;
+		
+	case EColor64K:
+		if (iBitmapHeader.iCompression == TBmpHeader::EBitFields)
+			{
+			imageReadCodec = CBmpBiRgbReadCodec::NewL(size, 2, palette);
+			}
+		else if (iBitmapHeader.iCompression == TBmpHeader::ENone)
+			{
+			imageReadCodec = CBmpBiRgbReadCodec::NewL(size, 2, NULL);
+			}
+		break;
+		
+	case EColor16M:
+		if(iBitmapHeader.iCompression == TBmpHeader::ENone)
+			{
+			imageReadCodec = CBmp24BppReadCodec::NewL(size);
+			}
+		break;
+
+	case EColor16MU:
+		if (iBitmapHeader.iCompression == TBmpHeader::EBitFields)
+			{
+			imageReadCodec = CBmpBiRgbReadCodec::NewL(size, 4, palette);
+			}
+		else if (iBitmapHeader.iCompression == TBmpHeader::ENone)
+			{
+			imageReadCodec = CBmp32BppReadCodec::NewL(size);
+			}
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		break;
+		}
+	
+	if (!imageReadCodec)
+		{
+		User::Leave(KErrNotSupported);
+		}
+
+	SetImageReadCodec(imageReadCodec);
+
+	ReadFrameHeadersL();
+	}
+
+void CBmpDecoder::ReadFormatL()
+	{
+	TPtrC8 bufferDes;
+
+	ReadDataL(0, bufferDes, (KBmpFileHeaderSize + KBmpInfoHeaderV1Size));
+
+	// Validate the header.
+	if (bufferDes.Length() < (KBmpFileHeaderSize + KBmpInfoHeaderV1Size))
+		User::Leave(KErrUnderflow);
+	
+	const TUint8* ptr = &bufferDes[0];
+	TUint16 sig = *ptr++;
+	sig |= (*ptr++ << 8);
+	if (sig != KBmpFileSignature)
+		User::Leave(KErrCorrupt);
+
+	// Read data length from header
+	TInt dataLength = PtrReadUtil::ReadUint32(ptr);
+	// If the data length is negative then return KErrCorrupt. Strictly speaking, 
+	// the data length is a 4-byte unsigned quantity (i.e. a TUint not a TInt) and 
+	// we should treat it as such, but this would involve an API change to SetDataLength()
+	// and changing iDataLength in CImageDecoderPriv.from a TInt to a TUint.
+	// Anyway it's reasonable to assume that if the length is > 0x7FFFFFFF, then
+	// the file is corrupt.
+	if (dataLength < (KBmpFileHeaderSize + KBmpInfoHeaderV1Size))
+		User::Leave(KErrCorrupt);
+
+	ptr += 4; // Increment pointer by 4 bytes
+
+	ptr += 4; // Skip bfReserved1 & bfReserved2
+
+	// Read image data offset from header
+	TInt imageDataOffset = PtrReadUtil::ReadUint32(ptr);
+	ptr += 4; // Increment pointer by 4 bytes
+
+	if(imageDataOffset < 0 || imageDataOffset > dataLength)
+		User::Leave(KErrCorrupt);
+	
+	dataLength -= imageDataOffset;
+	SetDataLength(dataLength);
+
+	TUint32 infoHeaderSize = PtrReadUtil::ReadUint32(ptr);
+	ptr += 4; // Skip biSize
+	if ((infoHeaderSize < KBmpInfoHeaderV1Size) || (infoHeaderSize > KBmpInfoMaxHeaderV2Size))
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	// Read image dimensions in pixels from header
+	if (infoHeaderSize == KBmpInfoHeaderV1Size)
+		{
+		iBitmapHeader.iSizeInPixels.iWidth = PtrReadUtil::ReadUint16(ptr);
+		ptr += 2;
+
+		iBitmapHeader.iSizeInPixels.iHeight = PtrReadUtil::ReadUint16(ptr);
+		ptr += 2;
+		}
+	else
+		{
+		iBitmapHeader.iSizeInPixels.iWidth = PtrReadUtil::ReadUint32(ptr);
+		ptr += 4; // Increment pointer by 4 bytes
+
+		iBitmapHeader.iSizeInPixels.iHeight = PtrReadUtil::ReadUint32(ptr);
+		ptr += 4; // Increment pointer by 4 bytes
+		}
+
+	// Check for valid image size
+	if (iBitmapHeader.iSizeInPixels.iWidth <= 0 || iBitmapHeader.iSizeInPixels.iHeight == 0)
+		User::Leave(KErrCorrupt);
+	//check for unsupported negative height
+	if(iBitmapHeader.iSizeInPixels.iHeight < 0)
+		{
+		User::Leave(KErrNotSupported);
+		}
+
+	if (infoHeaderSize > KBmpInfoHeaderV1Size)
+		{
+		// read the extra data associated with v2.x headers
+		ReadDataL((KBmpFileHeaderSize + KBmpInfoHeaderV1Size), bufferDes, (infoHeaderSize - KBmpInfoHeaderV1Size));
+		if (bufferDes.Length() < (infoHeaderSize - KBmpInfoHeaderV1Size))
+			{
+			User::Leave(KErrUnderflow);
+			}
+		ptr = &bufferDes[0];
+		}
+	
+	ptr += 2; // Skip biPlanes
+
+	// Read bits per pixel from header
+	iBitmapHeader.iBitCount = PtrReadUtil::ReadUint16(ptr);
+	ptr += 2; // Increment pointer by 2 bytes
+
+	// Check for valid bit count
+	if (iBitmapHeader.iBitCount < 1 || iBitmapHeader.iBitCount > 32)
+		User::Leave(KErrCorrupt);
+	TFrameInfo imageInfo;
+	imageInfo = ImageInfo();
+	imageInfo.iFrameSizeInTwips.iWidth = 0;
+	imageInfo.iFrameSizeInTwips.iHeight = 0;
+	TInt coloursUsed = 0;
+
+	if (infoHeaderSize == KBmpInfoHeaderV1Size)
+		{
+		// number of colours used equals number of bytes between the bitmap header and the bitmap data
+		// divided by the size of a single palette element
+		coloursUsed = (imageDataOffset - KBmpFileHeaderSize - KBmpInfoHeaderV1Size) / KBmpSizeofPaletteEntryV1;
+		}
+	else
+		{
+		// Read compresion type from header
+		TInt compression = PtrReadUtil::ReadUint32(ptr);
+		ptr += 4; // Increment pointer by 4 bytes
+		iBitmapHeader.iCompression = STATIC_CAST(TBmpHeader::TCompression, compression);
+
+		// Check for valid compression type
+		if (iBitmapHeader.iCompression != TBmpHeader::ENone &&
+			iBitmapHeader.iCompression != TBmpHeader::EEightBppRLE &&
+			iBitmapHeader.iCompression != TBmpHeader::EFourBppRLE &&
+			iBitmapHeader.iCompression != TBmpHeader::EBitFields)
+			User::Leave(KErrCorrupt);
+
+		TBmpCompression* compressionImageData = new(ELeave) TBmpCompression;
+		compressionImageData->iCompression = STATIC_CAST(TBmpCompression::TCompression, compression);
+		CleanupStack::PushL(compressionImageData);
+	
+		User::LeaveIfError(AppendImageData(compressionImageData));
+		CleanupStack::Pop();
+
+		//do not use image data size since it cannot be trusted
+		ptr += 4; // Skip biSizeImage
+
+		// Read Horizontal and vertical resolution
+		TInt xPelsPerMeter = PtrReadUtil::ReadInt32(ptr);
+		ptr += 4; // Increment pointer by 4 bytes
+	
+		TInt yPelsPerMeter = PtrReadUtil::ReadInt32(ptr);
+		ptr += 4; // Increment pointer by 4 bytes
+
+		TZoomFactor tempImageDevice;
+	
+		if (xPelsPerMeter > 0)
+			{
+			TInt64 twips = TInt64(iBitmapHeader.iSizeInPixels.iWidth) / TInt64(xPelsPerMeter);
+			twips *= 7200000;
+			twips /= 127;
+			imageInfo.iFrameSizeInTwips.iWidth = I64LOW(twips);
+			}
+	
+		if (yPelsPerMeter > 0)
+			{
+			TInt64 twips = TInt64(iBitmapHeader.iSizeInPixels.iHeight) / TInt64(yPelsPerMeter);
+			twips *= 7200000;
+			twips /= 127;
+			imageInfo.iFrameSizeInTwips.iHeight = I64LOW(twips);
+			}
+	
+		// Read colour count
+		coloursUsed = PtrReadUtil::ReadUint32(ptr); // read biClrUsed
+		ptr += 4; // Increment pointer by 4 bytes
+		}
+	if (coloursUsed == 0)
+		{
+		if (iBitmapHeader.iBitCount == 1)
+			{
+			iBitmapHeader.iPaletteEntries = 2;
+			}
+		else if (iBitmapHeader.iBitCount == 4)
+			{
+			iBitmapHeader.iPaletteEntries = 16;
+			}
+		else if (iBitmapHeader.iBitCount == 8)
+			{
+			iBitmapHeader.iPaletteEntries = 256;
+			}
+		else
+			{
+			iBitmapHeader.iPaletteEntries = 0; // 16bpp/24bpp/32bpp
+			}
+		}
+	else
+		{
+		if (iBitmapHeader.iBitCount == 24)
+			{
+			iBitmapHeader.iPaletteEntries = 0; // biClrUsed ignored for 24bpp
+			}
+		else
+			{
+			iBitmapHeader.iPaletteEntries = coloursUsed;
+			}
+		}
+		
+
+	// Check for valid palette entries.
+	if (iBitmapHeader.iPaletteEntries < 0 || iBitmapHeader.iPaletteEntries > KBmpMaxPaletteEntries)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	imageInfo.iFrameCoordsInPixels.SetRect(TPoint(0, 0), iBitmapHeader.iSizeInPixels);
+	imageInfo.iOverallSizeInPixels = iBitmapHeader.iSizeInPixels;
+	imageInfo.iBitsPerPixel = iBitmapHeader.iBitCount;
+	imageInfo.iDelay = 0;
+	imageInfo.iFlags = TFrameInfo::ECanDither;
+
+
+	if (imageInfo.iBitsPerPixel <= 0)
+		User::Leave(KErrCorrupt);
+
+	if (imageInfo.iBitsPerPixel == 1)
+		{
+		imageInfo.iFrameDisplayMode = EGray2;
+		}
+	else
+		{
+		imageInfo.iFlags |= TFrameInfo::EColor;
+		if (imageInfo.iBitsPerPixel == 4)
+			{
+			imageInfo.iFrameDisplayMode = EColor16;
+			}
+		else if (imageInfo.iBitsPerPixel == 8)
+			{
+			imageInfo.iFrameDisplayMode = EColor256;
+			}
+		else if (imageInfo.iBitsPerPixel == 16)
+			{
+			imageInfo.iFrameDisplayMode = EColor64K;		
+			}
+		else if (imageInfo.iBitsPerPixel == 24)
+			{
+			imageInfo.iFrameDisplayMode = EColor16M;
+			}
+		else if (imageInfo.iBitsPerPixel == 32)
+			{
+			imageInfo.iFrameDisplayMode = EColor16MU;
+			}
+		else
+			{
+			User::Leave(KErrCorrupt);
+			}
+		}
+		
+	// in case of EBitFields image type we have to read the channel masks		
+	// EBitFields is not supported in V1
+	if ((infoHeaderSize > KBmpInfoHeaderV1Size) && (iBitmapHeader.iCompression == TBmpHeader::EBitFields))
+		{
+		TInt numMaskBytes = imageDataOffset - (KBmpFileHeaderSize + infoHeaderSize);
+		
+		if ((numMaskBytes <= 0) && (infoHeaderSize != KBmpInfoDefaultHeaderV2Size))
+			{
+			// infoHeaderSize is possibly incorrect - correct to standard size
+			infoHeaderSize = KBmpInfoDefaultHeaderV2Size;
+			numMaskBytes = imageDataOffset - (KBmpFileHeaderSize + infoHeaderSize);
+			}
+			
+		if (iBitmapHeader.iPaletteEntries || numMaskBytes <= 0 || 
+				(numMaskBytes % KBmpSizeofPaletteEntryV2) != 0)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		iBitmapHeader.iPaletteEntries = numMaskBytes / KBmpSizeofPaletteEntryV2;
+		}
+		
+	if (iBitmapHeader.iPaletteEntries > KBmpMaxPaletteEntries)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	
+	if (iBitmapHeader.iPaletteEntries > 0)
+		{
+		// Read the palette.
+		TInt paletteLength;
+		if (infoHeaderSize == KBmpInfoHeaderV1Size)
+			{
+			paletteLength = iBitmapHeader.iPaletteEntries * KBmpSizeofPaletteEntryV1;
+			}
+		else
+			{
+			paletteLength = iBitmapHeader.iPaletteEntries * KBmpSizeofPaletteEntryV2;
+			}
+
+		ReadDataL((KBmpFileHeaderSize + infoHeaderSize), bufferDes, paletteLength);
+
+		if (bufferDes.Length() < paletteLength)
+			User::Leave(KErrUnderflow);
+
+		const TUint8* ptr = &bufferDes[0];
+		for (TInt count = 0; count < iBitmapHeader.iPaletteEntries; count++)
+			{
+			TInt blue = ptr[0];
+			TInt green = ptr[1];
+			TInt red = ptr[2];
+			
+			// Bitmaps with a palette do not contain an alpha channel
+			iPalette[count] = TRgb(red, green, blue);
+			ptr += (infoHeaderSize == KBmpInfoHeaderV1Size ?
+					KBmpSizeofPaletteEntryV1 :
+					KBmpSizeofPaletteEntryV2); // Skips RGBQUAD reserved value which is mandated 0x00
+			}
+		}
+ 
+	SetImageInfo(imageInfo);
+	SetStartPosition(imageDataOffset);
+	}
+
+CFrameInfoStrings* CBmpDecoder::FrameInfoStringsL(RFs& aFs, TInt aFrameNumber)
+	{
+	const TUid KBmpCodecDllUid = {KBMPCodecDllUidValue};
+
+	RResourceFile resourceFile;
+	OpenExtraResourceFileLC(aFs, KBmpCodecDllUid, resourceFile);
+
+	HBufC8* resourceInfo = resourceFile.AllocReadLC(THEDECODERINFO);
+	TResourceReader resourceReader;
+	resourceReader.SetBuffer(resourceInfo);
+
+	TBuf<KCodecResourceStringMax> info;
+	TBuf<KCodecResourceStringMax> templte;
+
+	const TFrameInfo& frameInfo = FrameInfo(aFrameNumber);
+	const CFrameImageData& frameData = FrameData(aFrameNumber); 
+	CFrameInfoStrings* frameInfoStrings = CFrameInfoStrings::NewLC();
+	const TBmpCompression* compressionImageData = STATIC_CAST(const TBmpCompression*, frameData.GetImageData(0));
+
+	info = resourceReader.ReadTPtrC();
+	frameInfoStrings->SetDecoderL(info);
+
+	info = resourceReader.ReadTPtrC();
+	frameInfoStrings->SetFormatL(info);
+
+	TInt width = frameInfo.iOverallSizeInPixels.iWidth;
+	TInt height = frameInfo.iOverallSizeInPixels.iHeight;
+	TInt depth = frameInfo.iBitsPerPixel;
+
+	templte = resourceReader.ReadTPtrC();
+	info.Format(templte, width, height);
+	frameInfoStrings->SetDimensionsL(info);
+
+	CDesCArrayFlat* resourceArray = resourceReader.ReadDesCArrayL();
+	CleanupStack::PushL(resourceArray);
+	TUint formatIndex = (frameInfo.iFlags & TFrameInfo::EColor) ? 1 : 0;
+	templte = (*resourceArray)[formatIndex];
+	CleanupStack::PopAndDestroy(resourceArray);
+	info.Format(templte, depth);
+	frameInfoStrings->SetDepthL(info);
+
+	resourceArray = resourceReader.ReadDesCArrayL();
+	CleanupStack::PushL(resourceArray);
+	formatIndex = (compressionImageData->iCompression) ? 1 : 0;
+	info = (*resourceArray)[formatIndex];
+	CleanupStack::PopAndDestroy(resourceArray);
+	frameInfoStrings->SetDetailsL(info);
+	
+	CleanupStack::Pop(frameInfoStrings);
+	CleanupStack::PopAndDestroy(2); // resourceInfo + resourceFile
+	return frameInfoStrings;
+	}
+
+// Bmp encoder
+CBmpEncoder* CBmpEncoder::NewL()
+	{
+	return new(ELeave) CBmpEncoder;
+	}
+
+CBmpEncoder::CBmpEncoder()
+	{
+	}
+
+CBmpEncoder::~CBmpEncoder()
+	{
+	Cleanup();
+	}
+
+void CBmpEncoder::Cleanup()
+	{
+	// Delete any objects we should get rid of
+	delete iReadBuffer; iReadBuffer = NULL; // Created in DoConvert()
+	// Base class included
+	CImageEncoderPlugin::Cleanup();
+	}
+
+void CBmpEncoder::PrepareEncoderL(const CFrameImageData* aFrameImageData)
+	{
+	iBitmapHeader.iBitCount = 0;
+
+	TInt count = (aFrameImageData) ? aFrameImageData->ImageDataCount() : 0;
+
+	if (count == 0)
+		iBitmapHeader.iBitCount = 24;	// default value
+
+	for (TInt index = 0 ; index<count ; index++)
+		{	
+		const TImageDataBlock* encoderData = aFrameImageData->GetImageData(index);
+		if (encoderData->DataType() == KBMPImageDataUid)
+			{
+			if (iBitmapHeader.iBitCount != 0)
+				User::Leave(KErrCorrupt);
+
+			const TBmpImageData* bmpImageData = STATIC_CAST(const TBmpImageData*, encoderData);
+			iBitmapHeader.iBitCount = bmpImageData->iBitsPerPixel;
+			}
+		else
+			User::Leave(KErrCorrupt);
+		}
+
+	if (iBitmapHeader.iBitCount == 0)
+		User::Leave(KErrCorrupt);
+
+	ASSERT(ImageWriteCodec() == NULL);
+
+	CBmpWriteCodec* imageWriteCodec = NULL;
+	if (iBitmapHeader.iBitCount==24)
+		{
+		imageWriteCodec = CBmp24BppWriteCodec::NewL();
+		iBitmapHeader.iPaletteEntries = 0;
+		}
+	else if (iBitmapHeader.iBitCount==8)
+		{
+		imageWriteCodec =  CBmp8BppWriteCodec::NewL();
+		iBitmapHeader.iPaletteEntries = 256;
+		}
+	else if (iBitmapHeader.iBitCount==4)
+		{
+		imageWriteCodec =  CBmp4BppWriteCodec::NewL();
+		iBitmapHeader.iPaletteEntries = 16;
+		}
+	else if (iBitmapHeader.iBitCount==1)
+		{
+		imageWriteCodec =  CBmp1BppWriteCodec::NewL();
+		iBitmapHeader.iPaletteEntries = 2;
+		}
+	else
+		User::Leave(KErrNotSupported);
+
+	SetImageWriteCodec(imageWriteCodec);
+
+	StartPosition() = KBmpFileHeaderSize + KBmpInfoDefaultHeaderV2Size + (iBitmapHeader.iPaletteEntries * KBmpSizeofPaletteEntryV2);
+	iBitmapHeader.iCompression = TBmpHeader::ENone;
+	}
+
+void CBmpEncoder::UpdateHeaderL()
+	{
+	TInt headerSize = KBmpFileHeaderSize + KBmpInfoDefaultHeaderV2Size + (iBitmapHeader.iPaletteEntries * KBmpSizeofPaletteEntryV2);
+	if (iReadBuffer && (iReadBuffer->Length() != headerSize))
+		{
+		delete iReadBuffer;
+		iReadBuffer = NULL;
+		}
+	if (!iReadBuffer)
+		iReadBuffer = HBufC8::NewMaxL(headerSize);
+	TUint8* headerPtr = &iReadBuffer->Des()[0];
+
+	// BITMAPFILEHEADER
+	*headerPtr++ = TUint8(KBmpFileSignature & 0xff);
+	*headerPtr++ = TUint8(KBmpFileSignature >> 8);
+
+	TInt imageSize = CurrentImageSizeL();
+	WriteTUint32(headerPtr, imageSize);
+	WriteTUint32(headerPtr, 0);
+	WriteTUint32(headerPtr, headerSize);
+
+	// BITMAPINFOHEADER
+	WriteTUint32(headerPtr, KBmpInfoDefaultHeaderV2Size); // biSize
+	WriteTUint32(headerPtr, FrameInfoOverallSizeInPixels().iWidth); // biWidth
+	WriteTUint32(headerPtr, FrameInfoOverallSizeInPixels().iHeight); // biHeight
+	WriteTUint32(headerPtr, 1 | (iBitmapHeader.iBitCount << 16)); // biPlanes | (biBitCount << 16)
+	WriteTUint32(headerPtr, 0); // biCompression
+	WriteTUint32(headerPtr, 0); // biSizeImage
+	WriteTUint32(headerPtr, 0); // biXPelsPerMetre
+	WriteTUint32(headerPtr, 0); // biYPelsPerMetre
+	WriteTUint32(headerPtr, 0); // biClrUsed
+	WriteTUint32(headerPtr, 0); // biClrImportant
+
+	// RGBQUAD
+	if (iBitmapHeader.iBitCount == 1)
+		{
+		for (TInt count = 0; count < iBitmapHeader.iPaletteEntries; count++)
+			{
+			TRgb color(TRgb::Gray2(count));
+			headerPtr[0] = TUint8(color.Blue());
+			headerPtr[1] = TUint8(color.Green());
+			headerPtr[2] = TUint8(color.Red());
+			headerPtr[3] = 0;
+			headerPtr+=4;
+			}
+		}
+	if (iBitmapHeader.iBitCount == 4)
+		{
+		for (TInt count = 0; count < iBitmapHeader.iPaletteEntries; count++)
+			{
+			TRgb color(TRgb::Color16(count));
+			headerPtr[0] = TUint8(color.Blue());
+			headerPtr[1] = TUint8(color.Green());
+			headerPtr[2] = TUint8(color.Red());
+			headerPtr[3] = 0;
+			headerPtr+=4;
+			}
+		}
+	else if (iBitmapHeader.iBitCount == 8)
+		{
+		for (TInt count = 0; count < iBitmapHeader.iPaletteEntries; count++)
+			{
+			TRgb color(TRgb::Color256(count));
+			headerPtr[0] = TUint8(color.Blue());
+			headerPtr[1] = TUint8(color.Green());
+			headerPtr[2] = TUint8(color.Red());
+			headerPtr[3] = 0;
+			headerPtr+=4;
+			}
+		}
+
+	TPtr8 bufferDes(iReadBuffer->Des());
+	WriteDataL(0,bufferDes);
+	}
+