|
1 /* |
|
2 * Copyright (c) 2006-2007 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: Task for scaling thumbnails. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <fbs.h> |
|
21 #include <e32math.h> |
|
22 #include <bitdev.h> |
|
23 #include <bitstd.h> |
|
24 |
|
25 #include "thumbnailscaletask.h" |
|
26 #include "thumbnailprovider.h" |
|
27 #include "thumbnailserver.h" |
|
28 #include "thumbnailmanagerconstants.h" |
|
29 #include "thumbnaillog.h" |
|
30 #include "thumbnailpanic.h" |
|
31 |
|
32 |
|
33 // ======== MEMBER FUNCTIONS ======== |
|
34 |
|
35 // --------------------------------------------------------------------------- |
|
36 // CThumbnailScaleTask::NewL() |
|
37 // Two-phased constructor. |
|
38 // --------------------------------------------------------------------------- |
|
39 // |
|
40 CThumbnailScaleTask* CThumbnailScaleTask::NewL( CThumbnailTaskProcessor& |
|
41 aProcessor, CThumbnailServer& aServer, const TDesC& aFilename, CFbsBitmap* |
|
42 aBitmap, const TSize& aOriginalSize, const TSize& aTargetSize, TBool aCrop, |
|
43 TDisplayMode aDisplayMode, TInt aPriority, const TDesC& aTargetUri, |
|
44 const TThumbnailSize aThumbnailSize, const TThumbnailId aThumbnailId, |
|
45 TBool aBitmapToPool, const TBool aEXIF) |
|
46 { |
|
47 // We take ownership of aBitmap |
|
48 CleanupStack::PushL( aBitmap ); |
|
49 CThumbnailScaleTask* self = new( ELeave )CThumbnailScaleTask( aProcessor, |
|
50 aServer, aFilename, aBitmap, aOriginalSize, aTargetSize, aCrop, |
|
51 aDisplayMode, aPriority, aTargetUri, aThumbnailSize, aThumbnailId, |
|
52 aBitmapToPool, aEXIF); |
|
53 CleanupStack::Pop( aBitmap ); |
|
54 CleanupStack::PushL( self ); |
|
55 self->ConstructL(); |
|
56 CleanupStack::Pop( self ); |
|
57 return self; |
|
58 } |
|
59 |
|
60 |
|
61 // --------------------------------------------------------------------------- |
|
62 // CThumbnailScaleTask::CThumbnailScaleTask() |
|
63 // C++ default constructor can NOT contain any code, that might leave. |
|
64 // --------------------------------------------------------------------------- |
|
65 // |
|
66 CThumbnailScaleTask::CThumbnailScaleTask( CThumbnailTaskProcessor& aProcessor, |
|
67 CThumbnailServer& aServer, const TDesC& aFilename, CFbsBitmap* aBitmap, |
|
68 const TSize& aOriginalSize, const TSize& aTargetSize, TBool aCrop, |
|
69 TDisplayMode aDisplayMode, TInt aPriority, const TDesC& aTargetUri, |
|
70 const TThumbnailSize aThumbnailSize, const TThumbnailId aThumbnailId, |
|
71 TBool aBitmapToPool, const TBool aEXIF): |
|
72 CThumbnailTask( aProcessor, aPriority ), iServer( aServer ), iOwnBitmap( aBitmap ), |
|
73 iOriginalSize( aOriginalSize ), iTargetSize( aTargetSize ), iCrop( aCrop ), |
|
74 iDisplayMode( aDisplayMode ), iFilename( aFilename ), iTargetUri( aTargetUri ), |
|
75 iThumbnailSize(aThumbnailSize), iThumbnailId(aThumbnailId), |
|
76 iBitmapToPool(aBitmapToPool), iEXIF(aEXIF) |
|
77 { |
|
78 TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::CThumbnailScaleTask()", this ); |
|
79 } |
|
80 |
|
81 |
|
82 // --------------------------------------------------------------------------- |
|
83 // CThumbnailScaleTask::ConstructL() |
|
84 // Symbian 2nd phase constructor can leave. |
|
85 // --------------------------------------------------------------------------- |
|
86 // |
|
87 void CThumbnailScaleTask::ConstructL() |
|
88 { |
|
89 iServer.AddBitmapToPoolL( NULL, iOwnBitmap ); |
|
90 |
|
91 // Successfully added bitmap to pool, we are no longer responsible for |
|
92 // deleting it directly. |
|
93 iBitmap = iOwnBitmap; |
|
94 iOwnBitmap = NULL; |
|
95 iBitmapInPool = ETrue; |
|
96 |
|
97 iScaledBitmap = NULL; |
|
98 iScaledBitmapHandle = 0; |
|
99 } |
|
100 |
|
101 |
|
102 // --------------------------------------------------------------------------- |
|
103 // CThumbnailScaleTask::~CThumbnailScaleTask() |
|
104 // Destructor. |
|
105 // --------------------------------------------------------------------------- |
|
106 // |
|
107 CThumbnailScaleTask::~CThumbnailScaleTask() |
|
108 { |
|
109 iServer.CancelScale(); |
|
110 |
|
111 if ( iBitmapInPool && iBitmap ) |
|
112 { |
|
113 TN_DEBUG1("CThumbnailScaleTask()::~CThumbnailScaleTask() delete original bitmap from pool"); |
|
114 |
|
115 // Original bitmap is owned by server, decrease reference count |
|
116 iServer.DeleteBitmapFromPool( iBitmap->Handle()); |
|
117 } |
|
118 |
|
119 if ( iScaledBitmapHandle ) |
|
120 { |
|
121 TN_DEBUG1("CThumbnailScaleTask()::~CThumbnailScaleTask() delete scaled bitmap from pool"); |
|
122 |
|
123 // Scaled bitmap is owned by server, decrease reference count |
|
124 iServer.DeleteBitmapFromPool( iScaledBitmapHandle ); |
|
125 } |
|
126 |
|
127 // Scaled bitmap is owned by us, delete now |
|
128 delete iScaledBitmap; |
|
129 } |
|
130 |
|
131 |
|
132 // --------------------------------------------------------------------------- |
|
133 // CThumbnailScaleTask::StartL() |
|
134 // --------------------------------------------------------------------------- |
|
135 // |
|
136 void CThumbnailScaleTask::StartL() |
|
137 { |
|
138 TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL()", this ); |
|
139 |
|
140 CThumbnailTask::StartL(); |
|
141 |
|
142 if ( !iCrop ) |
|
143 { |
|
144 // target size at max, keep aspect ratio |
|
145 CalculateTargetSize(); |
|
146 } |
|
147 else |
|
148 { |
|
149 // exact target size, crop excess |
|
150 CalculateCropRectangle(); |
|
151 } |
|
152 |
|
153 #ifdef _DEBUG |
|
154 aStart.UniversalTime(); |
|
155 #endif |
|
156 |
|
157 delete iScaledBitmap; |
|
158 iScaledBitmap = NULL; |
|
159 iScaledBitmap = new( ELeave )CFbsBitmap(); |
|
160 |
|
161 TSize bitmapSize = iBitmap->SizeInPixels(); |
|
162 |
|
163 if(bitmapSize.iHeight == iTargetSize.iHeight && bitmapSize.iWidth == iTargetSize.iWidth) |
|
164 { |
|
165 // copy bitmap 1:1 |
|
166 User::LeaveIfError( iScaledBitmap->Create( bitmapSize, iBitmap->DisplayMode() )); |
|
167 CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(iScaledBitmap); |
|
168 CleanupStack::PushL(device); |
|
169 CFbsBitGc* gc = NULL; |
|
170 User::LeaveIfError(device->CreateContext(gc)); |
|
171 CleanupStack::PushL(gc); |
|
172 gc->BitBlt(TPoint(0, 0), iBitmap); |
|
173 CleanupStack::PopAndDestroy(2, device); // gc |
|
174 |
|
175 TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL() - no need for scaling", this); |
|
176 TRAPD( err, StoreAndCompleteL()); |
|
177 Complete( err ); |
|
178 ResetMessageData(); |
|
179 } |
|
180 else |
|
181 { |
|
182 TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::StartL() - scaling", this); |
|
183 User::LeaveIfError( iScaledBitmap->Create( iTargetSize, iBitmap->DisplayMode() )); |
|
184 iServer.ScaleBitmapL( iStatus, * iBitmap, * iScaledBitmap, iCropRectangle ); |
|
185 SetActive(); |
|
186 } |
|
187 |
|
188 } |
|
189 |
|
190 |
|
191 // --------------------------------------------------------------------------- |
|
192 // CThumbnailScaleTask::RunL() |
|
193 // --------------------------------------------------------------------------- |
|
194 // |
|
195 void CThumbnailScaleTask::RunL() |
|
196 { |
|
197 TInt err = iStatus.Int(); |
|
198 |
|
199 TN_DEBUG3( "CThumbnailScaleTask(0x%08x)::RunL() err=%d)", this, err ); |
|
200 |
|
201 #ifdef _DEBUG |
|
202 aStop.UniversalTime(); |
|
203 TN_DEBUG2( "CThumbnailScaleTask::RunL() scale took %d ms", (TInt)aStop.MicroSecondsFrom(aStart).Int64()/1000); |
|
204 #endif |
|
205 |
|
206 if ( !err ) |
|
207 { |
|
208 TRAP( err, StoreAndCompleteL()); |
|
209 } |
|
210 |
|
211 Complete( err ); |
|
212 ResetMessageData(); |
|
213 } |
|
214 |
|
215 |
|
216 // --------------------------------------------------------------------------- |
|
217 // CThumbnailScaleTask::DoCancel() |
|
218 // --------------------------------------------------------------------------- |
|
219 // |
|
220 void CThumbnailScaleTask::DoCancel() |
|
221 { |
|
222 TN_DEBUG2( "CThumbnailScaleTask(0x%08x)::DoCancel()", this ); |
|
223 iServer.CancelScale(); |
|
224 } |
|
225 |
|
226 |
|
227 // --------------------------------------------------------------------------- |
|
228 // Calculates target size to be used for the thumbnail |
|
229 // --------------------------------------------------------------------------- |
|
230 // |
|
231 void CThumbnailScaleTask::CalculateTargetSize() |
|
232 { |
|
233 __ASSERT_DEBUG( iOriginalSize.iHeight && iTargetSize.iHeight, |
|
234 ThumbnailPanic( EThumbnailBadSize )); |
|
235 |
|
236 if ( (iThumbnailSize == EFullScreenThumbnailSize || |
|
237 iThumbnailSize == EImageFullScreenThumbnailSize || |
|
238 iThumbnailSize == EVideoFullScreenThumbnailSize || |
|
239 iThumbnailSize == EAudioFullScreenThumbnailSize) && |
|
240 iOriginalSize.iHeight < iTargetSize.iHeight && |
|
241 iOriginalSize.iWidth < iTargetSize.iWidth ) |
|
242 { |
|
243 // do not upscale fullscreen thumbs |
|
244 iTargetSize = iOriginalSize; |
|
245 } |
|
246 else if ( iOriginalSize.iHeight && iTargetSize.iHeight ) |
|
247 { |
|
248 const TReal32 srcAspect = static_cast < TReal32 > ( |
|
249 iOriginalSize.iWidth ) / iOriginalSize.iHeight; |
|
250 |
|
251 // scale to maximum size within target size |
|
252 if ( (iTargetSize.iHeight * srcAspect) <= iTargetSize.iWidth ) |
|
253 { |
|
254 TReal trg = 0; |
|
255 TReal src( iTargetSize.iHeight * srcAspect ); |
|
256 Math::Round( trg, src, 0 ); |
|
257 iTargetSize.SetSize( trg, iTargetSize.iHeight ); |
|
258 } |
|
259 else |
|
260 { |
|
261 TReal trg; |
|
262 TReal src( iTargetSize.iWidth / srcAspect ); |
|
263 Math::Round( trg, src, 0 ); |
|
264 iTargetSize.SetSize( iTargetSize.iWidth, trg ); |
|
265 } |
|
266 } |
|
267 else |
|
268 { |
|
269 iTargetSize.SetSize( 0, 0 ); |
|
270 } |
|
271 iCropRectangle.SetRect( TPoint(), iBitmap->SizeInPixels()); |
|
272 } |
|
273 |
|
274 |
|
275 // --------------------------------------------------------------------------- |
|
276 // Calculates target size to be used for the thumbnail |
|
277 // --------------------------------------------------------------------------- |
|
278 // |
|
279 void CThumbnailScaleTask::CalculateCropRectangle() |
|
280 { |
|
281 const TSize srcSize = iBitmap->SizeInPixels(); |
|
282 |
|
283 __ASSERT_DEBUG( srcSize.iHeight && iTargetSize.iHeight, ThumbnailPanic( |
|
284 EThumbnailBadSize )); |
|
285 |
|
286 if ( srcSize.iHeight && iTargetSize.iHeight ) |
|
287 { |
|
288 const TReal32 srcAspect = static_cast < TReal32 > ( srcSize.iWidth ) / |
|
289 srcSize.iHeight; |
|
290 const TReal32 reqAspect = static_cast < TReal32 > ( iTargetSize.iWidth ) |
|
291 / iTargetSize.iHeight; |
|
292 |
|
293 if ( (iTargetSize.iHeight * srcAspect) > iTargetSize.iWidth ) |
|
294 { |
|
295 // Thumbnail is wider than requested and we crop |
|
296 // some of the right and left parts. |
|
297 TReal trg; |
|
298 TReal src( srcSize.iHeight* reqAspect ); |
|
299 Math::Round( trg, src, 0 ); |
|
300 const TSize cropSize( trg, srcSize.iHeight ); |
|
301 iCropRectangle.iTl.SetXY(( srcSize.iWidth - cropSize.iWidth ) / 2, 0 ); |
|
302 iCropRectangle.SetSize( cropSize ); |
|
303 } |
|
304 else |
|
305 { |
|
306 // Thumbnail is taller than requested and we crop |
|
307 // some of the top and bottom parts. |
|
308 TReal trg; |
|
309 TReal src( srcSize.iWidth / reqAspect ); |
|
310 Math::Round( trg, src, 0 ); |
|
311 const TSize cropSize( srcSize.iWidth, trg ); |
|
312 iCropRectangle.iTl.SetXY(0, ( srcSize.iHeight - cropSize.iHeight ) / 2 ); |
|
313 iCropRectangle.SetSize( cropSize ); |
|
314 } |
|
315 |
|
316 } |
|
317 else |
|
318 { |
|
319 iTargetSize.SetSize( 0, 0 ); |
|
320 } |
|
321 } |
|
322 |
|
323 // --------------------------------------------------------------------------- |
|
324 // CThumbnailScaleTask::StoreAndCompleteL() |
|
325 // --------------------------------------------------------------------------- |
|
326 // |
|
327 void CThumbnailScaleTask::StoreAndCompleteL() |
|
328 { |
|
329 TN_DEBUG5( "CThumbnailScaleTask(0x%08x)::StoreAndCompleteL() iFilename=%S, iBitmap=0x%08x, iScaledBitmap=0x%08x)", |
|
330 this, &iFilename, iBitmap, iScaledBitmap ); |
|
331 |
|
332 // do not store TN if quality is too low eg. orignal size of image is smaller than requested size |
|
333 // (do not store upscaled images) |
|
334 if ( iTargetSize.iWidth >= iOriginalSize.iWidth && |
|
335 iTargetSize.iHeight >= iOriginalSize.iHeight && iEXIF) |
|
336 { |
|
337 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() too low quality"); |
|
338 //don't store preview image |
|
339 iDoStore = EFalse; |
|
340 } |
|
341 |
|
342 TN_DEBUG3("CThumbnailScaleTask(0x%08x)::StoreAndCompleteL() iDoStore = %d", this, iDoStore); |
|
343 |
|
344 if ( iDoStore ) |
|
345 { |
|
346 if (iTargetUri != KNullDesC) |
|
347 { |
|
348 if (iFilename != KNullDesC && iFilename.CompareF(iTargetUri) == 0) |
|
349 { |
|
350 // filename and target URI match, so thumb created from associated path |
|
351 iServer.StoreThumbnailL( iTargetUri, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, ETrue ); |
|
352 } |
|
353 else |
|
354 { |
|
355 // thumb not created from associated path |
|
356 iServer.StoreThumbnailL( iTargetUri, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, EFalse, EFalse ); |
|
357 } |
|
358 } |
|
359 else if (iFilename != KNullDesC) |
|
360 { |
|
361 iServer.StoreThumbnailL( iFilename, iScaledBitmap, iOriginalSize, iCrop, iThumbnailSize, iThumbnailId, ETrue ); |
|
362 } |
|
363 } |
|
364 |
|
365 if ( iMessage.Handle() ) |
|
366 { |
|
367 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() scaled bitmap handle to params"); |
|
368 |
|
369 TThumbnailRequestParams& params = iParamsBuf(); |
|
370 iMessage.ReadL( 0, iParamsBuf ); |
|
371 params.iBitmapHandle = iScaledBitmap->Handle(); |
|
372 |
|
373 // if need to add scaled bitmap to pool |
|
374 if (iBitmapToPool) |
|
375 { |
|
376 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() scaled bitmap to pool"); |
|
377 |
|
378 iServer.AddBitmapToPoolL( iRequestId.iSession, iScaledBitmap ); |
|
379 iScaledBitmapHandle = params.iBitmapHandle; |
|
380 } |
|
381 |
|
382 if( params.iQualityPreference == CThumbnailManager::EOptimizeForQualityWithPreview |
|
383 && iEXIF && !iDoStore) |
|
384 { |
|
385 // this is upscaled preview image |
|
386 params.iControlFlags = EThumbnailPreviewThumbnail; |
|
387 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() EThumbnailPreviewThumbnail"); |
|
388 } |
|
389 |
|
390 // Server owns the bitmap now. If the code below leaves, we will |
|
391 // release the bitmap reference in destructor using iScaledBitmapHandle. |
|
392 if (iBitmapToPool) |
|
393 { |
|
394 iScaledBitmap = NULL; |
|
395 } |
|
396 |
|
397 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() write params to message"); |
|
398 |
|
399 // pass bitmap handle to client |
|
400 iMessage.WriteL( 0, iParamsBuf ); |
|
401 |
|
402 // Successfully completed the message. The client will send |
|
403 // EReleaseBitmap message later to delete the bitmap from pool. |
|
404 // CThumbnailScaleTask is no longer responsible for that. |
|
405 iScaledBitmapHandle = 0; |
|
406 } |
|
407 |
|
408 TN_DEBUG1("CThumbnailScaleTask()::StoreAndCompleteL() - end"); |
|
409 } |
|
410 |
|
411 |
|
412 // --------------------------------------------------------------------------- |
|
413 // CThumbnailScaleTask::StoreAndCompleteL() |
|
414 // Changes priority of the task. |
|
415 // --------------------------------------------------------------------------- |
|
416 // |
|
417 void CThumbnailScaleTask::ChangeTaskPriority( TInt /*aNewPriority*/ ) |
|
418 { |
|
419 // The priority of scale tasks is fixed. Do nothing. |
|
420 } |
|
421 |
|
422 // --------------------------------------------------------------------------- |
|
423 // CThumbnailScaleTask::SetDoStore() |
|
424 // Changes the store flag |
|
425 // --------------------------------------------------------------------------- |
|
426 // |
|
427 void CThumbnailScaleTask::SetDoStore( TBool aDoStore ) |
|
428 { |
|
429 iDoStore = aDoStore; |
|
430 } |