diff -r 000000000000 -r 40261b775718 mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ExifThumbnailGenerator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ExifThumbnailGenerator.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,500 @@ +// Copyright (c) 2004-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 "ExifThumbnailGenerator.h" +#include +#include +#include "JpegTypes.h" +#include "jpegwritecodec.h" + +#include "ExifGeneralConsts.h" + +#include "exiftransformdataaccessor.h" + +CScaledJpegGenerator* CScaledJpegGenerator ::NewL(TRequestStatus* aNotifier, const MExifSource* aSource, + TBool aMaintainAspectRatio, CImageDecoder::TOptions aDecoderOptions) + { + CScaledJpegGenerator* self= new (ELeave) CScaledJpegGenerator(aNotifier, aMaintainAspectRatio, aDecoderOptions); + CleanupStack::PushL(self); + self->ConstructL(aSource); + CleanupStack::Pop(self); + + return self; + } + +HBufC8* CScaledJpegGenerator::GetJpegDataL() + { + if(iState!=EFinished) + { + User::Leave(KErrInUse); + } + if(iJPegImage.Count()==0) + { + User::Leave(KErrNotFound); + } + + TInt size=0; + TInt i; + for(i=0; iLength(); + } + HBufC8* thumbnailData=HBufC8::NewL(size); + TPtr8 bufPtr(thumbnailData->Des()); + + for(i=0; iAllocL(); + } + else + { + return NULL; + } + } + +CScaledJpegGenerator::CScaledJpegGenerator(TRequestStatus* aNotifier, TBool aMaintainAspectRatio, + CImageDecoder::TOptions aDecoderOptions) + : CActive(EPriorityStandard), iNotifier(aNotifier), iState(EFinished), + iMaintainAspectRatio(aMaintainAspectRatio) + { + iDecoderOptions = aDecoderOptions; + } + +CScaledJpegGenerator::~CScaledJpegGenerator() + { + Cancel(); + CleanData(); + iJPegImage.Close(); + } + +void CScaledJpegGenerator::ConstructL(const MExifSource* aSource) + { + ASSERT(aSource != NULL); + iSource = aSource; + CActiveScheduler::Add(this); + } + + + +void CScaledJpegGenerator::StartL(TSize aSize, TImageToGenerate aImageType) + { + if(iState!=EFinished) + { + User::Leave(KErrInUse); + } + + + CleanResultData(); + CleanTempData(); + iSize=aSize; + iImageType=aImageType; + + if(!iImageDecoder) + { + iImageDecoder = iSource->CreateImageDecoderL(iDecoderOptions); + TFrameInfo frameInfo= iImageDecoder->FrameInfo(); + + if(iBitmap) + { + delete iBitmap; + iBitmap = NULL; + } + iBitmap= new (ELeave) CFbsBitmap(); + + User::LeaveIfError(iBitmap->Create(frameInfo.iFrameCoordsInPixels.Size(), frameInfo.iFrameDisplayMode)); + iState=EDecode; + iImageDecoder->Convert(&iStatus, *iBitmap); + SetActive(); + } + else + { // the initialisation has already been done, there is no need to do it again + DoScaleBitmapL(); + SetActive(); + } + *iNotifier=KRequestPending; + } + +void CScaledJpegGenerator::RunL() + { + if(iStatus.Int()==KErrNone) + { + switch(iState) + { + case EDecode: + // the decode is finished, we now scale the image + DoScaleBitmapL(); + SetActive(); + break; + + case EScale: + // the scaling is over. We now Convert the image + DoConvertL(); + SetActive(); + break; + case EConvert: + { + switch(iFrameState) + { + case EFrameIncomplete: + DoConvertL(); + SetActive(); + break; + case EFrameComplete: + GenerationCompleteL(); + break; + default: + iStatus=KErrCorrupt; + RunError(KErrCorrupt); + } + } + break; + case EFinished: + break; + default: + break; + } + // we have the bitmap, now scale it + } + else + { + RunError(iStatus.Int()); + } + } + +void CScaledJpegGenerator::DoCancel() + { + if (iImageDecoder) + { + iImageDecoder->Cancel(); + } + if (iBitmapScaler) + { + iBitmapScaler->Cancel(); + } + CleanData(); + User::RequestComplete(iNotifier, KErrCancel); + iState=EFinished; + } + +void CScaledJpegGenerator::DoScaleBitmapL() + { + if(iBitmapScaler) + { + delete iBitmapScaler; + iBitmapScaler = NULL; + } + iBitmapScaler=CBitmapScaler::NewL(); + + iBitmapScaler->UseLowMemoryAlgorithm(ETrue); + iBitmapScaler->Scale(&iStatus, *iBitmap, iSize, iMaintainAspectRatio); + iState=EScale; + } + + + // returns ETrue if it is the last chunk of data to be received +void CScaledJpegGenerator::DoConvertL() + { + if(iState!=EConvert) + { + delete iBitmapScaler; + iBitmapScaler=NULL; + CreateJpegCodecL(); + if(iJpegChunck) + { + delete iJpegChunck; + iJpegChunck = NULL; + } + iJpegChunck=HBufC8::NewMaxL(4096); + iJpegChunckPtr.Set(*iJpegChunck); + + if(iImageType==EThumbnail) + { + // write SOI + iJpegChunckPtr[0] = (TUint8)((KJpgSOISignature & 0xff00) >> 8); + iJpegChunckPtr[1] = (TUint8)(KJpgSOISignature & 0xff); + iJpegChunckPtr.Shift(2); + } + + iJpegCodec->InitFrameL(iJpegChunckPtr, *iBitmap); + + if(iImageType==EThumbnail) + { + // Adjust iJpegChunckPtr to account for SOI added above + TInt len=iJpegChunckPtr.Length() + 2; + iJpegChunckPtr.Set(*iJpegChunck); + iJpegChunckPtr.SetLength(len); + } + + HBufC8* buf = iJpegChunckPtr.AllocLC(); + iJPegImage.AppendL(buf); + CleanupStack::Pop(buf); + iJpegChunckPtr.Set(*iJpegChunck); + iFrameState=EFrameIncomplete; + } + else + { + iFrameState= iJpegCodec->ProcessFrameL(iJpegChunckPtr); + HBufC8* buf = iJpegChunckPtr.AllocLC(); + iJPegImage.AppendL(buf); + CleanupStack::Pop(buf); + } + + + iStatus=KRequestPending; + TRequestStatus* status=&iStatus; + User::RequestComplete(status, KErrNone); + iState=EConvert; + } + + +void CScaledJpegGenerator::CreateJpegCodecL() + { + const CFrameImageData* frameImageData= &iImageDecoder->FrameData(); + + //PDEF115929 + //This should not be the case - corrupt file + if (frameImageData == NULL) + { + User::Leave(KErrCorrupt); + } + + TJpgFrameInfo frameInfo; + TInt qualityFactor; + + qualityFactor = 0; + + TInt count = frameImageData->ImageDataCount(); + + //PDEF115929 + //This should not be the case - corrupt file + if (count == 0) + { + User::Leave(KErrCorrupt); + } + + TBool jpgImageDataProcessed = EFalse; + for (TInt index = 0 ; indexGetImageData(index); + if (encoderData.DataType() == KJPGImageDataUid) + { + // Leave if we have already processed one of these. + if (jpgImageDataProcessed) + User::Leave(KErrCorrupt); + + const TJpegImageData& jpegImageData = STATIC_CAST(const TJpegImageData&, encoderData); + qualityFactor = jpegImageData.iQualityFactor; + + TJpegImageData::TColorSampling sampleScheme = jpegImageData.iSampleScheme; + frameInfo.iComponent[0].iQTable = 0; + if (sampleScheme == TJpegImageData::EMonochrome) + { + frameInfo.iNumberOfComponents = 1; + frameInfo.iComponent[0].iHorzSampleFactor = 1; + frameInfo.iComponent[0].iVertSampleFactor = 1; + } + else + { + frameInfo.iNumberOfComponents = 3; + switch (sampleScheme) + { + case TJpegImageData::EColor420: + frameInfo.iComponent[0].iHorzSampleFactor = 2; + frameInfo.iComponent[0].iVertSampleFactor = 2; + frameInfo.iComponent[1].iVertSampleFactor = 1; + frameInfo.iComponent[2].iVertSampleFactor = 1; + break; + case TJpegImageData::EColor422: + frameInfo.iComponent[0].iHorzSampleFactor = 2; + frameInfo.iComponent[0].iVertSampleFactor = 1; + frameInfo.iComponent[1].iVertSampleFactor = 1; + frameInfo.iComponent[2].iVertSampleFactor = 1; + break; + case TJpegImageData::EColor444: + frameInfo.iComponent[0].iHorzSampleFactor = 1; + frameInfo.iComponent[0].iVertSampleFactor = 1; + frameInfo.iComponent[1].iVertSampleFactor = 1; + frameInfo.iComponent[2].iVertSampleFactor = 1; + break; + default: + User::Leave(KErrNotSupported); + } + + frameInfo.iComponent[1].iHorzSampleFactor = 1; + frameInfo.iComponent[1].iQTable = 1; + frameInfo.iComponent[2].iHorzSampleFactor = 1; + frameInfo.iComponent[2].iQTable = 1; + } + + frameInfo.iMaxHorzSampleFactor = frameInfo.iComponent[0].iHorzSampleFactor; + frameInfo.iMaxVertSampleFactor = frameInfo.iComponent[0].iVertSampleFactor; + + jpgImageDataProcessed = ETrue; + } + else if (encoderData.DataType() == KJPGQTableUid) + { + const TJpegQTable& jpegQTable = STATIC_CAST(const TJpegQTable&, encoderData); + TInt tableIndex = jpegQTable.iTableIndex; + if ((tableIndex != TJpegQTable::ELumaTable) && (tableIndex != TJpegQTable::EChromaTable)) + { + // This can happen if client has given us a second chroma QTable + // replacement. We do not support this at present, so we ignore + // the extra Q table and encode using the same QTable for both + // chroma components. + continue; + } + + TUint8 values[KJpgQTableEntries]; + TUint8* valuePtr = values; + const TUint8* zigZagPtr = KZigZagSequence.iZigZag; + const TUint8* valuePtrLimit = valuePtr + KJpgQTableEntries; + + while (valuePtr < valuePtrLimit) + *valuePtr++ = jpegQTable.iEntries[*zigZagPtr++]; + + if (tableIndex == TJpegQTable::ELumaTable) + { + delete iLumaTable; + iLumaTable=NULL; + iLumaTable = new(ELeave) TQTable; + + iLumaTable->Set(values, EFalse); + } + else // tableIndex must be TJpegQTable::EChromaTable + { + delete iChromaTable; + iChromaTable=NULL; + iChromaTable = new(ELeave) TQTable; + + iChromaTable->Set(values, EFalse); + } + } + else if ((encoderData.DataType() == KJPGCommentUid)) + { + if (iImageType == EMainImage) + { + const TJpegComment& jpegComment = STATIC_CAST(const TJpegComment&, encoderData); + if (!jpegComment.iComment) + User::Leave(KErrNotFound); + + if ((jpegComment.iComment->Length() == 0) || (jpegComment.iComment->Length() > 65534)) + User::Leave(KErrNotSupported); + + HBufC8* thisComment = jpegComment.iComment->AllocL(); + TInt ret = iComment.Append(thisComment); + if (ret != KErrNone) + { + delete thisComment; + User::Leave(ret); + } + + } + } + else + User::Leave(KErrCorrupt); + } + + iJpegCodec= CJpgWriteCodec::NewL(frameInfo,qualityFactor,iLumaTable,iChromaTable,iComment,NULL); + } + + +TInt CScaledJpegGenerator::RunError(TInt aError) + { + CleanData(); + User::RequestComplete(iNotifier, aError); + iState=EFinished; + + return KErrNone; + } + +void CScaledJpegGenerator::GenerationCompleteL() + { + // write EOI + TBuf8<2> buffer2Bytes; + buffer2Bytes.SetLength(2); + TUint8* headerPtr2 = &buffer2Bytes[0]; + headerPtr2[0] = (TUint8)((KJpgEOISignature & 0xff00) >> 8); + headerPtr2[1] = (TUint8)(KJpgEOISignature & 0xff); + HBufC8* buf = buffer2Bytes.AllocLC(); + iJPegImage.AppendL(buf); + CleanupStack::Pop(buf); + iState=EFinished; + CleanTempData(); + User::RequestComplete(iNotifier, KErrNone); + } + +void CScaledJpegGenerator::CleanTempData() + { + delete iJpegCodec; + iJpegCodec=NULL; + delete iBitmapScaler; + iBitmapScaler=NULL; + + delete iJpegChunck; + iJpegChunck=NULL; + + iComment.ResetAndDestroy(); + delete iLumaTable; + iLumaTable=NULL; + delete iChromaTable; + iChromaTable=NULL; + } + +void CScaledJpegGenerator::CleanResultData() + { + iJPegImage.ResetAndDestroy(); + } + +void CScaledJpegGenerator::CleanData() + { + CleanTempData(); + CleanResultData(); + + delete iImageDecoder; + iImageDecoder=NULL; + delete iBitmap; + iBitmap=NULL; + } + +void CScaledJpegGenerator::GetScaledImageSize(TSize &aSize) + { + if (iBitmap) + { + aSize = iBitmap->SizeInPixels(); + } + else + { + aSize = iSize; + } + }