|
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "BitmapTransformsPlugin.h" |
|
17 |
|
18 #include "BitmapConverter.h" |
|
19 #include <bitmtrans/bitmtranspanic.h> |
|
20 #include <e32math.h> |
|
21 |
|
22 const TInt KFixedPointBits = 4; |
|
23 const TInt KFixedPointScale = (1 << KFixedPointBits); |
|
24 const TInt KLinesPerCall = 10; |
|
25 const TInt KBitsPerByte = 8; |
|
26 |
|
27 /* |
|
28 *The function NewL constructs a CBitmapScalerPlugin |
|
29 * |
|
30 *@return CBitmapScalerPlugin* |
|
31 */ |
|
32 MBitmapScalerPlugin* CBitmapScalerPlugin::NewL() |
|
33 { |
|
34 CBitmapScalerPlugin* self = new(ELeave) CBitmapScalerPlugin(); |
|
35 CleanupStack::PushL(self); |
|
36 self->ConstructL(); |
|
37 CleanupStack::Pop(self); |
|
38 return self; |
|
39 } |
|
40 |
|
41 /* |
|
42 * |
|
43 *CBitmapScalerPlugin() |
|
44 *Constructor for this class. Adds itself to CActiveScheduler. |
|
45 */ |
|
46 CBitmapScalerPlugin::CBitmapScalerPlugin() |
|
47 : CActive(CActive::EPriorityIdle), iOrigDes(NULL, 0), iDestDes(NULL, 0), |
|
48 iQualityLevel(CBitmapScaler::EMaximumQuality) |
|
49 { |
|
50 CActiveScheduler::Add(this); |
|
51 } |
|
52 |
|
53 /* |
|
54 * |
|
55 *ConstructL() |
|
56 *Performs second phase of construction. |
|
57 */ |
|
58 void CBitmapScalerPlugin::ConstructL() |
|
59 { |
|
60 iScanlineBitmap = new(ELeave) CFbsBitmap; |
|
61 |
|
62 SetPostProcessingEnabled(ETrue); |
|
63 ASSERT( GetCurrentState() == EInactiveState ); |
|
64 } |
|
65 |
|
66 |
|
67 /* |
|
68 * |
|
69 *~CBitmapScalerPlugin |
|
70 *This is the destructor for the CBitmapScalerPlugin |
|
71 *and is resposible for deallocating all resources |
|
72 *allocated by the CBitmapScalerPlugin. |
|
73 */ |
|
74 CBitmapScalerPlugin::~CBitmapScalerPlugin() |
|
75 { |
|
76 Cancel(); |
|
77 Cleanup(); |
|
78 |
|
79 delete iScanlineBitmap; |
|
80 |
|
81 // should have been deleted by cleanup |
|
82 ASSERT(iScaleBitmap==NULL || !(iFlags & EScaleBitmapIsOwned)); |
|
83 ASSERT(iFilterIndexTable==NULL); |
|
84 ASSERT(iFilterCoeffsTable==NULL); |
|
85 ASSERT(iDevice==NULL); |
|
86 ASSERT(iGc==NULL); |
|
87 ASSERT(iPostProcessBitmap == NULL ); |
|
88 ASSERT(iBitmapConverter == NULL ); |
|
89 ASSERT( GetCurrentState() == EInactiveState ); |
|
90 } |
|
91 |
|
92 /* |
|
93 *This function performs deallocation of memory allocated by the class |
|
94 *which is allocated on each scale as opposed to the entire liftime |
|
95 *of the scaler object. |
|
96 */ |
|
97 void CBitmapScalerPlugin::Cleanup() |
|
98 { |
|
99 delete[] iFilterIndexTable; |
|
100 iFilterIndexTable = NULL; |
|
101 delete[] iFilterCoeffsTable; |
|
102 iFilterCoeffsTable = NULL; |
|
103 |
|
104 if (iOrigDes.Length() != 0) // Test is required to avoid PANIC 45 |
|
105 { |
|
106 User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) ); |
|
107 iOrigDes.SetLength(0); |
|
108 } |
|
109 |
|
110 if (iDestDes.Length() != 0) // Test is required to avoid PANIC 45 |
|
111 { |
|
112 User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) ); |
|
113 iDestDes.SetLength(0); |
|
114 } |
|
115 |
|
116 if (iFlags & ECreatedTempBitmap) |
|
117 { |
|
118 delete iTempBitmap; |
|
119 iTempBitmap = NULL; |
|
120 iFlags &= ~ECreatedTempBitmap; |
|
121 } |
|
122 |
|
123 // Reset the EIsSourceBitmapResized flag here |
|
124 if (iFlags & EIsSourceBitmapResized) |
|
125 { |
|
126 iFlags &= ~EIsSourceBitmapResized; |
|
127 ASSERT((iFlags & EIsSourceBitmapResized) == 0); |
|
128 } |
|
129 |
|
130 // Only delete the scale bitmap if we created it. |
|
131 if (iFlags & EScaleBitmapIsOwned) |
|
132 { |
|
133 delete iScaleBitmap; |
|
134 iFlags &= ~EScaleBitmapIsOwned; |
|
135 } |
|
136 iScaleBitmap = NULL; |
|
137 |
|
138 delete iGc; |
|
139 iGc = NULL; |
|
140 delete iDevice; |
|
141 iDevice = NULL; |
|
142 iDestBmpPtr = NULL; // we don't own it |
|
143 delete iPostProcessBitmap; |
|
144 iPostProcessBitmap = NULL; |
|
145 delete iBitmapConverter; |
|
146 iBitmapConverter = NULL; |
|
147 SetCurrentState( EInactiveState ); |
|
148 } |
|
149 |
|
150 /* |
|
151 * Allocates some memory and assigns a pointer to it. |
|
152 * @param aPtr Pointer to the allocated memory |
|
153 * @param aAllocSize The size in bytes of the memory to allocate |
|
154 * @pre aAllocSize >= 0 |
|
155 * @pre InVariant |
|
156 */ |
|
157 TInt CBitmapScalerPlugin::AllocPtr( TPtr8& aPtr, TInt aAllocSize ) |
|
158 { |
|
159 //[ preconditions ] |
|
160 ASSERT(aAllocSize >= 0 ); |
|
161 ASSERT(InVariant()); |
|
162 |
|
163 TInt rc = KErrNone; |
|
164 |
|
165 // User::Alloc() returns NULL if no memory |
|
166 TUint8* addr = static_cast<TUint8*>(User::Alloc(aAllocSize + sizeof(TUint32) )); |
|
167 if (addr) |
|
168 { |
|
169 // coverity [memory_leak] |
|
170 addr = reinterpret_cast<TUint8*>( _ALIGN_UP(TLinAddr(addr), sizeof(TUint32)) ); |
|
171 aPtr.Set(addr, aAllocSize, aAllocSize); |
|
172 } |
|
173 else |
|
174 { |
|
175 rc = KErrNoMemory; |
|
176 } |
|
177 |
|
178 return rc; |
|
179 } |
|
180 |
|
181 // MBitmapScalerPlugin::Cancel() calls CActive::Cancel() |
|
182 void CBitmapScalerPlugin::Cancel() |
|
183 { |
|
184 CActive::Cancel(); |
|
185 } |
|
186 |
|
187 /* |
|
188 * |
|
189 * ScaleRequestPostcondition |
|
190 * @return 'ETrue' when post conditions for scale request are |
|
191 * correct |
|
192 * |
|
193 */ |
|
194 TBool CBitmapScalerPlugin::ScaleRequestPostcondition() const |
|
195 { |
|
196 TBool result = ETrue; |
|
197 |
|
198 if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality ) |
|
199 { |
|
200 if( ( iFinalOffset != iDestSize.iHeight ) || |
|
201 ( iFilterIndexTable != NULL ) || |
|
202 ( iFilterCoeffsTable != 0 ) ) |
|
203 { |
|
204 result = EFalse; |
|
205 } |
|
206 } |
|
207 else |
|
208 { |
|
209 // Using the original (maximum quality) algorithm |
|
210 if( ( iFlags & EVerticalScan) || |
|
211 ( iFilterIndexTable == NULL ) || |
|
212 ( iFinalOffset != iOrigSize.iHeight ) || |
|
213 ( iFilterCoeffsTable == 0 ) ) |
|
214 { |
|
215 result = EFalse; |
|
216 } |
|
217 |
|
218 if (( iDevice == NULL ) || |
|
219 ( iScanlineBitmap->Handle() == 0 ) || |
|
220 ( iCurOffset != 0 )) |
|
221 { |
|
222 result = EFalse; |
|
223 } |
|
224 } |
|
225 |
|
226 return result; |
|
227 } |
|
228 |
|
229 /** |
|
230 * |
|
231 * Begins the bitmap re-scaling operation. |
|
232 * |
|
233 * The scaling factor is based on the relative value of the source bitmap |
|
234 * size and the explicitly supplied size. The operation is asynchronous. |
|
235 * When it is complete, successfully or otherwise, the |
|
236 * <code>TRequestStatus</code>& is set, passing the state of the operation. |
|
237 * |
|
238 * @param "TRequestStatus* aRequestStatus" |
|
239 * |
|
240 * @param "CFbsBitmap& aBitmap" |
|
241 * The bitmap to be re-scaled. This reference is also the |
|
242 * target location for the re-scaled bitmap. |
|
243 * @param "const TSize& aDestinationSize" |
|
244 * The requested target size for the re-scaled bitmap. |
|
245 * @param "TBool aMaintainAspectRatio = ETrue" |
|
246 * <code>ETrue</code> - the aspect ratio is retained; |
|
247 * this is the default. The same scaling factor is |
|
248 * applied in both the horizontal and vertical |
|
249 * directions. This is the smaller of the horizontal |
|
250 * scaling factor and the vertical scaling factor. |
|
251 * <code>EFalse</code> - the aspect ratio need not be |
|
252 * retained. |
|
253 * |
|
254 */ |
|
255 void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus, |
|
256 CFbsBitmap& aBitmap, |
|
257 const TSize& aDestinationSize, |
|
258 TBool aMaintainAspectRatio) |
|
259 { |
|
260 //[ assert preconditions ] |
|
261 // [ panic if aRequestStatus is NULL ] |
|
262 __ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) ); |
|
263 |
|
264 //[ panic if the src has not been created] |
|
265 __ASSERT_ALWAYS( (aBitmap.Handle() != 0), Panic( ENoSourceBitmap ) ); |
|
266 |
|
267 iScaleStatus = aRequestStatus; |
|
268 *iScaleStatus = KRequestPending; |
|
269 |
|
270 if(aBitmap.ExtendedBitmapType()!=KNullUid) |
|
271 { |
|
272 RequestComplete(KErrNotSupported); |
|
273 return; |
|
274 } |
|
275 |
|
276 // Set up the sizes before they're lost |
|
277 iOrigSize = aBitmap.SizeInPixels(); |
|
278 iDestSize = aDestinationSize; |
|
279 |
|
280 // Dithering is not required if the tgt's display mode |
|
281 // is none of EGray256, EColor16M, EColor16MU, EColor16MA |
|
282 TBool dither = ETrue; |
|
283 iTgtDisplayMode = aBitmap.DisplayMode(); |
|
284 if ((iTgtDisplayMode == EGray256) || |
|
285 (iTgtDisplayMode == EColor16M) || |
|
286 (iTgtDisplayMode == EColor16MA)|| |
|
287 (iTgtDisplayMode == EColor16MU) ) |
|
288 { |
|
289 dither = EFalse; |
|
290 } |
|
291 |
|
292 // Create a temporary bitmap if we're not using the low memory algorithm |
|
293 // OR if we're using the low memory algorithm AND dithering |
|
294 TInt leaveErr = KErrNone; |
|
295 if (!UseLowMemoryAlgorithm() || |
|
296 (UseLowMemoryAlgorithm() && dither) ) |
|
297 { |
|
298 if (iFlags & ECreatedTempBitmap) |
|
299 { |
|
300 delete iTempBitmap; |
|
301 iTempBitmap = NULL; |
|
302 iFlags &= ~ECreatedTempBitmap; |
|
303 } |
|
304 |
|
305 iTempBitmap = new CFbsBitmap; |
|
306 |
|
307 if (iTempBitmap != NULL) |
|
308 { |
|
309 // iTempBitmap has been created so flag that it needs to be deleted |
|
310 iFlags |= ECreatedTempBitmap; |
|
311 leaveErr = iTempBitmap->Create(aDestinationSize, iTgtDisplayMode); |
|
312 } |
|
313 else |
|
314 { |
|
315 // No memory to new the temp bitmap |
|
316 leaveErr = KErrNoMemory; |
|
317 } |
|
318 } |
|
319 |
|
320 if (leaveErr == KErrNoMemory || |
|
321 (UseLowMemoryAlgorithm() && !dither) ) |
|
322 { |
|
323 // Either failed to create the tempbitmap OR |
|
324 // we explicitly want to use the low-memory algorithm. |
|
325 // Either way use the source directly in the manner of the low-memory algorithm. |
|
326 // Check if we need to delete the tempbitmap |
|
327 if (iFlags & ECreatedTempBitmap) |
|
328 { |
|
329 delete iTempBitmap; |
|
330 iTempBitmap = NULL; |
|
331 iFlags &= ~ECreatedTempBitmap; |
|
332 } |
|
333 iTempBitmap = &aBitmap; |
|
334 iFlags |= EIsSourceBitmapResized; |
|
335 } |
|
336 else if (leaveErr != KErrNone) |
|
337 { |
|
338 iScaleStatus = aRequestStatus; |
|
339 *iScaleStatus = KRequestPending; |
|
340 ProcessError(leaveErr); |
|
341 return; |
|
342 } |
|
343 |
|
344 Scale(aRequestStatus, aBitmap, *iTempBitmap, aMaintainAspectRatio); |
|
345 } |
|
346 |
|
347 /* |
|
348 * |
|
349 * Begins the bitmap re-scaling operation. |
|
350 * |
|
351 * The scaling factor is based on the relative sizes of the source |
|
352 * and target bitmaps. The operation is asynchronous. When it is |
|
353 * complete, successfully or otherwise, the TRequestStatus & |
|
354 * aStatus is set, passing the state of the operation. |
|
355 * |
|
356 * @param TRequestStatus* aRequestStatus |
|
357 * |
|
358 * @param "CFbsBitmap& aSrcBitmap" |
|
359 * The bitmap to be re-scaled. |
|
360 * @param "CFbsBitmap& aTgtBitmap" |
|
361 * The target location for the re-scaled bitmap. |
|
362 * @param "TBool aMaintainAspectRatio = ETrue" |
|
363 * ETrue - the aspect ratio is retained; |
|
364 * this is the default. The same scaling factor is |
|
365 * applied in both the horizontal and vertical |
|
366 * directions. This is the smaller of the horizontal |
|
367 * scaling factor and the vertical scaling factor. |
|
368 * EFalse - the aspect ratio need not be |
|
369 * retained. |
|
370 * |
|
371 * |
|
372 */ |
|
373 void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus, |
|
374 CFbsBitmap& aSrcBitmap, |
|
375 CFbsBitmap& aTgtBitmap, |
|
376 TBool aMaintainAspectRatio) |
|
377 { |
|
378 // [ precondition checking on arguments ] |
|
379 // [ panic if aRequestStatus is NULL ] |
|
380 __ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) ); |
|
381 |
|
382 //[ panic if the src has not been created] |
|
383 __ASSERT_ALWAYS( (aSrcBitmap.Handle() != 0), Panic( ENoSourceBitmap ) ); |
|
384 |
|
385 //[ panic if the tgt has not been created] |
|
386 __ASSERT_ALWAYS( (aTgtBitmap.Handle() != 0), Panic( ENoDestinationBitmap ) ); |
|
387 |
|
388 iScaleStatus = aRequestStatus; |
|
389 *iScaleStatus = KRequestPending; |
|
390 |
|
391 //[ current state must be inactive ] |
|
392 if( GetCurrentState() != EInactiveState ) |
|
393 { |
|
394 ProcessError( KErrGeneral ); |
|
395 return; |
|
396 } |
|
397 |
|
398 ASSERT(iDevice==NULL); |
|
399 |
|
400 if(aSrcBitmap.ExtendedBitmapType()!=KNullUid || aTgtBitmap.ExtendedBitmapType()!=KNullUid) |
|
401 { |
|
402 RequestComplete(KErrNotSupported); |
|
403 return; |
|
404 } |
|
405 |
|
406 iSrcBitmap = &aSrcBitmap; |
|
407 iTgtBitmap = &aTgtBitmap; |
|
408 |
|
409 if (!(iFlags & EIsSourceBitmapResized)) |
|
410 { |
|
411 // As we're not scaling directly to the source bitmap |
|
412 // we can determine the scaling sizes here (otherwise |
|
413 // we'd overwrite the values that we got prior to setting |
|
414 // the tgtBitmap to the srcBitmap!!) |
|
415 iOrigSize = iSrcBitmap->SizeInPixels(); |
|
416 iDestSize = iTgtBitmap->SizeInPixels(); |
|
417 } |
|
418 |
|
419 TInt err = KErrNone; |
|
420 |
|
421 // Target's colour depth |
|
422 iTgtDisplayMode = iTgtBitmap->DisplayMode(); |
|
423 |
|
424 // Check the aspect ratio and adjust the resolution if needed |
|
425 if (aMaintainAspectRatio) |
|
426 { |
|
427 //[ update destination height to preserve aspect ratio ] |
|
428 HeightAndWidthPreservingAspectRatio( iDestSize, iOrigSize ); |
|
429 } |
|
430 |
|
431 iIntermediateSize.iWidth = iDestSize.iWidth; |
|
432 if ( QualityAlgorithm() != CBitmapScaler::EMaximumQuality ) |
|
433 { |
|
434 // Using one of the lower quality algorithms so use the destination size |
|
435 // that we are scaling to. |
|
436 iIntermediateSize.iHeight = iDestSize.iHeight; |
|
437 } |
|
438 else |
|
439 { |
|
440 // Using the original algorithm (which firstly scales horizontally to |
|
441 // an intermediate bitmap), so the intermediate size requires the original |
|
442 // height unchanged. |
|
443 iIntermediateSize.iHeight = iOrigSize.iHeight; |
|
444 } |
|
445 |
|
446 // if either of the destination dimension is zero then |
|
447 // complete with KErrNone |
|
448 if ((iDestSize.iWidth == 0) || |
|
449 (iDestSize.iHeight == 0)) |
|
450 { |
|
451 ProcessError(KErrNone); |
|
452 return; |
|
453 } |
|
454 |
|
455 // if either of the source dimension is zero then send back an error |
|
456 if ((iOrigSize.iWidth == 0) || |
|
457 (iOrigSize.iHeight == 0)) |
|
458 { |
|
459 ProcessError( KErrArgument ); |
|
460 return; |
|
461 } |
|
462 |
|
463 // Scale to bitmap of display mode EColor16M except for |
|
464 // target bitmaps of EGray256, EColor16MU and EColor16MA |
|
465 if ( (iTgtDisplayMode == EGray256) || (iTgtDisplayMode == EColor16MU) |
|
466 || (iTgtDisplayMode == EColor16MA)) |
|
467 { |
|
468 iLocalDisplayMode = iTgtDisplayMode; |
|
469 } |
|
470 else |
|
471 { |
|
472 iLocalDisplayMode = EColor16M; |
|
473 } |
|
474 |
|
475 if (iTgtDisplayMode != EColor16M && iTgtDisplayMode != EColor16MA && iTgtDisplayMode != EColor16MU) |
|
476 { |
|
477 // Create an intermediate bitmap to scale to for cases other than EColor16M |
|
478 if (iScaleBitmap == NULL) |
|
479 { |
|
480 // Only want one instance of iScaleBitmap |
|
481 iScaleBitmap = new CFbsBitmap; |
|
482 iFlags |= EScaleBitmapIsOwned; // flag that we're the owner of the scale bitmap |
|
483 if (iScaleBitmap == NULL) |
|
484 { |
|
485 err = KErrNoMemory; |
|
486 } |
|
487 } |
|
488 if( err != KErrNone ) |
|
489 { |
|
490 ProcessError( err ); |
|
491 return; |
|
492 } |
|
493 |
|
494 err = iScaleBitmap->Create(iIntermediateSize, iLocalDisplayMode); |
|
495 |
|
496 if( err != KErrNone ) |
|
497 { |
|
498 ProcessError( err ); |
|
499 return; |
|
500 } |
|
501 |
|
502 iDestBmpPtr = iScaleBitmap; |
|
503 } |
|
504 else |
|
505 { |
|
506 // For EColor16M scale directly to TgtBitmap |
|
507 iScaleBitmap = iTgtBitmap; |
|
508 |
|
509 // Downscaling one bitmap to another requires |
|
510 // the scale bitmap to be resized to ensure that |
|
511 // the correct amount of data is read from the source. |
|
512 if (!(iFlags & EIsSourceBitmapResized)) |
|
513 { |
|
514 err = iScaleBitmap->Resize(iIntermediateSize); |
|
515 if (err != KErrNone) |
|
516 { |
|
517 ProcessError(err); |
|
518 return; |
|
519 } |
|
520 } |
|
521 } |
|
522 |
|
523 iComponentsPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(iLocalDisplayMode) / KBitsPerByte; |
|
524 if (iComponentsPerPixel == 0) |
|
525 { |
|
526 iComponentsPerPixel = 1; |
|
527 } |
|
528 |
|
529 iSrcY = 0; |
|
530 if (iDestSize.iHeight < iOrigSize.iHeight) |
|
531 { |
|
532 iCurY = 0; |
|
533 } |
|
534 else |
|
535 { |
|
536 iCurY = (iOrigSize.iHeight << KFixedPointScale); |
|
537 } |
|
538 |
|
539 if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality) |
|
540 { |
|
541 // Try to create and size the scanline bitmap here instead of in the ConstructL |
|
542 if ((err = iScanlineBitmap->Create(TSize(1, iDestSize.iHeight), iLocalDisplayMode)) != KErrNone) |
|
543 { |
|
544 ProcessError(err); |
|
545 return; |
|
546 } |
|
547 } |
|
548 |
|
549 // Upscaling so ensure we're writing to a suitably |
|
550 // large target |
|
551 TInt newWidth = iTgtBitmap->SizeInPixels().iWidth; |
|
552 TInt newHeight = iTgtBitmap->SizeInPixels().iHeight; |
|
553 |
|
554 TBool needsResize = EFalse; |
|
555 if(iDestSize.iWidth > iOrigSize.iWidth) |
|
556 { |
|
557 newWidth = iDestSize.iWidth; |
|
558 needsResize = ETrue; |
|
559 } |
|
560 |
|
561 if(iDestSize.iHeight > iOrigSize.iHeight) |
|
562 { |
|
563 newHeight = iDestSize.iHeight; |
|
564 needsResize = ETrue; |
|
565 } |
|
566 |
|
567 if(needsResize) |
|
568 { |
|
569 err = iTgtBitmap->Resize(TSize(newWidth, newHeight)); |
|
570 |
|
571 if( err != KErrNone ) |
|
572 { |
|
573 ProcessError(err); |
|
574 return; |
|
575 } |
|
576 } |
|
577 |
|
578 if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality) |
|
579 { |
|
580 // [Create device for normal condition where target bitmap is the |
|
581 // destination] |
|
582 TRAP(err, iDevice = CFbsBitmapDevice::NewL(iTgtBitmap)); |
|
583 if( err != KErrNone ) |
|
584 { |
|
585 ProcessError(KErrNoMemory); |
|
586 return; |
|
587 } |
|
588 } |
|
589 |
|
590 iDestBmpPtr = iTgtBitmap; |
|
591 |
|
592 SetProcessingNeeded( EFalse ); |
|
593 |
|
594 //[ Is Post processing required ] |
|
595 if( ( iTgtDisplayMode != EColor16M) && |
|
596 ( iTgtDisplayMode != EColor16MU) && |
|
597 ( iTgtDisplayMode != EColor16MA) && |
|
598 ( iTgtDisplayMode != EGray256) && |
|
599 (! IsPostProcessingDisabled() ) || |
|
600 ((iTgtDisplayMode == EGray256) && (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) && |
|
601 (iLocalDisplayMode != EGray256)) |
|
602 ) |
|
603 { |
|
604 SetProcessingNeeded( ETrue ); |
|
605 |
|
606 //[ create a bitmap converter to colour quantize the image |
|
607 // to the number of colours available in the output |
|
608 // note CFbsBitmap has a private constructor whence new is not |
|
609 //used ] |
|
610 TRAP(err, iBitmapConverter = CBitmapConverter::NewL()); |
|
611 if(err != KErrNone ) |
|
612 { |
|
613 ProcessError(err); |
|
614 return; |
|
615 } |
|
616 |
|
617 //[ create a post processing bitmap] |
|
618 iPostProcessBitmap = new CFbsBitmap; |
|
619 if( iPostProcessBitmap == NULL ) |
|
620 { |
|
621 err = KErrNoMemory; |
|
622 ProcessError(err); |
|
623 return; |
|
624 } |
|
625 |
|
626 //[ size the post processing bitmap ] |
|
627 if ((err = iPostProcessBitmap->Create(iDestSize, EColor16M )) != KErrNone) |
|
628 { |
|
629 ProcessError(err); |
|
630 return; |
|
631 } |
|
632 |
|
633 // Create device with post processing bitmap as the target |
|
634 delete iDevice; |
|
635 iDevice = NULL; |
|
636 iDestBmpPtr = NULL; |
|
637 if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality) |
|
638 { |
|
639 TRAP(err, iDevice = CFbsBitmapDevice::NewL(iPostProcessBitmap)); |
|
640 if( err != KErrNone ) |
|
641 { |
|
642 ProcessError(err); |
|
643 return; |
|
644 } |
|
645 } |
|
646 iDestBmpPtr = iPostProcessBitmap; |
|
647 } |
|
648 |
|
649 iCurOffset = 0; |
|
650 iCurOffsetUp = iDestSize.iHeight; |
|
651 if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) |
|
652 { |
|
653 // Using one of the lower quality algorithms |
|
654 iFinalOffset = iDestSize.iHeight; |
|
655 if (iTgtBitmap->SizeInPixels() != iDestSize && iTgtBitmap->Handle() != iSrcBitmap->Handle()) |
|
656 { |
|
657 err = iTgtBitmap->Resize(iDestSize); |
|
658 if( err != KErrNone ) |
|
659 { |
|
660 ProcessError(err); |
|
661 return; |
|
662 } |
|
663 } |
|
664 } |
|
665 else |
|
666 { |
|
667 // We're using the original scaling algorithm |
|
668 // Set Horizontal Scan flag |
|
669 iFlags &= ~EVerticalScan; |
|
670 iFinalOffset = iOrigSize.iHeight; |
|
671 iCurLineSize = iOrigSize.iWidth; |
|
672 |
|
673 // Set up filter tables |
|
674 err = FilterTables(); |
|
675 if( err != KErrNone ) |
|
676 { |
|
677 ProcessError( err ); |
|
678 return; |
|
679 } |
|
680 } |
|
681 |
|
682 // Allocate the buffers |
|
683 TInt allocErr = AllocPtr( iOrigDes, iOrigSize.iWidth * iComponentsPerPixel ); |
|
684 if (allocErr == KErrNone) |
|
685 { |
|
686 allocErr = AllocPtr( iDestDes, iDestSize.iWidth * iComponentsPerPixel ); |
|
687 } |
|
688 |
|
689 if( allocErr != KErrNone ) |
|
690 { |
|
691 ProcessError(allocErr); |
|
692 return; |
|
693 } |
|
694 |
|
695 if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality) |
|
696 { |
|
697 err = iDevice->CreateContext(iGc); |
|
698 } |
|
699 |
|
700 if (err != KErrNone) |
|
701 { |
|
702 ProcessError(err); |
|
703 return; |
|
704 } |
|
705 |
|
706 //[ set state to scaling ] |
|
707 SetCurrentState(EScalingState); |
|
708 |
|
709 //[ assert post conditions of scale request ] |
|
710 ASSERT( ScaleRequestPostcondition() ); |
|
711 |
|
712 // Start the active object |
|
713 SelfComplete(KErrNone); |
|
714 } |
|
715 |
|
716 /* |
|
717 * |
|
718 * FilterTables |
|
719 * Initialise the filter tables |
|
720 * |
|
721 */ |
|
722 TInt CBitmapScalerPlugin::FilterTables() |
|
723 { |
|
724 TInt result = KErrNone; |
|
725 |
|
726 ASSERT(iFilterCoeffsTable==NULL); |
|
727 ASSERT(iFilterIndexTable==NULL); |
|
728 |
|
729 if (iDestSize.iWidth > iDestSize.iHeight) |
|
730 { |
|
731 iFilterIndexNum = 2 * iDestSize.iWidth; |
|
732 } |
|
733 else |
|
734 { |
|
735 iFilterIndexNum = 2 * iDestSize.iHeight; |
|
736 } |
|
737 |
|
738 if (iDestSize.iWidth > iOrigSize.iWidth) |
|
739 { |
|
740 iFilterCoeffsNum = iDestSize.iWidth; |
|
741 } |
|
742 else |
|
743 { |
|
744 iFilterCoeffsNum = 2 * iOrigSize.iWidth; |
|
745 } |
|
746 |
|
747 TInt filterCoeffsNumVert; |
|
748 |
|
749 if (iDestSize.iHeight > iOrigSize.iHeight) |
|
750 { |
|
751 filterCoeffsNumVert = iDestSize.iHeight; |
|
752 } |
|
753 else |
|
754 { |
|
755 filterCoeffsNumVert = 2 * iOrigSize.iHeight; |
|
756 } |
|
757 |
|
758 if (filterCoeffsNumVert > iFilterCoeffsNum) |
|
759 { |
|
760 iFilterCoeffsNum = filterCoeffsNumVert; |
|
761 } |
|
762 |
|
763 //[ allocate a filter index table and check for memory alloc failure] |
|
764 iFilterIndexTable = new TInt[iFilterIndexNum]; |
|
765 if( iFilterIndexTable == NULL ) |
|
766 { |
|
767 return KErrNoMemory; |
|
768 } |
|
769 |
|
770 //[ alloc filter coefficient table and check for memory alloc failure] |
|
771 iFilterCoeffsTable = new TInt[iFilterCoeffsNum]; |
|
772 if( iFilterCoeffsTable == NULL ) |
|
773 { |
|
774 return KErrNoMemory; |
|
775 } |
|
776 |
|
777 // Calculate filter tables for horizontal scaling |
|
778 iFilterIndexTablePtr = iFilterIndexTable; |
|
779 iFilterCoeffsTablePtr = iFilterCoeffsTable; |
|
780 result = CalcFilterTables(iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTablePtr, iFilterCoeffsTablePtr); |
|
781 |
|
782 return result; |
|
783 } |
|
784 |
|
785 /* |
|
786 * |
|
787 * DoScale |
|
788 * This function does the scaling of a bitmap in chunks |
|
789 * |
|
790 */ |
|
791 void CBitmapScalerPlugin::DoScale() |
|
792 { |
|
793 //[assert the invariant ] |
|
794 __ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) ); |
|
795 |
|
796 switch( iCurrentState ) |
|
797 { |
|
798 case EScalingState: |
|
799 { |
|
800 //[ we are scaling the image] |
|
801 if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) |
|
802 { |
|
803 FastScale(); |
|
804 } |
|
805 else |
|
806 { |
|
807 Scale(); |
|
808 } |
|
809 break; |
|
810 } |
|
811 case EStartPostProcessState: |
|
812 { |
|
813 //[ we are setting up post processing] |
|
814 StartPostProcessing(); |
|
815 break; |
|
816 } |
|
817 case ECleanUpState: |
|
818 { |
|
819 //[ cleaning up ] |
|
820 ScaleCleanUp(); |
|
821 break; |
|
822 } |
|
823 default: |
|
824 { |
|
825 //[we can never get here |
|
826 // because the invariant has been asserted |
|
827 //assert the invariant ] |
|
828 __ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) ); |
|
829 } |
|
830 } |
|
831 |
|
832 //[assert the invariant ] |
|
833 __ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) ); |
|
834 } |
|
835 |
|
836 /** |
|
837 * |
|
838 * Scale |
|
839 * This method does the scaling |
|
840 * @pre current state is ScalingState |
|
841 */ |
|
842 void CBitmapScalerPlugin::Scale() |
|
843 { |
|
844 #if defined (__SCALING_PROFILING) |
|
845 RDebug::ProfileStart(7); |
|
846 #endif // __SCALING_PROFILING |
|
847 |
|
848 //[ assert precondition ] |
|
849 ASSERT( GetCurrentState() == EScalingState ); |
|
850 //[ assert invariant ] |
|
851 ASSERT( InVariant() ); |
|
852 |
|
853 TInt linesLeftPerCall = KLinesPerCall; |
|
854 |
|
855 while (linesLeftPerCall>0 && iCurOffset<iFinalOffset) |
|
856 { |
|
857 if (!(iFlags & EVerticalScan)) |
|
858 { |
|
859 // |
|
860 // Get current scan line |
|
861 #if defined (__SCALING_PROFILING) |
|
862 RDebug::ProfileStart(8); |
|
863 #endif // __SCALING_PROFILING |
|
864 iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode); |
|
865 #if defined (__SCALING_PROFILING) |
|
866 RDebug::ProfileEnd(8); |
|
867 #endif // __SCALING_PROFILING |
|
868 } |
|
869 else |
|
870 { |
|
871 #if defined (__SCALING_PROFILING) |
|
872 RDebug::ProfileStart(11); |
|
873 #endif // __SCALING_PROFILING |
|
874 // Get the vertical scan line... |
|
875 iScaleBitmap->GetVerticalScanLine(iOrigDes, iCurOffset, iLocalDisplayMode); |
|
876 #if defined (__SCALING_PROFILING) |
|
877 RDebug::ProfileEnd(11); |
|
878 #endif // __SCALING_PROFILING |
|
879 } |
|
880 |
|
881 if (!(iFlags & EVerticalScan)) |
|
882 { |
|
883 // Scale the scan line horizontally |
|
884 for (TInt i=0; i < iComponentsPerPixel; i++) |
|
885 { |
|
886 ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTable, iFilterCoeffsTable); |
|
887 } |
|
888 } |
|
889 else |
|
890 { |
|
891 // |
|
892 // Scale vertically |
|
893 for (TInt i=0; i < iComponentsPerPixel; i++) |
|
894 { |
|
895 ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTable, iFilterCoeffsTable); |
|
896 } |
|
897 } |
|
898 |
|
899 #if defined (__SCALING_PROFILING) |
|
900 RDebug::ProfileStart(10); |
|
901 #endif //__SCALING_PROFILING |
|
902 |
|
903 if (!(iFlags & EVerticalScan)) |
|
904 { |
|
905 // Set the scaled horizontal line back into the bitmap |
|
906 iScaleBitmap->SetScanLine(iDestDes, iCurOffset); |
|
907 } |
|
908 else |
|
909 { |
|
910 // Write to output bitmap |
|
911 // Lock & unlock the heap to prevent the Font & Bitmap server moving the bitmap around |
|
912 // Now writing to iScaleBitmap |
|
913 if (iDestBmpPtr->DisplayMode()==EColor16MA && iLocalDisplayMode==EColor16MA) |
|
914 { |
|
915 TUint8* dataAddress = reinterpret_cast<TUint8*>( iDestBmpPtr->DataAddress()); |
|
916 dataAddress +=iCurOffset*iComponentsPerPixel; |
|
917 const TInt scanLineLength = iDestBmpPtr->ScanLineLength(iDestBmpPtr->SizeInPixels().iWidth, iDestBmpPtr->DisplayMode() ); |
|
918 |
|
919 const TInt limit = iDestSize.iHeight * iComponentsPerPixel; |
|
920 const TUint8* ptr = iDestDes.Ptr(); |
|
921 for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength) |
|
922 { |
|
923 CopyPixel(dataAddress,ptr); |
|
924 ptr += iComponentsPerPixel; |
|
925 } |
|
926 } |
|
927 else |
|
928 { |
|
929 TUint8* dataAddress = reinterpret_cast<TUint8*>( iScanlineBitmap->DataAddress()); |
|
930 ASSERT( iScanlineBitmap->SizeInPixels().iWidth==1 ); // that must be a "column" |
|
931 const TInt scanLineLength = iScanlineBitmap->ScanLineLength(1, iScanlineBitmap->DisplayMode() ); |
|
932 |
|
933 const TInt limit = iDestSize.iHeight * iComponentsPerPixel; |
|
934 const TUint8* ptr = iDestDes.Ptr(); |
|
935 for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength) |
|
936 { |
|
937 CopyPixel(dataAddress, ptr); |
|
938 ptr += iComponentsPerPixel; |
|
939 } |
|
940 |
|
941 iGc->BitBlt(TPoint(iCurOffset, 0), iScanlineBitmap); |
|
942 } |
|
943 } |
|
944 |
|
945 #if defined (__SCALING_PROFILING) |
|
946 RDebug::ProfileEnd(10); |
|
947 #endif //__SCALING_PROFILING |
|
948 |
|
949 linesLeftPerCall--; |
|
950 iCurOffset++; |
|
951 } |
|
952 |
|
953 if ( IsScalingComplete() && !(iFlags & EVerticalScan)) |
|
954 { |
|
955 iCurLineSize = iOrigSize.iHeight; |
|
956 iCurOffset = 0; |
|
957 iFinalOffset = iDestSize.iWidth; |
|
958 iFlags |= EVerticalScan; |
|
959 // Finished the horizontal scaling so now need to setup descriptors |
|
960 // for the intermediate size as we're now longer using an intermediate |
|
961 // bitmap. |
|
962 iOrigSize = iIntermediateSize; |
|
963 |
|
964 User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) ); |
|
965 iOrigDes.SetLength(0); |
|
966 |
|
967 TInt allocErr = AllocPtr(iOrigDes, iOrigSize.iHeight * iComponentsPerPixel); |
|
968 if( allocErr != KErrNone ) |
|
969 { |
|
970 ProcessError( allocErr ); |
|
971 return; |
|
972 } |
|
973 |
|
974 User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) ); |
|
975 iDestDes.SetLength(0); |
|
976 |
|
977 allocErr = AllocPtr(iDestDes, iDestSize.iHeight * iComponentsPerPixel); |
|
978 if( allocErr != KErrNone ) |
|
979 { |
|
980 ProcessError( allocErr ); |
|
981 return; |
|
982 } |
|
983 iFilterIndexTablePtr = iFilterIndexTable; |
|
984 iFilterCoeffsTablePtr = iFilterCoeffsTable; |
|
985 TInt err = CalcFilterTables(iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTablePtr, iFilterCoeffsTablePtr); |
|
986 if( err != KErrNone ) |
|
987 { |
|
988 ProcessError(err); |
|
989 return; |
|
990 } |
|
991 } |
|
992 else if ( IsScalingComplete() ) |
|
993 { |
|
994 // Finished the vertical scaling so, as the tgtbitmap has been scaled in place (ie |
|
995 // to the intermediate size) we need to resize it to the true destination size |
|
996 TInt err = iTgtBitmap->Resize(iDestSize); |
|
997 if( err != KErrNone ) |
|
998 { |
|
999 ProcessError(err); |
|
1000 return; |
|
1001 } |
|
1002 |
|
1003 if( IsPostProcessingNeeded() ) |
|
1004 { |
|
1005 //[ transition to start post processing state] |
|
1006 SetCurrentState( EStartPostProcessState ); |
|
1007 } |
|
1008 else |
|
1009 { |
|
1010 //[ transition to cleanup state ] |
|
1011 SetCurrentState( ECleanUpState ); |
|
1012 } |
|
1013 } |
|
1014 |
|
1015 // Start the active object |
|
1016 SelfComplete(KErrNone); |
|
1017 |
|
1018 #if defined (__SCALING_PROFILING) |
|
1019 RDebug::ProfileEnd(7); |
|
1020 #endif // __SCALING_PROFILING |
|
1021 |
|
1022 //[ assert invariant ] |
|
1023 ASSERT( InVariant() ); |
|
1024 } |
|
1025 |
|
1026 /* |
|
1027 * |
|
1028 * StartPostProcessing |
|
1029 * |
|
1030 */ |
|
1031 void CBitmapScalerPlugin::StartPostProcessing() |
|
1032 { |
|
1033 ASSERT( InVariant() ); |
|
1034 ASSERT( GetCurrentState() == EStartPostProcessState ); |
|
1035 // set state to post processing in progress |
|
1036 // lauch async post process operation |
|
1037 SetCurrentState(ECleanUpState); |
|
1038 |
|
1039 iBitmapConverter->Convert( &iStatus, *iTgtBitmap, *iDestBmpPtr); |
|
1040 |
|
1041 SetActive(); |
|
1042 ASSERT( InVariant() ); |
|
1043 ASSERT( GetCurrentState() == ECleanUpState ); |
|
1044 } |
|
1045 |
|
1046 /* |
|
1047 * |
|
1048 * GetCurrentState |
|
1049 * @return CBitmapScalerPlugin::TScaleState The current state |
|
1050 * of the state machine |
|
1051 * |
|
1052 */ |
|
1053 CBitmapScalerPlugin::TScaleState CBitmapScalerPlugin::GetCurrentState() const |
|
1054 { |
|
1055 return iCurrentState; |
|
1056 } |
|
1057 |
|
1058 /* |
|
1059 * |
|
1060 * SetCurrentState |
|
1061 * @param aState |
|
1062 * @pre aState <= CleanUpState |
|
1063 * @pre aState >= InactiveState |
|
1064 * @post Invariant |
|
1065 * |
|
1066 */ |
|
1067 void CBitmapScalerPlugin::SetCurrentState( TScaleState aState ) |
|
1068 { |
|
1069 iCurrentState = aState; |
|
1070 } |
|
1071 |
|
1072 /* |
|
1073 * |
|
1074 * CleanUp |
|
1075 * |
|
1076 */ |
|
1077 void CBitmapScalerPlugin::ScaleCleanUp() |
|
1078 { |
|
1079 TInt errStatus = iStatus.Int(); |
|
1080 |
|
1081 if( errStatus == KErrNone ) |
|
1082 { |
|
1083 if ((iFlags & ECreatedTempBitmap) != 0) |
|
1084 { |
|
1085 if (iTempBitmap) |
|
1086 { |
|
1087 TInt handle = 0; |
|
1088 if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) |
|
1089 { |
|
1090 // medium OR min qualitity algorithm |
|
1091 handle = iDestBmpPtr->Handle(); |
|
1092 } |
|
1093 else |
|
1094 { |
|
1095 // Normal (maximum quality) algorithm |
|
1096 handle = iTgtBitmap->Handle(); |
|
1097 } |
|
1098 errStatus = iSrcBitmap->Duplicate(handle); |
|
1099 } |
|
1100 } |
|
1101 } |
|
1102 |
|
1103 ProcessError( errStatus ); |
|
1104 } |
|
1105 |
|
1106 /* |
|
1107 * |
|
1108 * ProcessError |
|
1109 * @param aErrorStatus |
|
1110 * |
|
1111 */ |
|
1112 void CBitmapScalerPlugin::ProcessError( TInt aErrorStatus ) |
|
1113 { |
|
1114 if( iPostProcessBitmap ) |
|
1115 { |
|
1116 iPostProcessBitmap->Reset(); |
|
1117 } |
|
1118 Cleanup(); |
|
1119 RequestComplete( aErrorStatus ); |
|
1120 } |
|
1121 |
|
1122 /* |
|
1123 * |
|
1124 * IsScalingComplete |
|
1125 * @return TBool scaling process has been completed |
|
1126 * |
|
1127 */ |
|
1128 TBool CBitmapScalerPlugin::IsScalingComplete() const |
|
1129 { |
|
1130 TBool result = EFalse ; |
|
1131 if(iCurOffset == iFinalOffset || iCurOffsetUp == 0) |
|
1132 { |
|
1133 result = ETrue; |
|
1134 } |
|
1135 return result; |
|
1136 } |
|
1137 |
|
1138 /* |
|
1139 * |
|
1140 * RunL |
|
1141 * Handles an active object’s request completion event. |
|
1142 * The function is called by the active scheduler |
|
1143 * when a request completion event occurs. |
|
1144 */ |
|
1145 void CBitmapScalerPlugin::RunL() |
|
1146 { |
|
1147 DoScale(); |
|
1148 } |
|
1149 |
|
1150 /* |
|
1151 * |
|
1152 * DoCancel |
|
1153 * Called by active object to prematurely terminate this bitmap scaling. |
|
1154 * |
|
1155 */ |
|
1156 void CBitmapScalerPlugin::DoCancel() |
|
1157 { |
|
1158 ASSERT( InVariant()); |
|
1159 |
|
1160 if( iBitmapConverter ) |
|
1161 { |
|
1162 iBitmapConverter->Cancel(); |
|
1163 } |
|
1164 |
|
1165 Cleanup(); |
|
1166 ASSERT( GetCurrentState() == EInactiveState ); |
|
1167 ASSERT( InVariant()); |
|
1168 RequestComplete(KErrCancel); |
|
1169 } |
|
1170 |
|
1171 /* |
|
1172 * |
|
1173 * RequestComplete |
|
1174 * @param "TInt aReason" |
|
1175 * |
|
1176 */ |
|
1177 void CBitmapScalerPlugin::RequestComplete(TInt aReason) |
|
1178 { |
|
1179 ASSERT(iScaleStatus); |
|
1180 TRequestStatus* status = iScaleStatus; |
|
1181 User::RequestComplete(status, aReason); |
|
1182 } |
|
1183 |
|
1184 /* |
|
1185 * |
|
1186 * SelfComplete |
|
1187 * This function activates the active object and |
|
1188 * signals completion of the current asynchronous operation |
|
1189 * |
|
1190 * @param "TInt aReason" |
|
1191 * |
|
1192 */ |
|
1193 void CBitmapScalerPlugin::SelfComplete(TInt aReason) |
|
1194 { |
|
1195 SetActive(); |
|
1196 TRequestStatus* status = &iStatus; |
|
1197 User::RequestComplete(status, aReason); |
|
1198 } |
|
1199 |
|
1200 /* |
|
1201 * |
|
1202 * This function calculates the filter tables for scaling |
|
1203 * CalcFilterTables |
|
1204 * @param "TInt aOrigWidth" |
|
1205 * @param "TInt aDestWidth" |
|
1206 * @param "TInt*& aFilterCoeffsTablePtr" |
|
1207 * |
|
1208 */ |
|
1209 TInt CBitmapScalerPlugin::CalcFilterTables(TInt aOrigWidth, TInt aDestWidth, TInt*& aFilterIndexTablePtr, TInt*& aFilterCoeffsTablePtr) |
|
1210 { |
|
1211 TInt inputWidth = aOrigWidth; |
|
1212 TInt scaledWidth = aDestWidth; |
|
1213 //this is added since to test indX<< KFixedPointBits for overflow |
|
1214 TInt fixedPointsVal = 1<<KFixedPointBits; |
|
1215 |
|
1216 if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth)) > KMaxTInt ) |
|
1217 { |
|
1218 return KErrOverflow; |
|
1219 } |
|
1220 //Checking OverFlow for ((indX << KFixedPointBits) * inputWidth) |
|
1221 if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth) * MAKE_TUINT64(0,fixedPointsVal)) > KMaxTInt ) |
|
1222 { |
|
1223 return KErrOverflow; |
|
1224 } |
|
1225 if ( scaledWidth > inputWidth ) |
|
1226 { |
|
1227 // Calculate tables for interpolation (scaling up) |
|
1228 for (TInt indX = 0; indX < scaledWidth; indX++) |
|
1229 { |
|
1230 const TInt indFilt = ((indX << KFixedPointBits) * inputWidth) / scaledWidth; |
|
1231 const TInt firstX = indFilt >> KFixedPointBits; |
|
1232 const TInt lastX = (firstX >= inputWidth - 1) ? firstX : firstX+1; |
|
1233 |
|
1234 *aFilterIndexTablePtr++ = firstX; |
|
1235 *aFilterIndexTablePtr++ = lastX; |
|
1236 *aFilterCoeffsTablePtr++ = indFilt - (firstX << KFixedPointBits); |
|
1237 } |
|
1238 } |
|
1239 else |
|
1240 { |
|
1241 // Calculate tables for decimation (scaling down) |
|
1242 const TInt ftNew = (inputWidth << KFixedPointBits)/scaledWidth; |
|
1243 TInt firstX = 0; |
|
1244 TInt lastX = 0; |
|
1245 for (TInt indX = 0; indX < scaledWidth; indX++) |
|
1246 { |
|
1247 firstX = lastX; |
|
1248 lastX = ((indX + 1) * inputWidth) / scaledWidth; |
|
1249 |
|
1250 *aFilterIndexTablePtr++ = firstX; |
|
1251 *aFilterIndexTablePtr++ = lastX; |
|
1252 |
|
1253 const TInt indOrig = ((indX << KFixedPointBits) * inputWidth) / scaledWidth; |
|
1254 const TInt indOrigInt = indOrig >> KFixedPointBits; |
|
1255 for (TInt indFilt = firstX; indFilt <= lastX; indFilt++) |
|
1256 { |
|
1257 TInt fixTap; |
|
1258 if(indFilt <= indOrigInt) |
|
1259 { |
|
1260 fixTap = ftNew - (indOrig - (indFilt << KFixedPointBits)); |
|
1261 } |
|
1262 else |
|
1263 { |
|
1264 fixTap = ftNew - ((indFilt << KFixedPointBits) - indOrig); |
|
1265 } |
|
1266 |
|
1267 if (fixTap < 0) |
|
1268 { |
|
1269 fixTap = 0; |
|
1270 } |
|
1271 *aFilterCoeffsTablePtr++ = (fixTap << KFixedPointBits) / ftNew; |
|
1272 } |
|
1273 } |
|
1274 } |
|
1275 return KErrNone; |
|
1276 } |
|
1277 |
|
1278 |
|
1279 /* |
|
1280 * This function calculates the filter tables for scaling |
|
1281 * ScaleLine |
|
1282 * @param "const TDesC8& aInDes" |
|
1283 * @param "TDes8& aOutDes" |
|
1284 * @param "TInt* aTableCoeffsPtr" |
|
1285 * |
|
1286 */ |
|
1287 void CBitmapScalerPlugin::ScaleLine(const TDesC8& aInDes, |
|
1288 TDes8& aOutDes, |
|
1289 TInt aStartIndex, |
|
1290 TInt aInputWidth, |
|
1291 TInt aOutputWidth, |
|
1292 TInt* aTableIndexPtr, TInt* aTableCoeffsPtr) |
|
1293 { |
|
1294 #if defined (__SCALING_PROFILING) |
|
1295 RDebug::ProfileStart(9); |
|
1296 #endif // __SCALING_PROFILING |
|
1297 |
|
1298 // Initialize variables |
|
1299 TInt* tableIndexesPtr = aTableIndexPtr; |
|
1300 TInt* tableCoeffsPtr = aTableCoeffsPtr; |
|
1301 |
|
1302 if (aOutputWidth == aInputWidth) |
|
1303 { |
|
1304 aOutDes = aInDes; |
|
1305 } |
|
1306 else if (aOutputWidth > aInputWidth) |
|
1307 { |
|
1308 // Perform interpolation when scaling up |
|
1309 const TInt startIndex = aStartIndex; |
|
1310 const TUint8* inputDesPtr = aInDes.Ptr(); |
|
1311 TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() ); |
|
1312 |
|
1313 for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel) |
|
1314 { |
|
1315 TInt firstX = *tableIndexesPtr++; |
|
1316 TInt lastX = *tableIndexesPtr++; |
|
1317 TInt fixTap = *tableCoeffsPtr++; |
|
1318 |
|
1319 // Stay in bounds |
|
1320 if (firstX >= aInputWidth) |
|
1321 { |
|
1322 firstX = aInputWidth - 1; |
|
1323 } |
|
1324 // Factor for aggregated colour component |
|
1325 firstX *= iComponentsPerPixel; |
|
1326 firstX += startIndex; |
|
1327 |
|
1328 // Stay in bounds |
|
1329 if (lastX >= aInputWidth) |
|
1330 { |
|
1331 lastX = aInputWidth - 1; |
|
1332 } |
|
1333 lastX *= iComponentsPerPixel; |
|
1334 lastX += startIndex; |
|
1335 |
|
1336 // Filtering |
|
1337 outputDesPtr[aStartIndex] = |
|
1338 TUint8(((fixTap * TInt(inputDesPtr[lastX])+ |
|
1339 (KFixedPointScale - fixTap) * TInt(inputDesPtr[firstX])) |
|
1340 >> KFixedPointBits)); |
|
1341 } |
|
1342 } |
|
1343 else |
|
1344 { |
|
1345 // Perform decimation if scaling down requested |
|
1346 const TInt startIndex = aStartIndex; |
|
1347 const TInt widthLimit = iComponentsPerPixel * aInputWidth; |
|
1348 const TInt16 startWidthlimit = widthLimit - iComponentsPerPixel + startIndex; |
|
1349 const TUint8* inputDesPtr = aInDes.Ptr(); |
|
1350 TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() ); |
|
1351 |
|
1352 for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel) |
|
1353 { |
|
1354 TInt firstX = *tableIndexesPtr++; |
|
1355 firstX *= iComponentsPerPixel; |
|
1356 firstX += startIndex; |
|
1357 |
|
1358 TInt lastX = *tableIndexesPtr++; |
|
1359 if (lastX >= aInputWidth) |
|
1360 { |
|
1361 lastX = aInputWidth - 1; |
|
1362 } |
|
1363 lastX *= iComponentsPerPixel; |
|
1364 lastX += startIndex; |
|
1365 |
|
1366 // Filtering |
|
1367 TInt sum = 0; |
|
1368 TInt fixTapSum = 0; |
|
1369 for(TInt indFilt = firstX; indFilt <= lastX; indFilt += iComponentsPerPixel) |
|
1370 { |
|
1371 TInt fixTap = *tableCoeffsPtr++; |
|
1372 TInt indIn; |
|
1373 if (indFilt < 0) |
|
1374 { |
|
1375 indIn = startIndex; |
|
1376 } |
|
1377 else if (indFilt >= widthLimit ) |
|
1378 { |
|
1379 indIn = startWidthlimit; |
|
1380 } |
|
1381 else |
|
1382 { |
|
1383 indIn = indFilt; |
|
1384 } |
|
1385 |
|
1386 sum += fixTap * TInt(inputDesPtr[indIn]); |
|
1387 fixTapSum = TInt(fixTapSum + fixTap); |
|
1388 } |
|
1389 |
|
1390 // Let's not divide by zero |
|
1391 if (fixTapSum == 0) |
|
1392 { |
|
1393 outputDesPtr[aStartIndex] = TUint8(sum); |
|
1394 } |
|
1395 else |
|
1396 { |
|
1397 outputDesPtr[aStartIndex] = TUint8(sum/fixTapSum); |
|
1398 } |
|
1399 } |
|
1400 } |
|
1401 #if defined (__SCALING_PROFILING) |
|
1402 RDebug::ProfileEnd(9); |
|
1403 #endif // __SCALING_PROFILING |
|
1404 } |
|
1405 |
|
1406 |
|
1407 /* |
|
1408 * |
|
1409 * InVariant |
|
1410 * Used to determine the state of health of the scaler body |
|
1411 * |
|
1412 */ |
|
1413 TBool CBitmapScalerPlugin::InVariant() const |
|
1414 { |
|
1415 return ((iCurrentState <= ECleanUpState ) && (iCurrentState >= EInactiveState )); |
|
1416 } |
|
1417 |
|
1418 /** |
|
1419 * |
|
1420 * SetProcessingNeeded |
|
1421 * @param aStatus ETrue EFalse |
|
1422 * |
|
1423 */ |
|
1424 void CBitmapScalerPlugin::SetProcessingNeeded( TBool aStatus ) |
|
1425 { |
|
1426 if(aStatus) |
|
1427 { |
|
1428 iFlags |= EIsPostProcessingNeeded; |
|
1429 } |
|
1430 else |
|
1431 { |
|
1432 iFlags &= ~EIsPostProcessingNeeded; |
|
1433 } |
|
1434 } |
|
1435 |
|
1436 /** |
|
1437 * |
|
1438 * SetDisablePostProcessing |
|
1439 * @param aStatus ETrue EFalse |
|
1440 * |
|
1441 */ |
|
1442 void CBitmapScalerPlugin::SetDisablePostProcessing( TBool aIsDisabled ) |
|
1443 { |
|
1444 if(aIsDisabled) |
|
1445 { |
|
1446 iFlags |= EDisablePostProcessing; |
|
1447 } |
|
1448 else |
|
1449 { |
|
1450 iFlags &= ~EDisablePostProcessing; |
|
1451 } |
|
1452 } |
|
1453 |
|
1454 /** |
|
1455 * |
|
1456 * IsPostProcessingDisabled |
|
1457 * @return ETrue, EFalse |
|
1458 * |
|
1459 */ |
|
1460 TBool CBitmapScalerPlugin::IsPostProcessingDisabled() |
|
1461 { |
|
1462 return ((iFlags & EDisablePostProcessing) != 0); |
|
1463 } |
|
1464 |
|
1465 /** |
|
1466 * |
|
1467 * IsPostProcessingNeeded |
|
1468 * @return TBool scaling process has been completed |
|
1469 * |
|
1470 */ |
|
1471 TBool CBitmapScalerPlugin::IsPostProcessingNeeded() const |
|
1472 { |
|
1473 return ((iFlags & EIsPostProcessingNeeded) != 0); |
|
1474 } |
|
1475 |
|
1476 /* |
|
1477 * |
|
1478 * HeightAndWidthPreservingAspectRatio |
|
1479 * @param aDestSize |
|
1480 * @param aOrigSize |
|
1481 * Calculates the destination bitmap size based on preserving |
|
1482 * the aspect ratio of the original bitmap |
|
1483 * @pre aOrigSize is not zero in any dimension |
|
1484 */ |
|
1485 void CBitmapScalerPlugin::HeightAndWidthPreservingAspectRatio( TSize& aDestSize, const TSize& aOrigSize ) const |
|
1486 { |
|
1487 |
|
1488 if ((aOrigSize.iWidth == 0) || (aOrigSize.iHeight == 0)) |
|
1489 { |
|
1490 return; |
|
1491 } |
|
1492 |
|
1493 // no need to optimise, it is not a kernal function which may get called many times |
|
1494 TReal widthRatio = (TReal)aDestSize.iWidth / (TReal)aOrigSize.iWidth; |
|
1495 TReal heightRatio = (TReal)aDestSize.iHeight / (TReal)aOrigSize.iHeight; |
|
1496 |
|
1497 // choose the smaller ratio to use |
|
1498 if(widthRatio < heightRatio) |
|
1499 { |
|
1500 TReal height; |
|
1501 Math::Round(height, aOrigSize.iHeight * widthRatio, 0); |
|
1502 aDestSize.iHeight = static_cast<TInt>(height); |
|
1503 } |
|
1504 else |
|
1505 { |
|
1506 TReal width; |
|
1507 Math::Round(width, aOrigSize.iWidth * heightRatio, 0); |
|
1508 aDestSize.iWidth = static_cast<TInt>(width); |
|
1509 } |
|
1510 } |
|
1511 |
|
1512 /* |
|
1513 * |
|
1514 * IsPostProcessingEnabled |
|
1515 * @return 'TBool' |
|
1516 * |
|
1517 */ |
|
1518 TBool CBitmapScalerPlugin::IsPostProcessingEnabled() const |
|
1519 { |
|
1520 return ((iFlags & EPostProcessingEnabled) != 0); |
|
1521 } |
|
1522 |
|
1523 /* |
|
1524 * |
|
1525 * SetPostProcessingEnabled |
|
1526 * @param aIsEnabled |
|
1527 * |
|
1528 */ |
|
1529 void CBitmapScalerPlugin::SetPostProcessingEnabled( TBool aIsEnabled ) |
|
1530 { |
|
1531 if(aIsEnabled) |
|
1532 { |
|
1533 iFlags |= EPostProcessingEnabled; |
|
1534 } |
|
1535 else |
|
1536 { |
|
1537 iFlags &= ~EPostProcessingEnabled; |
|
1538 } |
|
1539 } |
|
1540 |
|
1541 /* |
|
1542 * |
|
1543 * CustomCommand |
|
1544 * @param aUid |
|
1545 * @param aParam |
|
1546 * @return 'TInt' an error code indicating success or failure of the |
|
1547 * command |
|
1548 * |
|
1549 */ |
|
1550 TInt CBitmapScalerPlugin::CustomCommand(TUid aUid, TAny* aParam) |
|
1551 { |
|
1552 TInt status = KErrNotSupported; |
|
1553 if( ( aUid == KICLUidPostProcessCommand ) && ( aParam != NULL ) ) |
|
1554 { |
|
1555 TBool postProcess = *( reinterpret_cast<TBool*>(aParam)); |
|
1556 SetDisablePostProcessing( postProcess ); |
|
1557 status = KErrNone; |
|
1558 } |
|
1559 else if( ( aUid == KICLUidUseLowMemoryAlgorithmCommand ) && ( aParam != NULL ) ) |
|
1560 { |
|
1561 TBool useLowMemAlgorithm = *( reinterpret_cast<TBool*>(aParam) ); |
|
1562 SetUseLowMemoryAlgorithm( useLowMemAlgorithm ); |
|
1563 status = KErrNone; |
|
1564 } |
|
1565 else if( ( aUid == KICLUidSetQualityAlgorithmCommand ) && ( aParam != NULL ) ) |
|
1566 { |
|
1567 CBitmapScaler::TQualityAlgorithm quality = *( reinterpret_cast<CBitmapScaler::TQualityAlgorithm*>(aParam) ); |
|
1568 SetQualityAlgorithm(quality); |
|
1569 status = KErrNone; |
|
1570 } |
|
1571 |
|
1572 return status; |
|
1573 } |
|
1574 |
|
1575 /* |
|
1576 * |
|
1577 * UseLowMemoryAlgorithm |
|
1578 * @return 'TBool' |
|
1579 * |
|
1580 */ |
|
1581 TBool CBitmapScalerPlugin::UseLowMemoryAlgorithm() const |
|
1582 { |
|
1583 return ((iFlags & EUseLowMemoryAlgorithm) != 0); |
|
1584 } |
|
1585 |
|
1586 /* |
|
1587 * |
|
1588 * SetUseLowMemoryAlgorithm |
|
1589 * @param aUseLowMemoryAlgorithm |
|
1590 * |
|
1591 */ |
|
1592 void CBitmapScalerPlugin::SetUseLowMemoryAlgorithm(TBool aUseLowMemoryAlgorithm) |
|
1593 { |
|
1594 if(aUseLowMemoryAlgorithm) |
|
1595 { |
|
1596 iFlags |= EUseLowMemoryAlgorithm; |
|
1597 } |
|
1598 else |
|
1599 { |
|
1600 iFlags &= ~EUseLowMemoryAlgorithm; |
|
1601 } |
|
1602 } |
|
1603 |
|
1604 /* |
|
1605 * |
|
1606 * SetQualityAlgorithm |
|
1607 * @param CBitmapScaler::TQualityAlgorithm aQuality |
|
1608 * |
|
1609 */ |
|
1610 void CBitmapScalerPlugin::SetQualityAlgorithm( CBitmapScaler::TQualityAlgorithm aQuality) |
|
1611 { |
|
1612 iQualityLevel = aQuality; |
|
1613 } |
|
1614 |
|
1615 /* |
|
1616 * |
|
1617 * QualityAlgorithm |
|
1618 * @return CBitmapScaler::TQualityAlgorithm |
|
1619 * |
|
1620 */ |
|
1621 CBitmapScaler::TQualityAlgorithm CBitmapScalerPlugin::QualityAlgorithm() const |
|
1622 { |
|
1623 return iQualityLevel; |
|
1624 } |
|
1625 |
|
1626 /** |
|
1627 * This function is called when the state iCurrentState == EScalingState |
|
1628 * and either the UseMediumQualityAlgorithm or the UseMinimumQualityAlgorithm custom |
|
1629 * commands have been invoked. |
|
1630 * In terms of speed and quality, the normal algorithm, as implemented in Scale(), |
|
1631 * is the slowest / highest quality, whereas the fastest / lowest quality |
|
1632 * implementation is for the case when UseMinimumQualityAlgorithm is specified. |
|
1633 * The difference between the minimum quality and fast algorithms is that |
|
1634 * the fast algorithm forms the destination value from weighted averages of |
|
1635 * the x values prior to and proceeding the value under consideration. |
|
1636 */ |
|
1637 void CBitmapScalerPlugin::FastScale() |
|
1638 { |
|
1639 #if defined (__SCALING_PROFILING) |
|
1640 RDebug::ProfileStart(7); |
|
1641 #endif // __SCALING_PROFILING |
|
1642 TInt linesLeftPerCall = KLinesPerCall; |
|
1643 |
|
1644 // Height and width to scale to |
|
1645 const TInt maxX = iDestSize.iWidth * iComponentsPerPixel; |
|
1646 const TInt stepY = (iOrigSize.iHeight << KFixedPointScale) / iDestSize.iHeight; |
|
1647 const TInt destBufferLength = iDestDes.Length(); |
|
1648 const TInt divisor = (destBufferLength < iDestSize.iWidth ? destBufferLength : iDestSize.iWidth); |
|
1649 const TInt stepX = (iOrigSize.iWidth << KFixedPointScale) / divisor; |
|
1650 TInt sourceX = 0; // x |
|
1651 const TInt roundVal = 1; |
|
1652 if (iDestSize == iOrigSize) |
|
1653 { |
|
1654 // Same size so just directly copy values. |
|
1655 while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset) |
|
1656 { |
|
1657 iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode); |
|
1658 iDestBmpPtr->SetScanLine(iOrigDes, iCurOffset); |
|
1659 linesLeftPerCall--; |
|
1660 iCurOffset++; |
|
1661 } |
|
1662 } |
|
1663 else if (iDestSize.iHeight < iOrigSize.iHeight) |
|
1664 { |
|
1665 TInt currentX = 0; |
|
1666 // For downscaling (destination bitmap size is smaller than the original bitmap size) |
|
1667 while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset) |
|
1668 { |
|
1669 sourceX = 0; |
|
1670 // Fetch the relevant row from the source bitmap |
|
1671 iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode); |
|
1672 |
|
1673 // Get each colour component of each relevant pixel |
|
1674 for (TInt x = 0; x < maxX; x += iComponentsPerPixel) |
|
1675 { |
|
1676 //Line scaling |
|
1677 ScaleBitmapLine(x,sourceX); |
|
1678 // Increment to the next pixel |
|
1679 currentX += stepX; |
|
1680 // Avoid TInt rounding error |
|
1681 sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale; |
|
1682 // Factor for the number of components |
|
1683 sourceX *= iComponentsPerPixel; |
|
1684 // Stay in bounds |
|
1685 if (sourceX >= iOrigDes.Length()) |
|
1686 { |
|
1687 sourceX = iOrigDes.Length() - iComponentsPerPixel; |
|
1688 } |
|
1689 } |
|
1690 currentX = 0; // reset the x counter |
|
1691 iDestBmpPtr->SetScanLine(iDestDes, iCurOffset); // set the scaled line into the target |
|
1692 |
|
1693 // increment to the next row |
|
1694 iCurY += stepY; |
|
1695 // avoiding any rounding errors (using TInt = (TInt + 0.5) ) |
|
1696 iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale; |
|
1697 // Stay in bounds |
|
1698 if (iSrcY >= iOrigSize.iHeight) |
|
1699 { |
|
1700 iSrcY = iOrigSize.iHeight - 1; |
|
1701 } |
|
1702 linesLeftPerCall--; |
|
1703 iCurOffset++; |
|
1704 } |
|
1705 } |
|
1706 else |
|
1707 { |
|
1708 TInt currentX = 0; |
|
1709 //For upscaling (Destination bitmap size is bigger than the original bitmap size) |
|
1710 while(linesLeftPerCall > 0 && iCurOffsetUp !=0 ) |
|
1711 { |
|
1712 sourceX = 0; |
|
1713 // avoiding any rounding errors (using TInt = (TInt + 0.5) ) |
|
1714 iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale; |
|
1715 // Fetch the relevant row from the source bitmap |
|
1716 iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode); |
|
1717 |
|
1718 // Get each colour component of each relevant pixel |
|
1719 for (TInt x = 0; x < maxX; x += iComponentsPerPixel) |
|
1720 { |
|
1721 //Line scaling |
|
1722 ScaleBitmapLine(x,sourceX); |
|
1723 // Increment to the next pixel |
|
1724 currentX += stepX; |
|
1725 // Avoid TInt rounding error |
|
1726 sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale; |
|
1727 // Factor for the number of components |
|
1728 sourceX *= iComponentsPerPixel; |
|
1729 // Stay in bounds |
|
1730 if (sourceX >= iOrigDes.Length()) |
|
1731 { |
|
1732 sourceX = iOrigDes.Length() - iComponentsPerPixel; |
|
1733 } |
|
1734 } |
|
1735 currentX = 0; // reset the x counter |
|
1736 iDestBmpPtr->SetScanLine(iDestDes, iCurOffsetUp); // set the scaled line into the target |
|
1737 // Decrement to the next row from the end |
|
1738 iCurY -= stepY; |
|
1739 // Stay in bounds |
|
1740 if (iSrcY >= iOrigSize.iHeight) |
|
1741 { |
|
1742 iSrcY = iOrigSize.iHeight - 1; |
|
1743 } |
|
1744 linesLeftPerCall--; |
|
1745 iCurOffsetUp--; |
|
1746 } |
|
1747 } |
|
1748 if (IsScalingComplete()) |
|
1749 { |
|
1750 // in case of low memory algo and 1 bitmap we have to resize the resulting bitmap |
|
1751 if (iDestBmpPtr->Handle() == iSrcBitmap->Handle() |
|
1752 && iDestBmpPtr->SizeInPixels() != iDestSize ) |
|
1753 { |
|
1754 TInt err=iDestBmpPtr->Resize(iDestSize); |
|
1755 if (err != KErrNone) |
|
1756 { |
|
1757 ProcessError( err ); |
|
1758 return; |
|
1759 } |
|
1760 } |
|
1761 if( IsPostProcessingNeeded() ) |
|
1762 { |
|
1763 //[ transition to start post processing state] |
|
1764 SetCurrentState( EStartPostProcessState ); |
|
1765 } |
|
1766 else |
|
1767 { |
|
1768 //[ transition to cleanup state ] |
|
1769 SetCurrentState( ECleanUpState ); |
|
1770 } |
|
1771 } |
|
1772 // Start the active object |
|
1773 SelfComplete(KErrNone); |
|
1774 #if defined (__SCALING_PROFILING) |
|
1775 RDebug::ProfileEnd(7); |
|
1776 #endif // __SCALING_PROFILING |
|
1777 } |
|
1778 |
|
1779 /* |
|
1780 * |
|
1781 * ScaleBitmapLine |
|
1782 * @param aX |
|
1783 * @param aSourceX |
|
1784 * |
|
1785 */ |
|
1786 void CBitmapScalerPlugin::ScaleBitmapLine(TInt aX,TInt aSourceX) |
|
1787 { |
|
1788 TUint8* destDesPtr = const_cast<TUint8*>( iDestDes.Ptr() ); |
|
1789 const TUint8* orgDesPtr = iOrigDes.Ptr(); |
|
1790 |
|
1791 if (QualityAlgorithm() == CBitmapScaler::EMinimumQuality) |
|
1792 { |
|
1793 CopyPixel(destDesPtr + aX,orgDesPtr + aSourceX); |
|
1794 } |
|
1795 else // must be CBitmapScaler::EMediumQuality |
|
1796 { |
|
1797 // Better quality |
|
1798 TInt nextValue = 0; |
|
1799 TInt prevValue = 0; |
|
1800 TInt value = 0; |
|
1801 // eg weightedAv. = (w1*v1 + w2*v2 + w3*v3) / (w1 + w2 + w3) |
|
1802 // so if w1=w3=8 and w2=16 |
|
1803 // (v1 * 2<<3 + v2 * 2<<4 + v3 * 2<<3) >> 2 * 5 |
|
1804 const TInt minorShift = 3; // prev and next value weighting |
|
1805 const TInt majorShift = 4; // current value weighting |
|
1806 const TInt backShift = 5; // average |
|
1807 |
|
1808 for (TInt i = 0; i < iComponentsPerPixel; i++) |
|
1809 { |
|
1810 // Get the previous value |
|
1811 TInt index = aSourceX - iComponentsPerPixel; |
|
1812 if (index < 0) |
|
1813 { |
|
1814 index = i; |
|
1815 } |
|
1816 else |
|
1817 { |
|
1818 index += i; |
|
1819 } |
|
1820 prevValue = TInt(orgDesPtr[index]); |
|
1821 |
|
1822 // Weight the previous value |
|
1823 prevValue = prevValue << minorShift; |
|
1824 // Get the next value |
|
1825 index = aSourceX; |
|
1826 if (index + iComponentsPerPixel >= iOrigDes.Length()) |
|
1827 { |
|
1828 index += i; |
|
1829 } |
|
1830 else |
|
1831 { |
|
1832 index += (i + iComponentsPerPixel); |
|
1833 } |
|
1834 nextValue = TInt(orgDesPtr[index]); |
|
1835 |
|
1836 // Weight the next value |
|
1837 nextValue = nextValue << minorShift; |
|
1838 // Weight the current value |
|
1839 value = TInt(orgDesPtr[aSourceX+ i]); |
|
1840 |
|
1841 value = value << majorShift; |
|
1842 // Sum all values |
|
1843 value += prevValue; |
|
1844 value += nextValue; |
|
1845 // Average |
|
1846 value = value >> backShift; |
|
1847 destDesPtr[aX + i] = TUint8(value); |
|
1848 } |
|
1849 } |
|
1850 } |
|
1851 |