widgets/widgetinstaller/src/Iconconverter.cpp
changeset 0 dd21522fd290
child 48 79859ed3eea9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/widgetinstaller/src/Iconconverter.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,541 @@
+/*
+* 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 the License "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: 
+*     Icon convert to convert icon for png to mbm format
+*
+*
+*/
+
+#include <fbs.h>
+#include <ImageConversion.h>
+#include <BitmapTransforms.h>
+#include "IconConverter.h"
+#include "WidgetUIOperationsWatcher.h"
+
+
+// CONSTANTS
+_LIT( KTempPath,"c:\\system\\temp\\" );
+
+const TInt KIconSizeLarge = 88;
+const TInt KIconSizeMedium = 32;
+const TInt KIconSizeSmall = 24;
+
+
+using namespace SwiUI;
+
+// ============================================================================
+// CIconConverter::NewL()
+// two-phase constructor
+//
+// @since 3.1
+// @param aController - controller for callback to notify the completion
+// @param aFs - file session
+// @return pointer to CIconConverter
+// ============================================================================
+//
+CIconConverter* CIconConverter::NewL(
+    MConverterController* aController,
+    RFs& aFs )
+    {
+    CIconConverter* self =
+        new(ELeave) CIconConverter( aController , aFs );
+    CleanupStack::PushL( self );
+
+    self->ConstructL();
+
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ============================================================================
+// CIconConverter::CIconConverter()
+// C++ default constructor
+//
+// @since 3.1
+// ============================================================================
+CIconConverter::CIconConverter(
+    MConverterController* aController,
+    RFs& aFs ) :
+        CActive( EPriorityStandard ),
+        iController( aController ),
+        iFs( aFs )
+    {
+    RFbsSession::Connect();
+    CActiveScheduler::Add( this );
+    }
+
+// ============================================================================
+// CIconConverter::ConstructL()
+// Symbian default constructor
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::ConstructL()
+    {
+    // create the destination bitmap
+    iOriginalBitmap = new ( ELeave ) CFbsBitmap;
+    iOriginalBitmapMask = new ( ELeave ) CFbsBitmap;
+
+    iTempBitmap = new ( ELeave ) CFbsBitmap;
+    iTempBitmapMask = new ( ELeave ) CFbsBitmap;
+    iTempPath = KTempPath().AllocL();
+    iIconSizes = new CArrayFixFlat<TSize>( 3 );
+    iIconSizes->InsertL( 0, TSize( KIconSizeLarge, KIconSizeLarge ) );
+    iIconSizes->InsertL( 1, TSize( KIconSizeMedium, KIconSizeMedium ) );
+    iIconSizes->InsertL( 2, TSize( KIconSizeSmall, KIconSizeSmall ) );
+    }
+
+
+// ============================================================================
+// CIconConverter::~CIconConverter()
+// destructor
+//
+// @since 3.1
+// ============================================================================
+CIconConverter::~CIconConverter()
+    {
+    Cancel();
+
+    // CImageDecoder must be deleted first otherwise a related thread might panic
+    if ( iImageDecoder )
+        {
+        delete iImageDecoder;
+        }
+    if ( iOriginalBitmap )
+        {
+        delete iOriginalBitmap;
+        }
+    if ( iOriginalBitmapMask )
+        {
+        delete iOriginalBitmapMask;
+        }
+    if ( iOutputFileName )
+        {
+        delete iOutputFileName;
+        }
+    if ( iTempBitmap )
+        {
+        delete iTempBitmap;
+        }
+    if ( iTempBitmapMask )
+        {
+        delete iTempBitmapMask;
+        }
+    if ( iScaler )
+        {
+        delete iScaler;
+        }
+    if ( iTempPath )
+        {
+        delete iTempPath;
+        }
+    iIconFile.Close();
+    iIconPngFile.Close();
+    RFbsSession::Disconnect();
+    if ( iIconSizes )
+        {
+        iIconSizes->Reset();
+        delete iIconSizes;
+        }
+    }
+
+
+// ============================================================================
+// CIconConverter::StartToDecodeL
+// use image decoder to decode the image
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::StartToDecodeL(
+    const TDesC& aInputFileName,
+    const TDesC& aOutputFileName )
+    {
+    iState = EConvertingFile;
+    delete iImageDecoder;
+    iImageDecoder = NULL;
+
+    delete iOutputFileName;
+    iOutputFileName = 0;
+
+    iOutputFileName = aOutputFileName.AllocL();
+
+    // create the decoder
+    iImageDecoder = CImageDecoder::FileNewL( iFs, aInputFileName );
+
+    // Extract information about the image, now we've read the header
+    TFrameInfo info = iImageDecoder->FrameInfo( 0 );
+
+    iOriginalBitmap->Create( info.iOverallSizeInPixels, info.iFrameDisplayMode );
+
+    // If the PNG has a built in transparency, use it to build the mask
+    if ( info.iFlags & TFrameInfo::ETransparencyPossible )
+        {
+        // If we have a full alpha channel, use that
+        if ( info.iFlags & TFrameInfo::EAlphaChannel )
+            {
+            User::LeaveIfError( iOriginalBitmapMask->Create(
+                info.iOverallSizeInPixels,
+                EGray256 ) );
+            }
+        else
+            {
+            User::LeaveIfError( iOriginalBitmapMask->Create(
+                info.iOverallSizeInPixels,
+                EGray2 ) );
+            }
+
+        iImageDecoder->Convert(
+            &iStatus, *iOriginalBitmap, *iOriginalBitmapMask );
+        }
+    else
+        {
+        iImageDecoder->Convert( &iStatus, *iOriginalBitmap );
+        }
+
+    // start conversion to bitmap
+    SetActive();
+    }
+
+// ============================================================================
+// CIconConverter::RunL()
+// Handle various stages of icon conversion
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::RunL()
+    {
+    // If there is an error in the previous stage, then leave. Otherwise,
+    // call the handle function
+    User::LeaveIfError( iStatus.Int() );
+
+    switch ( iState )
+        {
+    case EConvertingFile:
+        DoProcessMaskL();
+        break;
+
+    case EScalingIcon:
+        DoMaskScalingL();
+        break;
+
+    case EScalingMask:
+    case EFinalize:
+        DoIconStoreL();
+        break;
+
+    default:
+        User::Leave( KErrNotSupported );
+        break;
+        };
+
+    }
+
+// ============================================================================
+// CIconConverter::RunError()
+// Notify client with error
+//
+// @since 3.1
+// ============================================================================
+TInt CIconConverter::RunError( TInt aError )
+    {
+    // If any error occurred, then complete the client with the error.
+    if ( iClientStatus )
+        {
+        User::RequestComplete( iClientStatus, aError );
+        }
+
+    // There is nothing more to do if NotifyCompletionL leaves.
+    TRAP_IGNORE( iController->NotifyCompletionL( aError ) );
+
+    return KErrNone;
+    }
+
+// ============================================================================
+// CIconConverter::DoCancel()
+// cancel icon conversion
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoCancel()
+    {
+    switch (iState)
+        {
+    case EConvertingFile:
+        if ( iImageDecoder )
+            {
+            iImageDecoder->Cancel();
+            }
+
+        break;
+
+    case EScalingIcon:
+    case EScalingMask:
+        if ( iScaler )
+            {
+            iScaler->Cancel();
+            }
+        break;
+
+        };
+
+    if ( iClientStatus )
+        {
+        User::RequestComplete( iClientStatus, KErrCancel );
+        }
+
+    // no need to call NotifyCompletionL() because cancel can only be
+    // caused by the client
+    }
+
+// ============================================================================
+// CIconConverter::DoProcessMaskL()
+// process the bitmap mask
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoProcessMaskL()
+    {
+    // we use white to mean transparent at this stage, simply for efficiency
+    // since all the canvases we will copy in to begin as white
+
+    if ( iOriginalBitmapMask->Handle() == 0 )
+        {
+        // Create a mask that shows the whole bitmap as an icon
+        // (all black)
+        User::LeaveIfError( iOriginalBitmapMask->Create(
+            iOriginalBitmap->SizeInPixels(), EGray2 ) );
+        CFbsBitmapDevice* device =
+            CFbsBitmapDevice::NewL( iOriginalBitmapMask );
+        CleanupStack::PushL( device );
+
+        CFbsBitGc* gc;
+        User::LeaveIfError( device->CreateContext( gc ) );
+        gc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+        gc->SetDrawMode( CGraphicsContext::EDrawModePEN );
+        gc->SetBrushColor( KRgbBlack );
+        // Create a big black image
+        gc->Clear();
+        delete gc;
+        CleanupStack::PopAndDestroy( device );
+        }
+    else
+        {
+        // Invert the mask obtained from the PNG
+        CFbsBitmapDevice* device =
+            CFbsBitmapDevice::NewL( iOriginalBitmapMask );
+        CleanupStack::PushL(device);
+        CFbsBitGc* gc;
+        User::LeaveIfError( device->CreateContext( gc ) );
+        gc->SetDrawMode( CGraphicsContext::EDrawModeNOTSCREEN );
+        gc->Clear();
+        delete gc;
+        CleanupStack::PopAndDestroy( device );
+        }
+
+    // Scale the icon to the sizes required
+    iCurrentSizeIndex = 0;
+    DoIconScalingL();
+    }
+
+// ============================================================================
+// CIconConverter::DoIconScalingL()
+// Scale the bitmap
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoIconScalingL()
+    {
+    // free any current icons to prevent memory leaks
+    iTempBitmap->Reset();
+    // current target size
+    TSize size = iIconSizes->At( iCurrentSizeIndex );
+
+    iState = EScalingIcon;
+    // Create a canvas to hold the scaled icon, of the same depth
+    User::LeaveIfError(
+        iTempBitmap->Create( size, iOriginalBitmap->DisplayMode() ) );
+    DoScalingL( *iOriginalBitmap, *iTempBitmap );
+    }
+
+// ============================================================================
+// CIconConverter::DoMaskScalingL()
+// Scale the bitmap mask
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoMaskScalingL()
+    {
+    // Reset the mask to prevent memory leaks
+    iTempBitmapMask->Reset();
+    // current target size
+    TSize size = iIconSizes->At( iCurrentSizeIndex );
+
+    iState = EScalingMask;
+    // Create a canvas to hold the scaled icon, of 8 bit colour depth
+    User::LeaveIfError( iTempBitmapMask->Create( size, EGray256 ) );
+    DoScalingL( *iOriginalBitmapMask, *iTempBitmapMask );
+    }
+
+// ============================================================================
+// CIconConverter::DoScalingL()
+// Scale
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoScalingL(
+    CFbsBitmap& aBitmapSource, CFbsBitmap& aBitmapTarget )
+    {
+    ScalerL().Scale( &iStatus, aBitmapSource, aBitmapTarget, ETrue );
+    SetActive();
+    }
+
+// ============================================================================
+// CIconConverter::ScalerL()
+// Create bitmap scalar
+//
+// @since 3.1
+// ============================================================================
+CBitmapScaler& CIconConverter::ScalerL()
+    {
+    if ( iScaler == NULL )
+        {
+        iScaler = CBitmapScaler::NewL();
+        // always use highest quality scaling
+        User::LeaveIfError( iScaler->SetQualityAlgorithm( CBitmapScaler::EMaximumQuality ) );
+        }
+    return *iScaler;
+    }
+
+// ============================================================================
+// CIconConverter::DoIconStoreL()
+// Store icon and mask files
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoIconStoreL()
+    {
+    // Store the icon and its mask in temporary files until we are ready
+    // to create the final icon
+
+    // Icon is stored at index n, mask at index n+1
+    TInt iconIndex = iCurrentSizeIndex * 2;
+    TFileName iconFile = *iTempPath;
+    GetTempIconName( iconIndex++, iconFile );
+
+    TFileName maskFile = *iTempPath;
+    GetTempIconName( iconIndex, maskFile );
+
+    // invert the masks before saving
+
+    CFbsBitmapDevice* device = CFbsBitmapDevice::NewL( iTempBitmapMask );
+    CleanupStack::PushL( device );
+
+    CFbsBitGc* gc;
+    User::LeaveIfError( device->CreateContext( gc ) );
+    gc->SetDrawMode( CGraphicsContext::EDrawModeNOTSCREEN );
+    gc->Clear();
+
+    delete gc;
+    CleanupStack::PopAndDestroy( device );
+
+    // save the bitmaps
+    User::LeaveIfError( iTempBitmap->Save( iconFile ) );
+    User::LeaveIfError( iTempBitmapMask->Save( maskFile ) );
+
+    if ( ++iCurrentSizeIndex < iIconSizes->Count() )
+        {
+        // do the next icon size
+        DoIconScalingL();
+        }
+    else
+        {
+        DoCreateFinalIconL();
+        }
+
+    }
+
+// ============================================================================
+// CIconConverter::DoCreateFinalIconL()
+// Create the final icon
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::DoCreateFinalIconL()
+    {
+    TInt i, elements = 0;
+    // one icon, one mask per size
+    TInt bitmapCount = iIconSizes->Count() * 2;
+
+    TFileName** filenames = new ( ELeave ) TFileName*[bitmapCount];
+    CleanupStack::PushL( filenames );
+    TInt32* uniqueIds = new ( ELeave ) TInt32[bitmapCount];
+    CleanupStack::PushL( uniqueIds );
+
+    TInt err = KErrNone;
+
+    for ( i = 0; i < bitmapCount; ++i )
+        {
+        filenames[i] = NULL;
+        filenames[i] = new TFileName( *iTempPath );
+        elements = i;
+        if ( filenames[i] == NULL )
+            {
+            // we need to cleanup this structure
+            err = KErrNoMemory;
+            goto cleanup;
+            }
+        GetTempIconName( i, *filenames[i] );
+        uniqueIds[i] = 0;
+        }
+
+    TRAP( err, CFbsBitmap::StoreL(
+        *iOutputFileName, bitmapCount, ( const TDesC** )filenames, uniqueIds ) );
+
+cleanup:
+    for ( i = 0; i <= elements; ++i )
+        {
+        if ( filenames[i] == NULL )
+            {
+            // if we failed to allocate a filename, then we would not have continued
+            break;
+            }
+        else
+            {
+            delete filenames[i];
+            }
+        }
+
+    CleanupStack::PopAndDestroy( 2, filenames );
+
+    // There is no recovery on a leave and we don't want to trigger
+    // RunError here since that will also call NotifyCompletionL.
+    TRAP_IGNORE( iController->NotifyCompletionL( err ) );
+    }
+
+// ============================================================================
+// CIconConverter::GetTempIconName()
+// Get temporary icon name
+//
+// @since 3.1
+// ============================================================================
+void CIconConverter::GetTempIconName( TInt aIndex, TFileName& aIconName )
+    {
+    _LIT( KIcon, "ICON" );
+    _LIT( KBmp, ".MBM" );
+    aIconName.Append( KIcon );
+    aIconName.AppendNum( static_cast<TInt64>( aIndex ) );
+    aIconName.Append( KBmp );
+    }
+
+