/*
* Copyright (c) 2008 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: Image processor and scaler
*
*/
#include "cvimpstimageprocessor.h"
#include "tvimpstconsts.h"
#include <imageconversion.h>
#include <bitmaptransforms.h>
#include <s32file.h>
#include <e32cmn.h>
#include "uiservicetabtracer.h"
// CONSTANTS
const TInt KChatCustomBitmapWidth = 65;
const TInt KChatCustomBitmapHeight = 65;
const TInt KMaxImageSize = 1800; //2k
const TInt KMimeLength = 16;
const TInt KScaleSize = 10;
//-----------------------------------------------------------------------------
// CCAImageLoader::CCAImageLoader
// ( Other items commented in header )
//-----------------------------------------------------------------------------
CVimpstImageProcessor::CVimpstImageProcessor( MCAImageProcessObserver* aObserver )
: CActive( CActive::EPriorityLow ),iObserver(aObserver),iScaleSize(KScaleSize)
{
CActiveScheduler::Add( this );
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::CVimpstImageProcessor
// ( Other items commented in header )
//-----------------------------------------------------------------------------
CVimpstImageProcessor::~CVimpstImageProcessor()
{
iFs.Close();
delete iImageDecoder;
delete iScaler;
delete iImageEncoder;
if(!isBitmapReturned)
{
delete iBitmap;
}
delete iMimeType;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::NewL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
CVimpstImageProcessor* CVimpstImageProcessor::NewL( MCAImageProcessObserver* aObserver)
{
TRACER_AUTO;
CVimpstImageProcessor* self =
new ( ELeave ) CVimpstImageProcessor(aObserver);
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ConstructL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ConstructL()
{
User::LeaveIfError( iFs.Connect() );
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::RunL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::RunL()
{
TRACER_AUTO;
TInt status = iStatus.Int();
if(!status)
{
switch(iProcessingState)
{
case EConvertImageDatatoBitmap:
{
ConvertImageToBitmapL();
break;
}
case EScaleBitmap:
{
ScaleBitmapL();
break;
}
case EConentFromScaledBitmap:
{
ContentFromScaledBitmapL();
break;
}
case EProcessingComplete:
{
if( iContent->Length() > KMaxImageSize)
{
delete iScaler;
iScaler = NULL;
delete iImageEncoder;
iImageEncoder = NULL;
delete iContent;
iTargetSize.SetSize( KChatCustomBitmapWidth - iScaleSize, KChatCustomBitmapHeight - iScaleSize );
iScaleSize += KScaleSize;
ScaleBitmapL();
}
else
{
TRACE("RunL completed ");
CompleteRequestL();
}
break;
}
default:
{
}
}
}
else
{
TRACE("RunL completed ");
CompleteRequestL();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ConvertImageToBitmapL()
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ConvertImageToBitmapL()
{
TRACER_AUTO;
TSize origSize( iImageDecoder->FrameInfo().iOverallSizeInPixels );
ScaleSize( origSize, iTargetSize );
TBool fullyScaleable( iImageDecoder->FrameInfo().iFlags & TFrameInfo::EFullyScaleable );
TSize decodeSize( DecodeSize( origSize, iTargetSize, fullyScaleable ) );
iBitmap = new (ELeave) CFbsBitmap();
User::LeaveIfError( iBitmap->Create( decodeSize,
iImageDecoder->FrameInfo().iFrameDisplayMode ) );
iImageDecoder->Convert( &iStatus, *iBitmap );
iProcessingState = EScaleBitmap; // set state to next step
if( !IsActive() )
{
SetActive();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ScaleBitmapL()
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ScaleBitmapL()
{
TRACER_AUTO;
TSize currentSize( iBitmap ? iBitmap->SizeInPixels() : iTargetSize );
if( currentSize != iTargetSize )
{
// bitmap exists and the size is wrong,
// we have to scale the bitmap
iScaler = CBitmapScaler::NewL();
iScaler->Scale( &iStatus, *iBitmap, iTargetSize );
iProcessingState = EConentFromScaledBitmap; // set state to next step
if( !IsActive() )
{
SetActive();
}
}
else
{ // get content from scaled bitmap
ContentFromScaledBitmapL();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ContentFromScaledBitmapL()
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ContentFromScaledBitmapL()
{
iContent = NULL;
iImageEncoder = CImageEncoder::DataNewL( iContent,*iMimeType);
iImageEncoder->Convert( &iStatus, *iBitmap );
iProcessingState = EProcessingComplete ; // set state to next step
if( !IsActive() )
{
SetActive();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::DoCancel
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::DoCancel()
{
ClearState();
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::RunError
// ( Other items commented in header )
//-----------------------------------------------------------------------------
TInt CVimpstImageProcessor::RunError( TInt aError )
{
if( IsActive() )
{
iStatus = aError;
Cancel();
}
if( aError == KErrNoMemory )
{
CActiveScheduler::Current()->Error( KErrNoMemory );
}
// Clean up and reset all pending messages
ClearState();
TRAP_IGNORE( ResetProcessingL( aError ) );
return KErrNone;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::StartProcessingFromDataL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
TInt CVimpstImageProcessor::ProcessFromDataL( const TDesC8& aImageData , const TDesC8& aMimeType)
{
TRACER_AUTO;
TInt err = KErrNone;
if ( aMimeType.Length())
{
// if the mimetype is passed then allocate the memory
iMimeType = aMimeType.AllocL();
}
else
{
// if no mimetype find the mimetype
iMimeType = HBufC8::NewL( KMimeLength);
TPtr8 mimePtr = iMimeType->Des();
TRAP(err,CImageDecoder::GetMimeTypeDataL( aImageData , mimePtr ));
if(KErrNone != err)
{
return err;
}
}
iImageDecoder = NULL;
// need to check for the mimetype length, as sometimes CImageDecoder::GetMimeTypeDataL
// is alos not able to give the mimetype
iImageDecoder = CImageDecoder::DataNewL(iFs, aImageData , *iMimeType);
iProcessingState = EConvertImageDatatoBitmap;
RunL();
return err;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ProcessFromFileL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ProcessFromFileL( const TDesC& aFileName , const TDesC8& aMimeType)
{
TRACER_AUTO;
iMimeType = aMimeType.AllocL();
iImageDecoder = NULL;
iImageDecoder = CImageDecoder::FileNewL(iFs, aFileName, *iMimeType );
iProcessingState = EConvertImageDatatoBitmap;
RunL();
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::CancelProcessing
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::CancelProcessing()
{
if( IsActive() )
{
Cancel();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::RegisterObserver
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::RegisterObserver( MCAImageProcessObserver* aObserver )
{
iObserver = aObserver;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::GetContentData
// ( Other items commented in header )
//-----------------------------------------------------------------------------
HBufC8* CVimpstImageProcessor::GetContentData()
{
return iContent;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::Bitmap
// ( Other items commented in header )
//-----------------------------------------------------------------------------
CFbsBitmap& CVimpstImageProcessor::Bitmap()
{
isBitmapReturned = ETrue;
return *iBitmap;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::DecodeSize
// Scale to nearest (larger or equal) size with ratio 1:1, 1:2, 1:4 or 1:8
//-----------------------------------------------------------------------------
TSize CVimpstImageProcessor::DecodeSize( const TSize& aSize, const TSize& aTargetSize,
TBool aAnyRatio )
{
TRACER_AUTO;
if( aAnyRatio || aSize == aTargetSize )
{
// decoder can scale to any ratio or the size is already correct
return aTargetSize;
}
// 1:1 is always valid ratio for decode scaling
TInt lastValidRatio( 1 );
for( TInt ratio( KDecodeScaleRatioMin ); ratio <= KDecodeScaleRatioMax; ratio <<= 1 )
{
if( aSize.iWidth % ratio + aSize.iHeight % ratio == 0 )
{
// this ratio is valid
if( aSize.iWidth / ratio < aTargetSize.iWidth ||
aSize.iHeight / ratio < aTargetSize.iHeight )
{
// the decoded size was smaller in some dimension,
// the last valid ratio should be used
break;
}
// this scale ratio results to greater or equal size
lastValidRatio = ratio;
}
}
// return the size scaled with correct ratio
return TSize( aSize.iWidth / lastValidRatio,
aSize.iHeight / lastValidRatio );
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ScaleSize
// ( Other items commented in header )
//-----------------------------------------------------------------------------
TBool CVimpstImageProcessor::ScaleSize( const TSize& aSize, TSize& aNewSize )
{
if( Max( aSize.iHeight, aSize.iWidth ) > KChatCustomBitmapWidth )
{
aNewSize.SetSize( KChatCustomBitmapWidth, KChatCustomBitmapHeight );
return ETrue;
}
// old size is correct
aNewSize = aSize;
return EFalse;
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::CompleteRequestL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::CompleteRequestL()
{
iObserver->HandleProcessingCompleteL( iStatus.Int() );
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ResetProcessingL
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ResetProcessingL( TInt aReason )
{
// cancel operation
if( IsActive() )
{
iStatus = aReason;
Cancel();
}
}
//-----------------------------------------------------------------------------
// CVimpstImageProcessor::ClearState
// ( Other items commented in header )
//-----------------------------------------------------------------------------
void CVimpstImageProcessor::ClearState()
{
if( iScaler )
{
iScaler->Cancel();
delete iScaler;
iScaler = NULL;
}
if( iImageDecoder )
{
iImageDecoder->Cancel();
delete iImageDecoder;
iImageDecoder = NULL;
}
if( iImageEncoder )
{
iImageEncoder->Cancel();
delete iImageEncoder;
iImageEncoder = NULL;
}
if( iBitmap )
{
delete iBitmap;
iBitmap = NULL;
}
if (iMimeType)
{
delete iMimeType;
iMimeType = NULL;
}
}
// End of file