harvester/common/src/harvesterexifutil.cpp
changeset 0 c53acadfccc6
child 14 646a02f170b9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/harvester/common/src/harvesterexifutil.cpp	Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,1847 @@
+/*
+* Copyright (c) 2007-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:
+*
+* Description:  Exif-utilities for harvester
+*
+*/
+
+#include "harvesterexifutil.h"
+
+#include "mdsutils.h"
+#include "mdeobjectdef.h"
+#include "mdeconstants.h"
+#include "mdeproperty.h"
+#include "tz.h"
+#include <ExifModify.h>
+
+
+
+using namespace MdeConstants;
+
+const TUint16 KIdColorSpace = 0xA001;
+const TUint16 KIdResolutionUnit = 0x0128;
+const TUint16 KIdYbCrPositioning = 0x0213;
+const TUint16 KIdImageDescription = 0x010E;
+const TUint16 KIdCopyright = 0x8298;
+const TUint16 KIdUserComment = 0x9286;
+const TUint16 KIdDateTime = 0x0132;
+const TUint16 KIdDateTimeOriginal = 0x9003;
+const TUint16 KIdDateTimeDigitized = 0x9004;
+const TUint16 KIdDateTimeModified = 0x132;
+const TUint16 KIdFNumber = 0x829D;
+const TUint16 KIdMake = 0x010F;
+const TUint16 KIdModel = 0x0110;
+const TUint16 KIdFocalLength = 0x920A;
+const TUint16 KIdFocalLengthIn35mm = 0xA405;
+const TUint16 KIdSamplesPerPixel = 0x0115;
+const TUint16 KIdISOSpeedRatings = 0x8827;
+const TUint16 KIdComponentsConfig = 0x9101;
+const TUint16 KIdArtist = 0x013B;
+const TUint16 KIdPixelXDimension = 0xA002;
+const TUint16 KIdPixelYDimension = 0xA003;
+const TUint16 KIdRelatedSoundFile = 0xA004;
+const TUint16 KIdFocalPlaneResolutionUnit = 0xA210;
+const TUint16 KIdFocalPlaneXResolution = 0xA20E;
+const TUint16 KIdFocalPlaneYResolution = 0xA20F;
+
+const TUint16 KIdExposureTime = 0x829A;
+const TUint16 KIdApertureValue = 0x9202;
+const TUint16 KIdExposureBias = 0x9204;
+const TUint16 KIdMeteringMode = 0x9207;
+const TUint16 KIdShutterSpeed = 0x9201;
+const TUint16 KIdXResolution = 0x011A;
+const TUint16 KIdYResolution = 0x011B;
+const TUint16 KIdWhiteBalance = 0xA403;
+const TUint16 KIdExposureProgram = 0x8822;
+const TUint16 KIdFlash = 0x9209;
+const TUint16 KIdOrientation = 0x112;
+
+const TUint16 KIdGpsLatitudeRef = 0x1;
+const TUint16 KIdGpsLatitude = 0x2;
+const TUint16 KIdGpsLongitudeRef = 0x3;
+const TUint16 KIdGpsLongitude = 0x4;
+const TUint16 KIdGpsAltitudeRef = 0x5;
+const TUint16 KIdGpsAltitude = 0x6;
+const TUint16 KIdGpsMeasureMode = 0xA;
+const TUint16 KIdGpsDop = 0xB;
+const TUint16 KIdGpsMapDatum = 0x12;
+
+_LIT( KExifDateTimeFormat, "%F%Y:%M:%D %H:%T:%S\0" );
+const TInt KDateBufferSize = 20;
+const TInt KCoordinateBufferSize = 24;
+
+// This is needed for exif description field
+_LIT8( KAsciiCodeDesignation,     "\x41\x53\x43\x49\x49\x00\x00\x00");
+_LIT8( KJisCodeDesignation,     "\x4A\x49\x53\x00\x00\x00\x00\x00");
+_LIT8( KUnicodeCodeDesignation, "\x55\x4E\x49\x43\x4F\x44\x45\x00");
+_LIT8( KUnknownCodeDesignation, "\x00\x00\x00\x00\x00\x00\x00\x00");
+
+_LIT8( KNorth, "N\0" );
+_LIT8( KSouth, "S\0" );
+_LIT8( KEast, "E\0" );
+_LIT8( KWest, "W\0" );
+_LIT8( KMeasureMode2, "2\0" );
+_LIT8( KMeasureMode3, "3\0" );
+_LIT8( KMapDatum, "WGS-84\0");
+
+CHarvesterExifUtil::CHarvesterExifUtil() :
+    iSession( NULL ), iDefaultNamespace( NULL )
+{
+}
+
+
+CHarvesterExifUtil::~CHarvesterExifUtil()
+{
+}
+
+EXPORT_C CHarvesterExifUtil* CHarvesterExifUtil::NewLC()
+{
+	CHarvesterExifUtil* self = new (ELeave)CHarvesterExifUtil();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+}
+
+EXPORT_C CHarvesterExifUtil* CHarvesterExifUtil::NewL()
+{
+	CHarvesterExifUtil* self=CHarvesterExifUtil::NewLC();
+	CleanupStack::Pop( self ); // self;
+	return self;
+}
+
+void CHarvesterExifUtil::ConstructL()
+{
+
+}
+
+EXPORT_C void CHarvesterExifUtil::SetSession( CMdESession* aSession )
+	{
+	iSession = aSession;
+	if ( !iDefaultNamespace && aSession )
+		{
+    	TRAP_IGNORE( iDefaultNamespace = &iSession->GetDefaultNamespaceDefL() );
+		}
+	}
+
+
+EXPORT_C TBool CHarvesterExifUtil::IsValidExifData(TPtr8 aPtr)
+	{
+	WRITELOG( "CHarvesterExifUtil::IsValidExifData start" );
+	
+	CExifRead* reader = NULL;
+	
+	TRAPD(err, reader = CExifRead::NewL(aPtr, CExifRead::ENoJpeg | CExifRead::ENoTagChecking));
+	if (err != KErrNone || !reader )
+		{
+		WRITELOG1( "CHarvesterExifUtil::IsValidExifData - error code: %d", err );
+	
+		return EFalse;
+		}
+	
+	delete reader;
+	
+	WRITELOG( "CHarvesterExifUtil::IsValidExifData end" );	
+	
+	return ETrue;
+	}
+
+void CHarvesterExifUtil::StripNulls( HBufC& aString )
+	{
+	_LIT( KNull, "\0" );
+	_LIT( KSpace, " " );
+	
+	TInt pos( 0 );
+    while( (pos = aString.Find( KNull ) ) != KErrNotFound )
+    	{
+    	aString.Des().Replace( pos, 1, KSpace );
+    	}
+    aString.Des().TrimAll();
+	}
+
+HBufC16* CHarvesterExifUtil::ReadExifTagL( const CExifRead& aReader, TExifIfdType aIFD, TUint16 aTagID )
+	{
+	HBufC16* destination = NULL;
+    if( aReader.TagExists( aTagID, aIFD ) )
+    	{
+        const CExifTag* tag = aReader.GetTagL( aIFD, aTagID );
+    	destination = CnvUtfConverter::ConvertToUnicodeFromUtf8L( tag->Data() );
+    	StripNulls( *destination );    	
+    	}	
+    return destination;
+	}
+
+EXPORT_C TInt CHarvesterExifUtil::ReadExifDataL( CHarvestData& aHd, CFileData& aFileData )
+    {
+    WRITELOG( "CHarvesterExifUtil::ReadExifDataL()" );
+
+    CExifRead* reader = CExifRead::NewL(
+    		aFileData.iImageData->Des(), CExifRead::ENoJpeg | CExifRead::ENoTagChecking);
+    CleanupStack::PushL(reader);
+    
+    // Getting description
+    aHd.iDescription16 = ReadExifTagL( *reader, EIfd0, KIdImageDescription );
+
+    // Getting UserComment
+    ReadUserCommentL( aHd, reader ); 
+          
+    // Getting copyright
+    aHd.iCopyright16 = ReadExifTagL( *reader, EIfd0, KIdCopyright );
+    
+    // Artist
+    aHd.iArtist = ReadExifTagL( *reader, EIfd0, KIdArtist );
+    
+    // Getting whitebalance
+    aHd.iStoreWhiteBalance = reader->GetWhiteBalance( aHd.iWhiteBalance ) == KErrNone;
+ 
+    // Getting aHd.iFlash    
+    aHd.iStoreFlash = reader->GetFlash( aHd.iFlash ) == KErrNone;
+    
+    // Getting exposure
+    aHd.iStoreExposureProgram = reader->GetExposureProgram( aHd.iExposureProgram ) == KErrNone;
+                
+    // Getting width
+    if ( reader->TagExists( KIdPixelXDimension, EIfdExif ) )
+        {
+        // PixelXDimension tag should be found in EXIF according to the standard.
+        reader->GetPixelXDimension(aHd.iImageWidthExif);
+        }
+    
+    // Getting height
+    if ( reader->TagExists( KIdPixelYDimension, EIfdExif ) )
+        {
+        // PixelYDimension tag should be found in EXIF according to the standard.
+        reader->GetPixelYDimension(aHd.iImageHeightExif);
+        }
+    
+    // Getting aFileData.iModified date
+    if ( reader->TagExists(KIdDateTime, EIfd0) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadExifDataL() - getting last aFileData.iModified date (exif)" );
+        aHd.iDateModified8 = reader->GetDateTimeL();
+        }
+    
+    // Getting original date
+    if ( reader->TagExists(KIdDateTimeOriginal, EIfdExif) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadExifDataL() - getting original date (exif)" );
+        aHd.iDateOriginal8 = reader->GetDateTimeOriginalL();
+        }
+        
+    // Getting date & time digitized
+    if ( reader->TagExists(KIdDateTimeDigitized, EIfdExif) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadExifDataL() - getting digitized date (exif)" );
+        aHd.iDateDigitized8 = reader->GetDateTimeDigitizedL();
+        }            
+    
+    //Getting camera maker
+    aHd.iMake = ReadExifTagL( *reader, EIfd0, KIdMake );
+    
+    //Getting camera aHd.iModel
+    aHd.iModel = ReadExifTagL( *reader, EIfd0, KIdModel );
+    
+    //Getting aHd.iOrientation
+    aHd.iStoreOrientation = reader->GetOrientation( aHd.iOrientation ) == KErrNone;
+    
+    //Getting X Resolution
+    ReadXResolutionL( aHd, reader ); 
+    
+    //Getting Y Resolution
+    ReadXResolutionL( aHd, reader ); 
+    
+    //Getting resolution unit (mandatory tag)
+    reader->GetResolutionUnit( aHd.iResolutionUnit );
+    
+    //Getting YCbCr Positioning
+    aHd.iStoreYCbCrPositioning = reader->GetYCbCrPositioning( aHd.iYCbCrPositioning ) == KErrNone;
+        
+    //Getting exposure bias value
+    ReadExposureBiasL( aHd, reader ); 
+    
+    //Getting exposure time
+    ReadExposureTimeL( aHd, reader ); 
+        
+    //Getting FNumber
+    ReadFNumberL( aHd, reader );
+    
+    //Getting Exif version
+    aHd.iStoreExifVersion = reader->GetExifVersion( aHd.iExifVersion ) == KErrNone;           
+        
+    //Getting FlashPix version
+    aHd.iStoreFlashPixVersion = reader->GetFlashPixVersion( aHd.iFlashPixVersion ) == KErrNone;
+    
+    // Shutter speed
+    ReadShutterSpeedL( aHd, reader );
+        
+    //Getting aHd.iAperture
+    ReadApertureValueL( aHd, reader );
+    
+    //Getting focal length
+    ReadFocalLengthL( aHd, reader );
+    
+    // Getting focal length in 35 mm
+    ReadFocalLength35mmL( aHd, reader );
+        
+    aHd.iStoreColourSpace = reader->GetColorSpace( aHd.iColourSpace ) == KErrNone;
+    
+    aHd.iStoreThumbCompression = reader->GetThumbnailCompression( aHd.iThumbCompression ) == KErrNone;
+    
+	TUint32 numerator = 0;
+    TUint32 denominator = 0;
+	
+    //Getting thumbnail X resolution    
+    TInt error = reader->GetThumbnailXResolution( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreThumbXResolution = ETrue;
+        aHd.iThumbXResolution = 0.0f;
+        if ( denominator > 0)
+            {
+            aHd.iThumbXResolution = numerator / denominator;
+            }
+        }
+    
+    //Getting thumbnail Y resolution
+    error = reader->GetThumbnailYResolution( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreThumbYResolution = ETrue;
+        aHd.iThumbYResolution = 0.0f;
+        if ( denominator > 0 )
+            {
+            aHd.iThumbYResolution = numerator / denominator;
+            }
+        }
+        
+    aHd.iStoreThumbResolutionUnit =
+    	reader->GetThumbnailResolutionUnit( aHd.iThumbResolutionUnit ) == KErrNone;
+       
+    // Bits per sample and Samples per pixel not recorded in JPEG Exif.
+    if ( reader->TagExists( KIdSamplesPerPixel, EIfd0 ) )
+        {
+        const CExifTag* tag = reader->GetTagL( EIfd0, KIdSamplesPerPixel );
+        TPtrC8 tagData = tag->Data();
+        
+        aHd.iSamplesPerPixel = MdsUtils::ToUInt16L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        aHd.iStoreSamplesPerPixel = ETrue;
+        
+        WRITELOG1( "CHarvesterExifUtil::ReadExifDataL() - samples per pixel: %d", aHd.iSamplesPerPixel );
+        }
+    
+    //Getting ISO speed rating.
+    if ( reader->TagExists(KIdISOSpeedRatings, EIfdExif) )
+        {
+        HBufC8* iso8 = reader->GetIsoSpeedRatingsL();
+        
+        if ( iso8 )
+            {
+            aHd.iStoreIsoSpeedRating = ETrue;
+            aHd.iIsoSpeedRating = iso8->Des()[0];
+            delete iso8;
+            iso8 = NULL;
+            }    
+        }
+    
+    //Getting components configuration
+    if ( reader->TagExists( KIdComponentsConfig, EIfdExif ) )
+        {
+        const CExifTag* tag = reader->GetTagL(
+        		EIfdExif, KIdComponentsConfig );
+        TPtrC8 tagData = tag->Data();
+        
+        aHd.iComponentsConfiguration = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        aHd.iStoreComponentsConfig = ETrue;
+        }
+    
+    // Getting thumbnail compression
+    aHd.iStoreThumbCompression =
+    	reader->GetThumbnailCompression( aHd.iThumbCompression ) == KErrNone;
+        
+    // Getting metering mode
+    aHd.iStoreMeteringMode = reader->GetMeteringMode( aHd.iMeteringMode ) ==KErrNone;
+    
+    // Getting related soundfile
+    aHd.iRelatedSoundFile = ReadExifTagL( *reader, EIfdExif, KIdRelatedSoundFile );
+        
+    // Getting focal plane resolution unit
+    if ( reader->TagExists(KIdFocalPlaneResolutionUnit, EIfdExif) )
+        {
+        const CExifTag* tag = reader->GetTagL(
+        		EIfdExif, KIdFocalPlaneResolutionUnit );
+        TPtrC8 tagData = tag->Data();
+        
+        aHd.iFocalPlaneResolutionUnit = MdsUtils::ToUInt16L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        aHd.iStoreFocalPlaneResolutionUnit = ETrue;
+        }
+    
+    // Getting focal plane X resolution
+    ReadFocalXPlaneResolutionL( aHd, reader );
+
+        
+    // Getting focal plane Y resolution
+    ReadFocalYPlaneResolutionL( aHd, reader );
+
+    // Get GPS tags
+    TBool latitudeExists = EFalse;
+    
+    // latitude
+    ReadGPSLatitudeL( aHd, reader, latitudeExists );
+
+    // longitude
+    ReadGPSLongitudeL( aHd, reader, latitudeExists );
+    
+    // altitude
+    ReadGPSAltitudeL( aHd, reader );
+        
+    CleanupStack::PopAndDestroy( reader );
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Time converting
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TTime CHarvesterExifUtil::ConvertExifDateTimeToSymbianTimeL(
+		const TDesC8& aDateTime )
+    {
+    WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL()" );
+    
+    TDateTime datetime( 0, EJanuary, 0, 0, 0, 0, 0 );
+    TBuf<4> text;
+    
+    // Year
+    TPtrC8 textPart = aDateTime.Left(4);
+    TLex8 lex( textPart );
+    TInt number = 0;
+    TInt error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get year" );
+        User::Leave( error );
+        }
+    datetime.SetYear( number );
+    
+    // Month
+    TPtrC8 textPart2 = aDateTime.Mid( 5,2 );
+    lex.Assign( textPart2 );
+    error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get month" );
+        User::Leave( error );
+        }        
+    number--;
+    TMonth month = (TMonth) number;
+    datetime.SetMonth( month );
+    
+    // Day
+    TPtrC8 textPart3 = aDateTime.Mid( 8,2 );
+    lex.Assign( textPart3 );
+    error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get date" );
+        User::Leave( error );
+        }
+    datetime.SetDay( number - 1 );
+    
+    // Hours
+    TPtrC8 textPart4 = aDateTime.Mid( 11,2 );
+    lex.Assign( textPart4 );
+    error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get hours" );
+        User::Leave( error );
+        }    
+    datetime.SetHour( number );
+    
+    // Minutes
+    TPtrC8 textPart5 = aDateTime.Mid( 14,2 );
+    lex.Assign( textPart5 );
+    error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get minutes" );
+        User::Leave( error );
+        }
+    datetime.SetMinute( number );
+    
+    // Seconds
+    TPtrC8 textPart6 = aDateTime.Mid( 17,2 );
+    lex.Assign( textPart6 );
+    error = lex.Val( number );
+    if ( error != KErrNone )
+        {
+        WRITELOG( "CHarvesterImagePluginAO::ConvertExifDateTimeToSymbianTimeL() - couldn't get seconds" );
+        User::Leave( error );
+        }
+    datetime.SetSecond( number );
+    
+    TTime time( datetime );
+
+    return time;
+    }
+
+void CHarvesterExifUtil::AddPropertyL( CMdEObjectDef& aObjectDef, CMdEObject& aMdeObject,
+		const TDesC& aProperty, TUint16 aValue )
+	{
+	CMdEPropertyDef& propDef = aObjectDef.GetPropertyDefL( aProperty );    
+	CMdEProperty* mdeProp = NULL;
+	
+	aMdeObject.Property( propDef, mdeProp, 0 );
+    if ( !mdeProp )
+        {
+        aMdeObject.AddUint16PropertyL( propDef, aValue );
+        }	
+	}
+
+void CHarvesterExifUtil::AddPropertyL( CMdEObjectDef& aObjectDef, CMdEObject& aMdeObject,
+		   const TDesC& aProperty, TUint32 aValue )
+{
+	CMdEPropertyDef& propDef = aObjectDef.GetPropertyDefL( aProperty );    
+	CMdEProperty* mdeProp = NULL;
+	
+	aMdeObject.Property( propDef, mdeProp, 0 );
+	if ( !mdeProp )
+		{
+		aMdeObject.AddUint32PropertyL( propDef, aValue );
+		}	
+}
+
+void CHarvesterExifUtil::SetExifDefaultsL( CMdEObject& aMdeObject, CExifModify& aExifModify )
+	{
+    const TUint32 KPixPerResolution = 72;
+    const TUint32 KPixPerResDenm = 1;
+    const TUint16 KResUnitInch = 2;
+    const TUint16 KYCbCrPositioning = 1;
+    const TUint8  KCompConf1st = 1;
+    const TUint8  KCompConf2nd = 2;
+    const TUint8  KCompConf3rd = 3;
+    const TUint8  KCompConf4rd = 0;
+    const TUint16 KColorSpaceRGB = 1;
+
+    CMdEObjectDef& imageDef = iDefaultNamespace->GetObjectDefL( Image::KImageObject );
+    
+    aExifModify.SetXResolutionL( KPixPerResolution, KPixPerResDenm );
+    aExifModify.SetYResolutionL( KPixPerResolution, KPixPerResDenm );
+
+    AddPropertyL( imageDef, aMdeObject, MediaObject::KResolutionUnitProperty,
+    		      KResUnitInch );
+    aExifModify.SetResolutionUnitL( KResUnitInch );
+
+    AddPropertyL( imageDef, aMdeObject, Image::KYCbCrPositioningProperty,
+    		      KYCbCrPositioning );
+    aExifModify.SetYCbCrPositioningL( KYCbCrPositioning );
+
+    TUint32 compUint32( 0 );
+    TUint8* components = (TUint8*) &compUint32;
+    *(components + 3) = KCompConf4rd;
+    *(components + 2) = KCompConf3rd;
+    *(components + 1) = KCompConf2nd;
+          *components = KCompConf1st;
+    
+    AddPropertyL( imageDef, aMdeObject, Image::KComponentsConfigurationProperty,
+    		      compUint32 );
+    aExifModify.SetComponentsConfigurationL( KCompConf1st, KCompConf2nd,
+    										 KCompConf3rd, KCompConf4rd );
+
+    AddPropertyL( imageDef, aMdeObject, Image::KColourSpaceProperty, KColorSpaceRGB );
+    aExifModify.SetColorSpaceL( KColorSpaceRGB );
+	}
+
+HBufC8* CHarvesterExifUtil::GetPropertyValueLC( const CMdEPropertyDef& aPropDef,
+		const CMdEProperty& aProperty )
+	{
+	switch( aPropDef.PropertyType() )
+		{
+		case EPropertyReal32:
+			{
+			TUint32 denominator = 1; 
+			if( aPropDef.Name().CompareF( Image::KExposureTimeProperty ) == 0 )
+				{
+				denominator = 1000000;
+				}
+			else if( aPropDef.Name().CompareF( Image::KApertureValueProperty ) == 0 )
+				{
+				denominator = 100;
+				}
+			else if( aPropDef.Name().CompareF( Image::KExposureBiasValueProperty ) == 0 )
+				{
+				denominator = 100;
+				}
+			else if( aPropDef.Name().CompareF( Image::KShutterSpeedValueProperty ) == 0 )
+				{
+				denominator = 1000;
+				}
+			else if( aPropDef.Name().CompareF( Image::KFNumberProperty ) == 0 )
+				{
+				denominator = 10;
+				}			
+			TUint32 value = TUint32( aProperty.Real32ValueL() * (TReal32)denominator );
+
+			HBufC8* buf8 = HBufC8::NewLC( 2 * sizeof(TUint32) );
+			TPtr8 ptr = buf8->Des();
+			ptr.Append( (TUint8*)&value, sizeof(TUint32) );
+			ptr.Append( (TUint8*)&denominator, sizeof(TUint32) );
+			
+			return buf8;
+			}
+		case EPropertyTime:
+			{
+	        TTime time = aProperty.TimeValueL();
+	        if( aPropDef.Name().CompareF( Image::KDateTimeProperty ) == 0 )
+	        	{
+	        	RTz timezone;
+	        	CleanupClosePushL( timezone );
+	        	User::LeaveIfError( timezone.Connect() );
+	        	timezone.ConvertToLocalTime( time );
+	        	CleanupStack::PopAndDestroy( &timezone );
+	        	}
+	        HBufC* buf = HBufC::NewLC( KDateBufferSize );
+	        TPtr ptr = buf->Des();
+	        time.FormatL( ptr, KExifDateTimeFormat );
+	        HBufC8* buf8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( ptr );
+	        CleanupStack::PopAndDestroy( buf );
+	        CleanupStack::PushL( buf8 );
+	        return buf8;
+			}
+		case EPropertyText:
+			{
+			TPtrC text = aProperty.TextValueL();
+			if( aPropDef.Name().CompareF( MediaObject::KCommentProperty ) == 0 )
+				{
+		        const TUint16 bufLength = KUnicodeCodeDesignation.iTypeLength + text.Size();
+		        HBufC8* commentBuf = HBufC8::NewLC( bufLength );
+		        TPtr8 commentPtr = commentBuf->Des();
+		        commentPtr.Append( KUnicodeCodeDesignation );
+		        commentPtr.Append( (TUint8*)text.Ptr(), text.Size() );
+		        return commentBuf;
+				}
+			HBufC8* buf = CnvUtfConverter::ConvertFromUnicodeToUtf8L( text );
+			CleanupStack::PushL( buf );
+	        return buf;
+			}
+		case EPropertyUint16:
+			{
+        	TUint16 value = aProperty.Uint16ValueL();
+        	HBufC8* buf = HBufC8::NewLC( sizeof(value) );
+        	TPtr8 ptr = buf->Des();
+        	ptr.Copy( (TUint8*)(&value), sizeof(value) );
+			return buf;
+			}
+		default:
+			User::Leave( KErrGeneral );
+		}
+	    return NULL;
+	}
+
+CExifTag::TExifTagDataType CHarvesterExifUtil::ExifTagDataType( TUint16 aTagID, const CMdEPropertyDef& aPropDef )
+	{
+	if( aTagID == KIdUserComment )
+		{
+		return CExifTag::ETagUndefined;   		
+		}
+	if( aTagID == KIdShutterSpeed || aTagID == KIdExposureBias )
+		{
+		return CExifTag::ETagSrational;
+		}
+	switch( aPropDef.PropertyType() )
+		{
+		case EPropertyBool:
+		case EPropertyInt8:
+		case EPropertyUint8:
+			return CExifTag::ETagByte;
+		case EPropertyInt16:
+		case EPropertyUint16:
+			return CExifTag::ETagShort;
+		case EPropertyUint32:
+			return CExifTag::ETagLong;
+		case EPropertyInt32:
+			return CExifTag::ETagSlong;
+		case EPropertyReal32:
+			return CExifTag::ETagRational;
+		case EPropertyTime:
+			return CExifTag::ETagAscii;
+		case EPropertyText:
+			return CExifTag::ETagAscii;
+		default:
+			return CExifTag::ETagUndefined;
+		}
+	}
+
+TBool CHarvesterExifUtil::CompareTag( TPtrC8 aMdeData, const CExifTag* aTag )
+	{
+	if( aTag->TagInfo().iDataType == CExifTag::ETagRational )
+		{
+		TUint32 denominator;
+		TUint32 value;
+        TPtrC8 ptr( aTag->Data() );
+        memcpy( &value, ptr.Ptr(), sizeof(value) );
+        memcpy( &denominator, ptr.Ptr()+sizeof(value), sizeof(denominator) );
+
+    	TReal32 tagValue = 0.0f;
+    	if ( denominator != 0 )
+    		{
+    		tagValue = (TReal32)value / (TReal32)denominator;
+    		}
+        ptr.Set( aMdeData );
+        memcpy( &value, ptr.Ptr(), sizeof(value) );
+        memcpy( &denominator, ptr.Ptr()+sizeof(value), sizeof(denominator) );
+
+    	TReal32 mdeValue = 0.0f;
+    	if ( denominator != 0 )
+    		{
+    		mdeValue = (TReal32)value / (TReal32)denominator;
+    		}
+    	return Abs( tagValue - mdeValue ) > 0.01f;
+		}
+	else
+		{
+		return aMdeData.CompareF( aTag->Data() ) != 0; 
+		}
+	}
+
+TBool CHarvesterExifUtil::ModifyExifTagL( CMdEObject& aMdeObject, CExifModify& aExifModify,
+		const TDesC& aProperty, TExifIfdType aIFD, TUint16 aTagID, TBool aRemove )
+	{
+	CMdEObjectDef& imageDef = iDefaultNamespace->GetObjectDefL( Image::KImageObject );
+	CMdEPropertyDef& propDef = imageDef.GetPropertyDefL( aProperty );    
+	CMdEProperty* mdeProp = NULL;
+	TBool exifChanged = EFalse;
+	
+	aMdeObject.Property( propDef, mdeProp, 0 );
+	TBool tagExists = EFalse;
+	if( aRemove )
+		{
+		tagExists = aExifModify.Reader()->TagExists( aTagID, aIFD );
+		}
+	if ( mdeProp )
+        {
+        HBufC8* mdedata = GetPropertyValueLC( propDef, *mdeProp );
+        TPtrC8 ptr = mdedata->Des();
+        TBool change = EFalse;
+        const CExifTag* tag = NULL;
+        TRAP_IGNORE( tag = aExifModify.Reader()->GetTagL( aIFD, aTagID ) );
+        if( !tag ) //create new exif tag
+        	{
+        	change = ETrue;
+        	}
+        else if( CompareTag( ptr, tag ) )
+            {
+            change = ETrue;
+            }
+        if( change )
+        	{
+        	CExifTag::TExifTagDataType type = ExifTagDataType( aTagID, propDef );
+        	TInt len = 1;
+        	if( type == CExifTag::ETagUndefined || type == CExifTag::ETagAscii  )
+        		{
+        		len = ptr.Length();
+        		}
+        	TExifTagInfo info( aTagID, type, len  );
+            aExifModify.SetTagL( aIFD, info, ptr );
+            exifChanged = ETrue;        	
+        	}
+        CleanupStack::PopAndDestroy( mdedata );
+        }
+	else if( tagExists ) // remove from exif
+        {
+        aExifModify.DeleteTag( aIFD, aTagID );
+        exifChanged = ETrue;
+        }
+    return exifChanged;
+	}
+
+// ---------------------------------------------------------------------------
+// ComposeExifData
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CHarvesterExifUtil::ComposeExifDataL( CMdEObject& aMdeObject, TPtr8 aImagePtr, HBufC8*& aModified )
+	{
+
+	if ( !iSession )
+		{
+		User::Leave( KErrSessionClosed );
+		}
+	
+    WRITELOG1( "CHarvesterExifUtil::ComposeExifData() - Compose Start Object ID: %d", aMdeObject.Id() );
+    TBool exifChanged = EFalse;
+
+    // 2. try to init EXIF data from image file's data
+    CExifModify* modifyExif = NULL;
+    TInt exifError = KErrNone;
+    TRAP( exifError, modifyExif = CExifModify::NewL( aImagePtr, 
+    		CExifModify::EModify, CExifModify::ENoJpegParsing ) );
+
+    // 3. Is this image format supported?
+    if ( exifError == KErrNotSupported )
+        {
+        WRITELOG( "CHarvesterExifUtil::ComposeExifData() - Image format not supported (!jpeg)" );
+        User::Leave( exifError );
+        }
+
+    // 4. if image does not contain EXIF data try to create it
+    if ( exifError != KErrNone )
+        {
+        WRITELOG( "CHarvesterExifUtil::ComposeExifData() - Image doesn't contain EXIF data" );
+        modifyExif = CExifModify::NewL( aImagePtr, 
+        		CExifModify::ECreate, CExifModify::ENoJpegParsing );
+        SetExifDefaultsL( aMdeObject, *modifyExif );
+        exifChanged = ETrue;
+        }
+    CleanupStack::PushL( modifyExif );
+    const CExifRead* readExif = modifyExif->Reader();
+    CMdEObjectDef& imageDef = iDefaultNamespace->GetObjectDefL( Image::KImageObject );
+    
+    // Set pixel X dimension tag (mandatory)
+    TBool changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KWidthProperty, EIfdExif, KIdPixelXDimension);
+    exifChanged = (exifChanged | changed);
+
+    // Set pixel Y dimension tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KHeightProperty, EIfdExif, KIdPixelYDimension);
+    exifChanged = (exifChanged | changed);
+
+    // Set white balance tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KWhiteBalanceProperty, EIfdExif, KIdWhiteBalance, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set flash tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFlashProperty, EIfdExif, KIdFlash, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set exposure program tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KExposureProgramProperty, EIfdExif, KIdExposureProgram, ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set description tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KDescriptionProperty, EIfd0, KIdImageDescription, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set user comment tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KCommentProperty, EIfdExif, KIdUserComment, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set copyright tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KCopyrightProperty, EIfd0, KIdCopyright, ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set DateTimeOriginal tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KDateTimeOriginalProperty, EIfdExif, KIdDateTimeOriginal, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set DateTimeDigitized tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KDateTimeDigitizedProperty, EIfdExif, KIdDateTimeDigitized, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set DateTime (_image_ modified) tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KDateTimeProperty, EIfd0, KIdDateTimeModified, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set maker tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KMakeProperty, EIfd1, KIdMake, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set model tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KModelProperty, EIfd1, KIdModel, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set orientation tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KOrientationProperty, EIfd0, KIdOrientation , ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set YCbCrPositioning tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KYCbCrPositioningProperty, EIfd1, KIdYbCrPositioning, EFalse );
+    exifChanged = (exifChanged | changed);
+    
+    // Set resolution unit tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		MediaObject::KResolutionUnitProperty, EIfd1, KIdResolutionUnit, EFalse );
+    exifChanged = (exifChanged | changed);
+    
+    // Set ISO speed tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KISOSpeedRatingsProperty, EIfdExif, KIdISOSpeedRatings, ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set related soundfile tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KRelatedSoundFileProperty, EIfdExif, KIdRelatedSoundFile, ETrue );
+    exifChanged = (exifChanged | changed);    
+    
+    // Set exposure time tag (recommended)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KExposureTimeProperty, EIfdExif, KIdExposureTime, ETrue );
+    exifChanged = (exifChanged | changed);   
+        
+    // Set aperture value tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KApertureValueProperty, EIfdExif, KIdApertureValue, ETrue );
+    exifChanged = (exifChanged | changed);  
+    
+    // Set colour space tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+		Image::KColourSpaceProperty, EIfdExif, KIdColorSpace , EFalse );
+    exifChanged = (exifChanged | changed);
+        
+    // Set exposure bias tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KExposureBiasValueProperty, EIfdExif, KIdExposureBias, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set metering mode tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KMeteringModeProperty, EIfdExif, KIdMeteringMode, ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set shutter speed tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KShutterSpeedValueProperty, EIfdExif, KIdShutterSpeed, ETrue );
+    exifChanged = (exifChanged | changed);
+
+    // Set X resolution tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KXResolutionProperty, EIfd0, KIdXResolution, EFalse );
+    exifChanged = (exifChanged | changed); 
+
+    // Set Y resolution tag (mandatory)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KYResolutionProperty, EIfd0, KIdYResolution, EFalse );
+    exifChanged = (exifChanged | changed); 
+    
+    // Set F number tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFNumberProperty, EIfdExif, KIdFNumber, ETrue );
+    exifChanged = (exifChanged | changed);     
+    
+    // Set focal length tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFocalLengthProperty, EIfdExif, KIdFocalLength, ETrue );
+    exifChanged = (exifChanged | changed);  
+    
+    // Set focal length in 35 mm film tag (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFocalLengthIn35mmFilmProperty, EIfdExif, KIdFocalLengthIn35mm, ETrue );
+    exifChanged = (exifChanged | changed);   
+
+    // Set focal plane resolution unit (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFocalPlaneResolutionUnitProperty, EIfdExif, KIdFocalPlaneResolutionUnit, ETrue );
+    exifChanged = (exifChanged | changed);   
+
+    // Set focal plane X resolution (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFocalPlaneXResolutionProperty, EIfdExif, KIdFocalPlaneXResolution, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    // Set focal plane Y resolution (optional)
+    changed = ModifyExifTagL( aMdeObject, *modifyExif,
+    		Image::KFocalPlaneYResolutionProperty, EIfdExif, KIdFocalPlaneYResolution, ETrue );
+    exifChanged = (exifChanged | changed);
+    
+    TUint16 uint16Value( 0 );
+    TUint32 uint32Value( 0 );
+    
+    // Set components configuration tag (mandatory)
+    const CMdEPropertyDef& componentsDef = imageDef.GetPropertyDefL(
+     		Image::KComponentsConfigurationProperty );
+        {
+        CMdEProperty* componentsProp = NULL;
+        aMdeObject.Property( componentsDef, componentsProp, 0 );
+
+        if ( componentsProp )
+            {
+            TUint32 componentsValue = componentsProp->Uint32ValueL();
+            TUint8* components = (TUint8*) &componentsValue;
+            const TUint8 KComponent4th = *(components + 3);
+            const TUint8 KComponent3rd = *(components + 2);
+            const TUint8 KComponent2nd = *(components + 1);
+            const TUint8 KComponent1st = *components;
+            
+            TUint8 exifComponent4th( 0 );
+            TUint8 exifComponent3rd( 0 );
+            TUint8 exifComponent2nd( 0 );
+            TUint8 exifComponent1st( 0 );
+            
+            exifError = readExif->GetComponentsConfiguration(
+              	exifComponent1st, exifComponent2nd, exifComponent3rd, exifComponent4th );
+            if ( exifError != KErrNone || 
+                 exifComponent1st != KComponent1st || exifComponent2nd != KComponent2nd ||
+                 exifComponent3rd != KComponent3rd || exifComponent4th != KComponent4th )
+                {
+                modifyExif->SetComponentsConfigurationL(
+                		KComponent1st, KComponent2nd, KComponent3rd, KComponent4th );
+                exifChanged = ETrue;
+                }
+            }
+        }        
+        
+	// Set thumbnail X resolution tag (mandatory)
+    const CMdEPropertyDef& thumbXDef = imageDef.GetPropertyDefL(
+        Image::KThumbXResolutionProperty );
+        {
+        CMdEProperty* thumbXProp = NULL;
+        aMdeObject.Property( thumbXDef, thumbXProp, 0 );
+
+        if ( thumbXProp )
+            {
+            const TUint32 thumbX = thumbXProp->Uint32ValueL();
+
+            TUint32 exifDenominator = 0;
+            exifError = readExif->GetThumbnailXResolution( uint32Value, exifDenominator );
+            TUint32 exifThumbXResol = 0;
+            if ( exifDenominator > 0 )
+                {
+                exifThumbXResol = uint32Value / exifDenominator;
+                }
+
+            if ( exifError != KErrNone || exifThumbXResol != thumbX )
+                {
+                const TUint32 KDenominator = 1;
+                modifyExif->SetThumbnailXResolutionL( thumbX, KDenominator );
+                exifChanged = ETrue;
+                }
+            }
+        }
+
+	// Set thumbnail Y resolution tag (mandatory)
+    const CMdEPropertyDef& thumbYDef = imageDef.GetPropertyDefL(
+      		Image::KThumbYResolutionProperty );
+        {
+        CMdEProperty* thumbYProp = NULL;
+        aMdeObject.Property( thumbYDef, thumbYProp, 0 );
+
+        if ( thumbYProp )
+            {
+            TUint32 thumbY = TUint32( thumbYProp->Uint32ValueL() );
+            TUint32 exifDenominator = 0;
+            exifError = readExif->GetThumbnailYResolution( uint32Value, exifDenominator );
+            TUint32 exifThumbYResol = 0;
+            if ( exifDenominator > 0 )
+                {
+                exifThumbYResol = uint32Value / exifDenominator;
+                }
+            
+            if ( exifError != KErrNone || exifThumbYResol != thumbY )
+                {
+                const TUint32 KDenominator = 1;
+                modifyExif->SetThumbnailYResolutionL( thumbY, KDenominator );
+                exifChanged = ETrue;
+                }
+            }
+        }
+
+	// Set thumbnail resolution unit tag (mandatory)
+    const CMdEPropertyDef& thumbResolutionUnitDef = imageDef.GetPropertyDefL(
+        	Image::KThumbResolutionUnitProperty );
+        {
+        CMdEProperty* thumbResolutionUnitProp = NULL;            
+        aMdeObject.Property( thumbResolutionUnitDef, thumbResolutionUnitProp, 0 );
+
+        if ( thumbResolutionUnitProp )
+            {
+            exifError = readExif->GetThumbnailResolutionUnit( uint16Value );
+            const TUint16 thumbnailResolutionUnitValue =
+             	thumbResolutionUnitProp->Uint16ValueL();
+            if ( exifError != KErrNone || uint16Value != thumbnailResolutionUnitValue )
+                {
+                modifyExif->SetThumbnailResolutionUnitL( thumbnailResolutionUnitValue );
+                exifChanged = ETrue;
+                }
+            }
+        }
+        
+    if ( exifChanged )
+        {
+        WRITELOG( "CHarvesterExifUtil::ComposeExifData() - write exif to buffer" );
+        aModified = modifyExif->WriteDataL( aImagePtr );
+        }
+    CleanupStack::PopAndDestroy( modifyExif );
+
+    WRITELOG1( "CHarvesterExifUtil::ComposeExifData() - Compose End Object ID: %d", aMdeObject.Id() );
+
+	return KErrNone;
+	}
+
+// ---------------------------------------------------------------------------
+// ComposeLocation
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CHarvesterExifUtil::ComposeLocationL( CMdEObject* aLocation, TPtr8 aImagePtr, HBufC8*& aModified )
+    {
+    CMdEProperty* latitudeProperty = NULL;
+    CMdEProperty* longitudeProperty = NULL;
+    CMdEProperty* altitudeProperty = NULL;
+    CMdEProperty* qualityProperty = NULL;
+    
+    CMdEObjectDef& locationDef = iDefaultNamespace->GetObjectDefL( Location::KLocationObject );
+
+    aLocation->Property( locationDef.GetPropertyDefL(
+    		Location::KLatitudeProperty ), latitudeProperty, 0 );
+    aLocation->Property( locationDef.GetPropertyDefL(
+    		Location::KLongitudeProperty ), longitudeProperty, 0 );
+    aLocation->Property( locationDef.GetPropertyDefL(
+    		Location::KAltitudeProperty ), altitudeProperty, 0 );
+    aLocation->Property( locationDef.GetPropertyDefL(
+    		Location::KQualityProperty ), qualityProperty, 0 );
+
+    CExifModify* exifWriter = CExifModify::NewL( aImagePtr, 
+    		CExifModify::EModify, CExifModify::ENoJpegParsing );
+    CleanupStack::PushL( exifWriter );
+    const CExifRead* exifReader = exifWriter->Reader();
+
+    TBool exifChanged = EFalse;
+    TBool changed = EFalse;
+    const TReal KAngleSecond = 1.0 / 3600.0;
+    TInt exifError( 0 );
+    // location data (all fields are optional)
+    // latitude
+    const CExifTag* exifLatitudeRefTag = NULL;
+    TRAP( exifError, exifLatitudeRefTag = exifReader->GetTagL( EIfdGps, KIdGpsLatitudeRef ) );
+    if ( latitudeProperty )
+        {
+        TBuf8<2> south( KSouth );
+        TBuf8<2> north( KNorth );
+        TReal64 latitude = latitudeProperty->Real64ValueL();
+
+        TReal64 exifLatitude( 0.0 );
+        TBuf8<2> exifLatitudeRef;
+        if ( exifError == KErrNone )
+            {
+            TPtrC8 exifLatitudeRefBuf( exifLatitudeRefTag->Data() );
+            exifLatitudeRef.Append( exifLatitudeRefBuf.Ptr(), 2 );
+
+            if ( latitude < 0 )
+                {
+                if ( south.Compare(exifLatitudeRef) )
+                    {
+                    changed = ETrue;
+                    }
+                }
+            else
+                {
+                if ( north.Compare(exifLatitudeRef) )
+                    {
+                    changed = ETrue;
+                    }
+                }
+
+            if ( !changed )
+                {
+                TBuf8<KCoordinateBufferSize> exifLatitudeBuf;
+                const CExifTag* exifLatitudeTag = NULL;
+                TRAPD( err, exifLatitudeTag = exifReader->GetTagL( EIfdGps, KIdGpsLatitude ) );
+                if ( err == KErrNone )
+                    {
+                    TPtrC8 exifLatitudeTagBuf( exifLatitudeTag->Data() );
+                    exifLatitudeBuf.Append( exifLatitudeTagBuf.Ptr(), KCoordinateBufferSize );
+                    MdsUtils::ConvertFromDegreesToDecimalL( exifLatitudeBuf, exifLatitude );
+                    }
+                else
+                    {
+                    exifError = err;
+                    }
+                }
+            }
+
+        if ( exifError != KErrNone || changed || Abs(exifLatitude - latitude) > KAngleSecond )
+            {
+            // latitude ref (N/S)
+            if ( latitude < 0 )
+                {
+                exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+                		KIdGpsLatitudeRef, CExifTag::ETagAscii, 2 ), south );
+                latitude = -latitude;
+                }
+            else
+                {
+                exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+                		KIdGpsLatitudeRef, CExifTag::ETagAscii, 2 ), north );
+                }
+
+            TBuf8<KCoordinateBufferSize> latitudeBuf;
+            MdsUtils::ConvertFromDecimalToDegreesL( latitude, latitudeBuf );
+            exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+            		KIdGpsLatitude, CExifTag::ETagRational, 3 ), latitudeBuf );
+            exifChanged = ETrue;
+            }
+        }
+    else if ( exifError == KErrNone )
+        {
+        exifWriter->DeleteTag( EIfdGps, KIdGpsLatitudeRef );
+        exifWriter->DeleteTag( EIfdGps, KIdGpsLatitude );
+        exifChanged = ETrue;
+        }
+
+    changed = EFalse;
+    
+    // longitude
+    const CExifTag* exifLongitudeRefTag = NULL;
+    TRAP( exifError, exifLongitudeRefTag = exifReader->GetTagL(
+    		EIfdGps, KIdGpsLongitudeRef ) );
+    if ( longitudeProperty )
+        {
+        TBuf8<2> west( KWest );
+        TBuf8<2> east( KEast );        
+        TReal64 longitude = longitudeProperty->Real64ValueL();
+        
+        TReal64 exifLongitude( 0.0 );
+        TBuf8<2> exifLongitudeRef;
+        if ( exifError == KErrNone )
+            {
+            TPtrC8 exifLongitudeRefBuf( exifLongitudeRefTag->Data() );
+            exifLongitudeRef.Append( exifLongitudeRefBuf.Ptr(), 2 );
+
+            if ( longitude < 0 )
+                {
+                if ( west.Compare(exifLongitudeRef) )
+                    {
+                    changed = ETrue;
+                    }
+                }
+            else
+                {
+                if ( east.Compare(exifLongitudeRef) )
+                    {
+                    changed = ETrue;
+                    }
+                }
+
+            if ( !changed )
+                {
+                TBuf8<KCoordinateBufferSize> exifLongitudeBuf;
+                const CExifTag* exifLongitudeTag = NULL;
+                TRAPD( err, exifLongitudeTag = exifReader->GetTagL( EIfdGps, KIdGpsLongitude ) );
+                if ( err == KErrNone )
+                    {
+                    TPtrC8 exifLongitudeTagBuf( exifLongitudeTag->Data() );
+                    exifLongitudeBuf.Append( exifLongitudeTagBuf.Ptr(), KCoordinateBufferSize );
+                    MdsUtils::ConvertFromDegreesToDecimalL( exifLongitudeBuf, exifLongitude );
+                    if ( exifLongitudeRef.Compare( KWest ) == 0 )
+                        {
+                        exifLongitude = -exifLongitude;
+                        }
+                    }
+                else
+                    {
+                    exifError = err;
+                    }
+                }
+            }
+
+        if ( exifError != KErrNone || changed || Abs(exifLongitude - longitude) > KAngleSecond )
+            {
+            // longitude ref (E/W)
+            if ( longitude < 0 )
+                {
+                exifWriter->SetTagL( EIfdGps,
+                		TExifTagInfo( KIdGpsLongitudeRef, CExifTag::ETagAscii, 2 ), west );
+                longitude = -longitude;
+                }
+            else
+                {
+                exifWriter->SetTagL( EIfdGps,
+                		TExifTagInfo( KIdGpsLongitudeRef, CExifTag::ETagAscii, 2 ), east );
+                }
+            
+            TBuf8<KCoordinateBufferSize> longitudeBuf;
+            MdsUtils::ConvertFromDecimalToDegreesL( longitude, longitudeBuf );
+            exifWriter->SetTagL( EIfdGps,
+            		TExifTagInfo( KIdGpsLongitude, CExifTag::ETagRational, 3 ), longitudeBuf );
+            exifChanged = ETrue;
+            }
+        }
+    else if ( exifError == KErrNone )
+        {
+        exifWriter->DeleteTag( EIfdGps, KIdGpsLongitudeRef );
+        exifWriter->DeleteTag( EIfdGps, KIdGpsLongitude  );
+        exifChanged = ETrue;
+        }
+
+    changed = EFalse;
+    
+    // altitude
+    const CExifTag* exifAltitudeRefTag = NULL;
+    TRAP( exifError, exifAltitudeRefTag = exifReader->GetTagL( EIfdGps, KIdGpsAltitudeRef ) );
+    if ( altitudeProperty )
+        {
+        TReal64 altitude = altitudeProperty->Real64ValueL();
+
+        TBuf8<8> altitudeBuf;
+        const TInt32 KAltDenominator = 100;
+        altitude *= KAltDenominator;
+
+        TUint8 altitudeRef = 0;
+        TBuf8<1> altRefBuf;
+        
+        if ( altitude < 0 )
+            {
+            altitudeRef = 1;
+            altitude = -altitude;
+            }        	
+        
+        altRefBuf.Append( &altitudeRef, 1 );
+
+        TInt32 exifAltitudeValue( 0 );
+        TInt32 exifAltDenominator( 0 );
+        TReal64 exifAltitude = 0.0f;
+        TBuf8<1> exifAltitudeRef;
+        if ( exifError == KErrNone )
+            {
+            TPtrC8 exifAltitudeRefBuf( exifAltitudeRefTag->Data() );
+            exifAltitudeRef.Append( exifAltitudeRefBuf.Ptr(), 1 );
+            const CExifTag* exifAltitudeTag = NULL;
+            TRAPD( err, exifAltitudeTag = exifReader->GetTagL( EIfdGps, KIdGpsAltitude ) );
+            if ( err == KErrNone )
+                {
+                TPtrC8 exifAltitudeTagBuf( exifAltitudeTag->Data() );
+                memcpy( &exifAltitudeValue, exifAltitudeTagBuf.Ptr(),
+                		sizeof(exifAltitudeValue) );
+                memcpy( &exifAltDenominator,
+                		exifAltitudeTagBuf.Ptr()+sizeof(exifAltitudeValue),
+                		sizeof(exifAltDenominator) );
+                }
+            else
+                {
+                exifError = err;
+                }
+            exifAltitude = (TReal64)exifAltitudeValue;
+            }
+
+        if ( exifError != KErrNone || exifAltitudeRef.Compare(altRefBuf) ||
+        		Abs(altitude - exifAltitude) > KAngleSecond )
+            {
+            exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+            		KIdGpsAltitudeRef, CExifTag::ETagByte, 1 ), altRefBuf );
+
+            TInt32 tmpAlt = (TInt32) altitude;
+            altitudeBuf.Append( (TUint8*) &tmpAlt, 4 );
+            altitudeBuf.Append( (TUint8*) &KAltDenominator, 4 );
+            exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+            		KIdGpsAltitude, CExifTag::ETagRational, 1 ), altitudeBuf );
+            exifChanged = ETrue;
+
+            changed = EFalse;            
+            }
+        // measure mode
+        const CExifTag* exifMeasureModeTag = NULL;
+        TRAPD( err, exifMeasureModeTag = exifReader->GetTagL( EIfdGps, KIdGpsMeasureMode ) );
+        if ( err == KErrNone )
+        	{
+        	
+        	TBuf8<2> exifMeasureMode;
+            TPtrC8 exifMeasureModeBuf( exifMeasureModeTag->Data() );
+            exifMeasureMode.Append( exifMeasureModeBuf.Ptr(), 2 );
+        	
+            if (altitude == 0)
+            	{
+            	if (exifMeasureMode.Compare(KMeasureMode3))
+            		{
+            		changed = ETrue;
+            		}
+            	}
+            else
+            	{
+            	if (exifMeasureMode.Compare(KMeasureMode2))
+            		{
+            		changed = ETrue;
+            		}
+            	}
+        	}
+        else
+            {
+            exifError = err;
+            }
+        
+        if (err != KErrNone || changed)
+        	{
+        	if (altitude == 0)
+            	{
+            	exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+            		KIdGpsMeasureMode, CExifTag::ETagAscii, 2 ), KMeasureMode2 );
+            	}
+        	else
+        		{
+        		exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+                		KIdGpsMeasureMode, CExifTag::ETagAscii, 2 ), KMeasureMode3 );
+        		}
+        	}
+        }
+    else if ( exifError == KErrNone )
+        {
+        exifWriter->DeleteTag( EIfdGps, KIdGpsAltitudeRef  );
+        exifWriter->DeleteTag( EIfdGps, KIdGpsAltitude  );
+        exifWriter->DeleteTag( EIfdGps, KIdGpsMeasureMode  );
+        exifChanged = ETrue;
+        } 
+    
+    changed = EFalse;
+    
+    // quality, DOP value
+    const CExifTag* exifQualityTag = NULL;
+    TRAPD( err, exifQualityTag = exifReader->GetTagL( EIfdGps, KIdGpsDop ) );
+    if (qualityProperty)
+    	{
+        CMdEReal32Property* qualityReal = static_cast<CMdEReal32Property*>(qualityProperty);
+        TReal32 quality = qualityReal->Value();
+        const TInt32 KQualityDenominator = 10;
+        TBuf8<8> qualityBuf;
+        TInt32 exifQualityValue( 0 );
+        TInt32 exifQualityDenominator( 0 );  
+        TReal32 exifQuality (0.0f);
+        quality = quality * KQualityDenominator;
+        
+	    if ( err == KErrNone )
+	        {
+                TPtrC8 exifQualityTagBuf( exifQualityTag->Data() );
+                memcpy( &exifQualityValue, exifQualityTagBuf.Ptr(),
+                		sizeof(exifQualityValue) );
+                memcpy( &exifQualityDenominator,
+                		exifQualityTagBuf.Ptr()+sizeof(exifQualityValue),
+                		sizeof(exifQualityDenominator) );
+	        }
+        else
+            {
+            exifError = err;
+            }
+	    
+	    if (exifQualityDenominator > 0)
+	    	{
+	    	exifQuality = (TReal32)exifQualityValue;
+	    	}
+	    
+	    if (exifError != KErrNone || Abs(quality - exifQuality) > 0.1f)
+	    	{
+	    	
+	    	TInt32 tmpQuality = (TInt32) quality;
+	    	qualityBuf.Append( (TUint8*) &tmpQuality, 4 );
+	    	qualityBuf.Append( (TUint8*) &KQualityDenominator, 4 );
+            exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+            		KIdGpsDop, CExifTag::ETagRational, 1 ), qualityBuf );
+            exifChanged = ETrue;	    	
+	    	}	    
+    	}
+    
+    const CExifTag* exifDatumTag = NULL;
+    TRAP( err, exifDatumTag = exifReader->GetTagL( EIfdGps, KIdGpsMapDatum ) );
+    TBuf8<7> mapdatum( KMapDatum );
+
+    
+    if ( err == KErrNone )
+        {        
+        if (exifDatumTag->Data().Compare(mapdatum))
+    		{
+    		changed = ETrue;
+    		}        	
+        }
+    else
+        {
+        exifError = err;
+        }
+    
+    if (exifError != KErrNone || changed)
+    	{        		
+		exifWriter->SetTagL( EIfdGps, TExifTagInfo(
+			KIdGpsMapDatum, CExifTag::ETagAscii, 7 ), mapdatum );
+    	}
+    
+    // write the EXIF data to the image
+    if ( exifChanged )
+        {
+        aModified = exifWriter->WriteDataL( aImagePtr );
+        }
+    CleanupStack::PopAndDestroy( exifWriter );
+    }
+
+void CHarvesterExifUtil::ReadUserCommentL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting UserComment
+    if ( aReader->TagExists(KIdUserComment, EIfdExif ) )
+        {
+        TUint16 KMaxCommentLength = 256;
+        
+        HBufC8* comment = aReader->GetUserCommentL();
+        CleanupStack::PushL( comment );
+        if( comment->Length() >= 8 )
+            {
+            TBuf8<8> commentFormat = comment->Mid( 0,8 );
+            
+            TUint16 commentLength = comment->Length();
+            
+            TPtrC8 userPtr = comment->Mid( 8, commentLength > KMaxCommentLength ?
+                    KMaxCommentLength - 8 : commentLength - 8 );
+            
+            if ( commentFormat.Compare(KUnicodeCodeDesignation) == 0 )
+                {
+                WRITELOG( "CHarvesterExifUtil::ReadUserCommentL() - comment, Unicode encoding" );
+                aHd.iComment16 = HBufC::NewL( userPtr.Length() );
+                TPtr ptr = aHd.iComment16->Des();
+                TPtrC16 ptr16( (TUint16*)(userPtr.Ptr()), (userPtr.Size()/2) );
+                ptr.Copy( ptr16 );
+                }
+            else if ( commentFormat.Compare(KAsciiCodeDesignation) == 0 ||
+                      commentFormat.Compare(KUnknownCodeDesignation) == 0 ||
+                      commentFormat.Compare(KJisCodeDesignation) == 0 )
+                {
+                aHd.iComment16 = CnvUtfConverter::ConvertToUnicodeFromUtf8L( userPtr ); 
+                }
+            else
+                {
+                WRITELOG( "CHarvesterExifUtil::ReadUserCommentL() - unknown comment encoding" );    
+                }
+            if( aHd.iComment16 )
+                {
+                StripNulls( *(aHd.iComment16) );
+                }
+            }
+        CleanupStack::PopAndDestroy( comment );
+        comment = NULL;
+        }
+    }
+
+void CHarvesterExifUtil::ReadXResolutionL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting X Resolution
+    TUint32 numerator = 0;
+    TUint32 denominator = 0;
+    const TInt error = aReader->GetXResolution( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreXResolution = ETrue;
+        aHd.iXResolution = 0.0f;
+        if ( denominator > 0 )
+            {
+            aHd.iXResolution = (TReal32) numerator / (TReal32) denominator;
+            }
+        }
+    }
+
+void CHarvesterExifUtil::ReadYResolutionL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting Y Resolution
+    TUint32 numerator = 0;
+    TUint32 denominator = 0;
+    const TInt error = aReader->GetYResolution( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreYResolution = ETrue;
+        aHd.iYResolution = 0.0f;
+        if ( denominator > 0 )
+            {
+            aHd.iYResolution = (TReal32) numerator / (TReal32) denominator;
+            }
+        }
+    }
+
+void CHarvesterExifUtil::ReadExposureBiasL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting exposure bias
+    TInt32 num( 0 );
+    TInt32 deno( 0 );
+    const TInt error = aReader->GetExposureBiasValue( num, deno );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreExposureBias = ETrue;
+        aHd.iExposureBias = 0.0f;
+        if ( deno != 0 )
+            {
+            aHd.iExposureBias = (TReal32) num / (TReal32) deno;    
+            }
+        }
+    }
+
+void CHarvesterExifUtil::ReadExposureTimeL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting exposure time
+    TUint32 numerator = 0;
+    TUint32 denominator = 0;
+    const TInt error = aReader->GetExposureTime( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreExposureTime = ETrue;
+        aHd.iExposureTime = 0.0f;
+        if ( denominator > 0 )
+            {
+            aHd.iExposureTime = (TReal32) numerator / (TReal32) denominator;
+            }
+        }
+    }
+
+void CHarvesterExifUtil::ReadFNumberL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting FNumber
+    if ( aReader->TagExists(KIdFNumber, EIfdExif) )
+        {
+        const CExifTag* tag = aReader->GetTagL( EIfdExif, KIdFNumber );
+        TPtrC8 tagData = tag->Data();
+        
+        TUint32 numerator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        TUint32 denominator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() + 4 ) );
+        if ( denominator == 0 )
+            {
+            denominator = 1;
+            }
+        
+        aHd.iFNumber = (TReal32) numerator / (TReal32) denominator;
+        aHd.iStoreFNumber = ETrue;
+        WRITELOG1( "CHarvesterExifUtil::ReadFNumberL() - fnumber %f", aHd.iFNumber );
+        }
+    }
+
+void CHarvesterExifUtil::ReadShutterSpeedL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting shutter speed value
+    TInt32 num( 0 );
+    TInt32 deno( 0 );
+    const TInt error = aReader->GetShutterSpeedValue( num, deno );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreShutterSpeed = ETrue;
+        aHd.iShutterSpeed = 0.0f;
+        if ( deno != 0 )
+            {
+            aHd.iShutterSpeed = (TReal32) num / (TReal32) deno;
+            }
+        
+        WRITELOG1( "CHarvesterExifUtil::ReadExifDataL() - shutter speed %f", aHd.iShutterSpeed );
+        }
+    }
+
+void CHarvesterExifUtil::ReadApertureValueL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting aHd.iAperture
+    TUint32 numerator = 0;
+    TUint32 denominator = 0;
+    const TInt error = aReader->GetApertureValue( numerator, denominator );
+    if ( error == KErrNone )
+        {
+        aHd.iStoreAperture = ETrue;
+        aHd.iAperture = 0.0f;
+        if ( denominator > 0 )
+            {
+            aHd.iAperture = (TReal32) numerator / (TReal32) denominator;
+            }
+      
+        WRITELOG1( "CHarvesterExifUtil::ReadExifDataL() - aHd.iAperture %f", aHd.iAperture );
+        }
+    }
+
+void CHarvesterExifUtil::ReadFocalLengthL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    //Getting focal length
+    TUint32 numerator = 0;
+    TUint32 denominator = 0;
+    if ( aReader->TagExists(KIdFocalLength, EIfdExif) )
+        {                
+        const CExifTag* tag = aReader->GetTagL( EIfdExif, KIdFocalLength );
+        TPtrC8 tagData = tag->Data();
+        
+        numerator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        denominator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() + 4 ) );
+        
+        if ( denominator == 0 )
+            {
+            denominator = 1;
+            }
+        
+        aHd.iFocalLength = (TReal32) numerator / (TReal32) denominator;
+        aHd.iStoreFocalLength = ETrue;
+        
+        WRITELOG1( "CHarvesterExifUtil::ReadExifDataL() - focal length %f", aHd.iFocalLength );
+        }
+    }
+
+void CHarvesterExifUtil::ReadFocalLength35mmL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting focal length in 35 mm
+    if ( aReader->TagExists(KIdFocalLengthIn35mm, EIfdExif) )
+        {
+        const CExifTag* tag = aReader->GetTagL( EIfdExif, KIdFocalLengthIn35mm );
+        TPtrC8 tagData = tag->Data();
+        
+        aHd.iFocalLengthIn35mm = MdsUtils::ToUInt16L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        
+        aHd.iStoreFocalLengthIn35 = ETrue;
+        
+        WRITELOG1( "CHarvesterExifUtil::ReadExifDataL() - focal length in 35 mm: %f", aHd.iFocalLengthIn35mm );
+        }
+    }
+
+void CHarvesterExifUtil::ReadFocalXPlaneResolutionL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting focal plane X resolution
+    if ( aReader->TagExists(KIdFocalPlaneXResolution, EIfdExif) )
+        {
+        const CExifTag* tag = aReader->GetTagL(
+                EIfdExif, KIdFocalPlaneXResolution );
+        TPtrC8 tagData = tag->Data();
+        
+        TUint32 numerator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        TUint32 denominator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() + 4 ) );
+        if ( denominator == 0 )
+            {
+            denominator = 1;
+            }
+        
+        aHd.iFocalPlaneXResolution = (TReal32) numerator / (TReal32) denominator;
+        aHd.iStoreFocalPlaneXResolution = ETrue;
+        }
+    }
+
+void CHarvesterExifUtil::ReadFocalYPlaneResolutionL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    // Getting focal plane Y resolution
+    if ( aReader->TagExists(KIdFocalPlaneYResolution, EIfdExif) )
+        {
+        const CExifTag* tag = aReader->GetTagL(
+                EIfdExif, KIdFocalPlaneYResolution );
+        TPtrC8 tagData = tag->Data();
+        
+        TUint32 numerator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() ) );
+        TUint32 denominator = MdsUtils::ToUInt32L( CONST_CAST( TUint8*, tagData.Ptr() + 4 ) );
+        if ( denominator == 0 )
+            {
+            denominator = 1;
+            }
+        
+        aHd.iFocalPlaneYResolution = (TReal32) numerator / (TReal32) denominator;
+        aHd.iStoreFocalPlaneYResolution = ETrue;
+        }
+    }
+
+void CHarvesterExifUtil::ReadGPSLatitudeL( CHarvestData& aHd, 
+                                                                       CExifRead* aReader, 
+                                                                       TBool& aLatitude )
+    {
+    const TInt KCoordinateBufferSize = 24;
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLatitudeL() - trying to read GPS Latitude" );
+    
+    // Getting GPS latitude   
+    if ( aReader->TagExists(KIdGpsLatitudeRef, EIfdGps) &&
+            aReader->TagExists(KIdGpsLatitude, EIfdGps) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadGPSLatitudeL() - GPS Latitude found" );
+        
+        TReal64 latitude = 0.0;
+        const CExifTag* refTag = aReader->GetTagL(
+                EIfdGps, KIdGpsLatitudeRef );
+        TBuf8<2> latitudeRef = refTag->Data();
+        const CExifTag* latitudeTag = aReader->GetTagL(
+                EIfdGps, KIdGpsLatitude );
+        TBuf8<KCoordinateBufferSize> latitudeBuf = latitudeTag->Data();
+        MdsUtils::ConvertFromDegreesToDecimalL( latitudeBuf, latitude );
+        if ( latitudeRef == KSouth )
+            {
+            latitude = -latitude;
+            }
+        aHd.iGpsLatitude = latitude;
+        aLatitude = ETrue;
+        }
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLatitudeL() - trying to read GPS Latitude - end" );
+    }
+
+void CHarvesterExifUtil::ReadGPSLongitudeL( CHarvestData& aHd, 
+                                                                          CExifRead* aReader, 
+                                                                          TBool& aLatitude )
+    {
+    const TInt KCoordinateBufferSize = 24;
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLongitudeL() - trying to read GPS Longitude" );
+    
+    // Getting GPS longitude
+    if ( aReader->TagExists(KIdGpsLongitudeRef, EIfdGps) &&
+            aReader->TagExists(KIdGpsLongitude, EIfdGps) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadGPSLatitudeL() - GPS Longitude found" );
+    
+        TReal64 longitude = 0.0;
+        const CExifTag* refTag = aReader->GetTagL(
+                EIfdGps, KIdGpsLongitudeRef );
+        TBuf8<2> longitudeRef = refTag->Data();
+        const CExifTag* longitudeTag = aReader->GetTagL(
+                EIfdGps, KIdGpsLongitude );
+        TBuf8<KCoordinateBufferSize> longitudeBuf = longitudeTag->Data();
+        MdsUtils::ConvertFromDegreesToDecimalL( longitudeBuf, longitude );
+        if ( longitudeRef == KWest )
+            {
+            longitude = -longitude;
+            }
+        aHd.iGpsLongitude = longitude;
+        if ( aLatitude )
+            {
+            aHd.iStoreGpsLatitudeAndLongitude = ETrue;
+            }
+        }
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLongitudeL() - trying to read GPS Longitude - end" );
+    }
+
+void CHarvesterExifUtil::ReadGPSAltitudeL( CHarvestData& aHd, CExifRead* aReader )
+    {
+    const TInt KAltitudeBufferSize = 8;
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLongitudeL() - trying to read GPS Altitude" );
+    
+    // Getting GPS altitude
+    if ( aReader->TagExists(KIdGpsAltitudeRef, EIfdGps) &&
+            aReader->TagExists(KIdGpsAltitude, EIfdGps) )
+        {
+        WRITELOG( "CHarvesterExifUtil::ReadGPSLatitudeL() - GPS Altitude found" );
+    
+        const CExifTag* refTag = aReader->GetTagL(
+                EIfdGps, KIdGpsAltitudeRef );
+        TBuf8<1> altitudeRef = refTag->Data();
+        const CExifTag* altitudeTag = aReader->GetTagL(
+                EIfdGps, KIdGpsAltitude );
+        TBuf8<KAltitudeBufferSize> altitudeBuf = altitudeTag->Data();
+        TInt32 altitude = MdsUtils::ToUInt32L(
+                CONST_CAST( TUint8*, altitudeBuf.Left(4).Ptr() ) );
+        TInt32 denominator =  MdsUtils::ToUInt32L(
+                CONST_CAST( TUint8*, altitudeBuf.Right(4).Ptr() ) );
+        TInt8 ref = *((TUint8*) altitudeRef.Ptr());
+
+        if ( ref == 1 )
+            {
+            altitude = -altitude;
+            }
+
+        aHd.iGpsAltitude = 0.0f;
+        if ( denominator != 0 )
+            {
+            aHd.iGpsAltitude = (TReal64)altitude / (TReal64)denominator;
+            }
+
+        aHd.iStoreGpsAltitude = ETrue;
+        }
+    
+    WRITELOG( "CHarvesterExifUtil::ReadGPSLongitudeL() - trying to read GPS Altitude - end" );
+    }
+
+// End of file