diff -r 57d4cdd99204 -r edfc90759b9f imageeditorengine/EngineWrapper/src/ImageEditorEngineWrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imageeditorengine/EngineWrapper/src/ImageEditorEngineWrapper.cpp Fri Jan 29 13:53:17 2010 +0200 @@ -0,0 +1,1968 @@ +/* +* Copyright (c) 2010 Ixonos Plc. +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the "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: +* Ixonos Plc +* +* Description: +* +*/ + + + +// INCLUDES +#include +#include +#include +#include + +//#include "ImageEditorPluginBase.hrh" +#include "platform_security_literals.hrh" + +#include "ImageEditorEngineWrapper.h" +#include "CFilterStack.h" +#include "MImageFilter.h" +#include "SystemParameters.h" +#include "ImageEditorError.h" +#include "ImageEditorUtils.h" +#include "EditorVersion.h" + + +#include "CExifParser.h" +#include "TBitmapHandle.h" +#include "MJpegSave.h" +#include "JpegSaveFactory.h" + + +// Debug logger definitions +#include "imageeditordebugutils.h" +_LIT( KEngineWrapperLogFile,"EngineWrapper.log" ); + + +// CONSTANTS + +// Minimum source image x-y value that the engine is able to render +const TInt KObMinSourceDimension = 16; + +// EXIF thumbnail quality +const TInt KThumbnailJpegQuality = 60; // [0,100] +const TInt KThumbnailMaxDimension = 160; + +// Used fixed point resolution for scales +const TInt KScaleBits = 12; + +const TReal KZoomScaleFactor = 0.5; + +// Comment tag to be written to the EXIF data of JPEG file. +_LIT8( KImageEditorExifComment, "Edited with Nokia Image Editor %d.%d.%d" ); + + +// Filter paths +_LIT(KFilterJpegSource, "FilterJpegSource.dll"); +_LIT(KFilterIclSource, "FilterIclSource.dll"); +_LIT(KFilterTarget, "FilterJpegTarget.dll"); +_LIT(KFilterBuffer, "FilterBuffer.dll"); +_LIT(KFilterScale, "FilterScale.dll"); +_LIT(KFilterRotate, "FilterRotate.dll"); + +//============================================================================= +EXPORT_C CEngineWrapper * CEngineWrapper::NewL () +{ + LOG_INIT ( KEngineWrapperLogFile ); + + CEngineWrapper * self = new (ELeave) CEngineWrapper; + CleanupStack::PushL (self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + +//============================================================================= +EXPORT_C CEngineWrapper::~CEngineWrapper () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::~CEngineWrapper"); + Cleanup(); + + delete iExifParser; + iExifParser = NULL; + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::CreateJpegSourceL (const TDesC & aFileName) +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL" ); +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL\taFileName: %S", &aFileName ); +#endif // VERBOSE + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Add JPEG source to engine + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- Add jpeg source" ); + if ( iMainEngine->NumFilters() == 0 ) + { + iMainEngine->AddFilterL ( KFilterJpegSource ); + } + else if ( IsSameString ( (TUint8*)iMainEngine->Filter(0)->Type(), (TUint8*)"iclsource" ) ) + { + iMainEngine->RemoveFilter (0); + iMainEngine->AddFilterL (KFilterJpegSource, 0); + } + else if ( !IsSameString ( (TUint8*)iMainEngine->Filter(0)->Type(), (TUint8*)"jpegsource" ) ) + { + iMainEngine->AddFilterL (KFilterJpegSource, 0); + } + iCmd.Copy ( _L("file \"")); + iCmd.Append ( aFileName ); + iCmd.Append ( _L("\"")); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: Cmd: %S", &aFileName ); + iMainEngine->FunctionL ( 0, iCmd ); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- Jpeg source added" ); + iMainEngine->FunctionL ( 0, _L("loadimage")); + + // Get source image size + TRect rect = iMainEngine->Filter (0)->Rect(); + iSourceSize = iMainEngine->Filter (0)->ViewPortSize(); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: source width: %d", iSourceSize.iWidth); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: source height: %d", iSourceSize.iHeight); + + // Check that the source image is of minimum size + if (iSourceSize.iWidth < KObMinSourceDimension || iSourceSize.iHeight < KObMinSourceDimension) + { + User::Leave (KSIEEOpenFile); + } + + // Initialize crop parameters + iBoundingRect.iTl.iX = 0; + iBoundingRect.iTl.iY = 0; + iBoundingRect.iBr.iX = iSourceSize.iWidth; + iBoundingRect.iBr.iY = iSourceSize.iHeight; + iScale = 1.0; + iMaxScale = 1.0; + iMinScale = (TReal)iScreenSize.iWidth / iSourceSize.iWidth; + iPanX = iSourceSize.iWidth * 0.5; + iPanY = iSourceSize.iHeight * 0.5; + iPanStep = 128.0; + iZoomMode = EZoomNormal; + + // Initialize system parameters + iSysPars->SourceSize() = iSourceSize; + iSysPars->Scale() = 1.0; + + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- Read EXIF data" ); + + // Read EXIF data pointer + iCmd.Copy ( _L("exifdata")); + TUint8 * exifptr = (TUint8 *)iMainEngine->FunctionL ( 0, iCmd ); + + // Read EXIF data length + iCmd.Copy ( _L("exiflength")); + TInt exiflen = (TInt)iMainEngine->FunctionL ( 0, iCmd ); + + // Create and initialize EXIF parser + TPtrC8 exifdata (exifptr, exiflen); + if (iExifParser) + { + delete iExifParser; + iExifParser = NULL; + } + + iExifParser = CExifParser::NewL (); + TRAPD( err, iExifParser->ParseL (exifdata) ); + if (KErrNone == err) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- EXIF data read." ); + } + else + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- FAILED to parse EXIF data. Ignored." ); + } + + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::CreateJpegTargetL ( + const TDesC & aFileName, + const TInt aQuality, + const TSize * aSize + ) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL" ); +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL\taFileName: %S", &aFileName ); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL\taQuality: %d", aQuality ); + if (aSize) + { + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL\taSize->iWidth: %d", aSize->iWidth); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL\taSize->iHeight: %d", aSize->iHeight); + } + else + { + LOG( KEngineWrapperLogFile, "aSize == NULL" ); + } + +#endif // VERBOSE + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + if ( aQuality < 0 || aQuality > 100) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL: Invalid parameter aQuality!" ); + User::Panic (KEnginePanic, KEnginePanicParameter); + } + if ( aSize && ( (aSize->iWidth < 0 || aSize->iHeight < 0) ) ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL: Invalid parameter aSize!" ); + User::Panic (KEnginePanic, KEnginePanicParameter); + } + + // Remove source buffer + iMainEngine->FunctionL (0, _L("fileoutput")); + + // Remove screen buffer + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Remove screen buffer" ); + if ( IsSameString ( (TUint8*)iMainEngine->Filter(iMainEngine->NumFilters() - 1)->Type(), (TUint8*)"buffer" ) ) + { + iMainEngine->RemoveFilter(iMainEngine->NumFilters() - 1); + } + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Screen buffer removed" ); + + // Remove jpeg target buffer + if ( IsSameString ( (TUint8*)iMainEngine->Filter(iMainEngine->NumFilters() - 1)->Type(), (TUint8*)"jpegtarget" ) ) + { + iMainEngine->RemoveFilter(iMainEngine->NumFilters() - 1); + } + + // Remove scale buffer, if image is not scaled + if ( iSysPars->Scale() == 1.0 ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Remove screen scale filter." ); + if ( IsSameString ( (TUint8*)iMainEngine->Filter(iMainEngine->NumFilters() - 1)->Type(), (TUint8*)"scale" ) ) + { + iMainEngine->RemoveFilter(iMainEngine->NumFilters() - 1); + } + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Screen scale filter removed." ); + } + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Add jpeg target filter." ); + iMainEngine->AddFilterL ( KFilterTarget ); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegTargetL --- Jpeg target filter added." ); + + // If external target size is given, set it to target. + if ( aSize ) + { + iCmd.Format( _L("width %d height %d"), aSize->iWidth, aSize->iHeight ); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); + } + + // Set the scaled source size to target + if ( iSysPars->Scale() != 1.0 ) + { + TReal scale = iSysPars->Scale(); + TSize tgtsize = iMainEngine->Filter ( iMainEngine->NumFilters() - 3 )->ViewPortSize(); + tgtsize.iWidth = (TInt)(tgtsize.iWidth * scale + 0.5); + tgtsize.iHeight = (TInt)(tgtsize.iHeight * scale + 0.5); + iCmd.Format( _L("width %d height %d"), tgtsize.iWidth, tgtsize.iHeight); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 2, _L("nop")); + } + + // Store save file name + iTargetFile.Copy ( aFileName ); + + LOG ( KEngineWrapperLogFile, "CreateJpegTargetL: Sink created" ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::CreateIclSourceL (const TDesC & aFileName) +{ + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL" ); +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL\taFileName: %S", &aFileName ); +#endif // VERBOSE + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Add JPEG source to engine + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL --- Add icl source" ); + if ( iMainEngine->NumFilters() == 0 ) + { + iMainEngine->AddFilterL ( KFilterIclSource ); + } + else if ( IsSameString ( (TUint8*)iMainEngine->Filter(0)->Type(), (TUint8*)"jpegsource" ) ) + { + iMainEngine->RemoveFilter(0); + iMainEngine->AddFilterL ( KFilterIclSource, 0); + } + else if ( !IsSameString ( (TUint8*)iMainEngine->Filter(0)->Type(), (TUint8*)"iclsource" ) ) + { + iMainEngine->AddFilterL ( KFilterIclSource, 0); + } + iCmd.Copy (_L("file \"")); + iCmd.Append ( aFileName ); + iCmd.Append (_L("\"")); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL: Cmd: %S", &iCmd ); + iMainEngine->FunctionL ( 0, iCmd ); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL --- Icl source added" ); + iMainEngine->FunctionL ( 0, _L("loadimage")); + + // Get source image size + TRect rect = iMainEngine->Filter (0)->Rect(); + iSourceSize = iMainEngine->Filter (0)->ViewPortSize(); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: source width: %d", iSourceSize.iWidth); + LOGFMT ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL: source height: %d", iSourceSize.iHeight); + + // Check that the source image is of minimum size + if (iSourceSize.iWidth < KObMinSourceDimension || iSourceSize.iHeight < KObMinSourceDimension) + { + User::Leave (KSIEEOpenFile); + } + + // Initialize crop parameters + iScale = 1.0; + iMaxScale = 1.0; + iMinScale = (TReal)iScreenSize.iWidth / iSourceSize.iWidth; + iPanX = iSourceSize.iWidth * 0.5; + iPanY = iSourceSize.iHeight * 0.5; + iPanStep = 128.0; + iZoomMode = EZoomNormal; + + // Initialize system parameters + iSysPars->SourceSize() = iSourceSize; + iSysPars->Scale() = 1.0; + + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateIclSourceL --- Create EXIF parser" ); + + if (iExifParser) + { + delete iExifParser; + iExifParser = NULL; + } + + iExifParser = CExifParser::NewL (); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateJpegSourceL --- EXIF parser created." ); + + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::CreateRGB888TargetL () +{ + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL " ); + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "\tiScreenSize.w: %d", iScreenSize.iWidth); + LOGFMT( KEngineWrapperLogFile, "\tiScreenSize.h: %d", iScreenSize.iHeight); +#endif + + // Create source buffer + iMainEngine->FunctionL (0, _L("bufferoutput")); + + // Remove target filter and add screen buffer + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Add buffer target." ); + TInt n = iMainEngine->NumFilters(); + if ( IsSameString ( (TUint8*)iMainEngine->Filter(n - 1)->Type(), (TUint8*)"jpegtarget") ) + { + iMainEngine->RemoveFilter(n - 1); + iMainEngine->AddFilterL ( KFilterBuffer ); + } + else if ( !IsSameString ( (TUint8*)iMainEngine->Filter(n - 1)->Type(), (TUint8*)"buffer" ) ) + { + iMainEngine->AddFilterL ( KFilterBuffer ); + } + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Buffer target added." ); + + // Set buffer size + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Set buffer size "); + iCmd.Format( _L("width %d height %d"), iScreenSize.iWidth, iScreenSize.iHeight ); + LOGDES (KEngineWrapperLogFile, iCmd); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Buffer size set." ); + + // Set scale buffer before screen buffer + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Add screen buffer scale filter"); + if ( !IsSameString ( (TUint8*)iMainEngine->Filter(iMainEngine->NumFilters() - 2)->Type(), (TUint8*)"scale") ) + { + iMainEngine->AddFilterL ( KFilterScale, iMainEngine->NumFilters() - 1); + } + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 2, iCmd ); + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL --- Screen buffer scale filter added."); + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::CreateRGB888TargetL: Sink created" ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::SetScreenSizeL (const TSize & aSize) +{ + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::SetScreenSizeL" ); +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::SetScreenSizeL\taSize.iWidth: %d", aSize.iWidth ); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::SetScreenSizeL\taSize.iHeight: %d", aSize.iHeight ); +#endif // VERBOSE + + // SANITY CHECKS + if ( aSize.iWidth < 0 || aSize.iHeight < 0) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::SetScreenSizeL: Invalid parameter aSize!" ); + User::Panic (KEnginePanic, KEnginePanicParameter); + } + + if ( aSize != iScreenSize ) + { + iScreenSize = aSize; + + // Set buffer size + TInt n = iMainEngine->NumFilters(); + if (n > 2) + { + if ( IsSameString ((TUint8*)iMainEngine->Filter(n - 1)->Type(), (TUint8*) "buffer" ) ) + { + iCmd.Format( _L("width %d height %d"), iScreenSize.iWidth, iScreenSize.iHeight); + iMainEngine->FunctionL ( n - 1, iCmd ); + iMainEngine->FunctionL ( n - 2, _L("nop")); + UpdateCropRectL(); + } + } + } +} + +//============================================================================= +EXPORT_C void CEngineWrapper::AddFilterL (const TDesC & aFilterName) +{ + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::AddFilterL (TDes & aFilterName: %S)", &aFilterName ); + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::AddFilterL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Check whether the filter is found + TFileName filtername; + filtername.Copy (aFilterName); + + /* + // no need for this as AddFilterL will leave if there is an error + if (FileExists (filtername) ) + { + TParse parse; + User::LeaveIfError( parse.Set( aFilterName ,NULL, NULL ) ); + filtername = parse.NameAndExt(); + }; + */ + + TInt n = iMainEngine->NumFilters(); + if (n >= 2) + { + iMainEngine->AddFilterL ( filtername, n - 2 ); + } + LOG ( KEngineWrapperLogFile, "CEngineWrapper::AddFilterL: Filter added" ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::SetParamsL (const TDesC & aParam) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::SetParamsL " ); + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::SetParamsL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Initialize error value + TInt n = iMainEngine->NumFilters(); + if ( n > 2 ) + { + LOGDES( KEngineWrapperLogFile, aParam ); + iMainEngine->FunctionL ( n - 3, aParam ); + } + + + if ( IsSameString ( (TUint8*)iMainEngine->Filter(n - 3)->Type(), (TUint8*) "rotate" ) ) + { + if (iScale == 1.0) + { + ComputeBoundingRectL(); + } + UpdateCropRectL(); + } + + + LOG( KEngineWrapperLogFile, "CEngineWrapper::SetParamsL: Parameters set " ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::RenderL (TInt* /*aMultiSessionBlockCount*/) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::RenderL" ); + + // SANITY CHECKS + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CEngineWrapper::RenderL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + TInt n = iMainEngine->NumFilters(); + for ( TInt i = 0; i < iMainEngine->NumFilters(); ++i) + { + iMainEngine->FunctionL (i, _L("nop")); + TBuf<100> buf; + buf.Copy(TPtrC8 ( (TUint8 *)iMainEngine->Filter(i)->Type() )); + LOGDES (KEngineWrapperLogFile, buf) ; + TRect rect = iMainEngine->Filter(i)->Rect(); + buf.Format( _L("%d %d %d %d"), rect.iTl.iX, rect.iTl.iY, rect.iBr.iX, rect.iBr.iY); + LOGDES (KEngineWrapperLogFile, buf) ; + } + + // Render to buffer target + if ( IsSameString ( (TUint8*)iMainEngine->Filter(n - 1)->Type(), (TUint8*) "buffer" ) ) + { + iCmd.Copy (_L("getbitmap")); + if ( iRenderScaleBuffer ) + { + iMainEngine->FunctionL ( 0, _L("loadimage")); + iRenderScaleBuffer = EFalse; + for ( TInt i = 0; i < iMainEngine->NumFilters(); ++i) + { + iMainEngine->FunctionL (i, _L("nop")); + } + } + + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::RenderL -- Render screen buffer." ); + TUint32 * buffer = (TUint32 *)iMainEngine->FunctionL ( n - 1, iCmd ); + CopyBufferL (buffer); + } + + // Render to JPEG target + else if ( IsSameString ( (TUint8*)iMainEngine->Filter(n - 1)->Type(), (TUint8*)"jpegtarget" ) ) + { + iCmd.Zero(); + + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::RenderL: Set EXIF data" ); + + // Update EXIF tags + UpdateExifTagsL(); + + // Update EXIF thumbnail + TPtrC8 savedexifdata = UpdateExifThumbnailL(); + + // Set EXIF data to target + iCmd.Format (_L("exifdata %d exiflen %d"), (TInt)(savedexifdata.Ptr()), savedexifdata.Length()); + + LOG ( KEngineWrapperLogFile, "CEngineWrapper::RenderL: EXIF data set." ); + + + iCmd.Append (_L(" file \"")); + iCmd.Append ( iTargetFile ); + iCmd.Append (_L("\"")); + iMainEngine->FunctionL ( n - 1, iCmd ); + } + + LOG( KEngineWrapperLogFile, "CEngineWrapper::RenderL: Rendered" ); +} + +//============================================================================= +EXPORT_C TInt CEngineWrapper::RenderBlockL() +{ +#ifdef VERBOSE_2 + LOG( KEngineWrapperLogFile, "CEngineWrapper::RenderBlockL" ); + + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::RenderBlockL\tiBlock: %d", iBlock); + if (iTestBitmap) + { + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::RenderBlock\tiTestBitmap->DataAddress(): %d", (TInt)iTestBitmap->DataAddress()); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::RenderBlock\tiTestBitmap->Handle(): %d", iTestBitmap->Handle()); + } + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::RenderBlockL\tiBuffer: %d", (TInt)iBuffer); +#endif + + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "RenderBlockL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + iCmd.Copy ( _L("store") ); + TInt percentage = iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); + if (percentage == 100) + { + iChangeCount = 0; + } + return percentage; +} + +//============================================================================= +EXPORT_C void CEngineWrapper::RenderAbortL() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::RenderAbortL" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "RenderAbort: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + iCmd.Copy ( _L("abort")); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::InitUndoRedo() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::InitUndoRedo" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "InitUndoRedo: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Purge undo stack + iUndoPoints.Reset(); + + // Undo + iPrevChangeCount = 0; + iChangeCount = 0; +} + +//============================================================================= +EXPORT_C void CEngineWrapper::AddUndoRedoStepL() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::AddUndoRedoStepL" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "AddUndoRedoStepL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Store undo point + TInt n = iMainEngine->NumFilters(); + if (n > 2) + { + // Set undo point before target filter + iUndoPoints.Append ( n - 3 ); + } + + iPrevChangeCount = iChangeCount; + iChangeCount++; + + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::AddUndoRedoStepL: iChangeCount = %d", iChangeCount); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::AddUndoRedoStepL: iPrevChangeCount = %d", iPrevChangeCount); + + // Store rotation and scale + User::LeaveIfError( iScaleUndoBuf.Append ( iSysPars->Scale() ) ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::UndoL() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::UndoL" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "UndoL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + TBool computeBoundingRect = EFalse; + TBool reloadImage = EFalse; + + if (iMainEngine->NumFilters() > 2) + { + TInt m = iUndoPoints.Count(); + TInt undoindex = iUndoPoints[m-1]; + while (iMainEngine->NumFilters() - 3 > undoindex) + { + TInt index = iMainEngine->NumFilters() - 3; + if ( IsSameString ( (TUint8*)iMainEngine->Filter(index)->Type(), (TUint8*) "rotate" ) ) + { + computeBoundingRect = ETrue; + } + else if ( IsSameString ( (TUint8*)iMainEngine->Filter(index)->Type(), (TUint8*) "crop" ) ) + { + reloadImage = ETrue; + } + + iMainEngine->RemoveFilter (index); + } + iUndoPoints.Remove (iUndoPoints.Count() - 1); + } + + iPrevChangeCount = iChangeCount; + iChangeCount--; + + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::UndoL: iChangeCount = %d", iChangeCount); + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::UndoL: iPrevChangeCount = %d", iPrevChangeCount); + + TInt count = iScaleUndoBuf.Count(); + if ( count > 0 ) + { + iSysPars->Scale() = iScaleUndoBuf[count - 1]; + iScaleUndoBuf.Remove (count - 1); + } + + if (reloadImage) + { + iCmd.Format( _L("ulc %d ulr %d lrc %d lrr %d"), 0,0,0,0); + iMainEngine->FunctionL ( 0, iCmd); + iMainEngine->FunctionL ( 0, _L("loadimage")); + for (TInt i = 0; i < iMainEngine->NumFilters(); ++i) + { + iMainEngine->FunctionL (i, _L("nop")); + } + ComputeBoundingRectL(); + } + + if ( iMainEngine->NumFilters() > 3 && computeBoundingRect && iScale == 1.0 ) + { + ComputeBoundingRectL(); + } + else if ( iMainEngine->NumFilters() <= 3 ) + { + iBoundingRect.iTl.iX = 0; + iBoundingRect.iTl.iY = 0; + iBoundingRect.iBr.iX = iSourceSize.iWidth; + iBoundingRect.iBr.iY = iSourceSize.iHeight; + } + UpdateCropRectL(); +} + +//============================================================================= +EXPORT_C TBool CEngineWrapper::CanUndo () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::CanUndo" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "CanUndo: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + if ( iUndoPoints.Count() > 0 ) + { + return ETrue; + } + else + { + return EFalse; + } +} + +//============================================================================= +EXPORT_C TBool CEngineWrapper::IsImageChanged() +{ + LOGFMT2( KEngineWrapperLogFile, "CEngineWrapper::IsImageChanged: iChangeCount = %d, iPrevChangeCount = %d", iChangeCount, iPrevChangeCount ); + + if ( iChangeCount || (iChangeCount == 0 && iPrevChangeCount < 0)) + { + return ETrue; + } + else + { + return EFalse; + } +} + +//============================================================================= +CEngineWrapper::CEngineWrapper () : +iScreenSize (), +iChangeCount(0), +iPrevChangeCount(0) +{ + +} + +//============================================================================= +void CEngineWrapper::ConstructL () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::ConstructL" ); + + // Create new engine + iMainEngine = CFilterStack::NewL(); + + // Set screen size to default + iScreenSize.iWidth = 1; + iScreenSize.iHeight = 1; + + // Create and initialize system parameters + LOG( KEngineWrapperLogFile, "CEngineWrapper: Creating system parameters" ); + iSysPars = new (ELeave) CSystemParameters; +} + +//============================================================================= +TInt CEngineWrapper::FileExists (TDes & aFileName) const +{ + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::FileExists (TDes & aFileName: %S)", &aFileName ); + + TInt result = KErrNone; + + RFs &fs = CEikonEnv::Static()->FsSession(); + + aFileName[0] = 'e'; + if ( !BaflUtils::FileExists (fs, aFileName) ) + { + aFileName[0] = 'c'; + if ( !BaflUtils::FileExists (fs, aFileName) ) + { + aFileName[0] = 'z'; + if ( !BaflUtils::FileExists (fs, aFileName) ) + { + return KErrNotFound; + } + } + } + + if ( !BaflUtils::FileExists (fs, aFileName) ) + { + result = KErrNotFound; + } + + LOGFMT( KEngineWrapperLogFile, "\tresult: %d", result ); + + return result; +} + +//============================================================================= +void CEngineWrapper::Cleanup() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::Cleanup" ); + + // Purge undo / redo information + iUndoPoints.Reset(); + + // Delete filters + for ( TInt i = 0; i < iMainEngine->NumFilters(); ++i) + { + iMainEngine->RemoveFilter(i); + } + + // Delete engine + if (iMainEngine) + { + delete iMainEngine; + iMainEngine = NULL; + } + + // Clear rotation and scale undo buffers + iScaleUndoBuf.Reset(); + + // Delete system parameters + if (iSysPars) + { + delete iSysPars; + iSysPars = NULL; + } + + if (iJpegComment) + { + delete iJpegComment; + iJpegComment = NULL; + } + + // Delete thumbnail buffer + delete[] iThumb; +} + +//============================================================================= +EXPORT_C void CEngineWrapper::StoreZoomL () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::StoreZoom" ); + + iScaleSt = iScale; + iPanXSt = iPanX; + iPanYSt = iPanY; + + iScale = 1.0; + iPanX = iSourceSize.iWidth * 0.5; + iPanY = iSourceSize.iHeight * 0.5; + UpdateCropRectL(); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::RestoreZoomL() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::RestoreZoom" ); + + if (iScale != iScaleSt) + { + iScale = iScaleSt; + iPanX = iPanXSt; + iPanY = iPanYSt; + UpdateCropRectL(); + } +} + +//============================================================================= +EXPORT_C void CEngineWrapper::ZoomL (const TZoom aZoom) + { + LOGFMT( KEngineWrapperLogFile, "CEngineWrapper::ZoomL: %d", (TInt)aZoom); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "ZoomFactor: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + if ( aZoom == EZoomMin ) + { + iScale = 1.0; + iZoomMode = EZoomNormal; + + } + else if ( aZoom == EZoomIn ) + { + + if ( iScale == 1.0 ) + { + ComputeBoundingRectL(); + } + + if ( iZoomMode < ( ENumOfZooms - 1 ) ) + { + // rescale + iScale *= KZoomScaleFactor; + // set next zoom mode + iZoomMode = ( TZoomMode )( ( TInt )iZoomMode + 1 ); + } + } + else + { + if ( iZoomMode > EZoomNormal ) + { + // rescale + iScale *= 1.0 / KZoomScaleFactor; + //set previous zoom mode + iZoomMode = ( TZoomMode )( ( TInt )iZoomMode - 1 ); + } + } + + UpdateCropRectL(); + } + +//============================================================================= +EXPORT_C TZoomMode CEngineWrapper::GetZoomMode() + { + return iZoomMode; + } + +//============================================================================= +EXPORT_C void CEngineWrapper::PanL (const TDirection aDir) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::PanL" ); + +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "\taDir: %d", (TInt)aDir); +#endif // VERBOSE + + if (iScale == 1.0) + { + return; + } + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "SetPanL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + TInt angle = ComputeRotationL(); + + switch (aDir) + { + case EDirectionUp: + { + if (angle == 0) + { + iPanY -= iPanStep * iScale; + } + else if (angle == 90) + { + iPanX -= iPanStep * iScale; + } + else if (angle == 180) + { + iPanY += iPanStep * iScale; + } + else if (angle == 270) + { + iPanX += iPanStep * iScale; + } + break; + } + case EDirectionDown: + { + if (angle == 0) + { + iPanY += iPanStep * iScale; + } + else if (angle == 90) + { + iPanX += iPanStep * iScale; + } + else if (angle == 180) + { + iPanY -= iPanStep * iScale; + } + else if (angle == 270) + { + iPanX -= iPanStep * iScale; + } + break; + } + case EDirectionLeft: + { + if (angle == 0) + { + iPanX -= iPanStep * iScale; + } + else if (angle == 90) + { + iPanY += iPanStep * iScale; + } + else if (angle == 180) + { + iPanX += iPanStep * iScale; + } + else if (angle == 270) + { + iPanY -= iPanStep * iScale; + } + break; + } + case EDirectionRight: + { + if (angle == 0) + { + iPanX += iPanStep * iScale; + } + else if (angle == 90) + { + iPanY -= iPanStep * iScale; + } + else if (angle == 180) + { + iPanX -= iPanStep * iScale; + } + else if (angle == 270) + { + iPanY += iPanStep * iScale; + } + break; + } + default: + break; + } + UpdateCropRectL(); + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::PanL( TInt aXChange, TInt aYChange ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::Pan" ); + +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "\taXChange: %d, aYChange: %d ", aXChange, aYChange ); +#endif // VERBOSE + + if (iScale == 1.0) + { + return; + } + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "SetPanL: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + TInt angle = ComputeRotationL(); + + if (angle == 0) + { + // X change + iPanX += aXChange*(iScale/iMinScale); + + // Y change + iPanY += aYChange*(iScale/iMinScale); + } + else if (angle == 90) + { + // X change + iPanX += aYChange*(iScale/iMinScale); + + // Y change + iPanY -= aXChange*(iScale/iMinScale); + } + else if (angle == 180) + { + // X change + iPanX -= aXChange*(iScale/iMinScale); + + // Y change + iPanY -= aYChange*(iScale/iMinScale); + } + else if (angle == 270) + { + // X change + iPanX -= aYChange*(iScale/iMinScale); + + // Y change + iPanY += aXChange*(iScale/iMinScale); + } + + UpdateCropRectL(); + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::RotateL (const TRotation aRot) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::RotateL" ); +#ifdef VERBOSE + LOGFMT( KEngineWrapperLogFile, "\taRot: %d", (TInt)aRot); +#endif // VERBOSE + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "Rotation: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + // Set undo / redo point + AddUndoRedoStepL (); + + // Add rotate filter + AddRotateFilterL(); + + // Set rotation pars + TBuf<128> cmd; + cmd.Copy (_L("angle ")); + + if ( ERotationCounterClockwise == aRot ) + { + cmd.AppendNum (270); + } + else if ( ERotationClockwise == aRot ) + { + cmd.AppendNum (90); + } + else if ( ERotation180 == aRot ) + { + cmd.AppendNum (180); + } + else + { + User::Leave (KErrArgument); + } + SetParamsL (cmd); +} + +//============================================================================= +EXPORT_C CSystemParameters * CEngineWrapper::GetSystemPars () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::GetSystemPars" ); + + ComputeSystemParameters(); + + return iSysPars; +} + +//============================================================================= +void CEngineWrapper::ComputeSystemParameters () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::ComputeSystemParameters" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "GetSystemPars: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } + + MImageFilter * filter = iMainEngine->Filter(iMainEngine->NumFilters() - 3); + TSize size = filter->ViewPortSize(); + iSysPars->ViewPortRect().iTl.iX = 0; + iSysPars->ViewPortRect().iTl.iY = 0; + iSysPars->ViewPortRect().iBr.iX = size.iWidth; + iSysPars->ViewPortRect().iBr.iY = size.iHeight; + + LOGFMT( KEngineWrapperLogFile, "ViewPortRect().iTl.iX: %d", iSysPars->ViewPortRect().iTl.iX ); + LOGFMT( KEngineWrapperLogFile, "ViewPortRect().iTl.iY: %d", iSysPars->ViewPortRect().iTl.iY ); + LOGFMT( KEngineWrapperLogFile, "ViewPortRect().iBr.iX: %d", iSysPars->ViewPortRect().iBr.iX ); + LOGFMT( KEngineWrapperLogFile, "ViewPortRect().iBr.iY: %d", iSysPars->ViewPortRect().iBr.iY ); + + iSysPars->VisibleImageRect() = filter->Rect(); + + LOGFMT( KEngineWrapperLogFile, "VisibleImageRect().iTl.iX: %d", iSysPars->VisibleImageRect().iTl.iX ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRect().iTl.iY: %d", iSysPars->VisibleImageRect().iTl.iY ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRect().iBr.iX: %d", iSysPars->VisibleImageRect().iBr.iX ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRect().iBr.iY: %d", iSysPars->VisibleImageRect().iBr.iY ); + + // Get the relative scale of the topmost filter + iSysPars->RelScale() = filter->Scale(); + + LOGFMT( KEngineWrapperLogFile, "RelScale(): %f", iSysPars->RelScale() ); + + TInt n = iMainEngine->NumFilters(); + if ( n > 3 ) + { + + TRect rect; + + TSize srcsize = iMainEngine->Filter(n - 3)->Rect().Size(); + TSize tgtsize = iMainEngine->Filter(n - 1)->Rect().Size(); + + // Compute aspect ratio of the source + TInt ars = (TReal)(srcsize.iWidth << KScaleBits) / srcsize.iHeight + 0.5; + + // Compute aspect ratio of the target + TInt art = (TReal)(tgtsize.iWidth << KScaleBits) / tgtsize.iHeight + 0.5; + + // Select scale so that aspect ratio is preserved + if ( ars >= art ) + { + TInt scale = (TReal)(tgtsize.iWidth << KScaleBits) / srcsize.iWidth + 0.5; + rect.iTl.iX = 0; + rect.iBr.iX = tgtsize.iWidth; + TInt h = (srcsize.iHeight * scale) >> KScaleBits; + rect.iTl.iY = (TReal)(tgtsize.iHeight - h) / 2 + 0.5; + rect.iBr.iY = (TReal)(tgtsize.iHeight + h) / 2 + 0.5; + } + else + { + TInt scale = (TReal)(tgtsize.iHeight << KScaleBits) / srcsize.iHeight + 0.5; + rect.iTl.iY = 0; + rect.iBr.iY = tgtsize.iHeight; + TInt w = (srcsize.iWidth * scale) >> KScaleBits; + rect.iTl.iX = (TReal)(tgtsize.iWidth - w) / 2 + 0.5; + rect.iBr.iX = (TReal)(tgtsize.iWidth + w) / 2 + 0.5; + } + + iSysPars->VisibleImageRectPrev() = rect; + + LOGFMT( KEngineWrapperLogFile, "VisibleImageRectPrev().iTl.iX: %d", iSysPars->VisibleImageRectPrev().iTl.iX ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRectPrev().iTl.iY: %d", iSysPars->VisibleImageRectPrev().iTl.iY ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRectPrev().iBr.iX: %d", iSysPars->VisibleImageRectPrev().iBr.iX ); + LOGFMT( KEngineWrapperLogFile, "VisibleImageRectPrev().iBr.iY: %d", iSysPars->VisibleImageRectPrev().iBr.iY ); + } +} + + + +//============================================================================= +EXPORT_C void CEngineWrapper::GetOutputImageSize ( TInt& /*aWidth*/, TInt& /*aHeight*/ ) const +{ + +} + +//============================================================================= +EXPORT_C void CEngineWrapper::SetJpegCommentL (const TDesC8& /*aComment*/) +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::SetJpegComment" ); + + // Check that the model is found + if ( !iMainEngine ) + { + LOG ( KEngineWrapperLogFile, "SetJpegComment: iMainEngine not created!" ); + User::Panic (KEnginePanic, KEnginePanicAllocation); + } +} + +//============================================================================= +void CEngineWrapper::AddRotateFilterL() +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::AddRotateFilterL()" ); + + // Add filter to engine + AddFilterL (KFilterRotate); +} + +//============================================================================= +TRect CEngineWrapper::ComputeViewPort (const TInt /*aStartInd*/) +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::ComputeViewPort()" ); + return TRect(); +} + +//============================================================================= +TRect CEngineWrapper::ComputeVisibleViewPort (const TRect & /*aViewPort*/) +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::ComputeVisibleViewPort()" ); + return TRect(0,0,0,0); +} + +//============================================================================= +TPoint CEngineWrapper::ComputeNewPanValue (const TRect & /*aVvpOld*/) +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::ComputeNewPanValue()" ); + + return TPoint(); +} + +//============================================================================= +void CEngineWrapper::CopyBufferL (TUint32 * aBuffer) +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::CopyBufferL" ); + + iScreenBitmap->LockHeapLC(); + + TSize size = iScreenBitmap->SizeInPixels(); + TDisplayMode dmode = iScreenBitmap->DisplayMode(); + TInt ws = iScreenBitmap->ScanLineLength (size.iWidth, dmode); + + TUint8 * tpos = (TUint8*)( iScreenBitmap->DataAddress() ); + TUint8 * tp; + + for ( TInt y = 0; y < size.iHeight; y++ ) + { + + tp = tpos; + tpos += ws; + + for ( TInt x = 0; x < size.iWidth; x++ ) + { + TUint32 c = *aBuffer++; + *tp++ = c & 0xFF; + c >>= 8; + *tp++ = c & 0xFF; + c >>= 8; + *tp++ = c & 0xFF; + } + } + + CleanupStack::PopAndDestroy(); // iScreenBitmap->LockHeapLC +} + +//============================================================================= +TBool CEngineWrapper::IsSameString ( + const TUint8 * aString1, + const TUint8 * aString2 + ) +{ + TPtrC8 s1( (TUint8*)aString1 ); + TPtrC8 s2( (TUint8*)aString2); + + if ( s1.Compare( s2 ) == 0 ) + { + return ETrue; + } + else + { + return EFalse; + } +} + +//============================================================================= +void CEngineWrapper::UpdateCropRectL () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateCropRect" ); + + TSize screensize = iScreenSize; + TSize imagesize = iBoundingRect.Size(); + TRect croprect = iBoundingRect; + + if (iScale != 1.0) + { + // check rotation + TInt angle = ComputeRotationL(); + TSize cropsize = imagesize; + TReal sw = 0.0; + TReal sh = 0.0; + if ((angle == 90) || (angle == 270)) + { + cropsize.iWidth = imagesize.iWidth; + cropsize.iHeight = (TReal)(screensize.iWidth * imagesize.iWidth) / screensize.iHeight + 0.5; + TReal ari = (TReal)cropsize.iWidth / cropsize.iHeight; + TReal ars = (TReal)screensize.iWidth / screensize.iHeight; + if (ari >= ars) + { + sw = 0.5 * iScale * cropsize.iWidth; + sh = 0.5 * iScale * cropsize.iHeight; + } + else + { + sh = 0.5 * iScale * cropsize.iHeight; + sw = 0.5 * iScale * cropsize.iWidth; + } + } + else + { + TReal ari = (TReal)cropsize.iWidth / cropsize.iHeight; + TReal ars = (TReal)screensize.iWidth / screensize.iHeight; + if (ari >= ars) + { + sw = 0.5 * iScale * cropsize.iWidth; + sh = 0.5 * iScale * (cropsize.iWidth / ars); + } + else + { + sh = 0.5 * iScale * cropsize.iHeight; + sw = 0.5 * iScale * (cropsize.iHeight * ars); + } + } + + // clip pan + if (iPanX - sw < iBoundingRect.iTl.iX) + { + if (iScale == 1.0) + { + iPanX = (iBoundingRect.iTl.iX + iBoundingRect.iBr.iX) / 2; + } + else + { + iPanX = iBoundingRect.iTl.iX + sw; + } + } + else if (iPanX + sw > iBoundingRect.iBr.iX) + { + if (iScale == 1.0) + { + iPanX = (iBoundingRect.iTl.iX + iBoundingRect.iBr.iX) / 2; + } + else + { + iPanX = iBoundingRect.iBr.iX - sw; + } + } + if (iPanY - sh < iBoundingRect.iTl.iY) + { + if (iScale == 1.0) + { + iPanY = (iBoundingRect.iTl.iY + iBoundingRect.iBr.iY) / 2; + } + else + { + iPanY = iBoundingRect.iTl.iY + sh; + } + } + else if (iPanY + sh > iBoundingRect.iBr.iY) + { + if (iScale == 1.0) + { + iPanY = (iBoundingRect.iTl.iY + iBoundingRect.iBr.iY) / 2; + } + else + { + iPanY = iBoundingRect.iBr.iY - sh; + } + } + + // scale rect + croprect = TRect(iPanX - sw, iPanY - sh, iPanX + sw, iPanY + sh); + if (croprect.iTl.iX < iBoundingRect.iTl.iX) + { + croprect.iTl.iX = iBoundingRect.iTl.iX; + } + if (croprect.iTl.iY < iBoundingRect.iTl.iY) + { + croprect.iTl.iY = iBoundingRect.iTl.iY; + } + if (croprect.iBr.iX > iBoundingRect.iBr.iX) + { + croprect.iBr.iX = iBoundingRect.iBr.iX; + } + if (croprect.iBr.iY > iBoundingRect.iBr.iY) + { + croprect.iBr.iY = iBoundingRect.iBr.iY; + } + + } + + if (croprect != iOldCropRect) + { + // Update crop rectangle + iCmd.Format( _L("ulc %d ulr %d lrc %d lrr %d"), croprect.iTl.iX, croprect.iTl.iY, + croprect.iBr.iX, croprect.iBr.iY); + LOGDES (KEngineWrapperLogFile, iCmd); + iMainEngine->FunctionL ( 0, iCmd ); + iRenderScaleBuffer = ETrue; + iOldCropRect = croprect; + } +} + + +//============================================================================= +TPtrC8 CEngineWrapper::UpdateExifThumbnailL () +{ + LOG ( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifThumbnailL" ); + + // Create Jpeg encoder for memory buffer + MJpegSave * encoder = JpegSaveFactory::CreateJpegSaveLC (0,0); + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::0" ); + + // Initialize saving + encoder->StartSaveL (iThumbSize, TPtr8(0,0), 65536, KThumbnailJpegQuality); + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::1" ); + + // Save in blocks + TBitmapHandle bmBlock; + bmBlock.iData = new (ELeave) TUint32 [16 * 8]; + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::2" ); + + for (TInt y = 0; y < iThumbSize.iHeight; y += 8) + { + for (TInt x = 0; x < iThumbSize.iWidth; x += 16) + { + + TInt lastY = y + 8; + if (lastY >= iThumbSize.iHeight) + { + lastY = iThumbSize.iHeight - 1; + } + TInt lastX = x + 16; + if (lastX >= iThumbSize.iWidth) + { + lastX = iThumbSize.iWidth - 1; + } + + TUint32 * pDOS = (TUint32 *)bmBlock.iData; + TUint32 * pSOS = iThumb + y * iThumbSize.iWidth + x; + + for (TInt yy = y; yy < lastY; yy++ ) + { + + TUint32 * pD = pDOS; + pDOS += 16; + + TUint32 * pS = pSOS; + pSOS += iThumbSize.iWidth; + + for (TInt xx = x; xx < lastX; xx++ ) + { + *pD++ = *pS++; + } + } + + + encoder->SaveBlock (bmBlock); + } + } + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::3" ); + + delete (TUint32 *)bmBlock.iData; + bmBlock.iData = NULL; + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::4" ); + + TPtrC8 thumbNail = encoder->Finalize(); + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::5" ); + + TPtrC8 exif = iExifParser->SaveL (thumbNail); + + LOG ( KEngineWrapperLogFile, "UpdateExifThumbnailL::6" ); + + CleanupStack::PopAndDestroy (); // encoder + + return exif; +} + +//============================================================================= +void CEngineWrapper::UpdateExifTagsL() +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL" ); + + // DateTime + LOG ( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- DateTime" ); + TBuf8<64> dateTimeBuf; + GetCurrentDateTime ( dateTimeBuf ); + iExifParser->DeleteTag ( CExifParser::EIfd0, 0x0132); + iExifParser->AddTagL ( CExifParser::EIfd0, 0x0132, dateTimeBuf.PtrZ()); + + TInt n = iMainEngine->NumFilters(); + MImageFilter * filter = iMainEngine->Filter(n - 2); + + TInt targetWidth = (TReal)(filter->ViewPortSize().iWidth * iSysPars->Scale()) + 0.5; + TInt targetHeight = (TReal)(filter->ViewPortSize().iHeight * iSysPars->Scale()) + 0.5; + + // ImageWidth - not needed + iExifParser->DeleteTag ( CExifParser::EIfd0, 0x0100); + + // ImageHeight - not needed + iExifParser->DeleteTag ( CExifParser::EIfd0, 0x0101); + + // Orientation + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x0112) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- Orientation" ); + iExifParser->AddTagL ( CExifParser::EIfd0, 0x0112, (TUint16)1); + } + + // EXIF version + TUint8 exifVersion [] = "0220"; + if ( !iExifParser->TagExist (CExifParser::ESubIfd, 0x9000) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- ExifVersion" ); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0x9000, TPtrC8 (exifVersion)); + } + + // FlashPixVersion + TUint8 flashPixVersion [] = "0100"; + if ( !iExifParser->TagExist (CExifParser::ESubIfd, 0xA000) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- FlashPixVersion" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA000); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0xA000, TPtrC8 (flashPixVersion)); + } + + // ComponentsConfiguration + TUint8 exifComponentsConfiguration [4] = {1,2,3,0}; + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- ComponentsConfiguration" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0x9101); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0x9101, TPtrC8(exifComponentsConfiguration, 4)); + + // ColorSpace + LOG ( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- ColorSpace" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA001); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0xA001, (TUint16)1); + + // Interoperability index + iExifParser->DeleteTag ( CExifParser::EInteroperability, 0x0001); + + // PixelXResolution + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- PlaneXResolution" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA002); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0xA002,(TUint32)targetWidth); + + // PixelYResolution + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- PlaneYResolution" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA003); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0xA003, (TUint32)targetHeight); + + // FocalPlaneResolutionUnit + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA210); + + // FocalPlaneXResolution + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA20E); + + // FocalPlaneYResolution + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0xA20F); + + // User Comment + TBuf8<256> comment; + TUint8 KCharCode[8] = {0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00}; // ASCII char code + comment.Append(TPtrC8(KCharCode, 8)); + comment.AppendFormat(KImageEditorExifComment, my_version_major, my_version_minor, my_version_build); + + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- UserComment" ); + iExifParser->DeleteTag ( CExifParser::ESubIfd, 0x9286); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0x9286, comment); + + TBuf8<128> make; + TBuf8<128> model; + ImageEditorUtils::GetMakeAndModelL ( make, model ); + + // Make + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x010F) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- Make updated" ); + iExifParser->AddTagL ( CExifParser::EIfd0, 0x010F, make.PtrZ()); + } + + // Model + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x0110) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- Model updated" ); + iExifParser->AddTagL ( CExifParser::EIfd0, 0x0110, model.PtrZ()); + } + + // DateTimeOriginal + if ( !iExifParser->TagExist (CExifParser::ESubIfd, 0x9003) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- DateTimeOriginal updated" ); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0x9003, dateTimeBuf.PtrZ()); + } + + // DateTimeDigitized + if ( !iExifParser->TagExist (CExifParser::ESubIfd, 0x9004) ) + { + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- DateTimeDigitized updated" ); + iExifParser->AddTagL ( CExifParser::ESubIfd, 0x9004, dateTimeBuf.PtrZ()); + } + + // XResolution + LOG ( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- XResolution" ); + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x011A) ) + { + iExifParser->AddTagL ( CExifParser::EIfd0, 0x011A, (TUint32)300, (TUint32)1); + } + + // YResolution + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- YResolution" ); + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x011B) ) + { + iExifParser->AddTagL ( CExifParser::EIfd0, 0x011B, (TUint32)300, (TUint32)1); + } + + // ResolutionUnit + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- ResolutionUnit" ); + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x0128) ) + { + iExifParser->AddTagL ( CExifParser::EIfd0, 0x0128, (TUint16)2 ); + } + + // YCbCrPositioning + LOG( KEngineWrapperLogFile, "CEngineWrapper::UpdateExifTagsL() -- YCbCrPositioning" ); + if ( !iExifParser->TagExist (CExifParser::EIfd0, 0x0213) ) + { + iExifParser->AddTagL ( CExifParser::EIfd0, 0x0213, (TUint16)1 ); + } + + +} + +//============================================================================= +void CEngineWrapper::GetCurrentDateTime (TDes8 & aDateTimeBuf) const +{ + // Time in microseconds since 0 AD nominal Gregorian + TTime time; + // year-month-day-hour-minute-second-microsecond + TDateTime dateTime; + + // Get current local time + time.HomeTime(); + + // Convert to fields + dateTime = time.DateTime(); + + // Create descriptors for the components. + // This is needed because the leading zeros + // cannotbe suppressed. + TBuf8<2> month; + TBuf8<2> day; + TBuf8<2> hour; + TBuf8<2> minute; + TBuf8<2> second; + + if( TInt(dateTime.Month()) < 9 ) + { + month.AppendNum( 0 ); + } + month.AppendNum( TInt(dateTime.Month()+1) ); + + if( dateTime.Day() < 9 ) + { + day.AppendNum( 0 ); + } + day.AppendNum( dateTime.Day()+1 ); + + if( dateTime.Hour() < 10 ) + { + hour.AppendNum( 0 ); + } + hour.AppendNum( dateTime.Hour() ); + + if( dateTime.Minute() < 10 ) + { + minute.AppendNum( 0 ); + } + minute.AppendNum( dateTime.Minute() ); + + if( dateTime.Second() < 10 ) + { + second.AppendNum( 0 ); + } + second.AppendNum( dateTime.Second() ); + + // Format the time to the format + // "YYYY:MM:DD HH:MM:SS" + _LIT8(KFormatTxt,"%d:%S:%S %S:%S:%S"); + aDateTimeBuf.Format( + KFormatTxt, + dateTime.Year(), + &month, + &day, + &hour, + &minute, + &second + ); +} + +//============================================================================= +EXPORT_C void CEngineWrapper::SetBitmap (CFbsBitmap * aBitmap) +{ + iScreenBitmap = aBitmap; +} + + +//============================================================================= +EXPORT_C void CEngineWrapper::CreateExifThumbNailL () +{ + LOG( KEngineWrapperLogFile, "CEngineWrapper::CreateExifThumbNailL" ); + +#ifdef EXIF_SUPPORT + + // Delete old thumbnail + delete[] iThumb; + iThumb = NULL; + + // Re-load the zoomed image if needed + if ( iRenderScaleBuffer ) + { + iMainEngine->FunctionL ( 0, _L("loadimage")); + iRenderScaleBuffer = EFalse; + } + for ( TInt i = 0; i < iMainEngine->NumFilters(); ++i) + { + iMainEngine->FunctionL (i, _L("nop")); + } + + TReal scale = 1.0; + TSize imagesize = iMainEngine->Filter(iMainEngine->NumFilters() - 3)->Rect().Size(); + if (imagesize.iWidth > imagesize.iHeight) + { + scale = (TReal)imagesize.iWidth / KThumbnailMaxDimension; + } + else + { + scale = (TReal)imagesize.iHeight / KThumbnailMaxDimension; + } + + // Crete new thumbnail + iThumbSize.iWidth = (TInt)((imagesize.iWidth / scale) + 0.5); + iThumbSize.iHeight = (TInt)((imagesize.iHeight / scale) + 0.5); + + // Just ensure that dimension are never 0 + if (iThumbSize.iWidth == 0) + { + iThumbSize.iWidth = 1; + } + if (iThumbSize.iHeight == 0) + { + iThumbSize.iHeight = 1; + } + + LOGFMT( KEngineWrapperLogFile, "iThumbSize.iWidth = %d", iThumbSize.iWidth); + LOGFMT( KEngineWrapperLogFile, "iThumbSize.iHeight = %d", iThumbSize.iHeight); + + iThumb = new (ELeave) TUint32 [iThumbSize.iWidth * iThumbSize.iHeight]; + + // Set thumbnail size to buffer filter + iCmd.Format( _L("width %d height %d"), iThumbSize.iWidth, iThumbSize.iHeight); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 1, iCmd ); + iMainEngine->FunctionL ( iMainEngine->NumFilters() - 2, _L("nop")); + + // Copy data to the new thumbnail + TUint32 * pBuffer = (TUint32 *)iMainEngine->FunctionL (iMainEngine->NumFilters() - 1, _L("getbitmap")); + Mem::Copy (iThumb, pBuffer, iThumbSize.iWidth * iThumbSize.iHeight * sizeof(TUint32)); + + LOG( KEngineWrapperLogFile, "EXIF thumbnail created!" ); + +#endif +} + + +//============================================================================= +TInt CEngineWrapper::ComputeRotationL () +{ + + TInt angle = 0; + TInt ind = 0; + while ( ind < iMainEngine->NumFilters() ) + { + MImageFilter * filter = iMainEngine->Filter(ind); + char * cmpstr = "rotate"; + TPtrC8 type ( (const TUint8 *)filter->Type() ); + TPtrC8 typecmp ((const TUint8 *)cmpstr); + if ( type == typecmp ) + { + angle += filter->CmdL(_L("getangle")); + } + ind++; + } + angle %= 360; + return angle; +} + + +//============================================================================= +void CEngineWrapper::ComputeBoundingRectL() +{ + MImageFilter * pFilter = iMainEngine->Filter(iMainEngine->NumFilters() - 3); + TReal relscale = pFilter->Scale(); + TRect rect = pFilter->Rect(); + TSize size = iMainEngine->Filter(0)->ViewPortSize(); + rect.iTl.iX = (TInt)((rect.iTl.iX / relscale) + 0.5); + rect.iTl.iY = (TInt)((rect.iTl.iY / relscale) + 0.5); + rect.iBr.iX = (TInt)((rect.iBr.iX / relscale) + 0.5); + rect.iBr.iY = (TInt)((rect.iBr.iY / relscale) + 0.5); + TInt angle = ComputeRotationL(); + + if (angle == 90 || angle == 270) + { + iBoundingRect.iTl.iX = rect.iTl.iY; + iBoundingRect.iTl.iY = rect.iTl.iX; + iBoundingRect.iBr.iX = rect.iBr.iY; + iBoundingRect.iBr.iY = rect.iBr.iX; + } + else + { + iBoundingRect = rect; + } + + size = iBoundingRect.Size(); + iPanX = (iBoundingRect.iTl.iX + iBoundingRect.iBr.iX) / 2; + iPanY = (iBoundingRect.iTl.iY + iBoundingRect.iBr.iY) / 2; +} + + +// End of File