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