diff -r 000000000000 -r 2014ca87e772 imagehandlingutilities/thumbnailmanager/thumbnailserver/src/thumbnailscaletask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imagehandlingutilities/thumbnailmanager/thumbnailserver/src/thumbnailscaletask.cpp Tue Jan 26 15:18:05 2010 +0200 @@ -0,0 +1,430 @@ +/* +* 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: Task for scaling thumbnails. + * +*/ + + +#include +#include +#include +#include +#include + +#include "thumbnailscaletask.h" +#include "thumbnailprovider.h" +#include "thumbnailserver.h" +#include "thumbnailmanagerconstants.h" +#include "thumbnaillog.h" +#include "thumbnailpanic.h" + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::NewL() +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CThumbnailScaleTask* CThumbnailScaleTask::NewL( CThumbnailTaskProcessor& + aProcessor, CThumbnailServer& aServer, const TDesC& aFilename, CFbsBitmap* + aBitmap, const TSize& aOriginalSize, const TSize& aTargetSize, TBool aCrop, + TDisplayMode aDisplayMode, TInt aPriority, const TDesC& aTargetUri, + const TThumbnailSize aThumbnailSize, const TThumbnailId aThumbnailId, + TBool aBitmapToPool, const TBool aEXIF) + { + // We take ownership of aBitmap + CleanupStack::PushL( aBitmap ); + CThumbnailScaleTask* self = new( ELeave )CThumbnailScaleTask( aProcessor, + aServer, aFilename, aBitmap, aOriginalSize, aTargetSize, aCrop, + aDisplayMode, aPriority, aTargetUri, aThumbnailSize, aThumbnailId, + aBitmapToPool, aEXIF); + CleanupStack::Pop( aBitmap ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::CThumbnailScaleTask() +// C++ default constructor can NOT contain any code, that might leave. +// --------------------------------------------------------------------------- +// +CThumbnailScaleTask::CThumbnailScaleTask( CThumbnailTaskProcessor& aProcessor, + CThumbnailServer& aServer, const TDesC& aFilename, CFbsBitmap* aBitmap, + const TSize& aOriginalSize, const TSize& aTargetSize, TBool aCrop, + TDisplayMode aDisplayMode, TInt aPriority, const TDesC& aTargetUri, + const TThumbnailSize aThumbnailSize, const TThumbnailId aThumbnailId, + TBool aBitmapToPool, const TBool aEXIF): + CThumbnailTask( aProcessor, aPriority ), iServer( aServer ), iOwnBitmap( aBitmap ), + iOriginalSize( aOriginalSize ), iTargetSize( aTargetSize ), iCrop( aCrop ), + iDisplayMode( aDisplayMode ), iFilename( aFilename ), iTargetUri( aTargetUri ), + iThumbnailSize(aThumbnailSize), iThumbnailId(aThumbnailId), + iBitmapToPool(aBitmapToPool), iEXIF(aEXIF) + { + TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::CThumbnailScaleTask()", this ); + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::ConstructL() +// Symbian 2nd phase constructor can leave. +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::ConstructL() + { + iServer.AddBitmapToPoolL( NULL, iOwnBitmap ); + + // Successfully added bitmap to pool, we are no longer responsible for + // deleting it directly. + iBitmap = iOwnBitmap; + iOwnBitmap = NULL; + iBitmapInPool = ETrue; + + iScaledBitmap = NULL; + iScaledBitmapHandle = 0; + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::~CThumbnailScaleTask() +// Destructor. +// --------------------------------------------------------------------------- +// +CThumbnailScaleTask::~CThumbnailScaleTask() + { + iServer.CancelScale(); + + if ( iBitmapInPool && iBitmap ) + { + TN_DEBUG1("CThumbnailScaleTask()::~CThumbnailScaleTask() delete original bitmap from pool"); + + // Original bitmap is owned by server, decrease reference count + iServer.DeleteBitmapFromPool( iBitmap->Handle()); + } + + if ( iScaledBitmapHandle ) + { + TN_DEBUG1("CThumbnailScaleTask()::~CThumbnailScaleTask() delete scaled bitmap from pool"); + + // Scaled bitmap is owned by server, decrease reference count + iServer.DeleteBitmapFromPool( iScaledBitmapHandle ); + } + + // Scaled bitmap is owned by us, delete now + delete iScaledBitmap; + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::StartL() +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::StartL() + { + TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL()", this ); + + CThumbnailTask::StartL(); + + if ( !iCrop ) + { + // target size at max, keep aspect ratio + CalculateTargetSize(); + } + else + { + // exact target size, crop excess + CalculateCropRectangle(); + } + +#ifdef _DEBUG + aStart.UniversalTime(); +#endif + + delete iScaledBitmap; + iScaledBitmap = NULL; + iScaledBitmap = new( ELeave )CFbsBitmap(); + + TSize bitmapSize = iBitmap->SizeInPixels(); + + if(bitmapSize.iHeight == iTargetSize.iHeight && bitmapSize.iWidth == iTargetSize.iWidth) + { + // copy bitmap 1:1 + User::LeaveIfError( iScaledBitmap->Create( bitmapSize, iBitmap->DisplayMode() )); + CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(iScaledBitmap); + CleanupStack::PushL(device); + CFbsBitGc* gc = NULL; + User::LeaveIfError(device->CreateContext(gc)); + CleanupStack::PushL(gc); + gc->BitBlt(TPoint(0, 0), iBitmap); + CleanupStack::PopAndDestroy(2, device); // gc + + TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL() - no need for scaling", this); + TRAPD( err, StoreAndCompleteL()); + Complete( err ); + ResetMessageData(); + } + else + { + TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL() - scaling", this); + User::LeaveIfError( iScaledBitmap->Create( iTargetSize, iBitmap->DisplayMode() )); + iServer.ScaleBitmapL( iStatus, * iBitmap, * iScaledBitmap, iCropRectangle ); + SetActive(); + } + + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::RunL() +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::RunL() + { + TInt err = iStatus.Int(); + + TN_DEBUG3( "CThumbnailScaleTask(0x%08x)::RunL() err=%d)", this, err ); + + #ifdef _DEBUG + aStop.UniversalTime(); + TN_DEBUG2( "CThumbnailScaleTask::RunL() scale took %d ms", (TInt)aStop.MicroSecondsFrom(aStart).Int64()/1000); + #endif + + if ( !err ) + { + TRAP( err, StoreAndCompleteL()); + } + + Complete( err ); + ResetMessageData(); + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::DoCancel() +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::DoCancel() + { + TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::DoCancel()", this ); + iServer.CancelScale(); + } + + +// --------------------------------------------------------------------------- +// Calculates target size to be used for the thumbnail +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::CalculateTargetSize() + { + __ASSERT_DEBUG( iOriginalSize.iHeight && iTargetSize.iHeight, + ThumbnailPanic( EThumbnailBadSize )); + + if ( (iThumbnailSize == EFullScreenThumbnailSize || + iThumbnailSize == EImageFullScreenThumbnailSize || + iThumbnailSize == EVideoFullScreenThumbnailSize || + iThumbnailSize == EAudioFullScreenThumbnailSize) && + iOriginalSize.iHeight < iTargetSize.iHeight && + iOriginalSize.iWidth < iTargetSize.iWidth ) + { + // do not upscale fullscreen thumbs + iTargetSize = iOriginalSize; + } + else if ( iOriginalSize.iHeight && iTargetSize.iHeight ) + { + const TReal32 srcAspect = static_cast < TReal32 > ( + iOriginalSize.iWidth ) / iOriginalSize.iHeight; + + // scale to maximum size within target size + if ( (iTargetSize.iHeight * srcAspect) <= iTargetSize.iWidth ) + { + TReal trg = 0; + TReal src( iTargetSize.iHeight * srcAspect ); + Math::Round( trg, src, 0 ); + iTargetSize.SetSize( trg, iTargetSize.iHeight ); + } + else + { + TReal trg; + TReal src( iTargetSize.iWidth / srcAspect ); + Math::Round( trg, src, 0 ); + iTargetSize.SetSize( iTargetSize.iWidth, trg ); + } + } + else + { + iTargetSize.SetSize( 0, 0 ); + } + iCropRectangle.SetRect( TPoint(), iBitmap->SizeInPixels()); + } + + +// --------------------------------------------------------------------------- +// Calculates target size to be used for the thumbnail +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::CalculateCropRectangle() + { + const TSize srcSize = iBitmap->SizeInPixels(); + + __ASSERT_DEBUG( srcSize.iHeight && iTargetSize.iHeight, ThumbnailPanic( + EThumbnailBadSize )); + + if ( srcSize.iHeight && iTargetSize.iHeight ) + { + const TReal32 srcAspect = static_cast < TReal32 > ( srcSize.iWidth ) / + srcSize.iHeight; + const TReal32 reqAspect = static_cast < TReal32 > ( iTargetSize.iWidth ) + / iTargetSize.iHeight; + + if ( (iTargetSize.iHeight * srcAspect) > iTargetSize.iWidth ) + { + // Thumbnail is wider than requested and we crop + // some of the right and left parts. + TReal trg; + TReal src( srcSize.iHeight* reqAspect ); + Math::Round( trg, src, 0 ); + const TSize cropSize( trg, srcSize.iHeight ); + iCropRectangle.iTl.SetXY(( srcSize.iWidth - cropSize.iWidth ) / 2, 0 ); + iCropRectangle.SetSize( cropSize ); + } + else + { + // Thumbnail is taller than requested and we crop + // some of the top and bottom parts. + TReal trg; + TReal src( srcSize.iWidth / reqAspect ); + Math::Round( trg, src, 0 ); + const TSize cropSize( srcSize.iWidth, trg ); + iCropRectangle.iTl.SetXY(0, ( srcSize.iHeight - cropSize.iHeight ) / 2 ); + iCropRectangle.SetSize( cropSize ); + } + + } + else + { + iTargetSize.SetSize( 0, 0 ); + } + } + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::StoreAndCompleteL() +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::StoreAndCompleteL() + { + TN_DEBUG5( "CThumbnailScaleTask(0x%08x)::StoreAndCompleteL() iFilename=%S, iBitmap=0x%08x, iScaledBitmap=0x%08x)", + this, &iFilename, iBitmap, iScaledBitmap ); + + // do not store TN if quality is too low eg. orignal size of image is smaller than requested size + // (do not store upscaled images) + if ( iTargetSize.iWidth >= iOriginalSize.iWidth && + iTargetSize.iHeight >= iOriginalSize.iHeight && iEXIF) + { + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() too low quality"); + //don't store preview image + iDoStore = EFalse; + } + + TN_DEBUG3("CThumbnailScaleTask(0x%08x)::StoreAndCompleteL() iDoStore = %d", this, iDoStore); + + if ( iDoStore ) + { + if (iTargetUri != KNullDesC) + { + if (iFilename != KNullDesC && iFilename.CompareF(iTargetUri) == 0) + { + // filename and target URI match, so thumb created from associated path + iServer.StoreThumbnailL( iTargetUri, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, ETrue ); + } + else + { + // thumb not created from associated path + iServer.StoreThumbnailL( iTargetUri, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, EFalse, EFalse ); + } + } + else if (iFilename != KNullDesC) + { + iServer.StoreThumbnailL( iFilename, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, ETrue ); + } + } + + if ( iMessage.Handle() ) + { + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() scaled bitmap handle to params"); + + TThumbnailRequestParams& params = iParamsBuf(); + iMessage.ReadL( 0, iParamsBuf ); + params.iBitmapHandle = iScaledBitmap->Handle(); + + // if need to add scaled bitmap to pool + if (iBitmapToPool) + { + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() scaled bitmap to pool"); + + iServer.AddBitmapToPoolL( iRequestId.iSession, iScaledBitmap ); + iScaledBitmapHandle = params.iBitmapHandle; + } + + if( params.iQualityPreference == CThumbnailManager::EOptimizeForQualityWithPreview + && iEXIF && !iDoStore) + { + // this is upscaled preview image + params.iControlFlags = EThumbnailPreviewThumbnail; + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() EThumbnailPreviewThumbnail"); + } + + // Server owns the bitmap now. If the code below leaves, we will + // release the bitmap reference in destructor using iScaledBitmapHandle. + if (iBitmapToPool) + { + iScaledBitmap = NULL; + } + + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() write params to message"); + + // pass bitmap handle to client + iMessage.WriteL( 0, iParamsBuf ); + + // Successfully completed the message. The client will send + // EReleaseBitmap message later to delete the bitmap from pool. + // CThumbnailScaleTask is no longer responsible for that. + iScaledBitmapHandle = 0; + } + + TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() - end"); + } + + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::StoreAndCompleteL() +// Changes priority of the task. +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::ChangeTaskPriority( TInt /*aNewPriority*/ ) + { + // The priority of scale tasks is fixed. Do nothing. + } + +// --------------------------------------------------------------------------- +// CThumbnailScaleTask::SetDoStore() +// Changes the store flag +// --------------------------------------------------------------------------- +// +void CThumbnailScaleTask::SetDoStore( TBool aDoStore ) + { + iDoStore = aDoStore; + }