diff -r 000000000000 -r e686773b3f54 phonebookui/Phonebook2/Presentation/src/CPbk2ImageReader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookui/Phonebook2/Presentation/src/CPbk2ImageReader.cpp Tue Feb 02 10:12:17 2010 +0200 @@ -0,0 +1,614 @@ +/* +* Copyright (c) 2005-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: +* Provides Phonebook2 image reader class methods. +* +*/ + + +// INCLUDE FILES +#include "CPbk2ImageReader.h" + +// From Phonebook2 +#include "MPbk2ImageReaderObserver.h" +#include "TPbk2ImageManagerParams.h" + +// From Virtual Phonebook + +// From System +#include +#include +#include + +/// Unnamed namespace for local defintions +namespace { + +// ============== LOCAL CONSTANTS AND MACROS =============== + +enum TReaderState + { + EStateIntialize = 0, + EStateOpenImage, + EStateConvertImageToBitmap, + EStateScaleBitmap, + EStateComplete, + EStateCancelled + }; + +// Definition for max mime type length +const TInt KMaxMimeTypeLength(256); + +#ifdef _DEBUG +enum TPanicCode + { + EPanicPreCond_ConvertImageToBitmapL = 1, + EPanicPreCond_ScaleBitmapL, + EPanicPreCond_Complete, + EPanicPostCond_Complete, + EPanicPostCond_OptimalLoadingSize + }; +#endif // _DEBUG + + +// ==================== LOCAL FUNCTIONS ==================== + +#ifdef _DEBUG +void Panic(TPanicCode aPanicCode) + { + _LIT(KPanicText, "CPbk2ImageReader"); + User::Panic(KPanicText, aPanicCode); + } +#endif // _DEBUG + +// -------------------------------------------------------------------------- + +/** + * Comparison operator for TSize objects. Compares width and height members. + * + * @param aLhs Reference to left hand side TSize + * @param aRhs Reference to right hand side TSize + * @return ETrue if lhs's width and height are less or equal to rhs's + * width and height. Otherwise returns EFalse. + */ +inline TBool operator<=(const TSize& aLhs, const TSize& aRhs) + { + return (aLhs.iWidth<=aRhs.iWidth && aLhs.iHeight<=aRhs.iHeight); + } + +/** + * Ceils division result based on modulus. + * + * @param aVal Divident. + * @param aDiv Divider. + * @return If modulus is zero, returns the result of aVal / aDiv. Otherwise + * returns returns the result of aVal / aDiv increased by one. + * + * NOTE: Copied from CPalbBitmap, remove when possible + */ +TInt Ceil(const TInt aVal, const TInt aDiv) + { + return (((aVal%aDiv)>0) ? (TInt)((aVal/aDiv)+1):(TInt)(aVal/aDiv)); + } + + +/** + * Calculates the the size based on divider. Uses Ceil function for ceiling + * the calculated size. + * + * @param aSize Orginal size. + * @param aDiv Divider. + * @return Calculated size. The result's width and height might be adjusted + * according to the results of calling Ceil function. + * + * @see Ceil + * + * NOTE: Copied from CPalbBitmap, remove when possible + */ + TSize SizeDividedByValueAndCeil(const TSize& aSize, const TInt aDiv) + { + return TSize( + Ceil( aSize.iWidth, aDiv), + Ceil( aSize.iHeight, aDiv) ); + } + +/** + * Calculates the optimal loading size. If optimal loading size cannot be + * calculated, function panics with + * CPbk2ImageReader:EPanicPostCond_OptimalLoadingSize panic code. + * + * @param aOriginalSize Orginal size. + * @param aNeededSize Needed size. + * @return Calculated optimal size. + * + * @see SizeDividedByValueAndCeil + * @see Ceil + * + * NOTE: Copied from CPalbBitmap, remove when possible + */ +TSize OptimalLoadingSize(const TSize& aOriginalSize, const TSize& aNeededSize) + { + TSize resSize = SizeDividedByValueAndCeil( aOriginalSize, 8 ); + if( !(aNeededSize <= resSize) ) + { + resSize = SizeDividedByValueAndCeil( aOriginalSize, 4 ); + if( !(aNeededSize <= resSize) ) + { + resSize = SizeDividedByValueAndCeil( aOriginalSize, 2 ); + if( !(aNeededSize <= resSize) ) + { + resSize = aOriginalSize; + } + } + } + + // if the resulting size is not the original size, + // it has to be between needed size and original size + __ASSERT_DEBUG(resSize == aOriginalSize + || (aNeededSize <= resSize && resSize <= aOriginalSize), + Panic(EPanicPostCond_OptimalLoadingSize)); + + return resSize; + } + +} // namespace + + +// ================= MEMBER FUNCTIONS ======================= + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::CPbk2ImageReader +// -------------------------------------------------------------------------- +// +inline CPbk2ImageReader::CPbk2ImageReader + (MPbk2ImageReaderObserver& aObserver) : + CActive(CActive::EPriorityStandard), + iObserver(aObserver) + { + CActiveScheduler::Add(this); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::~CPbk2ImageReader +// -------------------------------------------------------------------------- +// +CPbk2ImageReader::~CPbk2ImageReader() + { + Cancel(); + delete iBitmapScaler; + delete iImageDecoder; + delete iMimeString; + delete iBitmap; + iFsSession.Close(); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::NewL +// -------------------------------------------------------------------------- +// +CPbk2ImageReader* CPbk2ImageReader::NewL + (MPbk2ImageReaderObserver& aObserver) + { + CPbk2ImageReader* self = new(ELeave) CPbk2ImageReader(aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::ConstructL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::ConstructL() + { + User::LeaveIfError(iFsSession.Connect()); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::ReadFromFileL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::ReadFromFileL + (const TDesC& aFileName, const TPbk2ImageManagerParams* aParams) + { + InitReadL(aParams); + delete iImageDecoder; + iImageDecoder = NULL; + iImageDecoder = CImageDecoder::FileNewL(iFsSession, aFileName); + + // Make the open phase asynchronous as well by signaling own iStatus + iState = EStateOpenImage; + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::ReadFromBufferL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::ReadFromBufferL + (const TDesC8& aBuffer, const TPbk2ImageManagerParams* aParams/*=NULL*/) + { + InitReadL(aParams); + delete iImageDecoder; + iImageDecoder = NULL; + iImageDecoder = CImageDecoder::DataNewL(iFsSession, aBuffer); + + // Make the open phase asynchronous as well by signaling own iStatus + iState = EStateOpenImage; + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::MimeString +// -------------------------------------------------------------------------- +// +const TDesC8& CPbk2ImageReader::MimeString() const + { + if (iMimeString) + { + return *iMimeString; + } + else + { + return KNullDesC8; + } + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::RecognizeFormatFromFileL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::RecognizeFormatFromFileL(const TDesC& aFileName) + { + delete iMimeString; + iMimeString = NULL; + iMimeString = HBufC8::NewL(KMaxMimeTypeLength); + TPtr8 mimePtr = iMimeString->Des(); + CImageDecoder::GetMimeTypeFileL(iFsSession, aFileName, mimePtr); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::RecognizeFormatFromBufferL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::RecognizeFormatFromBufferL(const TDesC8& aBuffer) + { + delete iMimeString; + iMimeString = NULL; + iMimeString = HBufC8::NewL(KMaxMimeTypeLength); + TPtr8 mimePtr = iMimeString->Des(); + CImageDecoder::GetMimeTypeDataL(aBuffer, mimePtr); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::FrameInfo +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::FrameInfo(TInt aFrame, TFrameInfo& aInfo) const + { + aInfo = iImageDecoder->FrameInfo(aFrame); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::FrameCount +// -------------------------------------------------------------------------- +// +TInt CPbk2ImageReader::FrameCount() const + { + return iImageDecoder->FrameCount(); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::NextStateL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::NextStateL() + { + ++iState; + + switch (iState) + { + case EStateConvertImageToBitmap: + { + ConvertImageToBitmapL(); + break; + } + case EStateScaleBitmap: + { + CropImageToSquareL(); + ScaleBitmapL(); + break; + } + case EStateComplete: + { + Complete(); + break; + } + default: + { + // iImageReader might sometimes complete although it has been canceled. + // Catch those cases here. + break; + } + } + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::ConvertImageToBitmapL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::ConvertImageToBitmapL() + { + __ASSERT_DEBUG(iImageDecoder && !iBitmap, + Panic(EPanicPreCond_ConvertImageToBitmapL)); + + // Get image size + const TFrameInfo& frameInfo = + iImageDecoder->FrameInfo(iParams.iFrameNumber); + TSize bitmapSize = frameInfo.iOverallSizeInPixels; + if (iParams.iFlags & TPbk2ImageManagerParams::EScaleImage) + { + // Get optimal loading size >= desired size + bitmapSize = OptimalLoadingSize(bitmapSize,iParams.iSize); + } + + // Create bitmap + delete iBitmap; + iBitmap = NULL; + iBitmap = new(ELeave) CFbsBitmap; + User::LeaveIfError(iBitmap->Create(bitmapSize, iParams.iDisplayMode)); + + // Convert image to bitmap + iImageDecoder->Convert(&iStatus, *iBitmap, iParams.iFrameNumber); + SetActive(); + } + + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::CropImageToSquareL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::CropImageToSquareL() + { + TInt useCropping = 0x0008; + // if cropping is wanted + if( iParams.iFlags & useCropping ) //TODO change value ( contacts_plat/image_managemet_api/TPbk2ImageManagerParams ) + { + TSize size = iBitmap->SizeInPixels(); + // crop the image only if the width is bigger than height + if( size.iHeight >= size.iWidth ) + { + // no cropping + return; + } + // take the shorter side + TInt sideSize = size.iHeight; + + // set target size + TSize targetSize( sideSize,sideSize ); + + // crop from both sides + TRect targetRect( TPoint( ( size.iWidth - targetSize.iWidth ) / 2, + ( size.iHeight - targetSize.iHeight ) / 2 ), + targetSize ); + + // create new bitmap + CFbsBitmap* target = new( ELeave ) CFbsBitmap; + CleanupStack::PushL( target ); + User::LeaveIfError( target->Create( targetSize, iBitmap->DisplayMode() ) ); + + // get scanline + HBufC8* scanLine = HBufC8::NewLC( iBitmap->ScanLineLength + ( targetSize.iWidth, iBitmap->DisplayMode() ) ); + TPtr8 scanLinePtr = scanLine->Des(); + + TPoint startPoint( targetRect.iTl.iX, targetRect.iTl.iY ); + TInt targetY = 0; + for (; startPoint.iY < targetRect.iBr.iY; ++startPoint.iY ) + { + iBitmap->GetScanLine( scanLinePtr, startPoint, targetSize.iWidth, iBitmap->DisplayMode() ); + target->SetScanLine( scanLinePtr, targetY++ ); + } + + iBitmap->Reset(); + User::LeaveIfError( iBitmap->Duplicate( target->Handle() ) ); + CleanupStack::PopAndDestroy(2, target); // scanLine, target + } + } + + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::ScaleBitmapL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::ScaleBitmapL() + { + __ASSERT_DEBUG(iBitmap, Panic(EPanicPreCond_ScaleBitmapL)); + + if ((iParams.iFlags & TPbk2ImageManagerParams::EScaleImage) && + !(iParams.iFlags & TPbk2ImageManagerParams::EUseFastScaling)) + { + const TSize bitmapSize = iBitmap->SizeInPixels(); + if (bitmapSize.iWidth > iParams.iSize.iWidth || + bitmapSize.iHeight > iParams.iSize.iHeight) + { + if (!iBitmapScaler) + { + iBitmapScaler = CBitmapScaler::NewL(); + } + iBitmapScaler->Scale(&iStatus, *iBitmap, iParams.iSize); + SetActive(); + return; + } + } + + // No scaling requested or needed, go directly to next state + NextStateL(); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::Complete +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::Complete() + { + __ASSERT_DEBUG(iImageDecoder && iBitmap, Panic(EPanicPreCond_Complete)); + + // End state machine + ++iState; + + // Close the image source + CloseImage(); + + // Release ownership of iBitmap + CFbsBitmap* bitmap = iBitmap; + iBitmap = NULL; + + __ASSERT_DEBUG(!iImageDecoder && !iBitmap, + Panic(EPanicPostCond_Complete)); + + // Notify observer about completion + iObserver.ImageReadComplete(*this,bitmap); + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::InitReadL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::InitReadL(const TPbk2ImageManagerParams* aParams) + { + Cancel(); + if (aParams) + { + iParams = *aParams; + } + iState = EStateOpenImage; + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::CloseImage +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::CloseImage() + { + delete iImageDecoder; + iImageDecoder = NULL; + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::RunL +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::RunL() + { + TInt status = iStatus.Int(); + switch (status) + { + case KErrNone: + { + if (iState == EStateOpenImage) + { + iObserver.ImageOpenComplete(*this); + } + NextStateL(); + break; + } + case KErrCancel: + { + // In case of cancel the observer is not signaled + break; + } + default: + { + // Jpeg2000 decoder might need more heap than Phonebook can + // provide, the situation is handled so, that "Feature not + // supported" -note is shown if memory runs out when decoding + // Jpeg2000 image instead of "Out of memory" -note. + // + // Small jp2 images (e.g. 50*50 pixels) can be decoded, but + // heap runs out when decoding e.g. 1 mega pixel image. + // + // Increasing phonebook heap size doesn't help on this issue, + // since jp2 decoder heap usage is increased linearly when a bigger + // image is tried to be decoded. + if ( status == KErrNoMemory ) + { + TUid imageType; + TUid imageSubType; + iImageDecoder->ImageType(iParams.iFrameNumber, + imageType, + imageSubType); + + if ( imageType.iUid == KImageTypeJ2KUid ) + { + status = KErrNotSupported; + } + } + iObserver.ImageReadFailed(*this, status); + break; + } + } + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::Cancel +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::Cancel() + { + if (!IsActive()) + { + DoCancel(); + } + else + { + CActive::Cancel(); + } + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::RunError +// -------------------------------------------------------------------------- +// +TInt CPbk2ImageReader::RunError(TInt aError) + { + iObserver.ImageReadFailed(*this, aError); + return KErrNone; + } + +// -------------------------------------------------------------------------- +// CPbk2ImageReader::DoCancel +// -------------------------------------------------------------------------- +// +void CPbk2ImageReader::DoCancel() + { + if (iImageDecoder) + { + iImageDecoder->Cancel(); + } + if (iBitmapScaler) + { + iBitmapScaler->Cancel(); + } + CloseImage(); + delete iBitmap; + iBitmap = NULL; + iState = EStateCancelled; + } + +// End of File