|
1 // Copyright (c) 2001-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 "ImageConversion.h" |
|
17 #include "ImageClientMain.h" |
|
18 |
|
19 // BUFFERED IMAGE DECODER |
|
20 |
|
21 /** |
|
22 Creates a buffered decoder. |
|
23 |
|
24 The function leaves if the decoder object cannot be created or initialised. |
|
25 |
|
26 @param aFs |
|
27 A reference to a file server session for the decoder to use. |
|
28 |
|
29 @return A pointer to the newly created decoder. |
|
30 */ |
|
31 EXPORT_C CBufferedImageDecoder* CBufferedImageDecoder::NewL(RFs& aFs) |
|
32 { |
|
33 CBufferedImageDecoder* self = new (ELeave) CBufferedImageDecoder(aFs); |
|
34 return self; |
|
35 } |
|
36 |
|
37 /** |
|
38 Creates a decoder for the image in the source buffer. The client supplies |
|
39 a MIME type which will be used to try and select an appropriate plugin |
|
40 decoder. If it finds a decoder it creates it and then goes on to use that |
|
41 decoder to scan the beginning of the image file. |
|
42 |
|
43 @param aSourceData |
|
44 The buffer containing the image to be decoded. |
|
45 @param aMIMEType |
|
46 The MIME type of the image in the buffer. |
|
47 @param aOptions |
|
48 The options to use. |
|
49 |
|
50 @leave KEComErrNoInterfaceIdentified |
|
51 No plugin decoder could be found for the specified image. |
|
52 */ |
|
53 EXPORT_C void CBufferedImageDecoder::OpenL(const TDesC8& aSourceData, const TDesC8& aMIMEType, const CImageDecoder::TOptions aOptions) |
|
54 { |
|
55 __ASSERT_ALWAYS(iState == EStateCreated, Panic(EInvalidState)); |
|
56 |
|
57 ASSERT(iMimeType.Ptr() == NULL); |
|
58 const TInt mimeLength = aMIMEType.Length(); |
|
59 TUint8* ptr = STATIC_CAST(TUint8*, User::AllocL(mimeLength)); |
|
60 iMimeType.Set(ptr, mimeLength, mimeLength); |
|
61 iMimeType.Copy(aMIMEType); |
|
62 |
|
63 iOptions = aOptions; |
|
64 iImageTypeOpen = EFalse; |
|
65 |
|
66 AppendDataL(aSourceData); |
|
67 |
|
68 iState = EStateOpening; |
|
69 |
|
70 ContinueOpenL(); |
|
71 |
|
72 } |
|
73 |
|
74 /** |
|
75 Creates a decoder for the image in the source buffer. |
|
76 |
|
77 If the client supplies an image type (and sub-type, if applicable) or decoder uid, these will be |
|
78 used to try and select an appropriate plugin decoder. If not, then the selection |
|
79 will be done by matching the image header from the buffer. If it finds a decoder |
|
80 it creates it and then goes on to use that decoder to scan the beginning of |
|
81 the image buffer. If a decoder could not be created append data using AppendDataL() |
|
82 and call ContinueOpenL(). |
|
83 |
|
84 @param aSourceData |
|
85 The buffer containing the image to be decoded. |
|
86 @param aOptions |
|
87 The decoder options to use. |
|
88 @param aImageType |
|
89 The image type of the image in the file (optional). |
|
90 @param aImageSubType |
|
91 The image sub-type of the image in the file (optional). |
|
92 @param aDecoderUid |
|
93 The implementation UID for a specific codec or a decoder/encoder class UID (optional, defaults to KNullUid). |
|
94 If this option is selected for a specific codec the image type and image sub type for the displayer must be supplied. |
|
95 When loading plugins by class UID the image type and image subtype are not mandatory and the first valid plugin from |
|
96 the list of available plugins with the specified class UID will be loaded. |
|
97 @see KUidICLJpegEXIFInterface |
|
98 @see KUidICLJpegImageFrameInterface |
|
99 @leave KErrUnderflow |
|
100 Not enough data in descriptor to identify which plugin decoder to use. |
|
101 @leave KEComErrNoInterfaceIdentified |
|
102 No plugin decoder could be found for the specified image. |
|
103 @leave KErrNotFound |
|
104 The specified codec could not be found. |
|
105 */ |
|
106 EXPORT_C void CBufferedImageDecoder::OpenL(const TDesC8& aSourceData, const CImageDecoder::TOptions aOptions, const TUid aImageType, const TUid aImageSubType, const TUid aDecoderUid) |
|
107 { |
|
108 __ASSERT_ALWAYS(iState == EStateCreated,Panic(EInvalidState)); |
|
109 |
|
110 iOptions = aOptions; |
|
111 iImageType = aImageType; |
|
112 iImageSubType = aImageSubType; |
|
113 iDecoderUid = aDecoderUid; |
|
114 iImageTypeOpen = ETrue; |
|
115 |
|
116 AppendDataL(aSourceData); |
|
117 |
|
118 iState = EStateOpening; |
|
119 |
|
120 ContinueOpenL(); |
|
121 } |
|
122 |
|
123 /** |
|
124 Call this function to retry to create a decoder after OpenL() returned with |
|
125 KErrUnderFlow and extra data was added to the descriptor using AppendDataL(). |
|
126 This function can be recalled until ValidDecoder() return ETrue. |
|
127 |
|
128 @leave KErrUnderflow |
|
129 Not enough data in descriptor to identify which plugin decoder to use. |
|
130 */ |
|
131 EXPORT_C void CBufferedImageDecoder::ContinueOpenL() |
|
132 { |
|
133 |
|
134 __ASSERT_ALWAYS(iState == EStateOpening, Panic(EInvalidState)); |
|
135 TInt error = KErrNone; |
|
136 |
|
137 if(!ValidDecoder()) |
|
138 { |
|
139 if(iImageTypeOpen) |
|
140 { |
|
141 TRAP(error, iDecoder = CImageDecoder::DataNewL(iFileSession, iBuffer, iOptions, iImageType, iImageSubType, iDecoderUid)); |
|
142 } |
|
143 else |
|
144 { |
|
145 TRAP(error, iDecoder = CImageDecoder::DataNewL(iFileSession, iBuffer, iMimeType, iOptions)); |
|
146 } |
|
147 } |
|
148 |
|
149 if(error != KErrNone) |
|
150 { |
|
151 if(error != KErrUnderflow) |
|
152 User::Leave(error); |
|
153 } |
|
154 else |
|
155 iState = EStateOpen; |
|
156 |
|
157 } |
|
158 |
|
159 /** |
|
160 Destructor for this class. |
|
161 |
|
162 Stops decoding if it is in progress and frees all resources owned by the object prior to its destruction. |
|
163 */ |
|
164 EXPORT_C CBufferedImageDecoder::~CBufferedImageDecoder() |
|
165 { |
|
166 Cancel(); |
|
167 Reset(); |
|
168 ASSERT(iDecoder == NULL); // make sure decoder is deleted |
|
169 } |
|
170 |
|
171 /** |
|
172 Starts decoding an image frame asynchronously. |
|
173 |
|
174 When converting the operation can complete with KErrUnderflow, if there is insufficient |
|
175 information in the descriptor. In this situation, ContinueConvert() should be called repeatedly |
|
176 until the descriptor has accumulated enough information for ContinueConvert() to complete with KErrNone. |
|
177 |
|
178 @param aRequestStatus |
|
179 The request status. On completion contains an error code. |
|
180 KErrNone if frame was decoded successfully, |
|
181 KErrUnderflow if the frame was partially decoded |
|
182 otherwise another of the system-wide error codes. |
|
183 @param aDestination |
|
184 A bitmap that will contain the decoded frame. The bitmap |
|
185 must be created before the call and must be large enough |
|
186 for the frame and set to the required display mode. |
|
187 FrameInfo() can be used to obtain the size and display mode |
|
188 of the frame. |
|
189 @param aFrameNumber |
|
190 The frame in multi-frame image to decode (optional). |
|
191 */ |
|
192 EXPORT_C void CBufferedImageDecoder::Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, TInt aFrameNumber) |
|
193 { |
|
194 __ASSERT_ALWAYS(iState == EStateOpen || iState == EStateConverting, Panic(EInvalidState)); |
|
195 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
196 iDecoder->Convert(aRequestStatus, aDestination, aFrameNumber); |
|
197 iState = EStateConverting; |
|
198 } |
|
199 |
|
200 /** |
|
201 Starts decoding an image frame and mask asynchronously. |
|
202 |
|
203 When converting the operation can complete with KErrUnderflow, if there is insufficient |
|
204 information in the descriptor. In this situation, ContinueConvert() should be called repeatedly |
|
205 until the descriptor has accumulated enough information for ContinueConvert() to complete with KErrNone. |
|
206 |
|
207 @param aRequestStatus |
|
208 The request status. On completion contains an error code. |
|
209 KErrNone if frame was decoded successfully, |
|
210 KErrUnderflow if the frame was partially decoded |
|
211 otherwise another of the system-wide error codes. |
|
212 @param aDestination |
|
213 A bitmap that will contain the decoded frame. The bitmap |
|
214 must be created before the call and must be large enough |
|
215 for the frame and set to the required display mode. |
|
216 FrameInfo() can be used to obtain the size and display mode |
|
217 of the frame. |
|
218 @param aDestinationMask |
|
219 A bitmap that will contain the decoded frame mask. The bitmap |
|
220 must be created before the call and must be large enough |
|
221 for the mask. The display mode must be EGray2 or EGray256 and |
|
222 must be EGray256 if the image contains alpha-blending information. |
|
223 This information can be obtained from the iFlags property and |
|
224 TFrameInfoFlags of TFrameInfo |
|
225 obtained from a FrameInfo() call. |
|
226 @param aFrameNumber |
|
227 The frame in multi-frame image to decode (optional). |
|
228 */ |
|
229 EXPORT_C void CBufferedImageDecoder::Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, CFbsBitmap& aDestinationMask, TInt aFrameNumber) |
|
230 { |
|
231 __ASSERT_ALWAYS(iState == EStateOpen || iState == EStateConverting, Panic(EInvalidState)); |
|
232 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
233 iDecoder->Convert(aRequestStatus, aDestination, aDestinationMask, aFrameNumber); |
|
234 iState = EStateConverting; |
|
235 } |
|
236 |
|
237 /** |
|
238 Continues decoding a frame and/or mask after new image data was added to |
|
239 the source file or descriptor and a previous call to Convert() or |
|
240 ContinueConvert() returned KErrUnderflow. |
|
241 |
|
242 @param aRequestStatus |
|
243 The request status. On completion contains an error code. |
|
244 KErrNone if frame was decoded successfully, |
|
245 KErrUnderflow if the frame was partially decoded |
|
246 otherwise another of the system-wide error codes. |
|
247 */ |
|
248 EXPORT_C void CBufferedImageDecoder::ContinueConvert(TRequestStatus* aRequestStatus) |
|
249 { |
|
250 __ASSERT_ALWAYS(iState == EStateConverting, Panic(EInvalidState)); |
|
251 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
252 iDecoder->ContinueConvert(aRequestStatus); |
|
253 } |
|
254 |
|
255 /** |
|
256 Reset the decoder for reuse. |
|
257 |
|
258 Follow this call with OpenL() and new source data. |
|
259 */ |
|
260 EXPORT_C void CBufferedImageDecoder::Reset() |
|
261 { |
|
262 delete iDecoder; iDecoder = NULL; |
|
263 User::Free(STATIC_CAST(TAny*,CONST_CAST(TUint8*,iBuffer.Ptr()))); |
|
264 iBuffer.Set(NULL, 0 ,0); |
|
265 User::Free(STATIC_CAST(TAny*,CONST_CAST(TUint8*,iMimeType.Ptr()))); |
|
266 iMimeType.Set(NULL, 0 ,0); |
|
267 iImageType = KNullUid; |
|
268 iImageSubType = KNullUid; |
|
269 iDecoderUid = KNullUid; |
|
270 iOptions = CImageDecoder::EOptionNone; |
|
271 iState = EStateCreated; |
|
272 } |
|
273 |
|
274 /** |
|
275 Requests an asynchronous decode to terminate. |
|
276 |
|
277 Cancels any conversions currently in progress. |
|
278 */ |
|
279 EXPORT_C void CBufferedImageDecoder::Cancel() |
|
280 { |
|
281 if(iDecoder) |
|
282 iDecoder->Cancel(); |
|
283 } |
|
284 |
|
285 /** |
|
286 Adds new image data. |
|
287 |
|
288 A copy of the data is held internally, and the caller does not need to retain the data. |
|
289 |
|
290 @param aData |
|
291 The new image data to append. |
|
292 */ |
|
293 EXPORT_C void CBufferedImageDecoder::AppendDataL(const TDesC8& aData) |
|
294 { |
|
295 // Resize the buffer |
|
296 TInt oldLength = iBuffer.Length(); |
|
297 TInt newLength = oldLength + aData.Length(); |
|
298 |
|
299 if(iBuffer.Ptr() == NULL) |
|
300 { |
|
301 TUint8* ptr = STATIC_CAST(TUint8*,User::AllocL(newLength)); |
|
302 iBuffer.Set(ptr, newLength, newLength); |
|
303 iBuffer.Copy(aData); |
|
304 } |
|
305 |
|
306 if(iBuffer.MaxLength() < newLength) |
|
307 { |
|
308 TAny* oldBuffer = STATIC_CAST(TAny*, CONST_CAST(TUint8*, iBuffer.Ptr())); |
|
309 TUint8* newBuffer = STATIC_CAST(TUint8*, User::ReAllocL(oldBuffer,newLength)); |
|
310 iBuffer.Set(newBuffer,oldLength, newLength); |
|
311 iBuffer.Append(aData); |
|
312 } |
|
313 } |
|
314 |
|
315 /** |
|
316 Returns the number of frames in the image being decoded. This function can |
|
317 be called immediately after the call to create the decoder, thus enabling |
|
318 the caller to know how many frames need to be converted. |
|
319 |
|
320 @return The number of frames. |
|
321 */ |
|
322 EXPORT_C TInt CBufferedImageDecoder::FrameCount() const |
|
323 { |
|
324 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
325 return iDecoder->FrameCount(); |
|
326 } |
|
327 /** |
|
328 Returns the status of the image. |
|
329 |
|
330 If the image is incomplete or not terminated correctly EFalse will be returned |
|
331 |
|
332 @return A boolean indicating the image status. Returns ETrue if image header processing is complete, |
|
333 otherwise EFalse. |
|
334 */ |
|
335 EXPORT_C TBool CBufferedImageDecoder::IsImageHeaderProcessingComplete() const |
|
336 { |
|
337 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
338 return iDecoder->IsImageHeaderProcessingComplete(); |
|
339 } |
|
340 |
|
341 /** |
|
342 Continues processing image headers after new image data was appended. |
|
343 |
|
344 This function can be called until IsImageHeaderProcessingComplete() |
|
345 return ETrue. |
|
346 */ |
|
347 EXPORT_C void CBufferedImageDecoder::ContinueProcessingHeaderL() |
|
348 { |
|
349 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
350 iDecoder->ContinueProcessingHeaderL(); |
|
351 } |
|
352 |
|
353 /** |
|
354 Returns the frame info for a specified frame of the image. |
|
355 |
|
356 This function can be called immediately after the call to create the decoder, thus enabling |
|
357 the caller to know about each frame in advance of converting it. |
|
358 |
|
359 @param aFrameNumber |
|
360 The frame number. |
|
361 |
|
362 @return The information for the specified frame. |
|
363 */ |
|
364 EXPORT_C const TFrameInfo& CBufferedImageDecoder::FrameInfo(TInt aFrameNumber) const |
|
365 { |
|
366 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
367 return iDecoder->FrameInfo(aFrameNumber); |
|
368 } |
|
369 |
|
370 /** |
|
371 Returns the image data for a specific frame. |
|
372 |
|
373 Use FrameCount() to determine how many frames are contained in the image before using this function. |
|
374 |
|
375 @param aFrameNumber |
|
376 The frame number for which to return frame data. |
|
377 |
|
378 @return The data for the specified frame. |
|
379 */ |
|
380 EXPORT_C const CFrameImageData& CBufferedImageDecoder::FrameData(TInt aFrameNumber) const |
|
381 { |
|
382 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
383 return iDecoder->FrameData(aFrameNumber); |
|
384 } |
|
385 /** |
|
386 Returns the number of comments attached to the image (as opposed to |
|
387 a particular frame). |
|
388 |
|
389 @return The number of comments attached to the image. |
|
390 */ |
|
391 EXPORT_C TInt CBufferedImageDecoder::NumberOfImageComments() const |
|
392 { |
|
393 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
394 return iDecoder->NumberOfImageComments(); |
|
395 } |
|
396 |
|
397 /** |
|
398 Returns a particular comment attached to the image. |
|
399 Ownership of the returned buffer is transferred to the caller. |
|
400 |
|
401 Use NumberOfImageComments() to determine how many (if any) comments are contained within the image. |
|
402 |
|
403 @param aCommentNumber |
|
404 The comment number. |
|
405 |
|
406 @return A buffer containing the comment. |
|
407 */ |
|
408 EXPORT_C HBufC* CBufferedImageDecoder::ImageCommentL(TInt aCommentNumber) const |
|
409 { |
|
410 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
411 return iDecoder->ImageCommentL(aCommentNumber); |
|
412 } |
|
413 |
|
414 /** |
|
415 Returns the number of comments attached to a given frame of the image |
|
416 as opposed to the whole image. |
|
417 |
|
418 Use FrameCount() to retrieve the number of frames in the image to ensure that the value you use for |
|
419 aFrameNumber is valid. |
|
420 |
|
421 @param aFrameNumber |
|
422 The frame number. |
|
423 |
|
424 @return The number of comments attached to a given frame of the image. |
|
425 */ |
|
426 EXPORT_C TInt CBufferedImageDecoder::NumberOfFrameComments(TInt aFrameNumber) const |
|
427 { |
|
428 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
429 return iDecoder->NumberOfFrameComments(aFrameNumber); |
|
430 } |
|
431 |
|
432 /** |
|
433 Returns a particular comment attached to a given frame of the image. |
|
434 Ownership of the returned buffer is transferred to the caller. |
|
435 |
|
436 @param aFrameNumber |
|
437 The frame number. |
|
438 @param aCommentNumber |
|
439 The comment number. |
|
440 |
|
441 @return A buffer containing the comment. |
|
442 */ |
|
443 EXPORT_C HBufC* CBufferedImageDecoder::FrameCommentL(TInt aFrameNumber, TInt aCommentNumber) const |
|
444 { |
|
445 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
446 return iDecoder->FrameCommentL(aFrameNumber, aCommentNumber); |
|
447 } |
|
448 |
|
449 /** |
|
450 Returns the formatted frame information strings for a specific frame |
|
451 and leave it on the cleanup stack. |
|
452 |
|
453 Ownership is transferred to the caller. |
|
454 |
|
455 @param aFrameNumber |
|
456 The frame number. |
|
457 |
|
458 @return The formatted frame information strings. |
|
459 */ |
|
460 EXPORT_C CFrameInfoStrings* CBufferedImageDecoder::FrameInfoStringsLC(TInt aFrameNumber) |
|
461 { |
|
462 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
463 return iDecoder->FrameInfoStringsLC(aFrameNumber); |
|
464 } |
|
465 |
|
466 /** |
|
467 Returns the formatted frame information strings for a specific frame. |
|
468 |
|
469 Ownership is transferred to the caller. |
|
470 |
|
471 @param aFrameNumber |
|
472 The frame number. |
|
473 |
|
474 @return The formatted frame information strings. |
|
475 */ |
|
476 EXPORT_C CFrameInfoStrings* CBufferedImageDecoder::FrameInfoStringsL(TInt aFrameNumber) |
|
477 { |
|
478 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
479 return iDecoder->FrameInfoStringsL(aFrameNumber); |
|
480 } |
|
481 |
|
482 /** |
|
483 Returns the implementation UID of the decoder being used to decode the image. |
|
484 |
|
485 @return The implementation UID of the decoder. |
|
486 */ |
|
487 EXPORT_C TUid CBufferedImageDecoder::ImplementationUid() const |
|
488 { |
|
489 __ASSERT_ALWAYS(ValidDecoder(),Panic(EDecoderNotCreated)); |
|
490 return iDecoder->ImplementationUid(); |
|
491 } |
|
492 |
|
493 /** |
|
494 Determine if enough data was available to determine which plugin decoder |
|
495 to use. If this return EFalse append extra data using AppendDataL() and |
|
496 and call ContinueOpenL() |
|
497 |
|
498 @return A boolean indicating if the decoder plugin was successful. ETrue if a decoder plugin was |
|
499 created, otherwise EFalse. |
|
500 */ |
|
501 EXPORT_C TBool CBufferedImageDecoder::ValidDecoder () const |
|
502 { |
|
503 return iDecoder != NULL; |
|
504 } |
|
505 /** |
|
506 Constructor for this class. |
|
507 @internalTechnology |
|
508 */ |
|
509 CBufferedImageDecoder::CBufferedImageDecoder(RFs& aFs): |
|
510 iFileSession(aFs), |
|
511 iBuffer(NULL,0,0), |
|
512 iMimeType(NULL,0,0), |
|
513 iState(EStateCreated) |
|
514 { |
|
515 } |