|
1 /* |
|
2 * Copyright (c) 2005 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: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "CMIDImageDecoder.h" |
|
19 #include "LcdFbsImage.h" |
|
20 #include <j2me/jdebug.h> |
|
21 |
|
22 CMIDImageDecoder::CMIDImageDecoder(RFs& aFsSession, TDisplayMode aDisplayMode) |
|
23 : CActive(CActive::EPriorityStandard), iRFsSession(aFsSession), iDisplayMode(aDisplayMode) |
|
24 { |
|
25 CActiveScheduler::Add(this); |
|
26 iRFsSession = aFsSession; |
|
27 } |
|
28 |
|
29 void CMIDImageDecoder::ConstructL() |
|
30 { |
|
31 iDecoder = CBufferedImageDecoder::NewL(iRFsSession); |
|
32 } |
|
33 |
|
34 CMIDImageDecoder::~CMIDImageDecoder() |
|
35 { |
|
36 Cancel(); |
|
37 ASSERT(NULL == iCallback); |
|
38 delete iBitmapImage; |
|
39 delete iDecoder; |
|
40 } |
|
41 |
|
42 void CMIDImageDecoder::AppendL(const TDesC8& aBuffer) |
|
43 { |
|
44 TInt err = KErrNone; |
|
45 |
|
46 if (iState == EStart) |
|
47 { |
|
48 TRAP(err, iDecoder->OpenL(aBuffer, CImageDecoder::EOptionPngMissingiENDFail)); |
|
49 |
|
50 if (err == KEComErrNoInterfaceIdentified || err == KErrNotFound) |
|
51 { |
|
52 // If the format is unrecognised AND the first 2 bytes are 0 then we assume it |
|
53 // is a WBMP. This is a requirement of the below defect. |
|
54 // The first two bytes of other formats (e.g. ico) may also begin with 0, 0 |
|
55 // but they should have already been recognised by the first call to OpenL |
|
56 if (aBuffer[0] == 0 && aBuffer[1] == 0) |
|
57 { |
|
58 delete iDecoder; |
|
59 iDecoder = NULL; |
|
60 iDecoder = CBufferedImageDecoder::NewL(iRFsSession); |
|
61 DEBUG("* CMIDImageDecoder::AppendL - Format can't be fully identified, assuming this is WBMP"); |
|
62 _LIT8(KWBMPMimeType, "image/vnd.wap.wbmp"); |
|
63 TRAP(err, iDecoder->OpenL(aBuffer, KWBMPMimeType, CImageDecoder::EOptionPngMissingiENDFail)); |
|
64 } |
|
65 } |
|
66 |
|
67 if ((err != KErrUnderflow) && (err != KEComErrNoInterfaceIdentified) && (err != KErrNotFound)) |
|
68 { |
|
69 // |
|
70 // something's gone wrong that we can't fix by appending more data |
|
71 // |
|
72 User::LeaveIfError(err); |
|
73 } |
|
74 iState = EOpenPending; |
|
75 } |
|
76 else |
|
77 { |
|
78 iDecoder->AppendDataL(aBuffer); |
|
79 |
|
80 if (!iDecoder->ValidDecoder()) |
|
81 { |
|
82 TRAP(err, iDecoder->ContinueOpenL()); |
|
83 if ((err == KErrUnderflow) || (err == KEComErrNoInterfaceIdentified) || (err == KErrNotFound)) |
|
84 { |
|
85 // decoder or framework needs more data to determine codec. |
|
86 return; |
|
87 } |
|
88 |
|
89 // |
|
90 // If something else has gone wrong then we can't fix by appending more data |
|
91 // |
|
92 User::LeaveIfError(err); |
|
93 } |
|
94 } |
|
95 |
|
96 if (iDecoder->ValidDecoder()) |
|
97 { |
|
98 if (!iDecoder->IsImageHeaderProcessingComplete()) |
|
99 { |
|
100 iDecoder->ContinueProcessingHeaderL(); |
|
101 if (iDecoder->IsImageHeaderProcessingComplete()) |
|
102 { |
|
103 iState = EOpenComplete; |
|
104 } |
|
105 } |
|
106 else |
|
107 { |
|
108 iState = EOpenComplete; |
|
109 } |
|
110 } |
|
111 } |
|
112 |
|
113 void NullPointer(TAny* aPtr) |
|
114 { |
|
115 * static_cast<TAny**>(aPtr) = NULL; |
|
116 } |
|
117 |
|
118 void CMIDImageDecoder::DecodeL(MMIDImageObserver* aCallback) |
|
119 { |
|
120 // |
|
121 // If we are asked to decode, but have not yet managed to process the |
|
122 // image header we leave with KErrCorrrupt indicating that we think |
|
123 // the encoded image data is corrupt. |
|
124 // |
|
125 if (iState < EOpenComplete) |
|
126 { |
|
127 User::Leave(KErrCorrupt); |
|
128 } |
|
129 ASSERT(NULL == iCallback); |
|
130 CleanupStack::PushL(TCleanupItem(NullPointer, &iCallback)); |
|
131 iCallback = aCallback; |
|
132 ConvertL(); |
|
133 CleanupStack::Pop(); |
|
134 } |
|
135 |
|
136 void CMIDImageDecoder::Complete(TInt aResult) |
|
137 { |
|
138 if (iCallback) |
|
139 { |
|
140 iCallback->DecodeComplete(aResult); |
|
141 iCallback = NULL; |
|
142 } |
|
143 } |
|
144 |
|
145 void CMIDImageDecoder::ConvertL() |
|
146 { |
|
147 iState = EConvertPending; |
|
148 |
|
149 if (NULL == iBitmapImage) |
|
150 { |
|
151 const TFrameInfo& frameInfo = iDecoder->FrameInfo(); |
|
152 |
|
153 TSize size = frameInfo.iOverallSizeInPixels; |
|
154 |
|
155 // S60: Set the colormode of the bitmap to be exactly as the phone's display. |
|
156 // This will cause CLcdImage class just to duplicate the handle of this image, |
|
157 // and not converting the pixels from the image's original color format to phone's color format. |
|
158 // The image is needed to be in the same color format as the phone's display so BitBlt() is the most efficient. |
|
159 // |
|
160 // Decoding directly to 16MA does not work in 5.0 HW. It works only in emulator and not for JPEG. |
|
161 // The image decoders need to fix this. |
|
162 // We decode to 16MU still and then a conversion from 16MU->16MA will be done |
|
163 // |
|
164 // Insufficient information available to load image in its natural format. |
|
165 |
|
166 TDisplayMode colorMode = frameInfo.iFrameDisplayMode; |
|
167 TDisplayMode alphaMode = ENone; |
|
168 |
|
169 if (frameInfo.iFlags & TFrameInfo::ETransparencyPossible) |
|
170 { |
|
171 if (frameInfo.iFlags & TFrameInfo::EAlphaChannel) |
|
172 { |
|
173 alphaMode = EGray256; |
|
174 } |
|
175 else |
|
176 { |
|
177 alphaMode = EGray2; |
|
178 } |
|
179 } |
|
180 |
|
181 // |
|
182 // This step is the most likely to fail in low memory conditions. |
|
183 // |
|
184 CLcdFbsImage* fbsImage = CLcdFbsImage::NewL(size, colorMode, alphaMode); |
|
185 CleanupStack::PushL(fbsImage); |
|
186 iBitmapImage = new(ELeave) CMIDBitmapImage(*fbsImage); |
|
187 CleanupStack::Pop(fbsImage); |
|
188 } |
|
189 |
|
190 CFbsBitmap* colorBitmap = iBitmapImage->ColorBitmap(); |
|
191 CFbsBitmap* alphaBitmap = iBitmapImage->AlphaBitmap(); |
|
192 |
|
193 if (alphaBitmap) |
|
194 { |
|
195 iDecoder->Convert(&iStatus, *colorBitmap, *alphaBitmap, 0); |
|
196 } |
|
197 else |
|
198 { |
|
199 iDecoder->Convert(&iStatus, *colorBitmap, 0); |
|
200 } |
|
201 SetActive(); |
|
202 } |
|
203 |
|
204 void CMIDImageDecoder::Dispose() |
|
205 { |
|
206 delete this; |
|
207 } |
|
208 |
|
209 MMIDBitmapImage* CMIDImageDecoder::BitmapImage() const |
|
210 { |
|
211 return iBitmapImage; |
|
212 } |
|
213 |
|
214 void CMIDImageDecoder::RunL() |
|
215 { |
|
216 ASSERT(iState == EConvertPending); |
|
217 Complete(iStatus.Int()); |
|
218 } |
|
219 |
|
220 TInt CMIDImageDecoder::RunError(TInt aError) |
|
221 { |
|
222 ASSERT(KErrNone == aError); // should never happen |
|
223 return aError; |
|
224 } |
|
225 |
|
226 void CMIDImageDecoder::DoCancel() |
|
227 { |
|
228 ASSERT(iState == EConvertPending); |
|
229 iDecoder->Cancel(); |
|
230 } |
|
231 |
|
232 |