--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/photosgallery/collectionframework/thumbnailcreator/src/glxtnimageutility.cpp Thu Dec 17 08:45:44 2009 +0200
@@ -0,0 +1,737 @@
+/*
+* Copyright (c) 2008-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: Utility for creating bitmaps from video files
+*
+*/
+
+
+
+
+/**
+ * @internal reviewed 31/07/2007 by Simon Brooks
+ */
+
+#include "glxtnimageutility.h"
+
+#include <MIHLScaler.h> // MIHLScaler
+#include <fbs.h>
+#include <glxtracer.h>
+#include <glxpanic.h>
+#include <glxthumbnail.h>
+#include <imageconversion.h>
+
+#include "glxtnimagedecoderfactory.h"
+
+#include <ExifRead.h>
+#include <IclExtJpegApi.h>
+
+// All EXIF data is within the first KGlxMaxExifSize bytes of the file
+const TInt KGlxMaxExifSize = 0x10000;
+// -----------------------------------------------------------------------------
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CGlxtnImageUtility::CGlxtnImageUtility(RFs& aFs) : iFs(aFs)
+ {
+ TRACER("CGlxtnImageUtility::CGlxtnImageUtility()");
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CGlxtnImageUtility::~CGlxtnImageUtility()
+ {
+ TRACER("CGlxtnImageUtility::~CGlxtnImageUtility()");
+ delete iDecoder;
+ delete iScaler;
+ delete iBitGc;
+ }
+
+// -----------------------------------------------------------------------------
+// Cancel
+// -----------------------------------------------------------------------------
+//
+void CGlxtnImageUtility::Cancel()
+ {
+ TRACER("void CGlxtnImageUtility::Cancel()");
+ if ( iDecoder )
+ {
+ iDecoder->Cancel();
+ }
+ if ( iScaler && iScaler->IsBusy())
+ {
+ iScaler->CancelProcess();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// AdjustSize
+// -----------------------------------------------------------------------------
+//
+void CGlxtnImageUtility::AdjustSize(TSize& aTargetSize, const TSize& aSourceSize)
+ {
+ TRACER("void CGlxtnImageUtility::AdjustSize()");
+ if( (aSourceSize.iWidth <= aTargetSize.iWidth ) && (aSourceSize.iHeight <= aTargetSize.iHeight ))
+ {
+ aTargetSize.iWidth = aSourceSize.iWidth;
+ aTargetSize.iHeight = aSourceSize.iHeight;
+ }
+ else if ( aTargetSize.iHeight * aSourceSize.iWidth
+ < aTargetSize.iWidth * aSourceSize.iHeight )
+ {
+ // Source has taller aspect than target so reduce target width
+ aTargetSize.iWidth = ( ( aTargetSize.iHeight * aSourceSize.iWidth )
+ / ( aSourceSize.iHeight ) );
+ }
+ else
+ {
+ // Source has wider aspect than target so reduce target height
+ aTargetSize.iHeight = (aTargetSize.iWidth * aSourceSize.iHeight)
+ / aSourceSize.iWidth;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// DecodeImageL
+// -----------------------------------------------------------------------------
+//
+CFbsBitmap* CGlxtnImageUtility::DecodeImageL(TRequestStatus& aStatus,
+ const TDesC& aFileName, RArray<TSize>& aTargetSizes, TDisplayMode aMode)
+ {
+ TRACER("CFbsBitmap* CGlxtnImageUtility::DecodeImageL()");
+ delete iDecoder;
+ iDecoder = NULL;
+ //Get Exif Metadata and the orientation tag from the file first
+ TUint16 orientation = GetOrientationL(aFileName);
+ TInt isExtDecoderUsed = 0;
+ ///iDecoder = GlxtnImageDecoderFactory::NewL( iFs, aFileName );
+ iDecoder = GlxtnImageDecoderFactory::NewL( iFs, aFileName, isExtDecoderUsed );
+ iOriginalSize = iDecoder->FrameInfo().iOverallSizeInPixels;
+ //Get the orientation and set rotation on the decoder
+ //as well as update the original size
+ if (isExtDecoderUsed)
+ {
+ TInt rotAngle = 0;
+ TBool flip = EFalse;
+ GetRotationParameters(orientation,rotAngle,flip);
+ CExtJpegDecoder* extDecoder = (CExtJpegDecoder*)iDecoder;
+ extDecoder->SetRotationL(rotAngle);
+ if(flip)
+ {
+ extDecoder->SetMirroringL();
+ }
+ }
+ if ( 0 == iOriginalSize.iWidth || 0 == iOriginalSize.iHeight )
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ TInt count = aTargetSizes.Count();
+ TSize testSize;
+ TSize targetSize;
+ for ( TInt i = 0 ; i < count ; i++ )
+ {
+ testSize = aTargetSizes[i];
+ AdjustSize(testSize, iOriginalSize);
+ if( ( testSize.iWidth > targetSize.iWidth ) || ( testSize.iHeight > targetSize.iHeight ) )
+ {
+ targetSize = testSize;
+ }
+ }
+
+ // Find max scaling factor which won't make image smaller than target size
+ TInt shift = 3;
+ while ( shift
+ && ((iOriginalSize.iWidth >> shift) < targetSize.iWidth
+ || (iOriginalSize.iHeight >> shift) < targetSize.iHeight ) )
+ {
+ shift--;
+ }
+ TInt roundUp = (1 << shift) - 1;
+ TSize loadSize((iOriginalSize.iWidth + roundUp) >> shift,
+ (iOriginalSize.iHeight + roundUp) >> shift);
+
+ CFbsBitmap* image = new (ELeave) CFbsBitmap;
+ CleanupStack::PushL(image);
+ User::LeaveIfError(image->Create(loadSize, aMode));
+
+ iDecoder->Convert(&aStatus, *image);
+
+ CleanupStack::Pop(image);
+ return image;
+ }
+
+// -----------------------------------------------------------------------------
+// FreeDecoder
+// -----------------------------------------------------------------------------
+//
+void CGlxtnImageUtility::FreeDecoder()
+ {
+ TRACER("void CGlxtnImageUtility::FreeDecoder()");
+ delete iDecoder;
+ iDecoder = NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// OriginalSize
+// -----------------------------------------------------------------------------
+//
+const TSize& CGlxtnImageUtility::OriginalSize() const
+ {
+ TRACER("TSize& CGlxtnImageUtility::OriginalSize()");
+ return iOriginalSize;
+ }
+
+//---------------------------------------------------------------------------
+/**
+ K-Nearest neighbour scaling for EColor64K.
+ Code originally inherited from t_display.cpp by Toni Hemminki.
+ Added windowing and further optimized by Jarmo Nikula 2006-2007.
+
+ @param aSrc Source buffer pointer
+ @param aSrcStride Source buffer stride in bytes
+ @param aSrcCols Source columns
+ @param aSrcRows Source rows
+ @param aX Source window top-left X-coordinate
+ @param aY Source window top-left Y-coordinate
+ @param aW Source window width
+ @param aH Source window height
+ @param aDst Destination buffer pointer
+ @param aDstStride Destination buffer stride in bytes
+ @param aDstCols Destination columns, must be even
+ @param aDstRows Destination rows
+*/
+// OPTION's for MMP file:
+// Interleave assembly code with C, output can be found on txt-files on some BUILD directory:
+// OPTION ARMCC --asm --interleave
+// Modify optimization for ARM insturcion set and for maximum speed
+// OPTION_REPLACE ARMCC --arm -Otime
+/* aSource->LockHeap();
+ TUint16* sourceAddress = (TUint16*)aSource->DataAddress();
+ aSource->UnlockHeap();
+ aTarget->LockHeap();
+ TUint16* targetAddress = (TUint16*)aTarget->DataAddress();
+ aTarget->UnlockHeap();
+ ScaleColor64K(sourceAddress, aSource->DataStride(),
+ sourceSize.iWidth, sourceSize.iHeight, 0, 0, sourceSize.iWidth, sourceSize.iHeight,
+ targetAddress, aTarget->DataStride(),
+ targetSize.iWidth, targetSize.iHeight);
+*/
+
+void CGlxtnImageUtility::FilterImageL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, CFbsBitmap* aTarget)
+ {
+ TRACER("void CGlxtnImageUtility::FilterImageL()");
+ TSize sourceSize(aSource->SizeInPixels());
+ TSize targetSize(aTarget->SizeInPixels());
+
+ //Fix for EKLG-7PTET2:mpxcollectionserver.exe crash in thumbnailcreator because of div by zero event
+ if (targetSize.iWidth <= 0)
+ {
+ User::Leave(KErrDivideByZero);
+ }
+
+ TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100;
+
+ // no need to filter if close enough or smaller
+ if ( scalePercent >= 2 && ( aTarget->DisplayMode() == EColor64K ) )
+ {
+ FilterL(aSource, aFilteredSource, scalePercent);
+ }
+
+ *aStatus = KRequestPending;
+ User::RequestComplete(aStatus, KErrNone);
+ }
+
+// -----------------------------------------------------------------------------
+// ScaleImageL
+// -----------------------------------------------------------------------------
+//
+void CGlxtnImageUtility::ScaleImageL(TRequestStatus& aStatus, CFbsBitmap& aSrcBitmap,
+ const TRect& aSrcRect, CFbsBitmap& aDstBitmap,
+ const TRect& aDstRect)
+ {
+ TRACER("void CGlxtnImageUtility::ScaleImageL(IHL)");
+ if (!iScaler)
+ {
+ iScaler = IHLScaler::CreateL();
+ }
+ User::LeaveIfError(iScaler->Scale(aStatus, aSrcBitmap, aSrcRect, aDstBitmap, aDstRect));
+ }
+
+void CGlxtnImageUtility::ScaleImage64kL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap* aFilteredSource, CFbsBitmap* aTarget)
+ {
+ TRACER("void CGlxtnImageUtility::ScaleImage64kL()");
+ TSize sourceSize(aSource->SizeInPixels());
+ TSize targetSize(aTarget->SizeInPixels());
+ TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100;
+ TRect targetRect(targetSize);
+ TRect sourceRect(sourceSize);
+
+ CFbsBitmap* sourceImage = aFilteredSource;
+ if ( !aFilteredSource )
+ {
+ sourceImage = aSource;
+ }
+ if ( scalePercent < 2 )
+ {
+ if ( scalePercent > 0 )
+ {
+ sourceRect = targetRect;
+ }
+ sourceImage = aSource;
+ }
+ sourceImage->LockHeap();
+ TUint16* sourceAddress = (TUint16*)sourceImage->DataAddress();
+ sourceImage->UnlockHeap();
+ aTarget->LockHeap();
+ TUint16* targetAddress = (TUint16*)aTarget->DataAddress();
+ aTarget->UnlockHeap();
+ ScaleColor64K(sourceAddress, sourceImage->DataStride(),
+ sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight, 0, 0, sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight,
+ targetAddress, aTarget->DataStride(),
+ targetSize.iWidth, targetSize.iHeight);
+
+/* if ( !iBitGc )
+ {
+ iBitGc = CFbsBitGc::NewL();
+ }
+ CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aTarget);
+ CleanupStack::PushL(bitmapDevice);
+ iBitGc->Activate(bitmapDevice);
+ iBitGc->DrawBitmap(targetRect, sourceImage, sourceRect);
+ CleanupStack::PopAndDestroy(bitmapDevice);
+*/
+ *aStatus = KRequestPending;
+ User::RequestComplete(aStatus, KErrNone);
+ }
+
+void CGlxtnImageUtility::ScaleColor64K( TUint16* aSrc, TInt aSrcStride, TInt /*aSrcCols*/, TInt /*aSrcRows*/,
+ TInt aX, TInt aY, TInt aW, TInt aH,
+ TUint16* aDst, TInt aDstStride, TInt aDstCols, TInt aDstRows )
+ {
+ TRACER("void CGlxtnImageUtility::ScaleColor64K()");
+ const TUint KPrecision = 16;
+ TUint hInc = ( aW<< KPrecision ) / aDstCols;
+ TUint vInc = ( aH << KPrecision ) / aDstRows;
+ TUint v = 0;
+ for ( TUint row = aDstRows; row > 0; --row )
+ {
+ TInt h = hInc * (aDstCols - 1);
+ TUint linestart = aSrcStride * ( aY + ( v >> KPrecision ) ) / sizeof(TUint16) + aX;
+ TUint16* src = &aSrc[ linestart ];
+ TUint32* dst = (TUint32*)aDst + aDstCols / 2;
+ TUint32 pxl2x;
+ // This loop generates 11 assembly instructions per round
+ // when using "--arm --Otime" options. Since two pixels are handled per round,
+ // it means 5.5 instructions per pixel on average.
+ do {
+ pxl2x = src[ h >> KPrecision ]<<16;
+ h -= hInc;
+ pxl2x |= src[ h >> KPrecision ];
+ *--dst = pxl2x;
+ // Compiler eliminates CMP instruction when substraction
+ // is done inside the while () statement.
+ } while ( ( h -= hInc ) >= 0 );
+ v += vInc;
+ aDst += aDstStride / sizeof(TUint16);
+ }
+ }
+
+void CGlxtnImageUtility::FilterL( CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, TInt aFilterPercent )
+ {
+ TRACER("void CGlxtnImageUtility::FilterL()");
+ if ( !aFilteredSource )
+ {
+ TSize imageSize = aSource->SizeInPixels();
+ aFilteredSource = new (ELeave) CFbsBitmap;
+ aFilteredSource->Create(imageSize, aSource->DisplayMode());
+
+ CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aFilteredSource);
+ if ( !iBitGc )
+ {
+ iBitGc = CFbsBitGc::NewL();
+ }
+ iBitGc->Activate(bitmapDevice);
+ iBitGc->BitBlt(TPoint(), aSource, imageSize);
+ delete bitmapDevice;
+ }
+
+ TSize imageSize = aFilteredSource->SizeInPixels();
+ aFilteredSource->LockHeap();
+ TUint16* sourceAddress = (TUint16*)aFilteredSource->DataAddress();
+ aFilteredSource->UnlockHeap();
+ const TInt KGlxScalingNeeds4Filtering = 80; // if scaling more than 1.8 need to filter by 4
+ const TInt KGlxScalingNeeds8Filtering = 260; // if scaling more than 3.6 need to filter by 8
+ if ( KGlxScalingNeeds8Filtering < aFilterPercent )
+ {
+ FIRFiltering8(
+ sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16),
+ imageSize.iWidth, imageSize.iHeight );
+ }
+ else if ( KGlxScalingNeeds4Filtering < aFilterPercent )
+ {
+ FIRFiltering4(
+ sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16),
+ imageSize.iWidth, imageSize.iHeight );
+ }
+ else
+ {
+ FIRFiltering(
+ sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16),
+ imageSize.iWidth, imageSize.iHeight );
+ }
+ }
+
+#define rmask565 0xf800
+#define gmask565 0x07e0
+#define bmask565 0x001f
+#define rbmask565 (rmask565|bmask565)
+#define rm565( rgb ) ((rgb) & rmask565)
+#define gm565( rgb ) ((rgb) & gmask565)
+#define bm565( rgb ) ((rgb) & bmask565)
+#define rbm565( rgb ) ((rgb) & rbmask565)
+#define r565( rgb ) ((rgb)>>11)
+#define g565( rgb ) (gm565(rgb)>>5)
+#define b565( rgb ) (bm565(rgb))
+#define rgb565( r, g, b ) (((r)<<11)|((g)<<5)|(b))
+
+#define mask32gbr655 0x07e0f81f
+
+// Keep below three defs in sync with each other!
+#define KFIRLen 2
+#define KFIRCen (KFIRLen / 2)
+#define incFIRIndex( i ) i = (i + 1) & (KFIRLen - 1)
+// Keep above three defs in sync with each other!
+
+void CGlxtnImageUtility::FIRFiltering(
+ TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows )
+ {
+ TRACER("void CGlxtnImageUtility::FIRFiltering( )");
+ TUint firFifo[ KFIRLen ];
+ TUint i; // index for fifo in&out
+ TUint16 *p;
+ TUint32 px;
+ TInt row, col;
+ TUint FIRsum;
+ // Horizontal scan.
+ p = aDst;
+ for ( row = aDstRows - 1; row >= 0; row-- )
+ {
+ // read for cache
+ //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ];
+ // Fill in the FIR first.
+ // TODO: Fill in with extrapolated values at edges!
+ FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding
+ i = 0;
+ TUint32 mask1 = mask32gbr655;
+ for ( col = 0; col < KFIRLen; col++ )
+ {
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex( i );
+ }
+ TUint32 ave;
+ for ( ; col < aDstCols; col++ )
+ {
+ ave = ( FIRsum / KFIRLen ) & mask1;
+ p[ col - KFIRCen ] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex( i );
+ }
+ p += aDstStridep;
+ }
+ // Vertical scan.
+ for ( col = aDstCols - 1; col >= 0; col-- )
+ {
+ // Fill in the FIR first.
+ FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding
+ TUint32 mask1 = mask32gbr655;
+ i = 0;
+ p = aDst + col;
+ for ( row = 0; row < KFIRLen; row++ )
+ {
+ px = *p;
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex( i );
+ p += aDstStridep;
+ }
+ TUint32 ave;
+ p -= aDstStridep * KFIRCen;
+ for ( ; row < aDstRows; row++ )
+ {
+ ave = ( FIRsum / KFIRLen ) & mask1;
+ p[0] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ aDstStridep * KFIRCen ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex( i );
+ p += aDstStridep;
+ }
+ }
+ }
+//
+// Keep below three defs in sync with each other!
+#define KFIRLen4 4
+#define KFIRCen4 (KFIRLen4 / 2)
+#define incFIRIndex4( i ) i = (i + 1) & (KFIRLen4 - 1)
+// Keep above three defs in sync with each other!
+
+void CGlxtnImageUtility::FIRFiltering4(
+ TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows )
+ {
+ TRACER("void CGlxtnImageUtility::FIRFiltering4()");
+ TUint firFifo[ KFIRLen4 ];
+ TUint i; // index for fifo in&out
+ TUint16 *p;
+ TUint32 px;
+ TInt row, col;
+ TUint FIRsum;
+ // Horizontal scan.
+ p = aDst;
+ for ( row = aDstRows - 1; row >= 0; row-- )
+ {
+ // read for cache
+ //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ];
+ // Fill in the FIR first.
+ // TODO: Fill in with extrapolated values at edges!
+ FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding
+ i = 0;
+ TUint32 mask1 = mask32gbr655;
+ for ( col = 0; col < KFIRLen4; col++ )
+ {
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex4( i );
+ }
+ TUint32 ave;
+ for ( ; col < aDstCols; col++ )
+ {
+ ave = ( FIRsum / KFIRLen4 ) & mask1;
+ p[ col - KFIRCen4 ] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex4( i );
+ }
+ p += aDstStridep;
+ }
+ // Vertical scan.
+ for ( col = aDstCols - 1; col >= 0; col-- )
+ {
+ // Fill in the FIR first.
+ FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding
+ TUint32 mask1 = mask32gbr655;
+ i = 0;
+ p = aDst + col;
+ for ( row = 0; row < KFIRLen4; row++ )
+ {
+ px = *p;
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex4( i );
+ p += aDstStridep;
+ }
+ TUint32 ave;
+ p -= aDstStridep * KFIRCen4;
+ for ( ; row < aDstRows; row++ )
+ {
+ ave = ( FIRsum / KFIRLen4 ) & mask1;
+ p[0] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ aDstStridep * KFIRCen4 ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex4( i );
+ p += aDstStridep;
+ }
+ }
+ }
+
+// Keep below three defs in sync with each other!
+#define KFIRLen8 8
+#define KFIRCen8 (KFIRLen8 / 2)
+#define incFIRIndex8( i ) i = (i + 1) & (KFIRLen8 - 1)
+// Keep above three defs in sync with each other!
+
+void CGlxtnImageUtility::FIRFiltering8(
+ TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows )
+ {
+ TRACER("void CGlxtnImageUtility::FIRFiltering8()");
+ TUint firFifo[ KFIRLen8 ];
+ TUint i; // index for fifo in&out
+ TUint16 *p;
+ TUint32 px;
+ TInt row, col;
+ TUint FIRsum;
+ // Horizontal scan.
+ p = aDst;
+ for ( row = aDstRows - 1; row >= 0; row-- )
+ {
+ // read for cache
+ //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ];
+ // Fill in the FIR first.
+ // TODO: Fill in with extrapolated values at edges!
+ FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding
+ i = 0;
+ TUint32 mask1 = mask32gbr655;
+ for ( col = 0; col < KFIRLen8; col++ )
+ {
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex8( i );
+ }
+ TUint32 ave;
+ for ( ; col < aDstCols; col++ )
+ {
+ ave = ( FIRsum / KFIRLen8 ) & mask1;
+ p[ col - KFIRCen8 ] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ col ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex8( i );
+ }
+ p += aDstStridep;
+ }
+ // Vertical scan.
+ for ( col = aDstCols - 1; col >= 0; col-- )
+ {
+ // Fill in the FIR first.
+ FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding
+ TUint32 mask1 = mask32gbr655;
+ i = 0;
+ p = aDst + col;
+ for ( row = 0; row < KFIRLen8; row++ )
+ {
+ px = *p;
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex8( i );
+ p += aDstStridep;
+ }
+ TUint32 ave;
+ p -= aDstStridep * KFIRCen8;
+ for ( ; row < aDstRows; row++ )
+ {
+ ave = ( FIRsum / KFIRLen8 ) & mask1;
+ p[0] = TUint16( ave | (ave>>16) );
+ FIRsum -= firFifo[ i ];
+ px = p[ aDstStridep * KFIRCen8 ];
+ px = ((px<<16) | px) & mask1;
+ firFifo[ i ] = px;
+ FIRsum += px;
+ incFIRIndex8( i );
+ p += aDstStridep;
+ }
+ }
+ }
+// -----------------------------------------------------------------------------
+// GetOrientation
+// -----------------------------------------------------------------------------
+//
+TUint16 CGlxtnImageUtility::GetOrientationL(const TDesC& aFileName)
+ {
+ //Get Exif Metadata and the orientation tag from the file first
+ RFile file;
+ CleanupClosePushL(file);
+ User::LeaveIfError(file.Open(iFs,
+ aFileName, EFileRead));
+ TInt size;
+ User::LeaveIfError(file.Size(size));
+ if ( KGlxMaxExifSize < size )
+ {
+ size = KGlxMaxExifSize;
+ }
+ TUint16 orientation = 9;
+ HBufC8* exifData = HBufC8::NewLC(size);
+ TPtr8 ptr(exifData->Des());
+ User::LeaveIfError(file.Read(ptr));
+ CExifRead* exifReader = NULL;
+ TRAPD(exifErr,exifReader = CExifRead::NewL(*exifData, CExifRead::ENoJpeg));
+ if(exifErr == KErrNone)
+ {
+ CleanupStack::PushL(exifReader);
+
+ TInt readErr = exifReader->GetOrientation(orientation);
+ if(readErr != KErrNone)
+ {
+ orientation = 9;
+ }
+ CleanupStack::PopAndDestroy(exifReader);
+ }
+ CleanupStack::PopAndDestroy(exifData);
+ //Close and pop file Session
+ CleanupStack::PopAndDestroy(&file);
+ return orientation;
+ }
+
+// -----------------------------------------------------------------------------
+// GetRotationParameters
+// -----------------------------------------------------------------------------
+//
+void CGlxtnImageUtility::GetRotationParameters(TUint16 aOrientation,
+ TInt& aRotAngle, TBool& aFlipStatus)
+ {
+ //Get the orientation and set rotation on the decoder
+ //as well as update the original size
+ aRotAngle = 0;
+ aFlipStatus = EFalse;
+ TInt isOrientationOdd = aOrientation%2;
+ if(aOrientation>8)
+ {
+ return;
+ }
+ if(aOrientation >= 3 && aOrientation < 5)
+ {
+ aRotAngle = 180;
+ }
+ else if(aOrientation >= 5 && aOrientation < 7)
+ {
+ aRotAngle = 90;
+
+ }
+ else if(aOrientation >= 7 && aOrientation <= 8)
+ {
+ aRotAngle = 270;
+ }
+ if(aOrientation>4 )
+ {
+ iOriginalSize.SetSize(iOriginalSize.iHeight,iOriginalSize.iWidth); //Switch Height and width
+ if(isOrientationOdd )
+ {
+ aFlipStatus = ETrue;
+ }
+ }
+ }