mobilemessaging/unieditor/utils/src/UniImageProcessor.cpp
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *       Unified Message Editor - Combined image scaler & compressor
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include "UniImageProcessor.h"
       
    23 
       
    24 #include <imageconversion.h>
       
    25 #include <bitmaptransforms.h>
       
    26 
       
    27 #include <MsgMimeTypes.h>
       
    28 
       
    29 #include "UniEditorLogging.h"
       
    30 
       
    31 
       
    32 // ==========================================================
       
    33 
       
    34 // EXTERNAL DATA STRUCTURES
       
    35 
       
    36 // EXTERNAL FUNCTION PROTOTYPES
       
    37 
       
    38 // CONSTANTS
       
    39 
       
    40 // MACROS
       
    41 
       
    42 // LOCAL CONSTANTS AND MACROS
       
    43 
       
    44 // JPEG quality factor related constants:
       
    45 const TInt KHighQualityMaxWidth = 640;
       
    46 const TInt KHighQualityMaxHeight = 480;
       
    47 const TInt KJpegQualityFactorHigh = 80;
       
    48 const TInt KJpegQualityFactorNormal = 65;
       
    49 
       
    50 // MPix factor is relative to this value
       
    51 // 3MPix: Initial  factor 2/3 * Qfactor calculated above
       
    52 // 5MPix: 2/5*
       
    53 // 8MPix: 2/8*
       
    54 const TReal  KQFMPixfactor( 1600*1200 );
       
    55 
       
    56 // Count of compressing/scaling efforts
       
    57 const TInt  KIterationCount( 3 );
       
    58 
       
    59 const TInt KMPixfactorMin = 1;
       
    60 const TInt KMPixfactorMax = 5;
       
    61 const TInt KMPixSizeDivider = 4;
       
    62            
       
    63 // When compressing next QFactor is QFactor * (value from table) / 100
       
    64 const TInt KPercentCoefficientsCounts[KMPixfactorMax][KIterationCount] = 
       
    65         {  { 60, 30, 10 },
       
    66            { 40, 15, 3 },
       
    67            { 25, 10, 2 },
       
    68            { 12, 4,  0 },
       
    69            { 5, 2,  0 }
       
    70         };
       
    71         
       
    72 // MODULE DATA STRUCTURES
       
    73 
       
    74 // LOCAL FUNCTION PROTOTYPES
       
    75 
       
    76 // ================= MEMBER FUNCTIONS =======================
       
    77 
       
    78 // ---------------------------------------------------------
       
    79 // CUniImageProcessor::CUniImageProcessor
       
    80 //
       
    81 // Constructor.
       
    82 // ---------------------------------------------------------
       
    83 //
       
    84 EXPORT_C CUniImageProcessor::CUniImageProcessor( MUniImageProcessorCallback* aCallback ) : 
       
    85     CActive( EPriorityStandard ),
       
    86     iCallback( aCallback ),
       
    87     iMPixFactor ( KMPixfactorMin )
       
    88     {
       
    89     CActiveScheduler::Add( this );
       
    90     }
       
    91 
       
    92 // ---------------------------------------------------------
       
    93 // CUniImageProcessor::~CUniImageProcessor
       
    94 //
       
    95 // Destructor
       
    96 // ---------------------------------------------------------
       
    97 //
       
    98 CUniImageProcessor::~CUniImageProcessor()
       
    99     {
       
   100     Cancel();
       
   101     Reset();
       
   102     }
       
   103 
       
   104 // ---------------------------------------------------------
       
   105 // CUniImageProcessor::ProcessImageL
       
   106 //
       
   107 // ---------------------------------------------------------
       
   108 //
       
   109 EXPORT_C void CUniImageProcessor::ProcessImageL(
       
   110     RFile& aSourceFile,
       
   111     RFile& aDestFile,
       
   112     TSize& aTargetSize,
       
   113     const TDesC8& aTargetType,
       
   114     TBool aAspectRatio,
       
   115     TInt aTargetFileSize )
       
   116     {
       
   117     UNILOGGER_ENTERFN( "CUniImageProcessor: file-to-file scaling" );
       
   118     
       
   119     if ( iDecoder || iScaler || iEncoder )
       
   120         {
       
   121         User::Leave( KErrInUse );
       
   122         }
       
   123     
       
   124     iError = KErrNone;
       
   125     iFlags &= ~ECompressOnly;
       
   126     if ( aTargetType.CompareF( KMsgMimeImageJpeg ) == 0 )
       
   127         {
       
   128         iCompressTriesLeft = KIterationCount;
       
   129         User::LeaveIfError( aSourceFile.Size( iOriginalFileSize ) );
       
   130         // Make sure the resulting image won't be larger than the original
       
   131         if ( !aTargetFileSize || iOriginalFileSize < aTargetFileSize )
       
   132             {
       
   133             aTargetFileSize = iOriginalFileSize;
       
   134             iFlags |= EImplicitCompress;
       
   135             }
       
   136         iTargetFileSize = aTargetFileSize;
       
   137         }
       
   138     else
       
   139         {
       
   140         iCompressTriesLeft = 0;
       
   141         iTargetFileSize = 0;
       
   142         iOriginalFileSize = 0;
       
   143         }
       
   144 
       
   145     iQFactorCalculated = EFalse;
       
   146     iMPixFactor = KMPixfactorMin;
       
   147     iDestFile = &aDestFile;
       
   148     iAspectRatio = aAspectRatio;
       
   149     iDecoder = CImageDecoder::FileNewL( aSourceFile, ContentAccess::EPeek );
       
   150     iEncoder = CImageEncoder::FileNewL( aDestFile, aTargetType );
       
   151 
       
   152     const TFrameInfo& frameInfo = iDecoder->FrameInfo();
       
   153 
       
   154     TSize decodeSize( frameInfo.iOverallSizeInPixels );
       
   155     if ( !CalculateDecodeAndTargetSizes( aTargetSize, decodeSize, aAspectRatio ) )
       
   156         {
       
   157         // use bitmap plane scale
       
   158         iScaler = CBitmapScaler::NewL();
       
   159         iSourceBitmap = new ( ELeave ) CFbsBitmap;
       
   160         iFlags |= ESourceBitmapOwned;
       
   161         User::LeaveIfError( iSourceBitmap->Create(
       
   162             decodeSize,
       
   163             frameInfo.iFrameDisplayMode ) );
       
   164         }
       
   165     
       
   166     iDestBitmap = new ( ELeave ) CFbsBitmap;
       
   167     iFlags |= EDestBitmapOwned;
       
   168     User::LeaveIfError( iDestBitmap->Create(
       
   169         aTargetSize,
       
   170         frameInfo.iFrameDisplayMode ) );
       
   171 
       
   172     CreateImageDataL( aTargetType, aTargetSize );
       
   173 
       
   174     DecodeImage();
       
   175     }
       
   176 
       
   177 // ---------------------------------------------------------
       
   178 // CUniImageProcessor::ProcessImageL
       
   179 //
       
   180 // ---------------------------------------------------------
       
   181 //
       
   182 EXPORT_C void CUniImageProcessor::ScaleImageL(
       
   183     CFbsBitmap* aSourceBitmap,
       
   184     RFile& aDestFile,
       
   185     const TSize& aTargetSize,
       
   186     const TDesC8& aTargetType,
       
   187     TBool aAspectRatio )
       
   188     {
       
   189     UNILOGGER_ENTERFN( "CUniImageProcessor: bmp-to-file scaling" );
       
   190     if ( iDecoder || iScaler || iEncoder )
       
   191         {
       
   192         User::Leave( KErrInUse );
       
   193         }
       
   194 
       
   195     iError = KErrNone;
       
   196     iFlags &= ~ECompressOnly;
       
   197     iCompressTriesLeft = 0;
       
   198     iTargetFileSize = 0;
       
   199     iOriginalFileSize = 0;
       
   200 
       
   201     iQFactorCalculated = EFalse;
       
   202     iMPixFactor = KMPixfactorMin;
       
   203     iDestFile = &aDestFile;
       
   204     iAspectRatio = aAspectRatio;
       
   205     iScaler = CBitmapScaler::NewL();
       
   206     iEncoder = CImageEncoder::FileNewL( aDestFile, aTargetType );
       
   207 
       
   208     iSourceBitmap = aSourceBitmap;
       
   209 
       
   210     iDestBitmap = new ( ELeave ) CFbsBitmap;
       
   211     iFlags |= EDestBitmapOwned;
       
   212     TInt error = iDestBitmap->Create(
       
   213         aTargetSize,
       
   214         iSourceBitmap->DisplayMode() );
       
   215     User::LeaveIfError( error );
       
   216     
       
   217     CreateImageDataL( aTargetType, aTargetSize );
       
   218 
       
   219     ScaleImage( EFalse );
       
   220     }
       
   221 
       
   222 // ---------------------------------------------------------
       
   223 // CUniImageProcessor::ScaleImageL
       
   224 //
       
   225 // ---------------------------------------------------------
       
   226 //
       
   227 EXPORT_C void CUniImageProcessor::ScaleImageL(
       
   228     CFbsBitmap* aSourceBitmap,
       
   229     CFbsBitmap* aDestBitmap,
       
   230     TBool aAspectRatio )
       
   231     {
       
   232     UNILOGGER_ENTERFN( "CUniImageProcessor: bmp-to-bmp scaling" );
       
   233     if ( iDecoder || iScaler || iEncoder )
       
   234         {
       
   235         User::Leave( KErrInUse );
       
   236         }
       
   237 
       
   238     iError = KErrNone;
       
   239     iFlags &= ~ECompressOnly;
       
   240     iCompressTriesLeft = 0;
       
   241     iTargetFileSize = 0;
       
   242     iOriginalFileSize = 0;
       
   243 
       
   244     iAspectRatio = aAspectRatio;
       
   245     iScaler = CBitmapScaler::NewL();
       
   246     
       
   247     iSourceBitmap = aSourceBitmap;
       
   248     iDestBitmap = aDestBitmap;
       
   249 
       
   250     ScaleImage( EFalse );
       
   251     }
       
   252 
       
   253 // ---------------------------------------------------------
       
   254 // CUniImageProcessor::ScaleImageL
       
   255 //
       
   256 // ---------------------------------------------------------
       
   257 //
       
   258 EXPORT_C void CUniImageProcessor::ScaleImageL(
       
   259     RFile& aSourceFile,
       
   260     CFbsBitmap*& aDestBitmap,
       
   261     CFbsBitmap*& aDestMask,
       
   262     TSize& aTargetSize,
       
   263     TBool aAspectRatio )
       
   264     {
       
   265     UNILOGGER_ENTERFN( "CUniImageProcessor: file-to-bmp scaling" );
       
   266     if ( iDecoder || iScaler || iEncoder )
       
   267         {
       
   268         User::Leave( KErrInUse );
       
   269         }
       
   270 
       
   271     iError = KErrNone;
       
   272     iFlags &= ~ECompressOnly;
       
   273     iCompressTriesLeft = 0;
       
   274     iTargetFileSize = 0;
       
   275     iOriginalFileSize = 0;
       
   276 
       
   277     iQFactorCalculated = EFalse;
       
   278     iMPixFactor = KMPixfactorMin;
       
   279     iAspectRatio = aAspectRatio;
       
   280     iDecoder = CImageDecoder::FileNewL( aSourceFile, ContentAccess::EPeek );
       
   281 
       
   282     const TFrameInfo& frameInfo = iDecoder->FrameInfo();
       
   283 
       
   284     TSize decodeSize( frameInfo.iOverallSizeInPixels );
       
   285     TBool optimum = CalculateDecodeAndTargetSizes( aTargetSize, decodeSize, aAspectRatio );
       
   286     // Make sure "compress only flag is not set".
       
   287     iFlags &= ~ECompressOnly;
       
   288 
       
   289     if ( !optimum )
       
   290         {
       
   291         // use bitmap plane scale
       
   292         iScaler = CBitmapScaler::NewL();
       
   293         iSourceBitmap = new ( ELeave ) CFbsBitmap;
       
   294         iFlags |= ESourceBitmapOwned;
       
   295         User::LeaveIfError( iSourceBitmap->Create(
       
   296             decodeSize,
       
   297             frameInfo.iFrameDisplayMode ) );
       
   298         }
       
   299     
       
   300     iDestBitmap = new ( ELeave ) CFbsBitmap;
       
   301     iFlags |= EDestBitmapOwned;
       
   302     User::LeaveIfError( iDestBitmap->Create(
       
   303         aTargetSize,
       
   304         frameInfo.iFrameDisplayMode ) );
       
   305 
       
   306     if ( frameInfo.iFlags & TFrameInfo::ETransparencyPossible )
       
   307         {
       
   308         if ( !optimum )
       
   309             {
       
   310             iSourceMask = new ( ELeave ) CFbsBitmap;
       
   311             iFlags |= ESourceMaskOwned;
       
   312             User::LeaveIfError( iSourceMask->Create(
       
   313                 decodeSize,
       
   314                 frameInfo.iFlags & TFrameInfo::EAlphaChannel ? EGray256 : EGray2 ) );
       
   315             }
       
   316         iDestMask = new ( ELeave ) CFbsBitmap;
       
   317         iFlags |= EDestMaskOwned;
       
   318         User::LeaveIfError( iDestMask->Create(
       
   319             aTargetSize,
       
   320             frameInfo.iFlags & TFrameInfo::EAlphaChannel ? EGray256 : EGray2 ) );
       
   321         delete aDestMask; // just in case
       
   322         aDestMask = iDestMask;
       
   323         }
       
   324     else
       
   325         {
       
   326         delete aDestMask; // just in case
       
   327         aDestMask = NULL;
       
   328         }
       
   329 
       
   330     delete aDestBitmap; //just in case
       
   331     aDestBitmap = iDestBitmap;
       
   332     
       
   333     iFlags &= ~EDestBitmapOwned;
       
   334     iFlags &= ~EDestMaskOwned;
       
   335 
       
   336     DecodeImage();
       
   337     }
       
   338 
       
   339 // ---------------------------------------------------------
       
   340 // CUniImageProcessor::CalculateDecodeAndTargetSizes
       
   341 //
       
   342 // ---------------------------------------------------------
       
   343 //
       
   344 TBool CUniImageProcessor::CalculateDecodeAndTargetSizes(
       
   345         TSize& aTargetSize,
       
   346         TSize& aDecodeSize,
       
   347         TBool aAspectRatio )
       
   348     {
       
   349     UNILOGGER_ENTERFN( "CUniImageProcessor: CalculateDecodeAndTargetSizes()" );
       
   350 
       
   351     const TFrameInfo& frameInfo = iDecoder->FrameInfo();
       
   352     aDecodeSize = frameInfo.iOverallSizeInPixels;
       
   353 
       
   354     if ( aTargetSize.iWidth >= aDecodeSize.iWidth &&
       
   355          aTargetSize.iHeight >= aDecodeSize.iHeight &&
       
   356          !( iFlags & EAllowScalingUp ) )
       
   357         {
       
   358         // No need to scale at all!
       
   359         iFlags |= ECompressOnly;
       
   360         aTargetSize = aDecodeSize;
       
   361         return ETrue;
       
   362         }
       
   363     if ( aTargetSize == aDecodeSize )
       
   364         {
       
   365         // No need to scale at all!
       
   366         iFlags |= ECompressOnly;
       
   367         return ETrue;
       
   368         }
       
   369 
       
   370     if ( aAspectRatio )
       
   371         {
       
   372         // Adjust target size if aspect ratio needs to be maintained.
       
   373         TReal scaleRatio = CalculateScaleRatio( aTargetSize, aDecodeSize );
       
   374         aTargetSize.iHeight = scaleRatio * aDecodeSize.iHeight;
       
   375         aTargetSize.iWidth = scaleRatio * aDecodeSize.iWidth;
       
   376         }
       
   377 
       
   378     // Width or height should never be zero.
       
   379     aTargetSize.iWidth = Max(aTargetSize.iWidth, 1);
       
   380     aTargetSize.iHeight = Max(aTargetSize.iHeight, 1);
       
   381 
       
   382     TInt wRatio = aDecodeSize.iWidth / aTargetSize.iWidth;
       
   383     TInt hRatio = aDecodeSize.iHeight / aTargetSize.iHeight;
       
   384 
       
   385     TBool decodeOnly( frameInfo.iFlags & TFrameInfo::EFullyScaleable );
       
   386 
       
   387     if ( !decodeOnly &&
       
   388         !( aDecodeSize.iWidth % aTargetSize.iWidth ||
       
   389            aDecodeSize.iHeight % aTargetSize.iHeight ||
       
   390            wRatio != hRatio ||
       
   391           (wRatio != 2 && wRatio != 4 && wRatio != 8) ||
       
   392           (hRatio != 2 && hRatio != 4 && hRatio != 8) ) )
       
   393         {
       
   394         decodeOnly = ETrue;
       
   395         }
       
   396 
       
   397     if ( decodeOnly )
       
   398         {
       
   399         // Decoding directly to requested target size.
       
   400         aDecodeSize = aTargetSize;
       
   401         }
       
   402     else
       
   403         {
       
   404         TInt decodeFactor = 8;
       
   405         while ( decodeFactor > 1 )
       
   406             {
       
   407             if ( aDecodeSize.iWidth / decodeFactor >= aTargetSize.iWidth &&
       
   408                 aDecodeSize.iHeight / decodeFactor >= aTargetSize.iHeight )
       
   409                 {
       
   410                 // Smallest 1/2^n factor that creates image larger than target size
       
   411                 break;
       
   412                 }
       
   413             decodeFactor /= 2;
       
   414             }
       
   415         if ( ( iFlags & EOnlyDecodeTimeScaling ) && decodeFactor < 8 )
       
   416             {
       
   417             // Largest 1/2^n factor that creates image smaller than target size
       
   418             decodeFactor *= 2;
       
   419             decodeOnly = ETrue;
       
   420             }
       
   421         aDecodeSize.iWidth = ( aDecodeSize.iWidth + decodeFactor - 1 ) / decodeFactor;
       
   422         aDecodeSize.iHeight = ( aDecodeSize.iHeight + decodeFactor - 1 ) / decodeFactor;
       
   423         if ( decodeOnly )
       
   424             {
       
   425             // Decoding to target size. Make sure target & decode sizes match.
       
   426             // Target size may need to be changed was iOnlyDecodeTimeScaling is used.
       
   427             aTargetSize = aDecodeSize;
       
   428             }
       
   429         }
       
   430     return decodeOnly;
       
   431     }
       
   432 
       
   433 
       
   434 // ---------------------------------------------------------
       
   435 // CUniImageProcessor::DecodeImage
       
   436 //
       
   437 // ---------------------------------------------------------
       
   438 //
       
   439 void CUniImageProcessor::DecodeImage()
       
   440     {
       
   441     UNILOGGER_ENTERFN( "CUniImageProcessor: DecodeImage()" );
       
   442     
       
   443     iStatus = KRequestPending;
       
   444     if ( iScaler )
       
   445         {
       
   446         if ( iSourceMask )
       
   447             {
       
   448             iDecoder->Convert( &iStatus, *iSourceBitmap, *iSourceMask );
       
   449             }
       
   450         else
       
   451             {
       
   452             iDecoder->Convert( &iStatus, *iSourceBitmap );
       
   453             }
       
   454         }
       
   455     else
       
   456         {
       
   457         if ( iDestMask )
       
   458             {
       
   459             iDecoder->Convert( &iStatus, *iDestBitmap, *iDestMask );
       
   460             }
       
   461         else
       
   462             {
       
   463             iDecoder->Convert( &iStatus, *iDestBitmap );
       
   464             }
       
   465         }
       
   466     SetActive();
       
   467     }
       
   468 
       
   469 // ---------------------------------------------------------
       
   470 // CUniImageProcessor::ScaleImage
       
   471 //
       
   472 // ---------------------------------------------------------
       
   473 //
       
   474 void CUniImageProcessor::ScaleImage( TBool aMask )
       
   475     {
       
   476     UNILOGGER_ENTERFN( "CUniImageProcessor: ScaleImage()" );
       
   477     
       
   478     iStatus = KRequestPending;
       
   479     if ( aMask )
       
   480         {
       
   481         iScaler->Scale( &iStatus, *iSourceMask, *iDestMask, iAspectRatio );
       
   482         }
       
   483     else
       
   484         {
       
   485         iScaler->Scale( &iStatus, *iSourceBitmap, *iDestBitmap, iAspectRatio );
       
   486         }
       
   487     SetActive();
       
   488     }
       
   489 
       
   490 // ---------------------------------------------------------
       
   491 // CUniImageProcessor::EncodeImageL
       
   492 //
       
   493 // ---------------------------------------------------------
       
   494 //
       
   495 void CUniImageProcessor::EncodeImageL( TBool aCompressing )
       
   496     {
       
   497     UNILOGGER_ENTERFN( "CUniImageProcessor: EncodeImageL()" );
       
   498 
       
   499     if ( aCompressing )
       
   500         {
       
   501         delete iEncoder;
       
   502         iEncoder = NULL;
       
   503         // Make sure that the file is empty.
       
   504         User::LeaveIfError( iDestFile->SetSize( 0 ) );
       
   505         iEncoder = CImageEncoder::FileNewL( *iDestFile, KMsgMimeImageJpeg );
       
   506         }
       
   507     iCompressTriesLeft--;
       
   508     iStatus = KRequestPending;
       
   509     iEncoder->Convert( &iStatus, *iDestBitmap, iFrameImageData );
       
   510     SetActive();
       
   511     }
       
   512 
       
   513 // ---------------------------------------------------------
       
   514 // CUniImageProcessor::DoCancel
       
   515 //
       
   516 // ---------------------------------------------------------
       
   517 //
       
   518 void CUniImageProcessor::DoCancel()
       
   519     {
       
   520     UNILOGGER_ENTERFN( "CUniImageProcessor: DoCancel()" );
       
   521     if ( iDecoder )
       
   522         {
       
   523         iDecoder->Cancel();
       
   524         }
       
   525     if ( iScaler )
       
   526         {
       
   527         iScaler->Cancel();
       
   528         }
       
   529     if ( iEncoder )
       
   530         {
       
   531         iEncoder->Cancel();
       
   532         }
       
   533     
       
   534     iError = KErrCancel;    
       
   535     iCallback->ImageProcessingReady( TSize(), 0, EFalse );   
       
   536     }
       
   537 
       
   538 // ---------------------------------------------------------
       
   539 // CUniImageProcessor::RunL
       
   540 //
       
   541 // ---------------------------------------------------------
       
   542 //
       
   543 void CUniImageProcessor::RunL()
       
   544     {
       
   545     UNILOGGER_ENTERFN( "CUniImageProcessor: RunL()" );
       
   546     UNILOGGER_WRITEF( _L("iStatus: %d"), iStatus.Int() );
       
   547     TSize size( 0, 0 );
       
   548     if ( iStatus < 0 )
       
   549         {
       
   550         iError = iStatus.Int();
       
   551         }
       
   552     if ( iError )
       
   553         {
       
   554         UNILOGGER_WRITE( "Error occured. Scaling aborted." );
       
   555         TBool compressed( EFalse );
       
   556         if ( iTargetFileSize &&
       
   557             iCompressTriesLeft != KIterationCount &&
       
   558             !( iFlags & EImplicitCompress ) )
       
   559             {
       
   560             compressed = ETrue;
       
   561             }
       
   562         Reset();
       
   563         iCallback->ImageProcessingReady( size, 0, compressed );
       
   564         }
       
   565     else if ( iDecoder )
       
   566         {
       
   567         delete iDecoder;
       
   568         iDecoder = NULL;
       
   569         if ( iScaler )
       
   570             {
       
   571             if ( iSourceMask )
       
   572                 {
       
   573                 //scale mask first
       
   574                 ScaleImage( ETrue );
       
   575                 }
       
   576             else
       
   577                 {
       
   578                 ScaleImage( EFalse );
       
   579                 }
       
   580             }
       
   581         else if ( iEncoder )
       
   582             {
       
   583             if ( iFlags & ECompressOnly )
       
   584                 {
       
   585                 ResolveQFactorL();
       
   586                 }
       
   587             // In "compress only" case the "aCompressing" flag is
       
   588             // EFalse for first time because we do not want
       
   589             // to delete & recreate CImageEncoder unnecessarily.
       
   590             EncodeImageL( EFalse );
       
   591             }
       
   592         else
       
   593             {
       
   594             UNILOGGER_WRITE( "Scaling ready (no scaling nor endocing)." );
       
   595             size = iDestBitmap->SizeInPixels();
       
   596             Reset();
       
   597             iCallback->ImageProcessingReady( size, iResultFileSize, EFalse );
       
   598             }
       
   599         }
       
   600     else if ( iScaler )
       
   601         {
       
   602         if ( iSourceMask )
       
   603             {
       
   604             delete iSourceMask;
       
   605             iSourceMask = NULL;
       
   606             iFlags &= ~ESourceMaskOwned;
       
   607             //mask already scaled, scale bitmap
       
   608             ScaleImage( EFalse );
       
   609             }
       
   610         else
       
   611             {
       
   612             delete iScaler;
       
   613             iScaler = NULL;
       
   614             if ( iEncoder )
       
   615                 {
       
   616                 EncodeImageL( EFalse );
       
   617                 }
       
   618             else
       
   619                 {
       
   620                 UNILOGGER_WRITE( "Scaling ready (no endocing)." );
       
   621                 size = iDestBitmap->SizeInPixels();
       
   622                 Reset();
       
   623                 iCallback->ImageProcessingReady( size, iResultFileSize, EFalse );
       
   624                 }
       
   625             }
       
   626         }
       
   627     else 
       
   628         {
       
   629         UNILOGGER_WRITE( "Scaling ready." );
       
   630         if ( CheckEncodedFileSize() || 
       
   631              ( iCompressTriesLeft <= 0 ) )
       
   632             {
       
   633             size = iDestBitmap->SizeInPixels();
       
   634             TBool compressed( EFalse );
       
   635             if ( iTargetFileSize &&
       
   636                 iCompressTriesLeft != KIterationCount &&
       
   637                 !( iFlags & EImplicitCompress ) )
       
   638                 {
       
   639                 compressed = ETrue;
       
   640                 }
       
   641             Reset();
       
   642             iCallback->ImageProcessingReady( size, iResultFileSize, compressed );
       
   643             }
       
   644         else
       
   645             {
       
   646             ResolveQFactorL();
       
   647             EncodeImageL( ETrue );
       
   648             }
       
   649         }
       
   650     }
       
   651 
       
   652 // ---------------------------------------------------------
       
   653 // CUniImageProcessor::RunError
       
   654 //
       
   655 // ---------------------------------------------------------
       
   656 //
       
   657 TInt CUniImageProcessor::RunError( TInt aError )
       
   658     {
       
   659     UNILOGGER_ENTERFN( "CUniImageProcessor: RunError()" );
       
   660     UNILOGGER_WRITEF( _L("aError: %d"), aError );
       
   661     iError = aError;
       
   662     Cancel();
       
   663     //Complete self.
       
   664     iStatus = KRequestPending;
       
   665     TRequestStatus* pStatus = &iStatus;
       
   666     SetActive();
       
   667     User::RequestComplete( pStatus, KErrNone );
       
   668     return KErrNone;
       
   669     }
       
   670 
       
   671 // ---------------------------------------------------------
       
   672 // CUniImageProcessor::Reset
       
   673 //
       
   674 // ---------------------------------------------------------
       
   675 //
       
   676 EXPORT_C void CUniImageProcessor::Reset()
       
   677     {
       
   678     UNILOGGER_ENTERFN( "CUniImageProcessor: Reset()" );
       
   679     iDestFile = NULL;
       
   680     
       
   681     delete iDecoder;
       
   682     iDecoder = NULL;
       
   683     
       
   684     delete iScaler;
       
   685     iScaler = NULL;
       
   686     
       
   687     delete iEncoder;
       
   688     iEncoder = NULL;
       
   689     
       
   690     delete iFrameImageData;
       
   691     iFrameImageData = NULL;
       
   692     
       
   693     if ( iFlags & ESourceBitmapOwned )
       
   694         {
       
   695         delete iSourceBitmap;
       
   696         }
       
   697         
       
   698     iSourceBitmap = NULL;
       
   699     iFlags &= ~ESourceBitmapOwned;
       
   700     
       
   701     if ( iFlags & EDestBitmapOwned )
       
   702         {
       
   703         delete iDestBitmap;
       
   704         }
       
   705     
       
   706     iDestBitmap = NULL;
       
   707     iFlags &= ~EDestBitmapOwned;
       
   708     
       
   709     if ( iFlags & ESourceMaskOwned )
       
   710         {
       
   711         delete iSourceMask;
       
   712         }
       
   713     
       
   714     iSourceMask = NULL;
       
   715     iFlags &= ~ESourceMaskOwned;
       
   716     
       
   717     if ( iFlags & EDestMaskOwned )
       
   718         {
       
   719         delete iDestMask;
       
   720         }
       
   721     
       
   722     iDestMask = NULL;
       
   723     iFlags &= ~EDestMaskOwned;
       
   724     }
       
   725 
       
   726 
       
   727 // ---------------------------------------------------------
       
   728 // CUniImageProcessor::CreateImageDataL
       
   729 //
       
   730 // ---------------------------------------------------------
       
   731 //
       
   732 void CUniImageProcessor::CreateImageDataL( const TDesC8& aTargetType, const TSize& aTargetSize )
       
   733     {    
       
   734     if ( aTargetType.CompareF( KMsgMimeImageJpeg ) == 0 )
       
   735         {
       
   736         TInt targetQF( KJpegQualityFactorNormal );
       
   737         if ( aTargetSize.iWidth <= KHighQualityMaxWidth &&
       
   738             aTargetSize.iHeight <= KHighQualityMaxHeight )
       
   739             {
       
   740             //Use higher quality factor for small images
       
   741             targetQF = KJpegQualityFactorHigh;
       
   742             }
       
   743 
       
   744         // Use original image data if available
       
   745         if ( iDecoder )
       
   746             {
       
   747             iFrameImageData = iDecoder->FrameData().AllocL();
       
   748             
       
   749             TInt imageDataCount = iFrameImageData->ImageDataCount();
       
   750             while ( imageDataCount-- )
       
   751                 {
       
   752                 TImageDataBlock* data = iFrameImageData->GetImageData( imageDataCount );
       
   753                 const TUid type = data->DataType();
       
   754                 if ( type == KJPGQTableUid )
       
   755                     {
       
   756                     TJpegQTable* qdata = static_cast<TJpegQTable*>( data );
       
   757                     if ( qdata->iTableIndex != TJpegQTable::ELumaTable &&
       
   758                         qdata->iTableIndex != TJpegQTable::EChromaTable )
       
   759                         {
       
   760                         // Jpeg encoder supports only two QTables. Others (probably
       
   761                         // another chroma table) must be removed. Otherwise Jpeg
       
   762                         // encoder leaves.
       
   763                         iFrameImageData->RemoveImageData( imageDataCount );
       
   764                         delete qdata;
       
   765                         }
       
   766                     }
       
   767                 else if ( type == KJPGImageDataUid )
       
   768                     {
       
   769                     iJpegImageData = static_cast<TJpegImageData*>( data );
       
   770                     // iSourceBitmap is NULL, if image is in right size
       
   771                     iOriginalQualityFactor = iJpegImageData->iQualityFactor;
       
   772                     if ( iSourceBitmap )
       
   773                         {
       
   774                         CalculateMPixfactorL();
       
   775                         iJpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ;
       
   776                         iQFactorCalculated = ETrue;
       
   777                         }                    
       
   778                     }
       
   779                 }                
       
   780             }
       
   781         if ( !iJpegImageData )
       
   782             {
       
   783             // Delete possibly existing iFrameImageData. There maybe one at least
       
   784             // when converting PNG images to JPEG.
       
   785             delete iFrameImageData;
       
   786             iFrameImageData = NULL;
       
   787             iFrameImageData = CFrameImageData::NewL();
       
   788             TJpegImageData* jpegImageData = new ( ELeave ) TJpegImageData;
       
   789             CleanupStack::PushL( jpegImageData );
       
   790             jpegImageData->iSampleScheme = TJpegImageData::EColor420;
       
   791 
       
   792             iOriginalQualityFactor = targetQF;
       
   793             if ( iSourceBitmap )
       
   794                 {
       
   795                 iMPixFactor  = Max ( KMPixfactorMin, 
       
   796                     (   static_cast<TReal>( iSourceBitmap->SizeInPixels().iWidth ) * 
       
   797                         static_cast<TReal>( iSourceBitmap->SizeInPixels().iHeight ) ) / KQFMPixfactor );
       
   798                 iMPixFactor = Min( iMPixFactor, KMPixfactorMax );
       
   799                 jpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ;
       
   800                 iQFactorCalculated = ETrue;
       
   801                 }
       
   802             else
       
   803                 {
       
   804                 jpegImageData->iQualityFactor = iOriginalQualityFactor ;
       
   805                 }
       
   806             User::LeaveIfError( iFrameImageData->AppendImageData( jpegImageData ) );
       
   807             iJpegImageData = jpegImageData;
       
   808             CleanupStack::Pop(); // jpegFormat, ownership transferred
       
   809             }
       
   810         }
       
   811     }
       
   812     
       
   813 // ----------------------------------------------------------------------------
       
   814 // CUniImageProcessor::CalculateScaleRatio
       
   815 //
       
   816 // Calculates correct scaling ratio when aspect ratio needs to be preserved.
       
   817 // Correct scaling ratio is the smaller of the width and height original image
       
   818 // size and target image size ratios.
       
   819 // ----------------------------------------------------------------------------
       
   820 //
       
   821 TReal CUniImageProcessor::CalculateScaleRatio( const TSize& aTargetSize,
       
   822                                             const TSize& aOriginalSize ) const
       
   823     {
       
   824     TReal widthRatio = static_cast<TReal>( aTargetSize.iWidth ) / 
       
   825                        static_cast<TReal>( aOriginalSize.iWidth );
       
   826 	TReal heightRatio = static_cast<TReal>( aTargetSize.iHeight ) / 
       
   827 	                    static_cast<TReal>( aOriginalSize.iHeight );
       
   828 	return ( widthRatio < heightRatio ) ? widthRatio : heightRatio;
       
   829     }
       
   830 
       
   831 // ---------------------------------------------------------
       
   832 // CUniImageProcessor::ResolveQFactorL
       
   833 //
       
   834 // ---------------------------------------------------------
       
   835 //
       
   836 void CUniImageProcessor::ResolveQFactorL()
       
   837     {
       
   838     UNILOGGER_ENTERFN( "CUniImageProcessor: ResolveQFactorL()" );
       
   839     
       
   840     // Leave if "JPGImageData" was not found.
       
   841     if ( !iJpegImageData )
       
   842         {
       
   843         User::Leave( KErrNotSupported );
       
   844         }
       
   845 
       
   846     if ( !iQFactorCalculated ) // First try
       
   847         {
       
   848         if ( iSourceBitmap )
       
   849             {
       
   850             CalculateMPixfactorL();
       
   851             iJpegImageData->iQualityFactor = iOriginalQualityFactor / iMPixFactor ;
       
   852             }
       
   853         else
       
   854             {
       
   855             iJpegImageData->iQualityFactor = iOriginalQualityFactor * 
       
   856                 KPercentCoefficientsCounts[ iMPixFactor - 1 ][Min( KIterationCount-iCompressTriesLeft, KIterationCount )] / 100;
       
   857                 
       
   858             }
       
   859         iQFactorCalculated = ETrue;
       
   860         }
       
   861     else
       
   862         {
       
   863         iJpegImageData->iQualityFactor = iOriginalQualityFactor * 
       
   864             KPercentCoefficientsCounts[ iMPixFactor - 1 ][Min( KIterationCount-iCompressTriesLeft, KIterationCount )] / 100;
       
   865         }
       
   866     
       
   867     if ( iJpegImageData->iQualityFactor <= 0 )
       
   868         {
       
   869         iJpegImageData->iQualityFactor = 0;
       
   870         iCompressTriesLeft = 0; // No use to iterate more than this.
       
   871         }
       
   872     }
       
   873 
       
   874 // ---------------------------------------------------------
       
   875 // CUniImageProcessor::CheckEncodedFileSize
       
   876 //
       
   877 // ---------------------------------------------------------
       
   878 //
       
   879 TBool CUniImageProcessor::CheckEncodedFileSize()
       
   880     {
       
   881     TBool retVal = ETrue;
       
   882 
       
   883     // Get encoded file size. 
       
   884     // Store possible error to "iError".
       
   885     iError = iDestFile->Size( iResultFileSize );
       
   886     
       
   887     if ( iTargetFileSize )
       
   888         {
       
   889         // Compression requested. Check whether the size is small enough.
       
   890         retVal = ( iResultFileSize <= iTargetFileSize );
       
   891         }
       
   892     return retVal;
       
   893     }
       
   894 
       
   895 // ---------------------------------------------------------
       
   896 // CUniImageProcessor::CalculateMPixfactorL
       
   897 //
       
   898 // ---------------------------------------------------------
       
   899 //
       
   900 void CUniImageProcessor::CalculateMPixfactorL()
       
   901     {
       
   902     if ( iSourceBitmap )
       
   903         {
       
   904         iMPixFactor  = Max ( KMPixfactorMin, 
       
   905             (   static_cast<TReal>( iSourceBitmap->SizeInPixels().iWidth ) * 
       
   906                 static_cast<TReal>( iSourceBitmap->SizeInPixels().iHeight ) ) / KQFMPixfactor );
       
   907         }
       
   908     if (iMPixFactor == KMPixfactorMin )
       
   909         {
       
   910         // Sometimes on the emulator bitmap dimensions show completely wrong values.
       
   911         // Whether this happens also on the device is unknown
       
   912         // Just in case use files size as second option
       
   913         // As image size changes more rapidly as image dimension use extra divider
       
   914         if ( iTargetFileSize >= 0 )
       
   915             {
       
   916             iMPixFactor  = Max( KMPixfactorMin, ( iOriginalFileSize /  iTargetFileSize ) / KMPixSizeDivider );
       
   917             }
       
   918         }            
       
   919     iMPixFactor = Min( iMPixFactor, KMPixfactorMax );
       
   920     }
       
   921 
       
   922 //  End of File