mpxmusicplayer/commonui/src/mpximageutil.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:45:05 +0200
changeset 0 ff3acec5bc43
child 2 b70d77332e66
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2006 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:  Implementation of CMPXImageUtil.
*
*/

// INCLUDE FILES
#include <e32std.h>
#include <e32base.h>
#include <bitmaptransforms.h>
#include <mda/common/video.h>
#include <eikenv.h>
#include <icl/imagedata.h>
#include <imageconversion.h>
#include <IclExtJpegApi.h>

#include "mpximageutil.h"

//This value is used to stretch so the image fills the container.
const TReal MaxStretchRatio = 1.1f;

LOCAL_C TInt Stretch (TInt aValue, TInt aLimit)
    {
    TInt ret( aValue * MaxStretchRatio );
    ret = (ret>aLimit) ? aLimit : ret;
    return ret;
    }

// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMPXImageUtil* CMPXImageUtil::NewL(
                                    MMPXAlbumArtUtilObserver& aObserver)
    {
    CMPXImageUtil* self = new ( ELeave ) CMPXImageUtil(aObserver);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop(); // self
    return self; 
    }

// -----------------------------------------------------------------------------
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CMPXImageUtil::CMPXImageUtil(MMPXAlbumArtUtilObserver& aObserver) 
:   CActive(EPriorityStandard), iObserver(aObserver) 
    {
    iBitmap = NULL;
    iState = EIdle;
    }

