mmplugins/imagingplugins/codecs/GifCodec/GIFConvert.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/GifCodec/GIFConvert.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,458 @@
+// Copyright (c) 1997-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:
+// Licensed under US Patent No 4,558,302 and foreign counterparts
+// 
+//
+
+#include <imageconversion.h>
+#include "ImageClientMain.h"
+#include "ImageUtils.h"
+#include <barsc.h>
+#include <barsread.h>
+#include <bautils.h>
+#include <101F45B1_extra.rsg>
+#include "GIFConvert.h"
+#include "icl/ICL_UIDS.hrh"
+#include <gifscaler.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <icl/icl_uids_const.hrh>
+#include <icl/icl_uids_def.hrh>
+#include <icl/imagecodecdef.h>
+#endif
+
+_LIT(KGIFPanicCategory, "GIFConvertPlugin");
+
+// Global panic function
+GLDEF_C void Panic(TIclPanic aError)
+	{
+	User::Panic(KGIFPanicCategory, aError);
+	}
+
+CGifDecoder* CGifDecoder::NewL()
+	{
+	return new(ELeave) CGifDecoder;
+	}
+
+CGifDecoder::CGifDecoder()
+	{
+	}
+
+CGifDecoder::~CGifDecoder()
+	{
+	CImageDecoderPlugin::Cleanup();
+	}
+
+void CGifDecoder::ImageType(TInt aFrameNumber, TUid& aImageType, TUid& aImageSubType) const
+	{
+	__ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < NumberOfFrames()), Panic(EFrameNumberOutOfRange));
+	aImageType = KImageTypeGIFUid;
+	aImageSubType = KNullUid;
+	}
+
+TInt CGifDecoder::NumberOfImageComments() const
+	{
+	__ASSERT_ALWAYS(IsImageHeaderProcessingComplete(), Panic(EHeaderProcessingNotComplete));
+	const CFrameImageData& frameImageData = FrameData(0);
+	TInt imageCommentCount = 0;
+	const TInt imageDataCount = frameImageData.ImageDataCount();
+	for (TInt count = 0; count < imageDataCount; count++)
+		{
+		const TImageDataBlock* imageData = frameImageData.GetImageData(count);
+		if (imageData->DataType() == KGIFCommentUid)
+			imageCommentCount++;
+		}
+
+	return imageCommentCount;
+	}
+
+HBufC* CGifDecoder::ImageCommentL(TInt aCommentNumber) const
+	{
+	__ASSERT_ALWAYS(IsImageHeaderProcessingComplete(), Panic(EHeaderProcessingNotComplete));
+	__ASSERT_ALWAYS((aCommentNumber >= 0) && (aCommentNumber < NumberOfImageComments()), Panic(ECommentNumberOutOfRange));
+
+	const CFrameImageData& frameImageData = FrameData(0);
+	TInt commentCount = 0;
+	TInt imageDataCount = frameImageData.ImageDataCount();
+	const TImageDataBlock* imageData = NULL;
+	for (TInt count = 0; count < imageDataCount; count++)
+		{
+		imageData = frameImageData.GetImageData(count);
+		if (imageData->DataType() == KGIFCommentUid)
+			{
+			if (commentCount == aCommentNumber)
+				{
+				break;
+				}
+			commentCount++;
+			}
+		}
+
+	const TGifComment* gifComment = STATIC_CAST(const TGifComment*,imageData);
+	HBufC* comment = NULL;
+	if (gifComment)
+		{
+		comment = HBufC::NewL(gifComment->iComment->Length());
+		comment->Des().Copy(*(gifComment->iComment)); // Create a 16 bit copy of the 8 bit original	
+		}
+	
+	return comment;
+	}
+
+void CGifDecoder::ScanDataL()
+	{
+	ReadFormatL();
+
+	ASSERT(ImageReadCodec()==NULL);
+	CGifReadCodec* imageReadCodec = CGifReadCodec::NewL(iGlobalPalette, iFileInfo.iBackgroundColorIndex, iFileInfo.iScreenSize,
+	                                ( (DecoderOptions() & CImageDecoder::EPreferFastDecode) == CImageDecoder::EPreferFastDecode)
+	            );
+
+	SetImageReadCodec(imageReadCodec);
+	
+	if((DecoderOptions()&CImageDecoder::EOptionUseFrameSizeInPixels) == CImageDecoder::EOptionUseFrameSizeInPixels)
+		{
+		imageReadCodec->SetUseFrameSizeInPixels(ETrue);
+		}
+
+	ReadFrameHeadersL();
+	}
+
+void CGifDecoder::ReadFormatL()
+	{
+	TPtrC8 bufferDes;
+
+	// Read the header (+ 1 extra byte, so that we can check the first block id is valid)
+	ReadDataL(0, bufferDes, (KGifFileInformationSize + (KGifColorTableMaxEntries * KGifPaletteEntrySize) + 1));
+
+	// Validate the header.
+	if (bufferDes.Length() < KGifFileInformationSize)
+		User::Leave(KErrUnderflow);
+
+	iFileInfo.iSignature = bufferDes.Left(KGifSignatureLength);
+	if (iFileInfo.iSignature != KGif87aFileSignature && 
+		iFileInfo.iSignature != KGif89aFileSignature)
+		User::Leave(KErrCorrupt);
+
+	const TUint8* ptr = &bufferDes[KGifSignatureLength];
+	iFileInfo.iScreenSize.iWidth = PtrReadUtil::ReadUint16(ptr);
+	ptr+=2;
+
+	iFileInfo.iScreenSize.iHeight = PtrReadUtil::ReadUint16(ptr);
+	ptr+=2;
+
+	TUint8 flags = *ptr++;
+	iFileInfo.iBitsPerPixel = (flags & 0x07) + 1;
+	iFileInfo.iColorResolutionBits = ((flags & 0x70) >> 4) + 1;
+	iFileInfo.iGlobalColorMap = flags & 0x80;
+	if (iFileInfo.iSignature == KGif89aFileSignature)
+		iFileInfo.iSortedGlobalMap = flags & 0x08;
+
+	if (iFileInfo.iGlobalColorMap)
+		{
+		iFileInfo.iBackgroundColorIndex = *ptr;
+		iGlobalPaletteEntries = 1 << iFileInfo.iBitsPerPixel;
+		}
+	else
+		{
+		iFileInfo.iBackgroundColorIndex = KErrNotFound;
+		iGlobalPaletteEntries = 0;
+		}
+
+	ptr++;
+	TUint8 pixelAspectRatio = *ptr;
+	if (iFileInfo.iSignature == KGif87aFileSignature)
+		{
+		iFileInfo.iPixelAspectRatio = pixelAspectRatio & 0x7f;
+		iFileInfo.iSortedGlobalMap = pixelAspectRatio & 0x80;
+		}
+	else
+		iFileInfo.iPixelAspectRatio = pixelAspectRatio;
+
+	if (iFileInfo.iGlobalColorMap)
+		{
+		if (bufferDes.Length() < (KGifFileInformationSize + iGlobalPaletteEntries * KGifPaletteEntrySize))
+			User::Leave(KErrUnderflow);
+
+		const TUint8* ptr = &bufferDes[KGifFileInformationSize];
+		TRgb* palettePtr = iGlobalPalette;
+		TRgb* palettePtrLimit = iGlobalPalette + iGlobalPaletteEntries;
+
+		while (palettePtr < palettePtrLimit)
+			{
+			*palettePtr++ = TRgb(ptr[0],ptr[1],ptr[2]);
+			ptr += KGifPaletteEntrySize;
+			}
+
+		palettePtrLimit = iGlobalPalette + KGifColorTableMaxEntries;
+		while (palettePtr < palettePtrLimit)
+			*palettePtr++ = KRgbWhite;
+
+		TGifBackgroundColor* gifBackgroundColor = new(ELeave) TGifBackgroundColor;
+		gifBackgroundColor->iBackgroundColorIndex = iFileInfo.iBackgroundColorIndex;
+		gifBackgroundColor->iBackgroundColor = iGlobalPalette[iFileInfo.iBackgroundColorIndex];
+		CleanupStack::PushL(gifBackgroundColor);
+
+		User::LeaveIfError(AppendImageData(gifBackgroundColor));
+		CleanupStack::Pop(); // gifBackgroundColor
+		}
+
+	if (bufferDes.Length() < (KGifFileInformationSize + (iGlobalPaletteEntries * KGifPaletteEntrySize)) + 1)
+		User::Leave(KErrUnderflow);
+	
+	// Check that first byte after the global color table is a valid block id
+	TUint8 nextBlockId = bufferDes[KGifFileInformationSize + (iGlobalPaletteEntries * KGifPaletteEntrySize)];
+	switch (nextBlockId)
+		{
+		case KGifExtensionId:
+		case KGifImageDescriptorId:
+		case KGifPlainTextExtensionId:
+		case KGifGraphicControlExtensionId:
+		case KGifCommentExtensionId:
+		case KGifApplicationExtensionId:
+			break;
+
+		default:
+			User::Leave(KErrCorrupt);
+		}
+	
+	TInt startPosition = KGifFileInformationSize;
+	if (iFileInfo.iGlobalColorMap)
+		startPosition += iGlobalPaletteEntries * KGifPaletteEntrySize;
+	SetStartPosition(startPosition);
+
+	TFrameInfo imageInfo;
+	imageInfo = ImageInfo();
+	imageInfo.iOverallSizeInPixels = iFileInfo.iScreenSize;
+	imageInfo.iBitsPerPixel = iFileInfo.iBitsPerPixel;
+	imageInfo.iFrameSizeInTwips.SetSize(0,0);
+	if (iFileInfo.iGlobalColorMap)
+		{
+		imageInfo.iBackgroundColor = iGlobalPalette[iFileInfo.iBackgroundColorIndex];
+		if (iFileInfo.iColorResolutionBits<=4)
+			imageInfo.iFrameDisplayMode = EColor4K;
+		else
+			imageInfo.iFrameDisplayMode = EColor16M;
+		}
+	else
+		imageInfo.iFrameDisplayMode = EColor256;
+	imageInfo.iDelay = KErrNotFound;
+
+	SetImageInfo(imageInfo);
+	SetDataLength(KMaxTInt); // Set default data length in case format header doesn't contain this information
+	}
+
+CFrameInfoStrings* CGifDecoder::FrameInfoStringsL(RFs& aFs, TInt aFrameNumber)
+	{
+	const TUid KGifCodecDllUid = {KGIFCodecDllUidValue};
+
+	RResourceFile resourceFile;
+	OpenExtraResourceFileLC(aFs,KGifCodecDllUid,resourceFile);
+
+	HBufC8* resourceInfo = resourceFile.AllocReadLC(THEDECODERINFO);
+	TResourceReader resourceReader;
+	resourceReader.SetBuffer(resourceInfo);
+
+	TBuf<KCodecResourceStringMax> info;
+	TBuf<KCodecResourceStringMax> templte;
+
+	const TFrameInfo& frameInfo = FrameInfo(aFrameNumber);
+	CFrameInfoStrings* frameInfoStrings = CFrameInfoStrings::NewLC();
+
+	info = resourceReader.ReadTPtrC();
+	frameInfoStrings->SetDecoderL(info);
+
+	CDesCArrayFlat* resourceArray = resourceReader.ReadDesCArrayL();
+	CleanupStack::PushL(resourceArray);
+	TUint formatIndex = (iFileInfo.iSignature == KGif87aFileSignature) ? 0 : 1;
+	info = (*resourceArray)[formatIndex];
+	CleanupStack::PopAndDestroy(resourceArray);
+	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);
+
+	templte = resourceReader.ReadTPtrC();
+	info.Format(templte, depth);
+	frameInfoStrings->SetDepthL(info);
+
+	// leave details blank
+
+	CleanupStack::Pop(frameInfoStrings); 
+	CleanupStack::PopAndDestroy(2); // resourceInfo + resourceFile
+	return frameInfoStrings;
+	}
+
+// Gif encoder.
+CGifEncoder* CGifEncoder::NewL()
+	{
+	CGifEncoder* self = new(ELeave) CGifEncoder;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+
+	}
+
+CGifEncoder::CGifEncoder()
+	{
+	}
+
+void CGifEncoder::ConstructL()
+	{
+	iPalette = CPalette::NewDefaultL(EColor256);
+	}
+
+CGifEncoder::~CGifEncoder()
+	{
+	if (iGifScaler)
+		{
+		iGifScaler->Cancel();
+		delete iGifScaler;
+		}
+	delete iPalette;
+	delete iDest;
+	CImageEncoderPlugin::Cleanup();
+	}
+
+const CPalette* CGifEncoder::Palette() const
+	{
+	return iPalette;
+	}
+
+void CGifEncoder::WriteExifDataL(TRequestStatus*& aScaleCompletionStatus)
+	{
+	if ((EncoderOptions() & CImageEncoder::EOptionGenerateAdaptivePalette) == CImageEncoder::EOptionGenerateAdaptivePalette)
+		{
+		if (!iPalette)
+			{
+			iPalette = CPalette::NewL(KGifColorTableMaxEntries);	
+			}
+		iGifScaler->Scale(aScaleCompletionStatus, *iDest, *iPalette);
+		}
+	else
+		{
+		// the framework waits for aScaleCompletionStatus to complete
+		SelfComplete(KErrNone);
+		}
+	}
+
+void CGifEncoder::PrepareEncoderL(const CFrameImageData* aFrameImageData)
+	{
+	// Create the codec.
+	StartPosition() = KGifFileInformationSize;
+	StartPosition() += KGifColorTableMaxEntries * KGifPaletteEntrySize;
+	ASSERT(ImageWriteCodec() == NULL);
+	
+	// ensure iPalette is NULL to start with since CGifWriteCodec::FillBufferL() behaviour depends on it
+	delete iPalette;
+	iPalette = NULL;
+
+	// check to see if client has supplied a palette
+	if (aFrameImageData)
+		{
+		TInt frameDataCount = aFrameImageData->FrameDataCount();
+		TGifColorTable* gifColorTable = NULL;
+		for (TInt frameDataIndex = 0; frameDataIndex < frameDataCount; frameDataIndex++)
+			{
+			TFrameDataBlock* frameData = const_cast<TFrameDataBlock*>(aFrameImageData->GetFrameData(frameDataIndex));
+			if (frameData->DataType() == KGIFColorTableUid)
+				{
+				gifColorTable = static_cast<TGifColorTable*>(frameData);
+				}
+			}
+
+		if (gifColorTable)
+			{
+			if (!iPalette)
+				{
+				iPalette = CPalette::NewL(KGifColorTableMaxEntries);	
+				}
+			for (TInt i = 0; i < KGifColorTableMaxEntries; i++)
+				{
+				iPalette->SetEntry(i, gifColorTable->iPalette[i]);
+				}
+			}
+		}
+
+	if ((EncoderOptions() & CImageEncoder::EOptionGenerateAdaptivePalette) == CImageEncoder::EOptionGenerateAdaptivePalette)
+		{
+		CFbsBitmap* sourceBitmap = const_cast<CFbsBitmap*>(&Source());
+		delete iGifScaler;
+		iGifScaler = NULL;
+		iGifScaler = CGifScaler::NewL(*sourceBitmap);
+
+		delete iDest;
+		iDest = NULL;
+		iDest = new (ELeave) CFbsBitmap;
+		User::LeaveIfError(iDest->Create(sourceBitmap->SizeInPixels(), EColor256));
+		}
+
+	CGifWriteCodec* imageWriteCodec = CGifWriteCodec::NewL(*this);
+	
+	SetImageWriteCodec(imageWriteCodec);
+
+	}
+
+void CGifEncoder::UpdateHeaderL()
+	{
+	TInt headerSize = KGifFileInformationSize + (KGifColorTableMaxEntries * KGifPaletteEntrySize);
+
+	HBufC8* gifHeaderPtr = HBufC8::NewMaxLC(headerSize);
+	TUint8* headerPtr = &gifHeaderPtr->Des()[0];
+
+	Mem::Copy(headerPtr,&KGif87aFileSignature()[0],KGifSignatureLength); headerPtr += KGifSignatureLength;
+
+	TInt width = Source().SizeInPixels().iWidth;
+	TInt height = Source().SizeInPixels().iHeight;
+	PtrWriteUtil::WriteInt16(headerPtr, width);
+	headerPtr+=2;
+	PtrWriteUtil::WriteInt16(headerPtr, height);
+	headerPtr+=2;
+	TUint8 resolutionFlag = 0;
+	resolutionFlag |= 8 - 1; // Bpp - 1
+	resolutionFlag |= (8 - 1) << 4; // Color Resolution
+	resolutionFlag |= 0x80; // Global Color Table Flag
+	*headerPtr++ = resolutionFlag;
+	*headerPtr++ = 255; // Background Color Index
+	*headerPtr++ = 0; // Pixel Aspect Ratio
+
+	for (TInt paletteIndex = 0; paletteIndex < KGifColorTableMaxEntries; paletteIndex++)
+		{
+		TRgb entry;
+		if (iPalette)
+			{
+			entry = iPalette->GetEntry(paletteIndex);
+			}
+		else
+			{
+			entry = TRgb::Color256(paletteIndex);			
+			}
+
+		headerPtr[0] = (TUint8)entry.Red();
+		headerPtr[1] = (TUint8)entry.Green();
+		headerPtr[2] = (TUint8)entry.Blue();
+		headerPtr += 3;
+		}
+
+	TPtr8 bufferDes(gifHeaderPtr->Des());
+	WriteDataL(0,bufferDes);
+
+	CleanupStack::PopAndDestroy(); // gifHeaderPtr
+	}
+