Common/Src/IEEngineUtils.cpp
changeset 3 93fff7023be8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Common/Src/IEEngineUtils.cpp	Fri Oct 15 10:18:29 2010 +0900
@@ -0,0 +1,688 @@
+/*
+* Copyright (c) 2009 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: Juha Kauppinen, Mika Hokkanen
+* 
+* Description: Photo Browser
+*
+*/
+
+#include <exifmodify.h>
+#include <BAUTILS.H>
+#include "IEEngineUtils.h" 
+#include "ImagicConsts.h"
+#include "debug.h"
+#include <exifread.h>
+#include <ExifUtility.h> 
+#include <ICLExif.h> 
+//#include <iclextjpegapi.h>  // For CExtJpegDecoder
+
+#define KJpegDecIVAUidValue 0x10272C10
+#define KJpegOptUidValue 0x101FF555
+
+EXPORT_C CIEEngineUtils::CIEEngineUtils(RFs& aFs)
+    : iFs(aFs)
+    {
+    } 
+
+EXPORT_C CIEEngineUtils::~CIEEngineUtils()
+    {
+    }
+
+/* Generating IETNFileName with complete path */
+EXPORT_C void CIEEngineUtils::GenerateThumbnailFileName(
+        TThumbSize aTNResolution,
+        const TDesC& aSavedFileName, 
+        TDes &aIETNFileName)
+    {
+    TFileName tmpName;
+    TParse parser;
+    switch(aTNResolution)
+        {
+        case ESize512x512:
+            {
+            parser.Set(aSavedFileName, NULL, NULL);
+            tmpName = parser.DriveAndPath();//only path name
+            tmpName.Append(K512x512TNFilePath);
+            tmpName.Append(parser.NameAndExt());
+            tmpName.Append(K512x512Ext);
+            aIETNFileName.Copy(tmpName);
+            break;
+            }
+        case ESize128x128:
+           {
+           parser.Set(aSavedFileName, NULL, NULL);
+           tmpName = parser.DriveAndPath();//only path name
+           tmpName.Append(K128x128TNFilePath);
+           tmpName.Append(parser.NameAndExt());
+           tmpName.Append(K128x128Ext);
+           aIETNFileName.Copy(tmpName);
+           break;
+           }
+        case ESize32x32:
+           {
+           parser.Set(aSavedFileName, NULL, NULL);
+           tmpName = parser.DriveAndPath();//only path name
+           tmpName.Append(K32x32TNFilePath);
+           tmpName.Append(parser.NameAndExt());
+           tmpName.Append(K32x32Ext);
+           aIETNFileName.Copy(tmpName);
+           break;
+           }
+        default:
+           ASSERT(0);
+           break;
+        };
+    }
+
+EXPORT_C void CIEEngineUtils::DeleteThumbnails(TDesC& aFileName, RFs& aFs)
+    {
+    TThumbSize res[] = { ESize512x512, ESize128x128, ESize32x32 };
+    for (TInt i = 0;i < sizeof(res)/ sizeof(TThumbSize);i++)
+        {
+        TFileName thumbFileName;
+        GenerateThumbnailFileName(res[i], aFileName, thumbFileName);
+        BaflUtils::DeleteFile(aFs, thumbFileName);
+        }    
+    }
+
+/*Creating TN Folder */
+EXPORT_C TInt CIEEngineUtils::CreateTNFolder(RFs aFs, const TDesC& aTNPath)
+    {
+    TInt error = KErrNone;
+    if( !BaflUtils::PathExists( aFs, aTNPath ) )
+        {
+        error = aFs.MkDirAll( aTNPath );
+        error = aFs.SetAtt( aTNPath, KEntryAttHidden, NULL );
+        }
+   
+    return error;
+    }
+
+// Writes face coordinates to Exif data if faces was found
+EXPORT_C TInt CIEEngineUtils::AddFaceCoordinate(const TFileName aFilename, RArray<TRect>& aCordArray)
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::AddFaceCoordinate++"));
+    // Read first current maker note to new array from given file
+    RArray<TRect> newCordArray;
+    ReadFaceCoordinatesL(aFilename, newCordArray);
+     
+    // Append existing coords to new coords array
+    for(TInt i=0; i<newCordArray.Count(); i++)
+        {
+        aCordArray.Append(newCordArray[i]);
+        }
+              
+     // Write all coords to file exif data manufactorer note
+    WriteFaceCoordinatesL(aFilename, aCordArray);
+     
+    newCordArray.Close();
+    
+    DP0_IMAGIC(_L("CIEEngineUtils::AddFaceCoordinate--"));
+    return KErrNone;
+    }
+
+EXPORT_C HBufC8* CIEEngineUtils::ReadExifMakerNoteL(const TDes &aFileName)
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadExifMakerNoteL++"));
+    
+    HBufC8* exif = ReadExifHeaderL(iFs, aFileName);
+    CleanupStack::PushL( exif );
+    
+    CExifRead* exifRead = CExifRead::NewL(exif->Des(), CExifRead::ENoJpeg);
+    CleanupStack::PushL( exifRead );
+        
+    // Get required data from the Exif image...
+    /*TUint32  xRes;
+    TUint32  yRes;
+    exifRead->GetPixelXDimension(xRes);
+    exifRead->GetPixelYDimension(yRes);*/  
+    HBufC8* makerNote = exifRead->GetMakerNoteL();
+    CleanupStack::PushL( makerNote );
+            
+    CleanupStack::Pop( makerNote );
+    CleanupStack::PopAndDestroy( exifRead );
+    CleanupStack::PopAndDestroy( exif );
+
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadExifMakerNoteL--"));
+    return makerNote;
+    }
+
+EXPORT_C TInt CIEEngineUtils::RemoveFaceCoordinate(const TFileName a128x128TNFileName, RArray<TRect>& aCordArray)
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::RemoveFaceCoordinate++"));
+    
+    //Read first current make note
+    HBufC8* makerNote = ReadExifMakerNoteL(a128x128TNFileName);
+     
+    // Allocate buffer for coords to be removed
+    HBufC8* heapComment = HBufC8::NewL(100);
+    TPtr8 ptrCoords = heapComment->Des();
+    //Copy coords to be removed to descriptor
+    for(TInt i=0; i < aCordArray.Count(); i++)
+        {
+        ptrCoords.AppendNum(aCordArray[i].iTl.iX);
+        ptrCoords.Append(' ');
+        ptrCoords.AppendNum(aCordArray[i].iTl.iY);
+        ptrCoords.Append(' ');
+        ptrCoords.AppendNum(aCordArray[i].iBr.iX );
+        ptrCoords.Append(' ');
+        ptrCoords.AppendNum(aCordArray[i].iBr.iY);
+        ptrCoords.Trim();
+        }
+     
+    //Find coordinates from maker note
+    TPtr8 tmpPtr = makerNote->Des();
+    TInt res = tmpPtr.Find(ptrCoords);
+     
+    if(res == KErrNotFound)
+        return res;
+         
+    //Remove coordinates from maker note
+    TInt l = ptrCoords.Length();
+    tmpPtr.Delete(res, ptrCoords.Length()+1);
+     
+    //Find number of faces from maker note and update it
+    _LIT8(KNumberOfFace, "#");
+    res = tmpPtr.Find(KNumberOfFace);
+     
+    TLex8 lex(makerNote->Ptr());
+    lex.SkipAndMark(res+1);
+    TInt faceCount = 0;
+    lex.Val(faceCount);
+     
+    //Check lenght of number of faces string
+    TInt length = 0;
+    //TInt aFaceNumber = 1;
+    if(faceCount < 10)
+        length = 1;
+    else
+        length = 2;
+          
+    HBufC8* numberOfFaces = HBufC8::NewL(length);
+    TPtr8 FaceNroPtr = numberOfFaces->Des();
+    FaceNroPtr.AppendNum(faceCount-1);
+              
+    tmpPtr.Replace(res+1, length, FaceNroPtr);
+    //TPtr8 numberOfFaces;
+     
+    delete numberOfFaces;
+    //numberOfFaces.Copy();
+    
+    // 1. Read JPEG image from the file to a buffer...
+    RFile file;
+    User::LeaveIfError( file.Open( iFs, a128x128TNFileName, EFileWrite ) );
+    CleanupClosePushL( file );
+    TInt size = 0;
+    file.Size(size);
+    HBufC8* jpegImage = HBufC8::NewL( size );
+    CleanupStack::PushL( jpegImage );
+    TPtr8 bufferDes( jpegImage->Des() );
+    User::LeaveIfError( file.Read( bufferDes ) );
+    CleanupStack::Pop( jpegImage );
+    CleanupStack::PopAndDestroy();
+    CleanupStack::PushL( jpegImage );
+     
+    file.Close();
+     
+    // 2. Instantiate Exif modifier in ECreate mode...
+    CExifModify* modify = CExifModify::NewL( jpegImage->Des(), CExifModify::EModify );
+    CleanupStack::PushL( modify );
+     
+    //3. Insert (Set) at least the mandatory Exif data.
+    //TInt descSize = 300;
+    //HBufC8* heapComment = HBufC8::NewL(descSize);
+    TPtr8 ptr = makerNote->Des();
+     
+    modify->SetMakerNoteL(ptr);
+    //modify->SetMakerNoteL(makerNote->Des());
+     
+    // 4. Get the new Exif image...
+    // If zero length descriptor is given instead of jpeg->Des(), then only the
+    // Exif meta data is returned.
+    //HBufC8* newExif = modify->WriteDataL( jpegImage->Des() );
+    HBufC8* newExif;
+    TRAPD(err, newExif = modify->WriteDataL( jpegImage->Des() ));
+     
+    if(err != KErrNone)
+        {
+        TInt i=0;
+        }
+     
+    //TPtr8 tmp = newExif->Des();
+     
+    User::LeaveIfError( file.Replace( iFs, a128x128TNFileName, EFileWrite ) );
+    //Write Exif and jpeg image back to jpeg file
+    User::LeaveIfError(file.Write(*newExif));
+     
+    // Process the new Exif data
+    delete newExif;
+    newExif = NULL;
+     
+    // 5. Delete the modifier instance...
+    CleanupStack::PopAndDestroy( modify );
+    CleanupStack::PopAndDestroy( jpegImage );
+     
+    file.Close();
+    
+    DP0_IMAGIC(_L("CIEEngineUtils::RemoveFaceCoordinate--"));
+    return KErrNone;
+    }
+
+
+
+EXPORT_C void CIEEngineUtils::WriteFaceCoordinatesL(const TFileName a512x512TNFileName, RArray<TRect>& aCordArray)
+    {
+    DP1_IMAGIC(_L("CIEEngineUtils::WriteFaceCoordinatesL a512x512TNFileName = %S ++"), &a512x512TNFileName);
+    
+    TInt error = KErrNone;
+    RFile tnFile;
+    TInt size = 0;
+    
+    //Check that coords got from IDL makes sense. Eg. not out of image area etc.
+    /*TSize tnSize;
+    iImageDecoder->GetImageSizeL(iCurrentImageData->iMGTN_320x320_Filename, tnSize);
+    TInt brx;
+    
+    TInt count = aCordArray.Count();
+    TBool removed = EFalse;
+    for(TInt i=0; i<count; i++)
+        {
+        brx = aCordArray[i].iBr.iX;
+        brx = aCordArray[i].iBr.iY;
+        brx = aCordArray[i].iTl.iX;
+        brx = aCordArray[i].iTl.iY;
+        if(aCordArray[i].iTl.iX >= aCordArray[i].iBr.iX || aCordArray[i].iTl.iY >= aCordArray[i].iBr.iY)
+            {
+            aCordArray.Remove(i);
+            removed = ETrue;
+            }
+        if(removed)
+            count = aCordArray.Count();
+        }
+    */
+   
+    User::LeaveIfError(tnFile.Open(iFs, a512x512TNFileName, EFileRead));
+    
+    tnFile.Size(size);
+    
+    if(size <= 0) User::Leave(KErrUnderflow); // May be more meaningful error code shud be returned
+    
+    HBufC8* imageData = HBufC8::NewL(size);
+    
+    CleanupStack::PushL(imageData);
+    
+    TPtr8 imageDataPtr = imageData->Des();
+    
+    User::LeaveIfError(tnFile.Read(imageDataPtr));
+    
+    tnFile.Close();
+    
+    // Create the exifmodifier instance
+    CExifModify* exifModifier = CExifModify::NewL(imageDataPtr, CExifModify::ECreate);
+    
+    CleanupStack::PushL(exifModifier);
+    
+    //3. Insert (Set) at least the mandatory Exif data...
+    exifModifier->SetXResolutionL( 123, 1 ); 
+    exifModifier->SetYResolutionL( 512, 1 ); 
+    exifModifier->SetResolutionUnitL( 2 );
+    exifModifier->SetYCbCrPositioningL( 1 );
+    exifModifier->SetComponentsConfigurationL( 1, 2, 3, 0 );
+    exifModifier->SetColorSpaceL( 1 );
+    exifModifier->SetPixelXDimensionL( 512 );
+    exifModifier->SetPixelYDimensionL( 512 );
+    
+    TInt descSize = aCordArray.Count()*4*4 + 32+10; // Be careful calculating like this!!!
+    
+    HBufC8* heapComment = HBufC8::NewL(descSize);
+    
+    CleanupStack::PushL(heapComment);
+    
+    TPtr8 ptr = heapComment->Des();
+     
+    ptr.Append(KFaceCoordsHeader);
+    ptr.Append(KSpace);
+    ptr.Append(KFaceCoordsImagicVersion);
+    ptr.Append(KSpace);
+    ptr.Append(KHash);
+     
+    //Set number of faces detected to Exif data
+    if(aCordArray.Count() == 0)
+        ptr.Append(KZero);
+    else
+        {
+        ptr.AppendNum(aCordArray.Count());
+        ptr.Append(KSpace);
+        for(TInt i=0; i<aCordArray.Count(); i++)
+            {
+            //TInt size = ptr.Size();
+            ptr.AppendNum(aCordArray[i].iTl.iX);
+            ptr.Append(KSpace);
+            ptr.AppendNum(aCordArray[i].iTl.iY);
+            ptr.Append(KSpace);
+            ptr.AppendNum(aCordArray[i].iBr.iX);
+            ptr.Append(KSpace);
+            ptr.AppendNum(aCordArray[i].iBr.iY);
+            ptr.Append(KSpace);
+            }    
+        }
+    
+    exifModifier->SetMakerNoteL(ptr);
+    
+    HBufC8* newImageData = exifModifier->WriteDataL(imageDataPtr); // newImageData contains the image data with the modified exif data
+    CleanupStack::PushL(newImageData);
+    
+    if(newImageData == NULL)
+        User::Leave(KErrNotFound); // Better error code should be returned
+    
+    TPtr8 newImageDataPtr = newImageData->Des();
+    
+    // Create the new thumbnail image with modified exif data
+    User::LeaveIfError(tnFile.Replace(iFs, a512x512TNFileName, EFileWrite));
+    User::LeaveIfError(tnFile.Write(newImageDataPtr));
+    
+    tnFile.Flush();
+    tnFile.Close();
+    
+    CleanupStack::PopAndDestroy(4);
+    
+    DP0_IMAGIC(_L("CIEEngineUtils::WriteFaceCoordinatesL --"));
+    }
+
+EXPORT_C void CIEEngineUtils::ReadFaceCoordinatesL(const TFileName a512x512TNFileName, RArray<TRect>& aCordArray)
+    {
+    DP1_IMAGIC(_L("CIEEngineUtils::ReadFaceCoordinatesL, a512x512TNFileName = %S ++"), &a512x512TNFileName);
+    
+    TInt count = aCordArray.Count();
+    for(TInt i=0; i<count; i++)
+        aCordArray.Remove(0);
+    
+    HBufC8* imageData = ReadExifHeaderL(iFs, a512x512TNFileName);
+    CleanupStack::PushL(imageData);
+
+    CExifRead* exifReader;
+    exifReader = CExifRead::NewL(imageData->Des(), CExifRead::ENoJpeg);
+    CleanupStack::PushL(exifReader);
+    
+    HBufC8* makerNoteData = exifReader->GetMakerNoteL();
+    TPtr8 makerNoteDataPtr = makerNoteData->Des();
+
+    // No valid face information
+    if (makerNoteDataPtr.Find(KFaceCoordsHeader) != 0)
+        User::Leave(KErrNotFound);
+    
+    // 31 is the length of the string KFaceCoordsHeader+KSpace+KFaceCoordsImagicVersion+KSpace+KHash
+    makerNoteDataPtr.Delete(0, 31);
+
+    TRect rect(0,0,0,0);
+    TLex8 lex(makerNoteDataPtr.Ptr());
+    TInt faceCount = 0;
+    
+    lex.Val(faceCount);
+    
+    if(faceCount > 0)
+        {
+        for(TInt i=0; i<faceCount; i++)
+            {
+            lex.SkipSpaceAndMark(); 
+            lex.Val(rect.iTl.iX);
+            lex.SkipSpaceAndMark(); 
+            lex.Val(rect.iTl.iY);
+            
+            lex.SkipSpaceAndMark(); 
+            lex.Val(rect.iBr.iX);
+            lex.SkipSpaceAndMark(); 
+            lex.Val(rect.iBr.iY);
+            
+            aCordArray.Append(rect);
+            
+            DP4_IMAGIC(_L("Rect(%d, %d, %d, %d)"), rect.iTl.iX, rect.iTl.iY, rect.iBr.iX, rect.iBr.iY);
+            
+            rect = TRect(0,0,0,0);
+            }
+        aCordArray.SortSigned();
+        }
+    
+    CleanupStack::PopAndDestroy(2);
+        
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadFaceCoordinatesL --"));
+    }
+
+EXPORT_C void CIEEngineUtils::GetModifiedTimeL(const TDes &aFileName, TTime& aTime)
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::GetFileModifiedTimeL++"));
+   
+    // Read file modified date
+    RFile file;
+    TInt error = file.Open(iFs, aFileName , EFileRead);
+    DP1_IMAGIC(_L("CIEEngineUtils::GetFileModifiedTimeL - file open error = %d"), error);
+    User::LeaveIfError(error);
+    file.Modified(aTime);
+    file.Close();
+    DP0_IMAGIC(_L("CIEEngineUtils::GetFileModifiedTimeL--"));
+    }
+
+EXPORT_C void CIEEngineUtils::GetImageSizeL(const TDes &aFileName, TSize& aSize)
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::GetImageSizeL++"));
+    
+    CImageDecoder* imageDecoder = CImageDecoder::FileNewL(iFs, aFileName);
+    TFrameInfo frameInfo = imageDecoder->FrameInfo();
+    aSize = frameInfo.iFrameCoordsInPixels.Size();
+
+    delete imageDecoder;
+    imageDecoder = NULL;   
+    
+    DP2_IMAGIC(_L("CIEEngineUtils::GetImageSizeL-- [%d x %d]"), aSize.iWidth, aSize.iHeight);
+    }
+
+EXPORT_C HBufC8* CIEEngineUtils::ReadExifHeaderL(RFs& aFs, const TDesC &aFileName) 
+    {
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadExifHeaderL++"));
+    RFile file;
+    User::LeaveIfError(file.Open(aFs, aFileName, EFileRead|EFileShareReadersOnly));
+    CleanupClosePushL(file);
+    
+    TInt size;
+    file.Size(size);
+    size = Min(size, 64 * 1024);    // TODO use exact exif size
+        
+    HBufC8* exif = HBufC8::NewL(size);
+    CleanupStack::PushL(exif);
+    TPtr8 bufferPtr(exif->Des()); 
+    User::LeaveIfError(file.Read(bufferPtr));
+
+    CleanupStack::Pop(exif); // exif
+    CleanupStack::PopAndDestroy(); // file
+    
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadExifHeaderL--"));
+    return exif;
+    }
+
+EXPORT_C HBufC8* CIEEngineUtils::ReadExifThumbnailL(RFs& aFs, const TDesC& aFileName)
+    {
+    DP1_IMAGIC(_L("CIEEngineUtils::ReadExifThumbnailL++ %S"), &aFileName);
+    
+    HBufC8* exif = ReadExifHeaderL(aFs, aFileName);
+    CleanupStack::PushL(exif);
+    
+    // Instantiate Exif reader
+    CExifRead* exifRead = CExifRead::NewL(*exif, CExifRead::ENoJpeg);
+    CleanupStack::PushL(exifRead);
+    
+    // Get required data from the Exif image
+    HBufC8* exifThumb = exifRead->GetThumbnailL();
+    CleanupStack::PushL(exifThumb);
+
+    /*TUint32 w, w2, h, h2;
+    exifRead->GetThumbnailXResolution(w, w2);
+    exifRead->GetThumbnailYResolution(h, h2);*/
+    
+    CleanupStack::Pop(exifThumb);
+    CleanupStack::PopAndDestroy(exifRead);
+    CleanupStack::PopAndDestroy(exif);
+    DP0_IMAGIC(_L("CIEEngineUtils::ReadExifThumbnailL--"));
+    return exifThumb;
+    }
+
+//------------------------------------------------------------------------------
+// Read the JPEG EXIF creation timestamp and orientation
+//------------------------------------------------------------------------------
+EXPORT_C void CIEEngineUtils::GetExifDateTimeAndOrientationL(
+        const TDesC& aFilename, 
+        TTime& aExifDateTime,
+        TUint16& aOrientation)
+    {
+    HBufC8* exifDateTime = NULL;
+    
+//#define USE_EXIF_DECODER
+#ifdef USE_EXIF_DECODER
+    // First create the decoder and attach it to the JPEG file. The
+    // decoder implementation UID has to be specified or calling
+    // ExifMetadata() will crash.
+    CImageDecoder* imageDecoder = NULL;
+    imageDecoder = CImageDecoder::FileNewL(
+            iFs, 
+            aFilename, 
+            CImageDecoder::EOptionNone, 
+            KImageTypeJPGUid, 
+            KNullUid,
+            TUid::Uid(KJPGDecoderImplementationUidValue));
+
+    // The specific implementation UID makes the downcasting safe.
+    // Besides, there is no other way to use the decoder.
+    CJPEGExifDecoder* jpegDecoder = static_cast<CJPEGExifDecoder*>(imageDecoder);
+    CleanupStack::PushL(jpegDecoder);
+    // Read the EXIF timestamp, format "YYYY:MM:DD HH:MM:SS".
+    MExifMetadata* exifData = jpegDecoder->ExifMetadata();
+    if(!exifData)
+        User::Leave(KErrNotSupported);
+    
+    TExifReaderUtility reader(exifData);
+    exifDateTime = HBufC8::NewLC(KPMMExifDateTimeOriginalLength);
+    TInt error = reader.GetDateTimeOriginal(exifDateTime);
+    User::LeaveIfError(error);
+#else
+    HBufC8* exifData = ReadExifHeaderL(iFs, aFilename);
+    CleanupStack::PushL(exifData);
+    CExifRead* exifReader = CExifRead::NewL(*exifData, CExifRead::ENoJpeg);
+    CleanupStack::PushL(exifReader);
+    
+    exifDateTime = exifReader->GetDateTimeOriginalL();
+#endif    
+    // Convert the descriptor to a TDateTime as it cannot be converted
+    // directly to a TTime.
+    TLex8 lexer(*exifDateTime);
+    TInt timeValue;
+    TDateTime intermediateDateTime;
+    // Year
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetYear(timeValue);
+    lexer.Inc(); // Skip the colon.
+    // Month
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetMonth(TMonth(timeValue-1));
+    lexer.Inc();
+    // Day
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetDay(timeValue-1);
+    lexer.Inc();
+    // Hours
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetHour(timeValue);
+    lexer.Inc();
+    // Minutes
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetMinute(timeValue);
+    lexer.Inc();
+    // Seconds
+    User::LeaveIfError(lexer.Val(timeValue));
+    intermediateDateTime.SetSecond(timeValue);
+
+    // Finally, convert the TDateTime to a TTime.
+    aExifDateTime = intermediateDateTime;
+
+    // Read orientation
+    TUint16 exifOrientation;
+#ifdef USE_EXIF_DECODER    
+    if (reader.GetOrientation(exifOrientation) == KErrNone)
+#else
+    if (exifReader->GetOrientation(exifOrientation) == KErrNone)
+#endif        
+        {
+        switch (exifOrientation)
+            {
+            case 1: case 2:
+                aOrientation = 0;
+                break;
+
+            case 3: case 4:
+                aOrientation = 180;
+                break;
+                
+            case 5: case 8:
+                aOrientation = 90;
+                break;
+                
+            case 6: case 7:
+                aOrientation = 270;
+                break;
+                
+            default:
+                DP0_IMAGIC(_L("CIEEngineUtils::GetExifDateTimeAndOrientationL: invalid orientation"));
+            }
+        
+        DP1_IMAGIC(_L("CIEEngineUtils::GetExifDateTimeAndOrientationL: %d"), aOrientation);        
+        }
+    
+#ifdef USE_EXIF_DECODER
+    CleanupStack::PopAndDestroy(exifDateTime);    
+    CleanupStack::PopAndDestroy(jpegDecoder);
+#else
+    CleanupStack::PopAndDestroy(exifReader);
+    CleanupStack::PopAndDestroy(exifData);    
+#endif    
+    }
+
+EXPORT_C TUid CIEEngineUtils::GetImageDecoderUid()
+    {
+    CImplementationInformationType* type;
+    TInt error;
+
+    TUid uid = TUid::Uid(KJpegDecIVAUidValue);
+    TRAP(error, type = CImageDecoder::GetImplementationInformationL(uid));
+    if (error == KErrNone)
+        {
+        DP0_IMAGIC(_L("CIEEngineUtils::GetImageDecoderUid: IVA decoder found"));
+        return uid;
+        }
+
+    uid = TUid::Uid(KJpegOptUidValue);
+    TRAP(error, type = CImageDecoder::GetImplementationInformationL(uid));
+    if (error == KErrNone)
+        {
+        DP0_IMAGIC(_L("CIEEngineUtils::GetImageDecoderUid: Emuzed decoder found"));
+        return uid;
+        }
+   
+    /*CExtJpegDecoder* extDecoder;
+    TRAP(error, extDecoder = CImageDecoder::DataNewL(CExtJpegDecoder::EHwImplementation));
+    if (error == KErrNone)
+        return extDecoder->ImplementationUid();*/
+    
+    /*TRAP(error, type = CImageDecoder::GetImplementationInformationL(CExtJpegDecoder::ESwImplementation));
+    if (error == KErrNone)
+        return type->ImplementationUid();*/ 
+  
+    DP0_IMAGIC(_L("CIEEngineUtils::GetImageDecoderUid: no specified decoder found"));    
+    return KNullUid;
+    }