--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mobilemessaging/unieditor/application/src/UniEditorProcessImageOperation.cpp Wed Sep 01 12:31:54 2010 +0100
@@ -0,0 +1,666 @@
+/*
+* 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: Provides CUniEditorProcessImageOperation methods.
+*
+*/
+
+
+
+// ========== INCLUDE FILES ================================
+
+#include <apmstd.h>
+
+#include <icl/imagedata.h>
+
+#include <centralrepository.h>
+
+#include <messagingvariant.hrh>
+#include <messaginginternalcrkeys.h> // for Central Repository keys
+
+#include <MsgMediaResolver.h>
+#include <MsgImageInfo.h>
+#include <MmsConformance.h>
+#include <MsgMimeTypes.h>
+
+#include <uniimageprocessor.h>
+#include <unimsventry.h>
+
+#include <mmsvattachmentmanager.h>
+#include <mmsvattachmentmanagersync.h>
+#include <cmsvattachment.h>
+
+#include <msgtextutils.h>
+
+#include <mmssettingsdefs.h>
+
+#include <mmsversion.h>
+
+#include "UniClientMtm.h"
+#include "UniEditorEnum.h"
+#include "UniEditorDocument.h"
+#include "UniEditorProcessImageOperation.h"
+
+// ========== CONSTANTS ====================================
+
+// Leave some space after compression so that text can be inserted to the
+// message.
+const TInt KUniCompressionMargin = 10 * 1024; // 10 kB
+
+const TInt KUniMmsUploadImageWidth = 1600;
+const TInt KUniMmsUploadImageHeight = 1200;
+
+
+_LIT8( KUniExtImageJpeg_8, ".jpg" );
+_LIT8( KUniExtImageGif_8, ".gif" );
+
+// ========== MEMBER FUNCTIONS =============================
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::NewL
+//
+// Factory method.
+// ---------------------------------------------------------
+//
+CUniEditorProcessImageOperation* CUniEditorProcessImageOperation::NewL(
+ MUniEditorOperationObserver& aObserver,
+ CUniEditorDocument& aDocument,
+ RFs& aFs )
+ {
+ CUniEditorProcessImageOperation* self = new ( ELeave ) CUniEditorProcessImageOperation(
+ aObserver,
+ aDocument,
+ aFs );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::CUniEditorProcessImageOperation.
+// ---------------------------------------------------------
+//
+CUniEditorProcessImageOperation::CUniEditorProcessImageOperation(
+ MUniEditorOperationObserver& aObserver,
+ CUniEditorDocument& aDocument,
+ RFs& aFs ) :
+ CUniEditorOperation( aObserver, aDocument, aFs, EUniEditorOperationProcessImage ),
+ iNewAttaId( KMsvNullIndexEntryId ),
+ iOptimizedFlow(EFalse)
+ {
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::ConstructL
+//
+// 2nd phase constructor.
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::ConstructL()
+ {
+ BaseConstructL();
+
+ TInt featureBitmask( 0 );
+
+ CRepository* repository = CRepository::NewL( KCRUidMuiuVariation );
+ repository->Get( KMuiuMmsFeatures, featureBitmask );
+
+ iExactImageScaling = ( featureBitmask & KMmsFeatureIdExactImageScaling );
+
+ delete repository;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::~CUniEditorProcessImageOperation
+// ---------------------------------------------------------
+//
+CUniEditorProcessImageOperation::~CUniEditorProcessImageOperation()
+ {
+ Cancel();
+
+ delete iNewImageInfo;
+ iNewImageFile.Close();
+ delete iEditStore;
+ delete iImageProcessor;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::Process
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::Process( CMsgImageInfo* aImageInfo,
+ TMsvAttachmentId aAttachmentId,
+ TInt aMessageSize )
+ {
+ ResetErrors();
+
+ iImageInfo = aImageInfo;
+ iAttachmentId = aAttachmentId;
+ iMessageSize = aMessageSize;
+ iOperationState = EUniProcessImgCheck;
+
+ CompleteSelf( KErrNone );
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DetachAttachmentId
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DetachAttachmentId( TMsvAttachmentId& aAttachmentId )
+ {
+ // iNewImageInfo may be already detached in DetachImageInfo
+ aAttachmentId = iNewAttaId;
+ iNewAttaId = KMsvNullIndexEntryId;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::RunL
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::RunL()
+ {
+ PrintOperationAndState();
+ if ( iStatus.Int() != KErrNone )
+ {
+ SetError( iStatus.Int() );
+ iOperationState = EUniProcessImgError;
+ }
+
+ switch ( iOperationState )
+ {
+ case EUniProcessImgCheck:
+ {
+ DoStartCheck();
+ break;
+ }
+ case EUniProcessImgProcess:
+ {
+ DoStartProcessL();
+ break;
+ }
+ case EUniProcessImgResolve:
+ {
+ DoStartResolveL();
+ break;
+ }
+ case EUniProcessImgReady:
+ {
+ iObserver.EditorOperationEvent( EUniEditorOperationProcessImage,
+ EUniEditorOperationComplete );
+ break;
+ }
+ case EUniProcessImgError:
+ {
+ DoErrorWithoutStateChange();
+ iObserver.EditorOperationEvent( EUniEditorOperationProcessImage,
+ EUniEditorOperationError );
+ break;
+ }
+ default:
+ {
+ iObserver.EditorOperationEvent( EUniEditorOperationProcessImage,
+ EUniEditorOperationError );
+ break;
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DoCancelCleanup
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DoCancelCleanup()
+ {
+ if ( iImageProcessor )
+ {
+ iImageProcessor->Cancel();
+ }
+
+ DoErrorWithoutStateChange();
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DoStartCheck
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DoStartCheck()
+ {
+ if ( !CheckNeedToProcess() )
+ {
+ iOperationState = EUniProcessImgError;
+ }
+ else if ( iProcessMethod == EUniProcessImgMethodNone )
+ {
+ iOperationState = EUniProcessImgReady;
+ }
+ else
+ {
+ iOperationState = EUniProcessImgProcess;
+ }
+ CompleteSelf( KErrNone );
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DoStartProcessL
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DoStartProcessL()
+ {
+
+ if(iOptimizedFlow)
+ {
+ iObserver.EditorOperationEvent( EUniEditorOperationProcessImage,
+ EUniEditorOperationPartialComplete );
+ iOptimizedFlow = EFalse;
+ }
+ CreateEmptyAttachmentL();
+
+ if ( !iImageProcessor )
+ {
+ iImageProcessor = new( ELeave )CUniImageProcessor( this );
+ }
+
+ RFile sourceFile = OpenFileForReadingL();
+
+ CleanupClosePushL( sourceFile );
+
+ iImageProcessor->ProcessImageL( sourceFile,
+ iNewImageFile,
+ iScaleSize,
+ iTargetType.Des8(),
+ ETrue, // Always maintain aspect ratio
+ iDocument.MaxMessageSize() - KUniCompressionMargin );
+ SetPending();
+
+ CleanupStack::PopAndDestroy(); // sourceFile;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DoStartResolveL
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DoStartResolveL()
+ {
+ iNewImageInfo = static_cast<CMsgImageInfo*>(iDocument.DataModel()->MediaResolver().CreateMediaInfoL( iNewImageFile ) );
+ iDocument.DataModel()->MediaResolver().ParseInfoDetailsL( iNewImageInfo, iNewImageFile );
+
+ iOperationState = EUniProcessImgReady;
+
+ iNewImageFile.Close();
+
+ __ASSERT_DEBUG( iEditStore, Panic( EUniNullPointer ) );
+
+ iEditStore->CommitL();
+ delete iEditStore;
+ iEditStore = NULL;
+
+ CompleteSelf( KErrNone );
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DoErrorWithoutStateChange
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::DoErrorWithoutStateChange()
+ {
+ iNewImageFile.Close();
+ delete iNewImageInfo;
+ iNewImageInfo = NULL;
+
+ delete iEditStore;
+ iEditStore = NULL;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::ImageProcessingReady
+//
+// Image Compressor callback implementation.
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::ImageProcessingReady( TSize aBitmapSize, TInt aFileSize, TBool aCompressed )
+ {
+ TInt err = iImageProcessor->Error();
+
+ if ( err == KErrNone &&
+ ( aBitmapSize.iWidth == 0 || aBitmapSize.iHeight == 0 ||
+ ( aCompressed &&
+ ( aFileSize == 0 ||
+ aFileSize > ( iDocument.MaxMessageSize() - KUniCompressionMargin ) ) ) ) )
+ {
+ err = KErrGeneral;
+ }
+
+ switch ( err )
+ {
+ case KErrNone:
+ {
+ iOperationState = EUniProcessImgResolve;
+ if ( aCompressed )
+ {
+ SetError( EUniProcessImgCompressSuccessful );
+ }
+ break;
+ }
+ case KErrNoMemory:
+ {
+ iOperationState = EUniProcessImgError;
+ SetError( EUniProcessImgOutOfMemory );
+ break;
+ }
+ case KErrDiskFull:
+ {
+ iOperationState = EUniProcessImgError;
+ SetError( EUniProcessImgOutOfDisk );
+ break;
+ }
+ case KErrNotFound:
+ {
+ iOperationState = EUniProcessImgError;
+ SetError( EUniProcessImgNotFound );
+ break;
+ }
+ default:
+ {
+ iOperationState = EUniProcessImgError;
+ if ( aCompressed )
+ {
+ SetError( EUniProcessImgCompressFailed );
+ }
+ else
+ {
+ SetError( EUniProcessImgScalingFailed );
+ }
+ break;
+ }
+ }
+
+ if ( err == KErrCancel )
+ {
+ CompleteOperation( KErrCancel );
+ }
+ else
+ {
+ CompleteOperation( KErrNone );
+ }
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::CheckNeedToProcess
+//
+// Checks if scaling/converting/compression is needed.
+// ---------------------------------------------------------
+//
+TBool CUniEditorProcessImageOperation::CheckNeedToProcess()
+ {
+ iProcessMethod = EUniProcessImgMethodNone;
+
+ TMmsConformance conformance =
+ iDocument.DataModel()->MmsConformance().MediaConformance( *iImageInfo );
+
+ if ( conformance.iCanAdapt == EFalse )
+ {
+ return ETrue;
+ }
+
+ TSize origSize = iImageInfo->Dimensions();
+
+ if ( origSize.iWidth == 0 || origSize.iHeight == 0 )
+ {
+ // Cannot get size -> corrupted
+ SetError( EUniProcessImgCorrupted );
+ return ETrue;
+ }
+
+ TSize scaleSize = ImageSendSize();
+ TSize optimizedSize = origSize;
+
+ while ( optimizedSize.iWidth > scaleSize.iWidth ||
+ optimizedSize.iHeight > scaleSize.iHeight )
+ {
+ // Largest possible (1/2)^n size
+ optimizedSize.iWidth >>= 1;
+ optimizedSize.iHeight >>= 1;
+ }
+
+ if ( scaleSize.iWidth < origSize.iWidth ||
+ scaleSize.iHeight < origSize.iHeight )
+ {
+ if ( !iExactImageScaling &&
+ ( scaleSize.iWidth > KMmsUniImageSmallWidth ||
+ scaleSize.iHeight > KMmsUniImageSmallHeight ) )
+ {
+ // Use optimized (1/2^n) size when scaling
+ // to larger than "Small"
+ scaleSize = optimizedSize;
+ }
+ // else -> scale to exact (non-optimized) size
+
+ iProcessMethod |= EUniProcessImgMethodScale;
+ }
+ else
+ {
+ // Scaling not needed. Check possible conversion need.
+ scaleSize = origSize;
+
+ if ( conformance.iConfStatus & EMmsConfNokConversionNeeded )
+ {
+ // Conversion needed.
+ iProcessMethod |= EUniProcessImgMethodConvert;
+ }
+ }
+
+ if ( !( iProcessMethod & EUniProcessImgMethodScale ) &&
+ ( iImageInfo->FileSize() + iMessageSize ) > iDocument.MaxMessageSize() &&
+ iImageInfo->MimeType().CompareF( KMsgMimeImageJpeg ) == 0 &&
+ iMessageSize < KUniCompressionMargin )
+ {
+ // Only compression needed as image is JPEG that is larger than can be fitted
+ // into the message and scaling is not performed. Also current message size
+ // is under comression margin.
+ iProcessMethod |= EUniProcessImgMethodCompress;
+ }
+
+ TBool largeImageQuery = EFalse;
+ TInt conformanceWidth = KImageRichWidth;
+ TInt conformanceHeight = KImageRichHeight;
+
+ if (iDocument.DataModel()->MmsConformance().ConformanceVersion()> KMmsVersion12)
+ {
+ conformanceWidth = KImageMegapixelWidth;
+ conformanceHeight = KImageMegapixelHeight;
+ }
+
+ if ( iProcessMethod == EUniProcessImgMethodNone )
+ {
+ // Image won't be processed
+ if ( ( origSize.iWidth > conformanceWidth ||
+ origSize.iHeight > conformanceHeight ) &&
+ ( iImageInfo->FileSize() + iMessageSize ) < iDocument.MaxMessageSize() )
+ {
+ // Original image width or height is "non-conformant" and original image would
+ // fit to into the message without any processing.
+ largeImageQuery = ETrue;
+ }
+ }
+ else
+ {
+ // Image will be processed
+ if ( scaleSize.iWidth > conformanceWidth ||
+ scaleSize.iHeight > conformanceHeight )
+ {
+ // Processed image is "non-conformant" after processing.
+ largeImageQuery = ETrue;
+ }
+ }
+
+ if ( largeImageQuery && iDocument.CreationMode() == EMmsCreationModeWarning )
+ {
+ // Observer will make the final decision whether it will show the query or not.
+ if ( !iObserver.EditorOperationQuery( EUniEditorOperationProcessImage,
+ EMEOQueryGuidedInsertLarge ) )
+ {
+ SetError( EUniProcessImgUserAbort );
+ return EFalse; // Abort
+ }
+ }
+
+ iScaleSize = scaleSize;
+ return ETrue;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::CreateEmptyAttachmentL
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::CreateEmptyAttachmentL()
+ {
+ iNewAttaId = KMsvNullIndexEntryId;
+
+ // Get the file name from original full path name.
+ TParsePtrC parser( iImageInfo->FullFilePath() );
+
+ TFileName ext( parser.Ext() );
+ iTargetType = iImageInfo->MimeType();
+
+ if ( iTargetType.Des8().CompareF( KMsgMimeImagePng ) == 0 )
+ {
+ //png is non-conformant image type
+ //->convert to jpeg
+ iTargetType = TDataType( KMsgMimeImageJpeg );
+ ext.Zero();
+ ext.Copy( KUniExtImageJpeg_8 );
+ }
+ else if ( iTargetType.Des8().CompareF( KMsgMimeImageWbmp ) == 0 )
+ {
+ //no wbmp encoder
+ //->convert to gif if scaling is needed
+ iTargetType = TDataType( KMsgMimeImageGif );
+ ext.Zero();
+ ext.Copy( KUniExtImageGif_8 );
+ }
+
+ TFileName newFileName( parser.Name() );
+ newFileName.Append( ext );
+
+ iEditStore = iDocument.Mtm().Entry().EditStoreL();
+ MMsvAttachmentManagerSync& managerSync = iEditStore->AttachmentManagerExtensionsL();
+ CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
+ CleanupStack::PushL( attachment );
+
+ attachment->SetMimeTypeL( iTargetType.Des8() );
+
+ managerSync.CreateAttachmentL( newFileName, iNewImageFile, attachment );
+ CleanupStack::Pop( attachment ); // ownership transferred
+
+ iNewAttaId = attachment->Id();
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::ImageSendSize
+// ---------------------------------------------------------
+//
+TSize CUniEditorProcessImageOperation::ImageSendSize() const
+ {
+ TSize size;
+ if( TUniMsvEntry::IsMmsUpload( iDocument.Entry() ) )
+ {
+ size.iWidth = KUniMmsUploadImageWidth;
+ size.iHeight = KUniMmsUploadImageHeight;
+ }
+ else
+ {
+ size = iDocument.MaxImageSize();
+ }
+ return size;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::OpenFileForReadingL
+// ---------------------------------------------------------
+//
+RFile CUniEditorProcessImageOperation::OpenFileForReadingL()
+ {
+ RFile sourceFile;
+ if ( iAttachmentId != KMsvNullIndexEntryId )
+ {
+ __ASSERT_DEBUG( iEditStore, Panic( EUniNullPointer ) );
+ sourceFile = iEditStore->AttachmentManagerL().GetAttachmentFileL( iAttachmentId );
+ }
+ else
+ {
+ TInt err = sourceFile.Open(
+ iFs, iImageInfo->FullFilePath(), EFileRead | EFileShareAny );
+ if ( err )
+ {
+ err = sourceFile.Open(
+ iFs, iImageInfo->FullFilePath(), EFileRead | EFileShareReadersOnly );
+
+ User::LeaveIfError( err );
+ }
+ }
+ return sourceFile;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::RunError
+// ---------------------------------------------------------
+//
+TInt CUniEditorProcessImageOperation::RunError( TInt aError )
+ {
+ delete iImageProcessor;
+ iImageProcessor = NULL;
+
+ if ( aError == KErrNotFound )
+ {
+ aError = EUniProcessImgNotFound;
+ }
+ else if ( aError == KErrNoMemory )
+ {
+ aError = EUniProcessImgOutOfMemory;
+ }
+ else if ( aError == KErrDiskFull )
+ {
+ aError = EUniProcessImgOutOfDisk;
+ }
+ else if ( aError == KErrCorrupt )
+ {
+ aError = EUniProcessImgCorrupted;
+ }
+
+ return CUniEditorOperation::RunError( aError );
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::DetachImageInfo
+// ---------------------------------------------------------
+//
+CMsgImageInfo* CUniEditorProcessImageOperation::DetachImageInfo()
+ {
+ // ownership transferred
+ CMsgImageInfo* tempInfo = iNewImageInfo;
+ iNewImageInfo = NULL;
+ return tempInfo;
+ }
+
+// ---------------------------------------------------------
+// CUniEditorProcessImageOperation::SetOptimizedFlow
+// ---------------------------------------------------------
+//
+void CUniEditorProcessImageOperation::SetOptimizedFlow(TBool aOptimizedFlow)
+ {
+ iOptimizedFlow = aOptimizedFlow;
+ }
+// End of file