camerauis/cameraapp/generic/src/cameracontroller/camimagedecoder.cpp
branchRCL_3
changeset 24 bac7acad7cb3
--- /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