|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Utility for creating bitmaps from video files |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 /** |
|
22 * @internal reviewed 31/07/2007 by Simon Brooks |
|
23 */ |
|
24 |
|
25 #include "glxtnimageutility.h" |
|
26 |
|
27 #include <MIHLScaler.h> // MIHLScaler |
|
28 #include <fbs.h> |
|
29 #include <glxtracer.h> |
|
30 #include <glxpanic.h> |
|
31 #include <glxthumbnail.h> |
|
32 #include <imageconversion.h> |
|
33 |
|
34 #include "glxtnimagedecoderfactory.h" |
|
35 |
|
36 #include <ExifRead.h> |
|
37 #include <IclExtJpegApi.h> |
|
38 |
|
39 // All EXIF data is within the first KGlxMaxExifSize bytes of the file |
|
40 const TInt KGlxMaxExifSize = 0x10000; |
|
41 // ----------------------------------------------------------------------------- |
|
42 // Constructor |
|
43 // ----------------------------------------------------------------------------- |
|
44 // |
|
45 CGlxtnImageUtility::CGlxtnImageUtility(RFs& aFs) : iFs(aFs) |
|
46 { |
|
47 TRACER("CGlxtnImageUtility::CGlxtnImageUtility()"); |
|
48 } |
|
49 |
|
50 // ----------------------------------------------------------------------------- |
|
51 // Destructor |
|
52 // ----------------------------------------------------------------------------- |
|
53 // |
|
54 CGlxtnImageUtility::~CGlxtnImageUtility() |
|
55 { |
|
56 TRACER("CGlxtnImageUtility::~CGlxtnImageUtility()"); |
|
57 delete iDecoder; |
|
58 delete iScaler; |
|
59 delete iBitGc; |
|
60 } |
|
61 |
|
62 // ----------------------------------------------------------------------------- |
|
63 // Cancel |
|
64 // ----------------------------------------------------------------------------- |
|
65 // |
|
66 void CGlxtnImageUtility::Cancel() |
|
67 { |
|
68 TRACER("void CGlxtnImageUtility::Cancel()"); |
|
69 if ( iDecoder ) |
|
70 { |
|
71 iDecoder->Cancel(); |
|
72 } |
|
73 if ( iScaler && iScaler->IsBusy()) |
|
74 { |
|
75 iScaler->CancelProcess(); |
|
76 } |
|
77 } |
|
78 |
|
79 // ----------------------------------------------------------------------------- |
|
80 // AdjustSize |
|
81 // ----------------------------------------------------------------------------- |
|
82 // |
|
83 void CGlxtnImageUtility::AdjustSize(TSize& aTargetSize, const TSize& aSourceSize) |
|
84 { |
|
85 TRACER("void CGlxtnImageUtility::AdjustSize()"); |
|
86 if( (aSourceSize.iWidth <= aTargetSize.iWidth ) && (aSourceSize.iHeight <= aTargetSize.iHeight )) |
|
87 { |
|
88 aTargetSize.iWidth = aSourceSize.iWidth; |
|
89 aTargetSize.iHeight = aSourceSize.iHeight; |
|
90 } |
|
91 else if ( aTargetSize.iHeight * aSourceSize.iWidth |
|
92 < aTargetSize.iWidth * aSourceSize.iHeight ) |
|
93 { |
|
94 // Source has taller aspect than target so reduce target width |
|
95 aTargetSize.iWidth = ( ( aTargetSize.iHeight * aSourceSize.iWidth ) |
|
96 / ( aSourceSize.iHeight ) ); |
|
97 } |
|
98 else |
|
99 { |
|
100 // Source has wider aspect than target so reduce target height |
|
101 aTargetSize.iHeight = (aTargetSize.iWidth * aSourceSize.iHeight) |
|
102 / aSourceSize.iWidth; |
|
103 } |
|
104 } |
|
105 |
|
106 // ----------------------------------------------------------------------------- |
|
107 // DecodeImageL |
|
108 // ----------------------------------------------------------------------------- |
|
109 // |
|
110 CFbsBitmap* CGlxtnImageUtility::DecodeImageL(TRequestStatus& aStatus, |
|
111 const TDesC& aFileName, RArray<TSize>& aTargetSizes, TDisplayMode aMode) |
|
112 { |
|
113 TRACER("CFbsBitmap* CGlxtnImageUtility::DecodeImageL()"); |
|
114 delete iDecoder; |
|
115 iDecoder = NULL; |
|
116 //Get Exif Metadata and the orientation tag from the file first |
|
117 TUint16 orientation = GetOrientationL(aFileName); |
|
118 TInt isExtDecoderUsed = 0; |
|
119 ///iDecoder = GlxtnImageDecoderFactory::NewL( iFs, aFileName ); |
|
120 iDecoder = GlxtnImageDecoderFactory::NewL( iFs, aFileName, isExtDecoderUsed ); |
|
121 iOriginalSize = iDecoder->FrameInfo().iOverallSizeInPixels; |
|
122 //Get the orientation and set rotation on the decoder |
|
123 //as well as update the original size |
|
124 if (isExtDecoderUsed) |
|
125 { |
|
126 TInt rotAngle = 0; |
|
127 TBool flip = EFalse; |
|
128 GetRotationParameters(orientation,rotAngle,flip); |
|
129 CExtJpegDecoder* extDecoder = (CExtJpegDecoder*)iDecoder; |
|
130 extDecoder->SetRotationL(rotAngle); |
|
131 if(flip) |
|
132 { |
|
133 extDecoder->SetMirroringL(); |
|
134 } |
|
135 } |
|
136 if ( 0 == iOriginalSize.iWidth || 0 == iOriginalSize.iHeight ) |
|
137 { |
|
138 User::Leave(KErrCorrupt); |
|
139 } |
|
140 |
|
141 TInt count = aTargetSizes.Count(); |
|
142 TSize testSize; |
|
143 TSize targetSize; |
|
144 for ( TInt i = 0 ; i < count ; i++ ) |
|
145 { |
|
146 testSize = aTargetSizes[i]; |
|
147 AdjustSize(testSize, iOriginalSize); |
|
148 if( ( testSize.iWidth > targetSize.iWidth ) || ( testSize.iHeight > targetSize.iHeight ) ) |
|
149 { |
|
150 targetSize = testSize; |
|
151 } |
|
152 } |
|
153 |
|
154 // Find max scaling factor which won't make image smaller than target size |
|
155 TInt shift = 3; |
|
156 while ( shift |
|
157 && ((iOriginalSize.iWidth >> shift) < targetSize.iWidth |
|
158 || (iOriginalSize.iHeight >> shift) < targetSize.iHeight ) ) |
|
159 { |
|
160 shift--; |
|
161 } |
|
162 TInt roundUp = (1 << shift) - 1; |
|
163 TSize loadSize((iOriginalSize.iWidth + roundUp) >> shift, |
|
164 (iOriginalSize.iHeight + roundUp) >> shift); |
|
165 |
|
166 CFbsBitmap* image = new (ELeave) CFbsBitmap; |
|
167 CleanupStack::PushL(image); |
|
168 User::LeaveIfError(image->Create(loadSize, aMode)); |
|
169 |
|
170 iDecoder->Convert(&aStatus, *image); |
|
171 |
|
172 CleanupStack::Pop(image); |
|
173 return image; |
|
174 } |
|
175 |
|
176 // ----------------------------------------------------------------------------- |
|
177 // FreeDecoder |
|
178 // ----------------------------------------------------------------------------- |
|
179 // |
|
180 void CGlxtnImageUtility::FreeDecoder() |
|
181 { |
|
182 TRACER("void CGlxtnImageUtility::FreeDecoder()"); |
|
183 delete iDecoder; |
|
184 iDecoder = NULL; |
|
185 } |
|
186 |
|
187 // ----------------------------------------------------------------------------- |
|
188 // OriginalSize |
|
189 // ----------------------------------------------------------------------------- |
|
190 // |
|
191 const TSize& CGlxtnImageUtility::OriginalSize() const |
|
192 { |
|
193 TRACER("TSize& CGlxtnImageUtility::OriginalSize()"); |
|
194 return iOriginalSize; |
|
195 } |
|
196 |
|
197 //--------------------------------------------------------------------------- |
|
198 /** |
|
199 K-Nearest neighbour scaling for EColor64K. |
|
200 Code originally inherited from t_display.cpp by Toni Hemminki. |
|
201 Added windowing and further optimized by Jarmo Nikula 2006-2007. |
|
202 |
|
203 @param aSrc Source buffer pointer |
|
204 @param aSrcStride Source buffer stride in bytes |
|
205 @param aSrcCols Source columns |
|
206 @param aSrcRows Source rows |
|
207 @param aX Source window top-left X-coordinate |
|
208 @param aY Source window top-left Y-coordinate |
|
209 @param aW Source window width |
|
210 @param aH Source window height |
|
211 @param aDst Destination buffer pointer |
|
212 @param aDstStride Destination buffer stride in bytes |
|
213 @param aDstCols Destination columns, must be even |
|
214 @param aDstRows Destination rows |
|
215 */ |
|
216 // OPTION's for MMP file: |
|
217 // Interleave assembly code with C, output can be found on txt-files on some BUILD directory: |
|
218 // OPTION ARMCC --asm --interleave |
|
219 // Modify optimization for ARM insturcion set and for maximum speed |
|
220 // OPTION_REPLACE ARMCC --arm -Otime |
|
221 /* aSource->LockHeap(); |
|
222 TUint16* sourceAddress = (TUint16*)aSource->DataAddress(); |
|
223 aSource->UnlockHeap(); |
|
224 aTarget->LockHeap(); |
|
225 TUint16* targetAddress = (TUint16*)aTarget->DataAddress(); |
|
226 aTarget->UnlockHeap(); |
|
227 ScaleColor64K(sourceAddress, aSource->DataStride(), |
|
228 sourceSize.iWidth, sourceSize.iHeight, 0, 0, sourceSize.iWidth, sourceSize.iHeight, |
|
229 targetAddress, aTarget->DataStride(), |
|
230 targetSize.iWidth, targetSize.iHeight); |
|
231 */ |
|
232 |
|
233 void CGlxtnImageUtility::FilterImageL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, CFbsBitmap* aTarget) |
|
234 { |
|
235 TRACER("void CGlxtnImageUtility::FilterImageL()"); |
|
236 TSize sourceSize(aSource->SizeInPixels()); |
|
237 TSize targetSize(aTarget->SizeInPixels()); |
|
238 |
|
239 //Fix for EKLG-7PTET2:mpxcollectionserver.exe crash in thumbnailcreator because of div by zero event |
|
240 if (targetSize.iWidth <= 0) |
|
241 { |
|
242 User::Leave(KErrDivideByZero); |
|
243 } |
|
244 |
|
245 TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100; |
|
246 |
|
247 // no need to filter if close enough or smaller |
|
248 if ( scalePercent >= 2 && ( aTarget->DisplayMode() == EColor64K ) ) |
|
249 { |
|
250 FilterL(aSource, aFilteredSource, scalePercent); |
|
251 } |
|
252 |
|
253 *aStatus = KRequestPending; |
|
254 User::RequestComplete(aStatus, KErrNone); |
|
255 } |
|
256 |
|
257 // ----------------------------------------------------------------------------- |
|
258 // ScaleImageL |
|
259 // ----------------------------------------------------------------------------- |
|
260 // |
|
261 void CGlxtnImageUtility::ScaleImageL(TRequestStatus& aStatus, CFbsBitmap& aSrcBitmap, |
|
262 const TRect& aSrcRect, CFbsBitmap& aDstBitmap, |
|
263 const TRect& aDstRect) |
|
264 { |
|
265 TRACER("void CGlxtnImageUtility::ScaleImageL(IHL)"); |
|
266 if (!iScaler) |
|
267 { |
|
268 iScaler = IHLScaler::CreateL(); |
|
269 } |
|
270 User::LeaveIfError(iScaler->Scale(aStatus, aSrcBitmap, aSrcRect, aDstBitmap, aDstRect)); |
|
271 } |
|
272 |
|
273 void CGlxtnImageUtility::ScaleImage64kL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap* aFilteredSource, CFbsBitmap* aTarget) |
|
274 { |
|
275 TRACER("void CGlxtnImageUtility::ScaleImage64kL()"); |
|
276 TSize sourceSize(aSource->SizeInPixels()); |
|
277 TSize targetSize(aTarget->SizeInPixels()); |
|
278 TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100; |
|
279 TRect targetRect(targetSize); |
|
280 TRect sourceRect(sourceSize); |
|
281 |
|
282 CFbsBitmap* sourceImage = aFilteredSource; |
|
283 if ( !aFilteredSource ) |
|
284 { |
|
285 sourceImage = aSource; |
|
286 } |
|
287 if ( scalePercent < 2 ) |
|
288 { |
|
289 if ( scalePercent > 0 ) |
|
290 { |
|
291 sourceRect = targetRect; |
|
292 } |
|
293 sourceImage = aSource; |
|
294 } |
|
295 sourceImage->LockHeap(); |
|
296 TUint16* sourceAddress = (TUint16*)sourceImage->DataAddress(); |
|
297 sourceImage->UnlockHeap(); |
|
298 aTarget->LockHeap(); |
|
299 TUint16* targetAddress = (TUint16*)aTarget->DataAddress(); |
|
300 aTarget->UnlockHeap(); |
|
301 ScaleColor64K(sourceAddress, sourceImage->DataStride(), |
|
302 sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight, 0, 0, sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight, |
|
303 targetAddress, aTarget->DataStride(), |
|
304 targetSize.iWidth, targetSize.iHeight); |
|
305 |
|
306 /* if ( !iBitGc ) |
|
307 { |
|
308 iBitGc = CFbsBitGc::NewL(); |
|
309 } |
|
310 CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aTarget); |
|
311 CleanupStack::PushL(bitmapDevice); |
|
312 iBitGc->Activate(bitmapDevice); |
|
313 iBitGc->DrawBitmap(targetRect, sourceImage, sourceRect); |
|
314 CleanupStack::PopAndDestroy(bitmapDevice); |
|
315 */ |
|
316 *aStatus = KRequestPending; |
|
317 User::RequestComplete(aStatus, KErrNone); |
|
318 } |
|
319 |
|
320 void CGlxtnImageUtility::ScaleColor64K( TUint16* aSrc, TInt aSrcStride, TInt /*aSrcCols*/, TInt /*aSrcRows*/, |
|
321 TInt aX, TInt aY, TInt aW, TInt aH, |
|
322 TUint16* aDst, TInt aDstStride, TInt aDstCols, TInt aDstRows ) |
|
323 { |
|
324 TRACER("void CGlxtnImageUtility::ScaleColor64K()"); |
|
325 const TUint KPrecision = 16; |
|
326 TUint hInc = ( aW<< KPrecision ) / aDstCols; |
|
327 TUint vInc = ( aH << KPrecision ) / aDstRows; |
|
328 TUint v = 0; |
|
329 for ( TUint row = aDstRows; row > 0; --row ) |
|
330 { |
|
331 TInt h = hInc * (aDstCols - 1); |
|
332 TUint linestart = aSrcStride * ( aY + ( v >> KPrecision ) ) / sizeof(TUint16) + aX; |
|
333 TUint16* src = &aSrc[ linestart ]; |
|
334 TUint32* dst = (TUint32*)aDst + aDstCols / 2; |
|
335 TUint32 pxl2x; |
|
336 // This loop generates 11 assembly instructions per round |
|
337 // when using "--arm --Otime" options. Since two pixels are handled per round, |
|
338 // it means 5.5 instructions per pixel on average. |
|
339 do { |
|
340 pxl2x = src[ h >> KPrecision ]<<16; |
|
341 h -= hInc; |
|
342 pxl2x |= src[ h >> KPrecision ]; |
|
343 *--dst = pxl2x; |
|
344 // Compiler eliminates CMP instruction when substraction |
|
345 // is done inside the while () statement. |
|
346 } while ( ( h -= hInc ) >= 0 ); |
|
347 v += vInc; |
|
348 aDst += aDstStride / sizeof(TUint16); |
|
349 } |
|
350 } |
|
351 |
|
352 void CGlxtnImageUtility::FilterL( CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, TInt aFilterPercent ) |
|
353 { |
|
354 TRACER("void CGlxtnImageUtility::FilterL()"); |
|
355 if ( !aFilteredSource ) |
|
356 { |
|
357 TSize imageSize = aSource->SizeInPixels(); |
|
358 aFilteredSource = new (ELeave) CFbsBitmap; |
|
359 aFilteredSource->Create(imageSize, aSource->DisplayMode()); |
|
360 |
|
361 CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aFilteredSource); |
|
362 if ( !iBitGc ) |
|
363 { |
|
364 iBitGc = CFbsBitGc::NewL(); |
|
365 } |
|
366 iBitGc->Activate(bitmapDevice); |
|
367 iBitGc->BitBlt(TPoint(), aSource, imageSize); |
|
368 delete bitmapDevice; |
|
369 } |
|
370 |
|
371 TSize imageSize = aFilteredSource->SizeInPixels(); |
|
372 aFilteredSource->LockHeap(); |
|
373 TUint16* sourceAddress = (TUint16*)aFilteredSource->DataAddress(); |
|
374 aFilteredSource->UnlockHeap(); |
|
375 const TInt KGlxScalingNeeds4Filtering = 80; // if scaling more than 1.8 need to filter by 4 |
|
376 const TInt KGlxScalingNeeds8Filtering = 260; // if scaling more than 3.6 need to filter by 8 |
|
377 if ( KGlxScalingNeeds8Filtering < aFilterPercent ) |
|
378 { |
|
379 FIRFiltering8( |
|
380 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
381 imageSize.iWidth, imageSize.iHeight ); |
|
382 } |
|
383 else if ( KGlxScalingNeeds4Filtering < aFilterPercent ) |
|
384 { |
|
385 FIRFiltering4( |
|
386 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
387 imageSize.iWidth, imageSize.iHeight ); |
|
388 } |
|
389 else |
|
390 { |
|
391 FIRFiltering( |
|
392 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
393 imageSize.iWidth, imageSize.iHeight ); |
|
394 } |
|
395 } |
|
396 |
|
397 #define rmask565 0xf800 |
|
398 #define gmask565 0x07e0 |
|
399 #define bmask565 0x001f |
|
400 #define rbmask565 (rmask565|bmask565) |
|
401 #define rm565( rgb ) ((rgb) & rmask565) |
|
402 #define gm565( rgb ) ((rgb) & gmask565) |
|
403 #define bm565( rgb ) ((rgb) & bmask565) |
|
404 #define rbm565( rgb ) ((rgb) & rbmask565) |
|
405 #define r565( rgb ) ((rgb)>>11) |
|
406 #define g565( rgb ) (gm565(rgb)>>5) |
|
407 #define b565( rgb ) (bm565(rgb)) |
|
408 #define rgb565( r, g, b ) (((r)<<11)|((g)<<5)|(b)) |
|
409 |
|
410 #define mask32gbr655 0x07e0f81f |
|
411 |
|
412 // Keep below three defs in sync with each other! |
|
413 #define KFIRLen 2 |
|
414 #define KFIRCen (KFIRLen / 2) |
|
415 #define incFIRIndex( i ) i = (i + 1) & (KFIRLen - 1) |
|
416 // Keep above three defs in sync with each other! |
|
417 |
|
418 void CGlxtnImageUtility::FIRFiltering( |
|
419 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
420 { |
|
421 TRACER("void CGlxtnImageUtility::FIRFiltering( )"); |
|
422 TUint firFifo[ KFIRLen ]; |
|
423 TUint i; // index for fifo in&out |
|
424 TUint16 *p; |
|
425 TUint32 px; |
|
426 TInt row, col; |
|
427 TUint FIRsum; |
|
428 // Horizontal scan. |
|
429 p = aDst; |
|
430 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
431 { |
|
432 // read for cache |
|
433 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
434 // Fill in the FIR first. |
|
435 // TODO: Fill in with extrapolated values at edges! |
|
436 FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding |
|
437 i = 0; |
|
438 TUint32 mask1 = mask32gbr655; |
|
439 for ( col = 0; col < KFIRLen; col++ ) |
|
440 { |
|
441 px = p[ col ]; |
|
442 px = ((px<<16) | px) & mask1; |
|
443 firFifo[ i ] = px; |
|
444 FIRsum += px; |
|
445 incFIRIndex( i ); |
|
446 } |
|
447 TUint32 ave; |
|
448 for ( ; col < aDstCols; col++ ) |
|
449 { |
|
450 ave = ( FIRsum / KFIRLen ) & mask1; |
|
451 p[ col - KFIRCen ] = TUint16( ave | (ave>>16) ); |
|
452 FIRsum -= firFifo[ i ]; |
|
453 px = p[ col ]; |
|
454 px = ((px<<16) | px) & mask1; |
|
455 firFifo[ i ] = px; |
|
456 FIRsum += px; |
|
457 incFIRIndex( i ); |
|
458 } |
|
459 p += aDstStridep; |
|
460 } |
|
461 // Vertical scan. |
|
462 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
463 { |
|
464 // Fill in the FIR first. |
|
465 FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding |
|
466 TUint32 mask1 = mask32gbr655; |
|
467 i = 0; |
|
468 p = aDst + col; |
|
469 for ( row = 0; row < KFIRLen; row++ ) |
|
470 { |
|
471 px = *p; |
|
472 px = ((px<<16) | px) & mask1; |
|
473 firFifo[ i ] = px; |
|
474 FIRsum += px; |
|
475 incFIRIndex( i ); |
|
476 p += aDstStridep; |
|
477 } |
|
478 TUint32 ave; |
|
479 p -= aDstStridep * KFIRCen; |
|
480 for ( ; row < aDstRows; row++ ) |
|
481 { |
|
482 ave = ( FIRsum / KFIRLen ) & mask1; |
|
483 p[0] = TUint16( ave | (ave>>16) ); |
|
484 FIRsum -= firFifo[ i ]; |
|
485 px = p[ aDstStridep * KFIRCen ]; |
|
486 px = ((px<<16) | px) & mask1; |
|
487 firFifo[ i ] = px; |
|
488 FIRsum += px; |
|
489 incFIRIndex( i ); |
|
490 p += aDstStridep; |
|
491 } |
|
492 } |
|
493 } |
|
494 // |
|
495 // Keep below three defs in sync with each other! |
|
496 #define KFIRLen4 4 |
|
497 #define KFIRCen4 (KFIRLen4 / 2) |
|
498 #define incFIRIndex4( i ) i = (i + 1) & (KFIRLen4 - 1) |
|
499 // Keep above three defs in sync with each other! |
|
500 |
|
501 void CGlxtnImageUtility::FIRFiltering4( |
|
502 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
503 { |
|
504 TRACER("void CGlxtnImageUtility::FIRFiltering4()"); |
|
505 TUint firFifo[ KFIRLen4 ]; |
|
506 TUint i; // index for fifo in&out |
|
507 TUint16 *p; |
|
508 TUint32 px; |
|
509 TInt row, col; |
|
510 TUint FIRsum; |
|
511 // Horizontal scan. |
|
512 p = aDst; |
|
513 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
514 { |
|
515 // read for cache |
|
516 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
517 // Fill in the FIR first. |
|
518 // TODO: Fill in with extrapolated values at edges! |
|
519 FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding |
|
520 i = 0; |
|
521 TUint32 mask1 = mask32gbr655; |
|
522 for ( col = 0; col < KFIRLen4; col++ ) |
|
523 { |
|
524 px = p[ col ]; |
|
525 px = ((px<<16) | px) & mask1; |
|
526 firFifo[ i ] = px; |
|
527 FIRsum += px; |
|
528 incFIRIndex4( i ); |
|
529 } |
|
530 TUint32 ave; |
|
531 for ( ; col < aDstCols; col++ ) |
|
532 { |
|
533 ave = ( FIRsum / KFIRLen4 ) & mask1; |
|
534 p[ col - KFIRCen4 ] = TUint16( ave | (ave>>16) ); |
|
535 FIRsum -= firFifo[ i ]; |
|
536 px = p[ col ]; |
|
537 px = ((px<<16) | px) & mask1; |
|
538 firFifo[ i ] = px; |
|
539 FIRsum += px; |
|
540 incFIRIndex4( i ); |
|
541 } |
|
542 p += aDstStridep; |
|
543 } |
|
544 // Vertical scan. |
|
545 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
546 { |
|
547 // Fill in the FIR first. |
|
548 FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding |
|
549 TUint32 mask1 = mask32gbr655; |
|
550 i = 0; |
|
551 p = aDst + col; |
|
552 for ( row = 0; row < KFIRLen4; row++ ) |
|
553 { |
|
554 px = *p; |
|
555 px = ((px<<16) | px) & mask1; |
|
556 firFifo[ i ] = px; |
|
557 FIRsum += px; |
|
558 incFIRIndex4( i ); |
|
559 p += aDstStridep; |
|
560 } |
|
561 TUint32 ave; |
|
562 p -= aDstStridep * KFIRCen4; |
|
563 for ( ; row < aDstRows; row++ ) |
|
564 { |
|
565 ave = ( FIRsum / KFIRLen4 ) & mask1; |
|
566 p[0] = TUint16( ave | (ave>>16) ); |
|
567 FIRsum -= firFifo[ i ]; |
|
568 px = p[ aDstStridep * KFIRCen4 ]; |
|
569 px = ((px<<16) | px) & mask1; |
|
570 firFifo[ i ] = px; |
|
571 FIRsum += px; |
|
572 incFIRIndex4( i ); |
|
573 p += aDstStridep; |
|
574 } |
|
575 } |
|
576 } |
|
577 |
|
578 // Keep below three defs in sync with each other! |
|
579 #define KFIRLen8 8 |
|
580 #define KFIRCen8 (KFIRLen8 / 2) |
|
581 #define incFIRIndex8( i ) i = (i + 1) & (KFIRLen8 - 1) |
|
582 // Keep above three defs in sync with each other! |
|
583 |
|
584 void CGlxtnImageUtility::FIRFiltering8( |
|
585 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
586 { |
|
587 TRACER("void CGlxtnImageUtility::FIRFiltering8()"); |
|
588 TUint firFifo[ KFIRLen8 ]; |
|
589 TUint i; // index for fifo in&out |
|
590 TUint16 *p; |
|
591 TUint32 px; |
|
592 TInt row, col; |
|
593 TUint FIRsum; |
|
594 // Horizontal scan. |
|
595 p = aDst; |
|
596 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
597 { |
|
598 // read for cache |
|
599 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
600 // Fill in the FIR first. |
|
601 // TODO: Fill in with extrapolated values at edges! |
|
602 FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding |
|
603 i = 0; |
|
604 TUint32 mask1 = mask32gbr655; |
|
605 for ( col = 0; col < KFIRLen8; col++ ) |
|
606 { |
|
607 px = p[ col ]; |
|
608 px = ((px<<16) | px) & mask1; |
|
609 firFifo[ i ] = px; |
|
610 FIRsum += px; |
|
611 incFIRIndex8( i ); |
|
612 } |
|
613 TUint32 ave; |
|
614 for ( ; col < aDstCols; col++ ) |
|
615 { |
|
616 ave = ( FIRsum / KFIRLen8 ) & mask1; |
|
617 p[ col - KFIRCen8 ] = TUint16( ave | (ave>>16) ); |
|
618 FIRsum -= firFifo[ i ]; |
|
619 px = p[ col ]; |
|
620 px = ((px<<16) | px) & mask1; |
|
621 firFifo[ i ] = px; |
|
622 FIRsum += px; |
|
623 incFIRIndex8( i ); |
|
624 } |
|
625 p += aDstStridep; |
|
626 } |
|
627 // Vertical scan. |
|
628 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
629 { |
|
630 // Fill in the FIR first. |
|
631 FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding |
|
632 TUint32 mask1 = mask32gbr655; |
|
633 i = 0; |
|
634 p = aDst + col; |
|
635 for ( row = 0; row < KFIRLen8; row++ ) |
|
636 { |
|
637 px = *p; |
|
638 px = ((px<<16) | px) & mask1; |
|
639 firFifo[ i ] = px; |
|
640 FIRsum += px; |
|
641 incFIRIndex8( i ); |
|
642 p += aDstStridep; |
|
643 } |
|
644 TUint32 ave; |
|
645 p -= aDstStridep * KFIRCen8; |
|
646 for ( ; row < aDstRows; row++ ) |
|
647 { |
|
648 ave = ( FIRsum / KFIRLen8 ) & mask1; |
|
649 p[0] = TUint16( ave | (ave>>16) ); |
|
650 FIRsum -= firFifo[ i ]; |
|
651 px = p[ aDstStridep * KFIRCen8 ]; |
|
652 px = ((px<<16) | px) & mask1; |
|
653 firFifo[ i ] = px; |
|
654 FIRsum += px; |
|
655 incFIRIndex8( i ); |
|
656 p += aDstStridep; |
|
657 } |
|
658 } |
|
659 } |
|
660 // ----------------------------------------------------------------------------- |
|
661 // GetOrientation |
|
662 // ----------------------------------------------------------------------------- |
|
663 // |
|
664 TUint16 CGlxtnImageUtility::GetOrientationL(const TDesC& aFileName) |
|
665 { |
|
666 //Get Exif Metadata and the orientation tag from the file first |
|
667 RFile file; |
|
668 CleanupClosePushL(file); |
|
669 User::LeaveIfError(file.Open(iFs, |
|
670 aFileName, EFileRead)); |
|
671 TInt size; |
|
672 User::LeaveIfError(file.Size(size)); |
|
673 if ( KGlxMaxExifSize < size ) |
|
674 { |
|
675 size = KGlxMaxExifSize; |
|
676 } |
|
677 TUint16 orientation = 9; |
|
678 HBufC8* exifData = HBufC8::NewLC(size); |
|
679 TPtr8 ptr(exifData->Des()); |
|
680 User::LeaveIfError(file.Read(ptr)); |
|
681 CExifRead* exifReader = NULL; |
|
682 TRAPD(exifErr,exifReader = CExifRead::NewL(*exifData, CExifRead::ENoJpeg)); |
|
683 if(exifErr == KErrNone) |
|
684 { |
|
685 CleanupStack::PushL(exifReader); |
|
686 |
|
687 TInt readErr = exifReader->GetOrientation(orientation); |
|
688 if(readErr != KErrNone) |
|
689 { |
|
690 orientation = 9; |
|
691 } |
|
692 CleanupStack::PopAndDestroy(exifReader); |
|
693 } |
|
694 CleanupStack::PopAndDestroy(exifData); |
|
695 //Close and pop file Session |
|
696 CleanupStack::PopAndDestroy(&file); |
|
697 return orientation; |
|
698 } |
|
699 |
|
700 // ----------------------------------------------------------------------------- |
|
701 // GetRotationParameters |
|
702 // ----------------------------------------------------------------------------- |
|
703 // |
|
704 void CGlxtnImageUtility::GetRotationParameters(TUint16 aOrientation, |
|
705 TInt& aRotAngle, TBool& aFlipStatus) |
|
706 { |
|
707 //Get the orientation and set rotation on the decoder |
|
708 //as well as update the original size |
|
709 aRotAngle = 0; |
|
710 aFlipStatus = EFalse; |
|
711 TInt isOrientationOdd = aOrientation%2; |
|
712 if(aOrientation>8) |
|
713 { |
|
714 return; |
|
715 } |
|
716 if(aOrientation >= 3 && aOrientation < 5) |
|
717 { |
|
718 aRotAngle = 180; |
|
719 } |
|
720 else if(aOrientation >= 5 && aOrientation < 7) |
|
721 { |
|
722 aRotAngle = 90; |
|
723 |
|
724 } |
|
725 else if(aOrientation >= 7 && aOrientation <= 8) |
|
726 { |
|
727 aRotAngle = 270; |
|
728 } |
|
729 if(aOrientation>4 ) |
|
730 { |
|
731 iOriginalSize.SetSize(iOriginalSize.iHeight,iOriginalSize.iWidth); //Switch Height and width |
|
732 if(isOrientationOdd ) |
|
733 { |
|
734 aFlipStatus = ETrue; |
|
735 } |
|
736 } |
|
737 } |