diff -r 000000000000 -r 40261b775718 mmplugins/imagingplugins/codecs/GifCodec/GIFConvert.cpp --- /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 +#include "ImageClientMain.h" +#include "ImageUtils.h" +#include +#include +#include +#include <101F45B1_extra.rsg> +#include "GIFConvert.h" +#include "icl/ICL_UIDS.hrh" +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#include +#include +#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 info; + TBuf 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(aFrameImageData->GetFrameData(frameDataIndex)); + if (frameData->DataType() == KGIFColorTableUid) + { + gifColorTable = static_cast(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(&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 + } +