--- /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 <e32base.h>
+#include <fbs.h>
+#include <e32math.h>
+#include <bitdev.h>
+#include <bitstd.h>
+
+#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;
+ }