diff -r 000000000000 -r 72b543305e3a mobilemessaging/unieditor/utils/src/UniImageProcessor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobilemessaging/unieditor/utils/src/UniImageProcessor.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,922 @@ +/* +* Copyright (c) 2006-2007 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: +* Unified Message Editor - Combined image scaler & compressor +* +*/ + + + +// INCLUDE FILES +#include "UniImageProcessor.h" + +#include +#include + +#include + +#include "UniEditorLogging.h" + + +// ========================================================== + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// JPEG quality factor related constants: +const TInt KHighQualityMaxWidth = 640; +const TInt KHighQualityMaxHeight = 480; +const TInt KJpegQualityFactorHigh = 80; +const TInt KJpegQualityFactorNormal = 65; + +// MPix factor is relative to this value +// 3MPix: Initial factor 2/3 * Qfactor calculated above +// 5MPix: 2/5* +// 8MPix: 2/8* +const TReal KQFMPixfactor( 1600*1200 ); + +// Count of compressing/scaling efforts +const TInt KIterationCount( 3 ); + +const TInt KMPixfactorMin = 1; +const TInt KMPixfactorMax = 5; +const TInt KMPixSizeDivider = 4; + +// When compressing next QFactor is QFactor * (value from table) / 100 +const TInt KPercentCoefficientsCounts[KMPixfactorMax][KIterationCount] = + { { 60, 30, 10 }, + { 40, 15, 3 }, + { 25, 10, 2 }, + { 12, 4, 0 }, + { 5, 2, 0 } + }; + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// ================= MEMBER FUNCTIONS ======================= + +// --------------------------------------------------------- +// CUniImageProcessor::CUniImageProcessor +// +// Constructor. +// --------------------------------------------------------- +// +EXPORT_C CUniImageProcessor::CUniImageProcessor( MUniImageProcessorCallback* aCallback ) : + CActive( EPriorityStandard ), + iCallback( aCallback ), + iMPixFactor ( KMPixfactorMin ) + { + CActiveScheduler::Add( this ); + } + +// --------------------------------------------------------- +// CUniImageProcessor::~CUniImageProcessor +// +// Destructor +// --------------------------------------------------------- +// +CUniImageProcessor::~CUniImageProcessor() + { + Cancel(); + Reset(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::ProcessImageL +// +// --------------------------------------------------------- +// +EXPORT_C void CUniImageProcessor::ProcessImageL( + RFile& aSourceFile, + RFile& aDestFile, + TSize& aTargetSize, + const TDesC8& aTargetType, + TBool aAspectRatio, + TInt aTargetFileSize ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: file-to-file scaling" ); + + if ( iDecoder || iScaler || iEncoder ) + { + User::Leave( KErrInUse ); + } + + iError = KErrNone; + iFlags &= ~ECompressOnly; + if ( aTargetType.CompareF( KMsgMimeImageJpeg ) == 0 ) + { + iCompressTriesLeft = KIterationCount; + User::LeaveIfError( aSourceFile.Size( iOriginalFileSize ) ); + // Make sure the resulting image won't be larger than the original + if ( !aTargetFileSize || iOriginalFileSize < aTargetFileSize ) + { + aTargetFileSize = iOriginalFileSize; + iFlags |= EImplicitCompress; + } + iTargetFileSize = aTargetFileSize; + } + else + { + iCompressTriesLeft = 0; + iTargetFileSize = 0; + iOriginalFileSize = 0; + } + + iQFactorCalculated = EFalse; + iMPixFactor = KMPixfactorMin; + iDestFile = &aDestFile; + iAspectRatio = aAspectRatio; + iDecoder = CImageDecoder::FileNewL( aSourceFile, ContentAccess::EPeek ); + iEncoder = CImageEncoder::FileNewL( aDestFile, aTargetType ); + + const TFrameInfo& frameInfo = iDecoder->FrameInfo(); + + TSize decodeSize( frameInfo.iOverallSizeInPixels ); + if ( !CalculateDecodeAndTargetSizes( aTargetSize, decodeSize, aAspectRatio ) ) + { + // use bitmap plane scale + iScaler = CBitmapScaler::NewL(); + iSourceBitmap = new ( ELeave ) CFbsBitmap; + iFlags |= ESourceBitmapOwned; + User::LeaveIfError( iSourceBitmap->Create( + decodeSize, + frameInfo.iFrameDisplayMode ) ); + } + + iDestBitmap = new ( ELeave ) CFbsBitmap; + iFlags |= EDestBitmapOwned; + User::LeaveIfError( iDestBitmap->Create( + aTargetSize, + frameInfo.iFrameDisplayMode ) ); + + CreateImageDataL( aTargetType, aTargetSize ); + + DecodeImage(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::ProcessImageL +// +// --------------------------------------------------------- +// +EXPORT_C void CUniImageProcessor::ScaleImageL( + CFbsBitmap* aSourceBitmap, + RFile& aDestFile, + const TSize& aTargetSize, + const TDesC8& aTargetType, + TBool aAspectRatio ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: bmp-to-file scaling" ); + if ( iDecoder || iScaler || iEncoder ) + { + User::Leave( KErrInUse ); + } + + iError = KErrNone; + iFlags &= ~ECompressOnly; + iCompressTriesLeft = 0; + iTargetFileSize = 0; + iOriginalFileSize = 0; + + iQFactorCalculated = EFalse; + iMPixFactor = KMPixfactorMin; + iDestFile = &aDestFile; + iAspectRatio = aAspectRatio; + iScaler = CBitmapScaler::NewL(); + iEncoder = CImageEncoder::FileNewL( aDestFile, aTargetType ); + + iSourceBitmap = aSourceBitmap; + + iDestBitmap = new ( ELeave ) CFbsBitmap; + iFlags |= EDestBitmapOwned; + TInt error = iDestBitmap->Create( + aTargetSize, + iSourceBitmap->DisplayMode() ); + User::LeaveIfError( error ); + + CreateImageDataL( aTargetType, aTargetSize ); + + ScaleImage( EFalse ); + } + +// --------------------------------------------------------- +// CUniImageProcessor::ScaleImageL +// +// --------------------------------------------------------- +// +EXPORT_C void CUniImageProcessor::ScaleImageL( + CFbsBitmap* aSourceBitmap, + CFbsBitmap* aDestBitmap, + TBool aAspectRatio ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: bmp-to-bmp scaling" ); + if ( iDecoder || iScaler || iEncoder ) + { + User::Leave( KErrInUse ); + } + + iError = KErrNone; + iFlags &= ~ECompressOnly; + iCompressTriesLeft = 0; + iTargetFileSize = 0; + iOriginalFileSize = 0; + + iAspectRatio = aAspectRatio; + iScaler = CBitmapScaler::NewL(); + + iSourceBitmap = aSourceBitmap; + iDestBitmap = aDestBitmap; + + ScaleImage( EFalse ); + } + +// --------------------------------------------------------- +// CUniImageProcessor::ScaleImageL +// +// --------------------------------------------------------- +// +EXPORT_C void CUniImageProcessor::ScaleImageL( + RFile& aSourceFile, + CFbsBitmap*& aDestBitmap, + CFbsBitmap*& aDestMask, + TSize& aTargetSize, + TBool aAspectRatio ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: file-to-bmp scaling" ); + if ( iDecoder || iScaler || iEncoder ) + { + User::Leave( KErrInUse ); + } + + iError = KErrNone; + iFlags &= ~ECompressOnly; + iCompressTriesLeft = 0; + iTargetFileSize = 0; + iOriginalFileSize = 0; + + iQFactorCalculated = EFalse; + iMPixFactor = KMPixfactorMin; + iAspectRatio = aAspectRatio; + iDecoder = CImageDecoder::FileNewL( aSourceFile, ContentAccess::EPeek ); + + const TFrameInfo& frameInfo = iDecoder->FrameInfo(); + + TSize decodeSize( frameInfo.iOverallSizeInPixels ); + TBool optimum = CalculateDecodeAndTargetSizes( aTargetSize, decodeSize, aAspectRatio ); + // Make sure "compress only flag is not set". + iFlags &= ~ECompressOnly; + + if ( !optimum ) + { + // use bitmap plane scale + iScaler = CBitmapScaler::NewL(); + iSourceBitmap = new ( ELeave ) CFbsBitmap; + iFlags |= ESourceBitmapOwned; + User::LeaveIfError( iSourceBitmap->Create( + decodeSize, + frameInfo.iFrameDisplayMode ) ); + } + + iDestBitmap = new ( ELeave ) CFbsBitmap; + iFlags |= EDestBitmapOwned; + User::LeaveIfError( iDestBitmap->Create( + aTargetSize, + frameInfo.iFrameDisplayMode ) ); + + if ( frameInfo.iFlags & TFrameInfo::ETransparencyPossible ) + { + if ( !optimum ) + { + iSourceMask = new ( ELeave ) CFbsBitmap; + iFlags |= ESourceMaskOwned; + User::LeaveIfError( iSourceMask->Create( + decodeSize, + frameInfo.iFlags & TFrameInfo::EAlphaChannel ? EGray256 : EGray2 ) ); + } + iDestMask = new ( ELeave ) CFbsBitmap; + iFlags |= EDestMaskOwned; + User::LeaveIfError( iDestMask->Create( + aTargetSize, + frameInfo.iFlags & TFrameInfo::EAlphaChannel ? EGray256 : EGray2 ) ); + delete aDestMask; // just in case + aDestMask = iDestMask; + } + else + { + delete aDestMask; // just in case + aDestMask = NULL; + } + + delete aDestBitmap; //just in case + aDestBitmap = iDestBitmap; + + iFlags &= ~EDestBitmapOwned; + iFlags &= ~EDestMaskOwned; + + DecodeImage(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::CalculateDecodeAndTargetSizes +// +// --------------------------------------------------------- +// +TBool CUniImageProcessor::CalculateDecodeAndTargetSizes( + TSize& aTargetSize, + TSize& aDecodeSize, + TBool aAspectRatio ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: CalculateDecodeAndTargetSizes()" ); + + const TFrameInfo& frameInfo = iDecoder->FrameInfo(); + aDecodeSize = frameInfo.iOverallSizeInPixels; + + if ( aTargetSize.iWidth >= aDecodeSize.iWidth && + aTargetSize.iHeight >= aDecodeSize.iHeight && + !( iFlags & EAllowScalingUp ) ) + { + // No need to scale at all! + iFlags |= ECompressOnly; + aTargetSize = aDecodeSize; + return ETrue; + } + if ( aTargetSize == aDecodeSize ) + { + // No need to scale at all! + iFlags |= ECompressOnly; + return ETrue; + } + + if ( aAspectRatio ) + { + // Adjust target size if aspect ratio needs to be maintained. + TReal scaleRatio = CalculateScaleRatio( aTargetSize, aDecodeSize ); + aTargetSize.iHeight = scaleRatio * aDecodeSize.iHeight; + aTargetSize.iWidth = scaleRatio * aDecodeSize.iWidth; + } + + // Width or height should never be zero. + aTargetSize.iWidth = Max(aTargetSize.iWidth, 1); + aTargetSize.iHeight = Max(aTargetSize.iHeight, 1); + + TInt wRatio = aDecodeSize.iWidth / aTargetSize.iWidth; + TInt hRatio = aDecodeSize.iHeight / aTargetSize.iHeight; + + TBool decodeOnly( frameInfo.iFlags & TFrameInfo::EFullyScaleable ); + + if ( !decodeOnly && + !( aDecodeSize.iWidth % aTargetSize.iWidth || + aDecodeSize.iHeight % aTargetSize.iHeight || + wRatio != hRatio || + (wRatio != 2 && wRatio != 4 && wRatio != 8) || + (hRatio != 2 && hRatio != 4 && hRatio != 8) ) ) + { + decodeOnly = ETrue; + } + + if ( decodeOnly ) + { + // Decoding directly to requested target size. + aDecodeSize = aTargetSize; + } + else + { + TInt decodeFactor = 8; + while ( decodeFactor > 1 ) + { + if ( aDecodeSize.iWidth / decodeFactor >= aTargetSize.iWidth && + aDecodeSize.iHeight / decodeFactor >= aTargetSize.iHeight ) + { + // Smallest 1/2^n factor that creates image larger than target size + break; + } + decodeFactor /= 2; + } + if ( ( iFlags & EOnlyDecodeTimeScaling ) && decodeFactor < 8 ) + { + // Largest 1/2^n factor that creates image smaller than target size + decodeFactor *= 2; + decodeOnly = ETrue; + } + aDecodeSize.iWidth = ( aDecodeSize.iWidth + decodeFactor - 1 ) / decodeFactor; + aDecodeSize.iHeight = ( aDecodeSize.iHeight + decodeFactor - 1 ) / decodeFactor; + if ( decodeOnly ) + { + // Decoding to target size. Make sure target & decode sizes match. + // Target size may need to be changed was iOnlyDecodeTimeScaling is used. + aTargetSize = aDecodeSize; + } + } + return decodeOnly; + } + + +// --------------------------------------------------------- +// CUniImageProcessor::DecodeImage +// +// --------------------------------------------------------- +// +void CUniImageProcessor::DecodeImage() + { + UNILOGGER_ENTERFN( "CUniImageProcessor: DecodeImage()" ); + + iStatus = KRequestPending; + if ( iScaler ) + { + if ( iSourceMask ) + { + iDecoder->Convert( &iStatus, *iSourceBitmap, *iSourceMask ); + } + else + { + iDecoder->Convert( &iStatus, *iSourceBitmap ); + } + } + else + { + if ( iDestMask ) + { + iDecoder->Convert( &iStatus, *iDestBitmap, *iDestMask ); + } + else + { + iDecoder->Convert( &iStatus, *iDestBitmap ); + } + } + SetActive(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::ScaleImage +// +// --------------------------------------------------------- +// +void CUniImageProcessor::ScaleImage( TBool aMask ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: ScaleImage()" ); + + iStatus = KRequestPending; + if ( aMask ) + { + iScaler->Scale( &iStatus, *iSourceMask, *iDestMask, iAspectRatio ); + } + else + { + iScaler->Scale( &iStatus, *iSourceBitmap, *iDestBitmap, iAspectRatio ); + } + SetActive(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::EncodeImageL +// +// --------------------------------------------------------- +// +void CUniImageProcessor::EncodeImageL( TBool aCompressing ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: EncodeImageL()" ); + + if ( aCompressing ) + { + delete iEncoder; + iEncoder = NULL; + // Make sure that the file is empty. + User::LeaveIfError( iDestFile->SetSize( 0 ) ); + iEncoder = CImageEncoder::FileNewL( *iDestFile, KMsgMimeImageJpeg ); + } + iCompressTriesLeft--; + iStatus = KRequestPending; + iEncoder->Convert( &iStatus, *iDestBitmap, iFrameImageData ); + SetActive(); + } + +// --------------------------------------------------------- +// CUniImageProcessor::DoCancel +// +// --------------------------------------------------------- +// +void CUniImageProcessor::DoCancel() + { + UNILOGGER_ENTERFN( "CUniImageProcessor: DoCancel()" ); + if ( iDecoder ) + { + iDecoder->Cancel(); + } + if ( iScaler ) + { + iScaler->Cancel(); + } + if ( iEncoder ) + { + iEncoder->Cancel(); + } + + iError = KErrCancel; + iCallback->ImageProcessingReady( TSize(), 0, EFalse ); + } + +// --------------------------------------------------------- +// CUniImageProcessor::RunL +// +// --------------------------------------------------------- +// +void CUniImageProcessor::RunL() + { + UNILOGGER_ENTERFN( "CUniImageProcessor: RunL()" ); + UNILOGGER_WRITEF( _L("iStatus: %d"), iStatus.Int() ); + TSize size( 0, 0 ); + if ( iStatus < 0 ) + { + iError = iStatus.Int(); + } + if ( iError ) + { + UNILOGGER_WRITE( "Error occured. Scaling aborted." ); + TBool compressed( EFalse ); + if ( iTargetFileSize && + iCompressTriesLeft != KIterationCount && + !( iFlags & EImplicitCompress ) ) + { + compressed = ETrue; + } + Reset(); + iCallback->ImageProcessingReady( size, 0, compressed ); + } + else if ( iDecoder ) + { + delete iDecoder; + iDecoder = NULL; + if ( iScaler ) + { + if ( iSourceMask ) + { + //scale mask first + ScaleImage( ETrue ); + } + else + { + ScaleImage( EFalse ); + } + } + else if ( iEncoder ) + { + if ( iFlags & ECompressOnly ) + { + ResolveQFactorL(); + } + // In "compress only" case the "aCompressing" flag is + // EFalse for first time because we do not want + // to delete & recreate CImageEncoder unnecessarily. + EncodeImageL( EFalse ); + } + else + { + UNILOGGER_WRITE( "Scaling ready (no scaling nor endocing)." ); + size = iDestBitmap->SizeInPixels(); + Reset(); + iCallback->ImageProcessingReady( size, iResultFileSize, EFalse ); + } + } + else if ( iScaler ) + { + if ( iSourceMask ) + { + delete iSourceMask; + iSourceMask = NULL; + iFlags &= ~ESourceMaskOwned; + //mask already scaled, scale bitmap + ScaleImage( EFalse ); + } + else + { + delete iScaler; + iScaler = NULL; + if ( iEncoder ) + { + EncodeImageL( EFalse ); + } + else + { + UNILOGGER_WRITE( "Scaling ready (no endocing)." ); + size = iDestBitmap->SizeInPixels(); + Reset(); + iCallback->ImageProcessingReady( size, iResultFileSize, EFalse ); + } + } + } + else + { + UNILOGGER_WRITE( "Scaling ready." ); + if ( CheckEncodedFileSize() || + ( iCompressTriesLeft <= 0 ) ) + { + size = iDestBitmap->SizeInPixels(); + TBool compressed( EFalse ); + if ( iTargetFileSize && + iCompressTriesLeft != KIterationCount && + !( iFlags & EImplicitCompress ) ) + { + compressed = ETrue; + } + Reset(); + iCallback->ImageProcessingReady( size, iResultFileSize, compressed ); + } + else + { + ResolveQFactorL(); + EncodeImageL( ETrue ); + } + } + } + +// --------------------------------------------------------- +// CUniImageProcessor::RunError +// +// --------------------------------------------------------- +// +TInt CUniImageProcessor::RunError( TInt aError ) + { + UNILOGGER_ENTERFN( "CUniImageProcessor: RunError()" ); + UNILOGGER_WRITEF( _L("aError: %d"), aError ); + iError = aError; + Cancel(); + //Complete self. + iStatus = KRequestPending; + TRequestStatus* pStatus = &iStatus; + SetActive(); + User::RequestComplete( pStatus, KErrNone ); + return KErrNone; + } + +// --------------------------------------------------------- +// CUniImageProcessor::Reset +// +// --------------------------------------------------------- +// +EXPORT_C void CUniImageProcessor::Reset() + { + UNILOGGER_ENTERFN( "CUniImageProcessor: Reset()" ); + iDestFile = NULL; + + delete iDecoder; + iDecoder = NULL; + + delete iScaler; + iScaler = NULL; + + delete iEncoder; + iEncoder = NULL; + + delete iFrameImageData; + iFrameImageData = NULL; + + if ( iFlags & ESourceBitmapOwned ) + { + delete iSourceBitmap; + } + + iSourceBitmap = NULL; + iFlags &= ~ESourceBitmapOwned; + + if ( iFlags & EDestBitmapOwned ) + { + delete iDestBitmap; + } + + iDestBitmap = NULL; + iFlags &= ~EDestBitmapOwned; + + if ( iFlags & ESourceMaskOwned ) + { + delete iSourceMask; + } + + iSourceMask = NULL; + iFlags &= ~ESourceMaskOwned; + + if ( iFlags & EDestMaskOwned ) + { + delete iDestMask; + } + + iDestMask = NULL; + iFlags &= ~EDestMaskOwned; + } + + +// --------------------------------------------------------- +// CUniImageProcessor::CreateImageDataL +// +// --------------------------------------------------------- +// +void CUniImageProcessor::CreateImageDataL( const TDesC8& aTargetType, const TSize& aTargetSize ) + { + if ( aTargetType.CompareF( KMsgMimeImageJpeg ) == 0 ) + { + TInt targetQF( KJpegQualityFactorNormal ); + if ( aTargetSize.iWidth <= KHighQualityMaxWidth && + aTargetSize.iHeight <= KHighQualityMaxHeight ) + { + //Use higher quality factor for small images + targetQF = KJpegQualityFactorHigh; + } + + // Use original image data if available + if ( iDecoder ) + { + iFrameImageData = iDecoder->FrameData().AllocL(); + + TInt imageDataCount = iFrameImageData->ImageDataCount(); + while ( imageDataCount-- ) + { + TImageDataBlock* data = iFrameImageData->GetImageData( imageDataCount ); + const TUid type = data->DataType(); + if ( type == KJPGQTableUid ) + { + TJpegQTable* qdata = static_cast( data ); + if ( qdata->iTableIndex != TJpegQTable::ELumaTable && + qdata->iTableIndex != TJpegQTable::EChromaTable ) + { + // Jpeg encoder supports only two QTables. Others (probably + // another chroma table) must be removed. Otherwise Jpeg + // encoder leaves. + iFrameImageData->RemoveImageData( imageDataCount ); + delete qdata; + } + } + else if ( type == KJPGImageDataUid ) + { + iJpegImageData = static_cast( data ); + // iSourceBitmap is NULL, if image is in right size + iOriginalQualityFactor = iJpegImageData->iQualityFactor; + if ( iSourceBitmap ) + { + CalculateMPixfactorL(); + iJpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ; + iQFactorCalculated = ETrue; + } + } + } + } + if ( !iJpegImageData ) + { + // Delete possibly existing iFrameImageData. There maybe one at least + // when converting PNG images to JPEG. + delete iFrameImageData; + iFrameImageData = NULL; + iFrameImageData = CFrameImageData::NewL(); + TJpegImageData* jpegImageData = new ( ELeave ) TJpegImageData; + CleanupStack::PushL( jpegImageData ); + jpegImageData->iSampleScheme = TJpegImageData::EColor420; + + iOriginalQualityFactor = targetQF; + if ( iSourceBitmap ) + { + iMPixFactor = Max ( KMPixfactorMin, + ( static_cast( iSourceBitmap->SizeInPixels().iWidth ) * + static_cast( iSourceBitmap->SizeInPixels().iHeight ) ) / KQFMPixfactor ); + iMPixFactor = Min( iMPixFactor, KMPixfactorMax ); + jpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ; + iQFactorCalculated = ETrue; + } + else + { + jpegImageData->iQualityFactor = iOriginalQualityFactor ; + } + User::LeaveIfError( iFrameImageData->AppendImageData( jpegImageData ) ); + iJpegImageData = jpegImageData; + CleanupStack::Pop(); // jpegFormat, ownership transferred + } + } + } + +// ---------------------------------------------------------------------------- +// CUniImageProcessor::CalculateScaleRatio +// +// Calculates correct scaling ratio when aspect ratio needs to be preserved. +// Correct scaling ratio is the smaller of the width and height original image +// size and target image size ratios. +// ---------------------------------------------------------------------------- +// +TReal CUniImageProcessor::CalculateScaleRatio( const TSize& aTargetSize, + const TSize& aOriginalSize ) const + { + TReal widthRatio = static_cast( aTargetSize.iWidth ) / + static_cast( aOriginalSize.iWidth ); + TReal heightRatio = static_cast( aTargetSize.iHeight ) / + static_cast( aOriginalSize.iHeight ); + return ( widthRatio < heightRatio ) ? widthRatio : heightRatio; + } + +// --------------------------------------------------------- +// CUniImageProcessor::ResolveQFactorL +// +// --------------------------------------------------------- +// +void CUniImageProcessor::ResolveQFactorL() + { + UNILOGGER_ENTERFN( "CUniImageProcessor: ResolveQFactorL()" ); + + // Leave if "JPGImageData" was not found. + if ( !iJpegImageData ) + { + User::Leave( KErrNotSupported ); + } + + if ( !iQFactorCalculated ) // First try + { + if ( iSourceBitmap ) + { + CalculateMPixfactorL(); + iJpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ; + } + else + { + iJpegImageData->iQualityFactor = iOriginalQualityFactor * + KPercentCoefficientsCounts[ iMPixFactor - 1 ][Min( KIterationCount-iCompressTriesLeft, KIterationCount )] / 100; + + } + iQFactorCalculated = ETrue; + } + else + { + iJpegImageData->iQualityFactor = iOriginalQualityFactor * + KPercentCoefficientsCounts[ iMPixFactor - 1 ][Min( KIterationCount-iCompressTriesLeft, KIterationCount )] / 100; + } + + if ( iJpegImageData->iQualityFactor <= 0 ) + { + iJpegImageData->iQualityFactor = 0; + iCompressTriesLeft = 0; // No use to iterate more than this. + } + } + +// --------------------------------------------------------- +// CUniImageProcessor::CheckEncodedFileSize +// +// --------------------------------------------------------- +// +TBool CUniImageProcessor::CheckEncodedFileSize() + { + TBool retVal = ETrue; + + // Get encoded file size. + // Store possible error to "iError". + iError = iDestFile->Size( iResultFileSize ); + + if ( iTargetFileSize ) + { + // Compression requested. Check whether the size is small enough. + retVal = ( iResultFileSize <= iTargetFileSize ); + } + return retVal; + } + +// --------------------------------------------------------- +// CUniImageProcessor::CalculateMPixfactorL +// +// --------------------------------------------------------- +// +void CUniImageProcessor::CalculateMPixfactorL() + { + if ( iSourceBitmap ) + { + iMPixFactor = Max ( KMPixfactorMin, + ( static_cast( iSourceBitmap->SizeInPixels().iWidth ) * + static_cast( iSourceBitmap->SizeInPixels().iHeight ) ) / KQFMPixfactor ); + } + if (iMPixFactor == KMPixfactorMin ) + { + // Sometimes on the emulator bitmap dimensions show completely wrong values. + // Whether this happens also on the device is unknown + // Just in case use files size as second option + // As image size changes more rapidly as image dimension use extra divider + if ( iTargetFileSize >= 0 ) + { + iMPixFactor = Max( KMPixfactorMin, ( iOriginalFileSize / iTargetFileSize ) / KMPixSizeDivider ); + } + } + iMPixFactor = Min( iMPixFactor, KMPixfactorMax ); + } + +// End of File