// -----------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::ConstructL()
    {
    iScaler = CBitmapScaler::NewL();
    User::LeaveIfError(iFs.Connect());
    CActiveScheduler::Add( this );
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CMPXImageUtil::~CMPXImageUtil()
    {
    Cancel();
    delete iImageDecoder; // CImageDecoder must be deleted before the 
    delete iScaler;
    iFs.Close();
    delete iImageData;
    }

// -----------------------------------------------------------------------------
// Starts to decode an image from a file. 
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::StartToDecodeL(const TDesC& aFileName, 
                                      const TSize& aSize, 
                                      TDisplayMode aDisplayMode /*=EColor64K*/)
    {
    if(iState)
        {
        User::Leave(KErrNotReady);
        }

    delete iImageDecoder; 
    iImageDecoder = NULL;
    delete iBitmap; 
    iBitmap = NULL;
    delete iImageData;
    iImageData = NULL;
    
    // create the decoder

    TRAPD( err, iImageDecoder = CExtJpegDecoder::FileNewL( 
            CExtJpegDecoder::EHwImplementation, 
            iFs, 
            aFileName, 
            CImageDecoder::EOptionNone ) );
    if (KErrNone != err)
        {
            TRAP(err,iImageDecoder = CExtJpegDecoder::FileNewL( 
                    CExtJpegDecoder::ESwImplementation, 
                    iFs, 
                    aFileName, 
                    CImageDecoder::EOptionNone ) );
        if (KErrNone != err)
            {
            iImageDecoder = CImageDecoder::FileNewL(
                    iFs, 
                    aFileName,
                    CImageDecoder::EOptionNone);
            }
        }

    // Get image size
    TSize bitmapSize = CalculateDecodeSize(aSize);
    // create the destination bitmap
    iBitmap = new (ELeave) CFbsBitmap();
    User::LeaveIfError(iBitmap->Create(bitmapSize, aDisplayMode)); 

    // start conversion to bitmap
    iState = EDecoding;
    iImageDecoder->Convert(&iStatus, *iBitmap);
    
    iObserver.ExtractAlbumArtStarted();
    SetActive();
    }

// -----------------------------------------------------------------------------
// CMPXImageUtil::DoCancel
// Implementation of CActive
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::DoCancel()
    {
    switch ( iState )
        {
        case EDecoding:
            {
            iImageDecoder->Cancel();
            // need to delete bitmap as we have are still the owner until the 
            // operation completes
            if ( iBitmap )
                {
                delete iBitmap;
                iBitmap = NULL;
                }
            break;
            }
        case EScaling:
            {
            iScaler->Cancel();
            if ( iBitmap )
                {
                delete iBitmap;
                iBitmap = NULL;
                }
            break;
            }
        default: // No Asynchronous events are taking place, do nothing.
            {
            break;
            }
        }

    delete iImageData;
    iImageData = NULL;
    delete iImageDecoder;
    iImageDecoder = NULL;
    }

// -----------------------------------------------------------------------------
// Implementation of CActive
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::RunL()
    {
    TInt deleteDecoder( ETrue );
    switch( iState ) 
        {
        case EDecoding:
            {
            if( iStatus == KErrNone ) 
                {
                if ( !iScaleRquired )
                    {   
                    iState = EIdle;
                    iObserver.ExtractAlbumArtCompleted(iBitmap,KErrNone);
                    iBitmap = NULL;
                    }
                else 
                    {
                    deleteDecoder = EFalse;
                    ScaleL();
                    }
                break;
                }
            else
                {
                // some error
                if ( iBitmap )
                    {
                    delete iBitmap;
                    iBitmap = NULL;                        
                    }
                iState = EIdle;
                iObserver.ExtractAlbumArtCompleted(iBitmap, iStatus.Int());
                break;   
                }
            }
        case EScaling:
            {
            iState = EIdle;
            iObserver.ExtractAlbumArtCompleted(iBitmap,iStatus.Int());
            iBitmap = NULL; 
            }
            break;

        default: // some error
            {
            iState = EIdle;
            iObserver.ExtractAlbumArtCompleted(iBitmap,iStatus.Int());
            break;
            }
        }

    // It's safe to destroy iImageData here
    delete iImageData;
    iImageData = NULL;
    
    if ( deleteDecoder )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    }

// -----------------------------------------------------------------------------
// Scales iBitmap by iSize
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::ScaleL()
    {
    iScaler->Scale(&iStatus, *iBitmap, iSize, EFalse);
    iState = EScaling;
    SetActive();
    }

// -----------------------------------------------------------------------------
// Starts to decode an image from a buffer. 
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::StartToDecodeL( const TSize& aSize,
        HBufC8* aAlbumArt, TDisplayMode aDisplayMode/*=EColor64K*/ )
    {
    if(iState)
        {
        User::Leave( KErrNotReady );
        }
                               
    delete iImageDecoder; 
    iImageDecoder = NULL;
    delete iBitmap; 
    iBitmap = NULL;
    delete iImageData;
    iImageData = NULL;
    // storing the pointer to aAlbumArt, ownership was transferred to us.
    iImageData = aAlbumArt;
    // create the decoder
    
    
    TRAPD( err, iImageDecoder = CExtJpegDecoder::DataNewL( 
            CExtJpegDecoder::EHwImplementation, 
            iFs, 
            *iImageData, 
            CImageDecoder::EOptionNone ) );
    if ( KErrNone != err )
        {
        TRAP(err,iImageDecoder = CExtJpegDecoder::DataNewL( 
                CExtJpegDecoder::ESwImplementation, 
                iFs, 
                *iImageData, 
                CImageDecoder::EOptionNone ) );
        if ( KErrNone != err )
            {
            iImageDecoder = CImageDecoder::DataNewL( 
                    iFs, 
                    *iImageData, 
                    CImageDecoder::EOptionNone );
            }
        }
    
    

    
    TSize bitmapSize = CalculateDecodeSize( aSize );

    // create the destination bitmap
    iBitmap = new ( ELeave ) CFbsBitmap();
    User::LeaveIfError( iBitmap->Create( bitmapSize, aDisplayMode ) );
    // start conversion to bitmap
    iState = EDecoding;
    iImageDecoder->Convert( &iStatus, *iBitmap );
    
    iObserver.ExtractAlbumArtStarted();
    SetActive();
    }
// -----------------------------------------------------------------------------
// Calculates the decode size and prepares members for scaling. 
// -----------------------------------------------------------------------------
//
TSize CMPXImageUtil::CalculateDecodeSize(const TSize& aSize)
    {
    const TFrameInfo& frameInfo = iImageDecoder->FrameInfo();
    TSize bitmapSize = frameInfo.iOverallSizeInPixels;
    TReal sourceAspectRatio( TReal( bitmapSize.iWidth) / bitmapSize.iHeight );
    TReal destinationAspectRatio( TReal( aSize.iWidth ) / aSize.iHeight );
    TReal xScale = TReal( bitmapSize.iWidth ) / aSize.iWidth;
    TReal yScale = TReal( bitmapSize.iHeight ) / aSize.iHeight;
    TReal scale(0.0f);
    
    if ( sourceAspectRatio > destinationAspectRatio )
        {
        scale = xScale;
        iSize.iWidth = aSize.iWidth;
        iSize.iHeight = Stretch( TReal( bitmapSize.iHeight ) / scale , 
                                 aSize.iHeight );
        }
    else
        {
        scale = yScale;
        iSize.iWidth = Stretch( TReal( bitmapSize.iWidth ) / scale ,
                                aSize.iWidth);
        iSize.iHeight = aSize.iHeight;
        }
     
    if ((frameInfo.iFlags & TFrameInfo::EFullyScaleable))
        {
        iScaleRquired = EFalse;
        bitmapSize = iSize;
        }
    else
        //Decoder only supports 2, 4 and 8 scallyng, the image will need 
        //to be reescaled after decoding.
        //Decoding to a scale that is just a bit bigger thant the target,
        //this will save memory and resources and we will get a sharp image 
        //after scaling.
        {
        TInt intscale = ( scale >= 8 ) ? 8 : 
                ( scale >= 4 ) ? 4 :
                ( scale >= 2 ) ? 2 : 1;
        TUint xCorrection = ( bitmapSize.iWidth % intscale ) ? 1 : 0;
        TUint yCorrection = ( bitmapSize.iHeight % intscale ) ? 1 : 0;
        bitmapSize.iWidth /= intscale;
        bitmapSize.iHeight /= intscale;
        bitmapSize += TSize( xCorrection, yCorrection );
        iScaleRquired = ETrue;
        }
    return bitmapSize;
    }

// -----------------------------------------------------------------------------
// CMPXImageUtil::CancelRequest
// Cancel Asynch requests
// -----------------------------------------------------------------------------
//
void CMPXImageUtil::CancelRequest()
    {
    Cancel();
    }

//  End of File