diff -r 000000000000 -r c53acadfccc6 harvester/common/src/harvesterexifutil.cpp --- /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 + + + +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 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 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 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 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(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 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 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 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