--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/camerauis/cameraapp/generic/src/cameracontroller/camimagedecoder.cpp Wed Sep 01 12:30:54 2010 +0100
@@ -0,0 +1,438 @@
+/*
+* Copyright (c) 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: Implementation of Camera image decoder
+*
+*/
+
+
+#include <imageconversion.h>
+#include <ExifRead.h>
+#include <ecam.h> // MCameraBuffer
+
+#include <eikenv.h>
+#include <SvgCodecImageConstants.hrh>
+#include <SVGEngineInterfaceImpl.h>
+
+#include "camlogging.h"
+#include "camfilesaveutility.h"
+#include "cambuffershare.h"
+
+#include "camimagedecoder.h"
+
+// ===========================================================================
+// Local constants
+
+namespace NCamCameraController
+ {
+ // Decoding flags
+ static const TUint32 KConversionOptions =
+ ( CImageDecoder::EOptionNone
+ | CImageDecoder::EOptionAlwaysThread
+ | CImageDecoder::EPreferFastDecode
+ );
+
+ // EXIF reader flags
+ // Only need the thumbnail, so no need to parse the
+ // main (jpeg) image.
+ static const TUint KExifReaderFlags = CExifRead::ENoJpeg;
+
+ // Other constants
+ static const TInt KMaxRetries = 10;
+ static const TInt KPriority = CActive::EPriorityHigh;
+ }
+
+using namespace NCamCameraController;
+
+// ===========================================================================
+// public constructor and destructor
+
+CCamImageDecoder*
+CCamImageDecoder::NewL( MCamImageDecoderObserver& aObserver )
+ {
+ CCamImageDecoder* self =
+ new (ELeave) CCamImageDecoder( aObserver );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+
+CCamImageDecoder::~CCamImageDecoder()
+ {
+ PRINT( _L("Camera => ~CCamImageDecoder") );
+ Cancel();
+
+ delete iDecoder;
+
+ SetImageData( NULL );
+ if(iDecodedBitmap)
+ {
+ delete iDecodedBitmap;
+ iDecodedBitmap = NULL;
+ }
+ if ( iDecodedMask )
+ {
+ delete iDecodedMask;
+ iDecodedMask = NULL;
+ }
+
+ delete iSvgEngine;
+ iFs.Close();
+ PRINT( _L("Camera <= ~CCamImageDecoder") );
+ }
+
+// ===========================================================================
+// public methods
+void
+CCamImageDecoder::StartConversionL( CCamBufferShare* aBuffer )
+ {
+ PRINT( _L("Camera => CCamImageDecoder::StartConversionL") );
+
+ // Data for CImageDecoder must be available throughout the conversion.
+ // Need to stop any outstanding operation before deleting the descriptor.
+ Cancel();
+
+ PRINT( _L("Camera <> CCamImageDecoder: Copying image data..") );
+
+ SetImageData( aBuffer );
+
+ // GetImageDataL leaves if no data available.
+ TDesC8* imageData = GetImageDataL();
+
+ PRINT( _L("Camera <> CCamImageDecoder: Creating decoder..") );
+
+ delete iDecoder;
+ iDecoder = NULL;
+ iDecoder = CImageDecoder::DataNewL( iFs, *imageData, (CImageDecoder::TOptions)KConversionOptions );
+
+ if( iDecoder->FrameCount() > 0 )
+ {
+ const TFrameInfo& info( iDecoder->FrameInfo() );
+
+#ifdef _DEBUG
+ TSize size = info.iOverallSizeInPixels;
+ PRINT2( _L("Camera <> CCamImageDecoder: Bmp size(%d,%d)"), size.iWidth, size.iHeight );
+ PRINT1( _L("Camera <> CCamImageDecoder: Bmp dispmode(%d)"), info.iFrameDisplayMode );
+#endif
+
+ PRINT( _L("Camera <> CCamImageDecoder: Create bitmap for snapshot..") );
+ if( !iDecodedBitmap ) iDecodedBitmap = new (ELeave) CFbsBitmap;
+ else iDecodedBitmap->Reset();
+
+ TInt createError = iDecodedBitmap->Create( info.iOverallSizeInPixels,
+ info.iFrameDisplayMode );
+ if( KErrNone != createError )
+ {
+ delete iDecodedBitmap;
+ iDecodedBitmap = NULL;
+ User::Leave( createError );
+ }
+
+ PRINT( _L("Camera <> CCamImageDecoder: start conversion..") );
+ iRetryCounter = 0;
+ iDecoder->Convert( &iStatus, *iDecodedBitmap, 0 );
+ SetActive();
+ }
+ else
+ {
+ PRINT( _L("Camera <> CCamImageDecoder: No frame provided, leave..") );
+ User::Leave( KErrNotFound );
+ }
+
+ PRINT( _L("Camera <= CCamImageDecoder::StartConversionL") );
+ }
+
+// ---------------------------------------------------------------------------
+// CCamImageDecoder::StartIconConversionL
+// ---------------------------------------------------------------------------
+//
+void CCamImageDecoder::StartIconConversionL( TDesC* aFilePath, TSize& aSize )
+ {
+ PRINT3( _L("Camera => CCamImageDecoder::StartIconConversionL, file:[%S], size:(%d,%d)"),
+ &(*aFilePath), aSize.iWidth, aSize.iHeight );
+
+ // Delete any previous bitmaps, if any
+ delete iDecodedBitmap,
+ iDecodedBitmap = NULL;
+ delete iDecodedMask;
+ iDecodedMask = NULL;
+
+ // Create bitmap for use while decoding
+ CFbsBitmap* frameBuffer = new (ELeave) CFbsBitmap;
+ CleanupStack::PushL( frameBuffer );
+
+ TFontSpec spec;
+ if ( !iSvgEngine )
+ {
+ iSvgEngine = CSvgEngineInterfaceImpl::NewL( frameBuffer, NULL, spec );
+ }
+
+ TInt domHandle = KErrNotFound;
+ MSvgError* serr = iSvgEngine->PrepareDom( *aFilePath, domHandle );
+ PRINT3( _L("Camera <> prepare svg dom reader, warning:%d, err code:%d, description:[%S]"),
+ serr->IsWarning(), serr->ErrorCode(), &(serr->Description()) );
+ if ( serr->HasError() && !serr->IsWarning() )
+ {
+ PRINT1( _L("Camera <> leaving with error:%d"), serr->SystemErrorCode() );
+ User::Leave( serr->SystemErrorCode() );
+ }
+
+ // create image bitmap
+ PRINT( _L("Camera <> CCamImageDecoder: Create bitmap for snapshot..") );
+ if( !iDecodedBitmap ) iDecodedBitmap = new (ELeave) CFbsBitmap;
+ else iDecodedBitmap->Reset();
+
+ if( !iDecodedMask ) iDecodedMask = new (ELeave) CFbsBitmap;
+ else iDecodedMask->Reset();
+
+ TRAPD ( createError,
+ {
+ iDecodedBitmap->Create( aSize, EColor64K );
+ iDecodedMask->Create( aSize, EGray256 );
+ } );
+ if( createError )
+ {
+ PRINT1( _L("Camera <> Error while creating bitmaps:%d"), createError );
+ delete iDecodedBitmap;
+ iDecodedBitmap = NULL;
+ delete iDecodedMask;
+ iDecodedMask = NULL;
+ User::Leave( createError );
+ }
+
+ // create soft mask
+ iSvgEngine->SetViewportHeight((CSvgDocumentImpl *)domHandle, aSize.iHeight);
+ iSvgEngine->SetViewportWidth((CSvgDocumentImpl *)domHandle, aSize.iWidth);
+
+ // render svg image
+ serr = iSvgEngine->RenderDom( domHandle, iDecodedBitmap, iDecodedMask );
+ PRINT3( _L("Camera <> render svg, warning:%d, err code:%d, description:[%S]"),
+ serr->IsWarning(), serr->ErrorCode(), &(serr->Description()) );
+ if ( serr->HasError() && !serr->IsWarning() )
+ {
+ PRINT1( _L("Camera <> leaving with error:%d"), serr->SystemErrorCode() );
+ User::Leave( serr->SystemErrorCode() );
+ }
+
+ CleanupStack::PopAndDestroy( frameBuffer );
+ if ( !IsActive() )
+ {
+ SetActive();
+ }
+
+ PRINT( _L("Camera <= CCamImageDecoder::StartIconConversionL") );
+ }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+TDesC8*
+CCamImageDecoder::GetImageDataL()
+ {
+ PRINT( _L("Camera => CCamImageDecoder::GetImageDataL") );
+
+ if( !iSharedImageData ||
+ !iSharedImageData->SharedBuffer() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ TDesC8* data = iSharedImageData->SharedBuffer()->DataL( 0 );
+
+ if( !data )
+ User::Leave( KErrNotFound );
+
+ delete iThumbnailData;
+ iThumbnailData = ReadExifThumbNail( *data ); // Returns NULL on errors
+
+#ifdef CAMERAAPP_CREATE_TESTIMAGE
+ TRAPD( saveStatus1, SaveImageDataToFileL( *data, _L("testimagefull.jpg") ) );
+ PRINT1( _L("Camera <> CCamImageDecoder: Save full image to file status:%d"), saveStatus1 );
+ if( iThumbnailData )
+ {
+ TRAPD( saveStatus2, SaveImageDataToFileL( *iThumbnailData, _L("testimagethumb.jpg") ) );
+ PRINT1( _L("Camera <> CCamImageDecoder: Save thumbnail to file status:%d"), saveStatus2 );
+ }
+#endif
+
+
+ if( iThumbnailData )
+ {
+ data = iThumbnailData;
+ }
+
+ PRINT1( _L("Camera <= CCamImageDecoder::GetImageDataL, data size:%d"), data->Size() );
+ return data;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+HBufC8*
+CCamImageDecoder::ReadExifThumbNail( const TDesC8& aExifData )
+ {
+ PRINT( _L("Camera => CCamImageDecoder::ReadExifThumbNailL") );
+ HBufC8* thumb = NULL;
+ TRAP_IGNORE(
+ {
+ CExifRead* reader = CExifRead::NewL( aExifData, KExifReaderFlags );
+ CleanupStack::PushL( reader );
+ thumb = reader->GetThumbnailL();
+ CleanupStack::PopAndDestroy( reader );
+ });
+
+ PRINT( _L("Camera <= CCamImageDecoder::ReadExifThumbNailL") );
+ return thumb;
+ }
+
+// ===========================================================================
+// from CActive
+
+// ---------------------------------------------------------------------------
+// virtual
+// ---------------------------------------------------------------------------
+//
+void
+CCamImageDecoder::DoCancel()
+ {
+ PRINT( _L("Camera => CCamImageDecoder::DoCancel") );
+
+ if( iDecoder )
+ {
+ iDecoder->Cancel();
+ delete iDecoder;
+ iDecoder = NULL;
+ }
+
+ SetImageData( NULL );
+
+ PRINT( _L("Camera <= CCamImageDecoder::DoCancel") );
+ }
+
+
+// ---------------------------------------------------------------------------
+// virtual
+// ---------------------------------------------------------------------------
+//
+void
+CCamImageDecoder::RunL()
+ {
+ PRINT1( _L("Camera => CCamImageDecoder::RunL, iStatus:%d"), iStatus.Int() );
+
+ switch( iStatus.Int() )
+ {
+ case KErrNone :
+ {
+ // CImageDecoder has finished using the data,
+ // so we are able to free it.
+ if ( iSvgEngine )
+ {
+ iSvgEngine->Destroy();
+ delete iSvgEngine;
+ iSvgEngine = NULL;
+ }
+ SetImageData( NULL );
+ iObserver.ImageDecodedL( iStatus.Int(), iDecodedBitmap, iDecodedMask );
+ break;
+ }
+ case KErrUnderflow :
+ {
+ // Decoder did not have enough data to convert.
+ // CImageDecoder documentation recommends calling
+ // repeatedly ContinueConvert.
+ if( iRetryCounter++ < KMaxRetries )
+ {
+ iStatus = KErrNone;
+ iDecoder->ContinueConvert( &iStatus );
+ SetActive();
+ }
+ else
+ {
+ // Handled in RunError
+ User::Leave( KErrUnderflow );
+ }
+ break;
+ }
+ case KErrCancel :
+ default :
+ {
+ User::Leave( iStatus.Int() );
+ break;
+ }
+ }
+
+ PRINT( _L("Camera <= CCamImageDecoder::RunL") );
+ }
+
+
+// ---------------------------------------------------------------------------
+// virtual
+// ---------------------------------------------------------------------------
+//
+TInt
+CCamImageDecoder::RunError( TInt aError )
+ {
+ PRINT1( _L("Camera => CCamImageDecoder::RunError(%d)"), aError );
+
+ SetImageData( NULL );
+ // Leave has occurred in RunL.
+ // Notify observer with error.
+ TRAP_IGNORE(iObserver.ImageDecodedL( aError, NULL, NULL ));
+
+ PRINT( _L("Camera <= CCamImageDecoder::RunError") );
+ return KErrNone;
+ }
+
+
+// ===========================================================================
+void
+CCamImageDecoder::SetImageData( CCamBufferShare* aBuffer )
+ {
+ if( iSharedImageData )
+ {
+ iSharedImageData->Release();
+ iSharedImageData = NULL;
+ }
+
+ iSharedImageData = aBuffer;
+
+ if( iSharedImageData )
+ iSharedImageData->Reserve();
+ }
+
+// ===========================================================================
+// private constructors
+
+
+void
+CCamImageDecoder::ConstructL()
+ {
+ User::LeaveIfError( iFs.Connect() );
+
+ CActiveScheduler::Add( this );
+ }
+
+
+
+CCamImageDecoder::CCamImageDecoder( MCamImageDecoderObserver& aObserver )
+ : CActive( KPriority ),
+ iObserver( aObserver )
+ {
+ }
+
+// end of file