|
1 /******************************************************************************* |
|
2 * Copyright (c) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * Nokia Corporation - initial API and implementation |
|
10 *******************************************************************************/ |
|
11 |
|
12 #include "imagebase.h" |
|
13 #include "gfxlog.h" |
|
14 |
|
15 namespace Java { namespace GFX { |
|
16 |
|
17 ImageBase::ImageBase() : mAlpha(-1), mHasMask(false) |
|
18 { |
|
19 } |
|
20 |
|
21 ImageBase::~ImageBase() |
|
22 { |
|
23 } |
|
24 |
|
25 void ImageBase::doGetRgb(QImage& image, int* aRgbdata, int aOffset, int aScanlength, |
|
26 int aX, int aY, int aWidth, int aHeight) |
|
27 { |
|
28 GFX_LOG_FUNC_CALL(); |
|
29 |
|
30 if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height()) |
|
31 { |
|
32 image = image.copy(aX, aY, aWidth, aHeight); |
|
33 if(image.isNull()) |
|
34 { |
|
35 throw GfxException(EGfxErrorNoMemory, "copying from original image failed"); |
|
36 } |
|
37 } |
|
38 |
|
39 // If image is not 32bpp we need to convert it |
|
40 if(image.format() != QImage::Format_RGB32 && |
|
41 image.format() != QImage::Format_ARGB32) |
|
42 { |
|
43 image = image.convertToFormat(QImage::Format_ARGB32); |
|
44 if(image.isNull()) |
|
45 { |
|
46 throw GfxException(EGfxErrorNoMemory, "format convertion to 32bpp failed"); |
|
47 } |
|
48 } |
|
49 |
|
50 // Temporary storage for pixels |
|
51 QRgb* pixel = NULL; |
|
52 |
|
53 // dataArray index, start from offset |
|
54 int targetIndex = aOffset; |
|
55 // Iterate through lines |
|
56 for(int b = 0; b < aHeight; ++b) |
|
57 { |
|
58 // Obtain pointer to start of current line (y) |
|
59 const unsigned char* lineStart = image.scanLine(b); |
|
60 // Iterate through pixels on each line |
|
61 for (int a = 0; a < aWidth; ++a) |
|
62 { |
|
63 // Set the current pixel, relative to line start |
|
64 pixel = ((QRgb*)lineStart) + a; |
|
65 // Move target pointer to the next slot |
|
66 targetIndex = aOffset + a + (b * aScanlength); |
|
67 // Shift pixels to correct places, needed for 32-bit format |
|
68 // as the bits order in memory may vary between systems |
|
69 aRgbdata[targetIndex] = ((qAlpha(*pixel) & 0xff) << 24) | |
|
70 ((qRed(*pixel) & 0xff) << 16) | |
|
71 ((qGreen(*pixel) & 0xff) << 8 ) | |
|
72 ((qBlue(*pixel) & 0xff)); |
|
73 } |
|
74 } |
|
75 } |
|
76 |
|
77 void ImageBase::doGetRgb(QImage& image, char* aRgbdata, char* aTransparencyMask,int aOffset, |
|
78 int aScanlength, int aX, int aY, int aWidth, int aHeight, int aFormat) |
|
79 { |
|
80 GFX_LOG_FUNC_CALL(); |
|
81 |
|
82 if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height()) |
|
83 { |
|
84 image = image.copy(aX, aY, aWidth, aHeight); |
|
85 if(image.isNull()) |
|
86 { |
|
87 throw GfxException(EGfxErrorNoMemory, "copying from original image failed"); |
|
88 } |
|
89 } |
|
90 |
|
91 if(aScanlength < 0) |
|
92 { |
|
93 image = image.mirrored(false, true); |
|
94 if(image.isNull()) |
|
95 { |
|
96 throw GfxException(EGfxErrorNoMemory, "Mirroring failed"); |
|
97 } |
|
98 } |
|
99 |
|
100 // If image is not monochrome we need to convert it |
|
101 if(image.format() != QImage::Format_Mono) |
|
102 { |
|
103 image = image.convertToFormat(QImage::Format_Mono); |
|
104 if(image.isNull()) |
|
105 { |
|
106 throw GfxException(EGfxErrorNoMemory, "Format conversion to 8bpp failed"); |
|
107 } |
|
108 } |
|
109 |
|
110 // dataArray index, start from offset |
|
111 int targetIndex = aOffset; |
|
112 |
|
113 const unsigned char* imageStart = image.bits(); |
|
114 QImage mask = image.alphaChannel(); |
|
115 const unsigned char* maskStart = mask.bits(); |
|
116 |
|
117 // Find the number of full bytes |
|
118 int fullBytes = aWidth/8; |
|
119 int bpl = image.bytesPerLine(); |
|
120 |
|
121 if(bpl == fullBytes) |
|
122 { |
|
123 memcpy(aRgbdata+targetIndex, imageStart, bpl*aHeight); |
|
124 memcpy(aTransparencyMask+targetIndex, maskStart, bpl*aHeight); |
|
125 } |
|
126 else |
|
127 { |
|
128 memcpy(aRgbdata+targetIndex, imageStart, fullBytes*aHeight + aHeight); |
|
129 memcpy(aTransparencyMask+targetIndex, maskStart, fullBytes*aHeight + aHeight); |
|
130 } |
|
131 } |
|
132 |
|
133 void ImageBase::doGetRgb(QImage& image, short* aRgbdata, int aOffset, int aScanlength, |
|
134 int aX, int aY, int aWidth, int aHeight, int aFormat) |
|
135 { |
|
136 GFX_LOG_FUNC_CALL(); |
|
137 |
|
138 // Match format to QT |
|
139 int format; |
|
140 switch (aFormat) { |
|
141 case EFormatRGB555: |
|
142 format = QImage::Format_RGB555; |
|
143 break; |
|
144 case EFormatRGB16: |
|
145 format = QImage::Format_RGB16; |
|
146 break; |
|
147 case EFormatRGB444: |
|
148 format = QImage::Format_RGB444; |
|
149 break; |
|
150 case EFormatARGB4444Premultiplied: |
|
151 format = QImage::Format_ARGB4444_Premultiplied; |
|
152 break; |
|
153 default: |
|
154 format = QImage::Format_RGB16; |
|
155 } |
|
156 |
|
157 if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height()) |
|
158 { |
|
159 image = image.copy(aX, aY, aWidth, aHeight); |
|
160 if(image.isNull()) |
|
161 { |
|
162 throw GfxException(EGfxErrorNoMemory, "copying from original image failed"); |
|
163 } |
|
164 } |
|
165 |
|
166 // If image is not format we need, convert it |
|
167 if(image.format() != format) |
|
168 { |
|
169 image = image.convertToFormat((QImage::Format)format); |
|
170 if(image.isNull()) |
|
171 { |
|
172 throw GfxException(EGfxErrorNoMemory, "format convertion to 16bpp failed"); |
|
173 } |
|
174 } |
|
175 |
|
176 // Temporary storage for pixels |
|
177 short* pixel = NULL; |
|
178 // dataArray index, start from offset |
|
179 int targetIndex = aOffset; |
|
180 |
|
181 // Iterate through lines |
|
182 for(int b=0; b < aHeight; b++) |
|
183 { |
|
184 // Obtain pointer to start of current line (y) |
|
185 const unsigned char* lineStart = image.scanLine(b); |
|
186 // Iterate through pixels on each line |
|
187 for(int a=0; a < aWidth; a++) |
|
188 { |
|
189 // Set the current pixel, relative to line start |
|
190 pixel = ((short*)lineStart) + a; |
|
191 // Move target pointer to the next slot |
|
192 targetIndex = aOffset + a + (b * aScanlength); |
|
193 aRgbdata[targetIndex] = *pixel; |
|
194 } |
|
195 } |
|
196 } |
|
197 |
|
198 QTransform ImageBase::generateTransformMatrix(TTransform aTransform) |
|
199 { |
|
200 GFX_LOG_FUNC_CALL(); |
|
201 |
|
202 // In case there's both mirror and rotate is requested, the angle of rotation |
|
203 // must be negative since when the transform is applied the z-axis is processed |
|
204 // before y-axis, while the spec mandates reverse order. So by having negative |
|
205 // degrees for rotation along z-axis here, gives correct output. |
|
206 QTransform transform; |
|
207 switch(aTransform) |
|
208 { |
|
209 case ETransNone: |
|
210 // No transform or mirror |
|
211 break; |
|
212 case ETransRot90: |
|
213 transform.rotate(90, Qt::ZAxis); |
|
214 break; |
|
215 case ETransRot180: |
|
216 transform.rotate(180, Qt::ZAxis); |
|
217 break; |
|
218 case ETransRot270: |
|
219 transform.rotate(270, Qt::ZAxis); |
|
220 break; |
|
221 case ETransMirror: |
|
222 transform.rotate(180,Qt::YAxis); |
|
223 break; |
|
224 case ETransMirrorRot90: |
|
225 transform.rotate(180, Qt::YAxis); |
|
226 transform.rotate(-90, Qt::ZAxis); |
|
227 break; |
|
228 case ETransMirrorRot180: |
|
229 transform.rotate(180, Qt::YAxis); |
|
230 transform.rotate(-180, Qt::ZAxis); |
|
231 break; |
|
232 case ETransMirrorRot270: |
|
233 transform.rotate(180, Qt::YAxis); |
|
234 transform.rotate(-270, Qt::ZAxis); |
|
235 break; |
|
236 default: |
|
237 Q_ASSERT_X(false, "Graphics", "Transform type not recognized"); |
|
238 } |
|
239 return transform; |
|
240 } |
|
241 |
|
242 int ImageBase::getAlpha() |
|
243 { |
|
244 return mAlpha; |
|
245 } |
|
246 |
|
247 bool ImageBase::hasMask() |
|
248 { |
|
249 return mHasMask; |
|
250 } |
|
251 |
|
252 QImage ImageBase::imageDataToQImage(ImageDataWrapper* aData) |
|
253 { |
|
254 if(aData->getDepth() != 32) |
|
255 { |
|
256 // Java side always converts the ImageData to 32 bit before passing it |
|
257 // to native side, bail out if we get something else |
|
258 throw GfxException(EGfxErrorNoMemory, "Only 32 bit ImageData is supported in Image creation"); |
|
259 } |
|
260 |
|
261 int bpp = 4; // bit depth = 32, 4 bytes per pixel |
|
262 int size = aData->getWidth()*aData->getHeight()*bpp; |
|
263 char* pixelData = aData->getData(ImageDataWrapper::EPixelData); |
|
264 |
|
265 for(int index = 0; index < size; index += bpp) |
|
266 { |
|
267 int pixel = *(reinterpret_cast<int*>(pixelData+index)); |
|
268 |
|
269 pixelData[index] = (uchar)(pixel >> 24) & 0xFF; |
|
270 pixelData[index+1] = (uchar)(pixel >> 16) & 0xFF; |
|
271 pixelData[index+2] = (uchar)(pixel >> 8) & 0xFF; |
|
272 pixelData[index+3] = 0xFF; // Set alpha to opaque here, alpha channel data will be handled later |
|
273 } |
|
274 |
|
275 QImage image(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EPixelData)), |
|
276 aData->getWidth(), |
|
277 aData->getHeight(), |
|
278 aData->getBytesPerLine(), |
|
279 QImage::Format_ARGB32); |
|
280 if(image.isNull()) |
|
281 { |
|
282 throw GfxException(EGfxErrorNoMemory, "Image creation failed"); |
|
283 } |
|
284 |
|
285 // Set indexed palette (if one is set) |
|
286 if(!aData->isDirect()) |
|
287 { |
|
288 image.setColorTable(*aData->getPaletteData()->getIndexedPalette()); |
|
289 } |
|
290 |
|
291 mHasMask = false; |
|
292 mAlpha = aData->getAlpha(); |
|
293 |
|
294 if(aData->getData(ImageDataWrapper::EMaskData)) |
|
295 { |
|
296 QImage mask(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EMaskData)), |
|
297 aData->getWidth(), |
|
298 aData->getHeight(), |
|
299 QImage::Format_Mono); |
|
300 if(mask.isNull()) |
|
301 { |
|
302 throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed"); |
|
303 } |
|
304 image.setAlphaChannel(mask); |
|
305 mHasMask = true; |
|
306 } |
|
307 else if(mAlpha != -1) |
|
308 { |
|
309 // Global alpha is set, overrides alpha channel data |
|
310 QImage alpha(aData->getWidth(), aData->getHeight(), QImage::Format_Indexed8); |
|
311 if(alpha.isNull()) |
|
312 { |
|
313 throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed"); |
|
314 } |
|
315 |
|
316 alpha.fill(aData->getAlpha()); |
|
317 image.setAlphaChannel(alpha); |
|
318 } |
|
319 else if(aData->getData(ImageDataWrapper::EAlphaData)) |
|
320 { |
|
321 // Alpha channel data is set |
|
322 const int w = aData->getWidth(); |
|
323 QImage alpha(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EAlphaData)), |
|
324 w, |
|
325 aData->getHeight(), |
|
326 w, |
|
327 QImage::Format_Indexed8); |
|
328 QVector<QRgb> colors(255); |
|
329 for(int i=0; i<255; i++) |
|
330 { |
|
331 colors[i] = qRgb(i, i, i); |
|
332 } |
|
333 alpha.setColorTable(colors); |
|
334 colors.clear(); |
|
335 |
|
336 if(alpha.isNull()) |
|
337 { |
|
338 throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed"); |
|
339 } |
|
340 image.setAlphaChannel(alpha); |
|
341 } |
|
342 return image; |
|
343 } |
|
344 |
|
345 |
|
346 QImage::Format ImageBase::mapInternalFormatToQt(TImageFormat internalImageFormat) |
|
347 { |
|
348 switch (internalImageFormat) |
|
349 { |
|
350 case EFormatARGB32: |
|
351 return QImage::Format_ARGB32; |
|
352 case EFormatRGB32: |
|
353 return QImage::Format_RGB32; |
|
354 case EFormatARGB32Premultiplied: |
|
355 return QImage::Format_ARGB32_Premultiplied; |
|
356 case EFormatRGB16: |
|
357 return QImage::Format_RGB16; |
|
358 case EFormatRGB555: |
|
359 return QImage::Format_RGB555; |
|
360 case EFormatRGB444: |
|
361 return QImage::Format_RGB444; |
|
362 case EFormatARGB4444Premultiplied: |
|
363 return QImage::Format_ARGB4444_Premultiplied; |
|
364 case EFormatMONO: |
|
365 return QImage::Format_Mono; |
|
366 default: |
|
367 return QImage::Format_Invalid; |
|
368 } |
|
369 } |
|
370 |
|
371 TImageFormat ImageBase::mapQtFormatToInternal(QImage::Format qtImageFormat) |
|
372 { |
|
373 switch (qtImageFormat) |
|
374 { |
|
375 case QImage::Format_ARGB32: |
|
376 return EFormatARGB32; |
|
377 case QImage::Format_RGB32: |
|
378 return EFormatRGB32; |
|
379 case QImage::Format_ARGB32_Premultiplied: |
|
380 return EFormatARGB32Premultiplied; |
|
381 case QImage::Format_RGB16: |
|
382 return EFormatRGB16; |
|
383 case QImage::Format_RGB555: |
|
384 return EFormatRGB555; |
|
385 case QImage::Format_RGB444: |
|
386 return EFormatRGB444; |
|
387 case QImage::Format_ARGB4444_Premultiplied: |
|
388 return EFormatARGB4444Premultiplied; |
|
389 case QImage::Format_Mono: |
|
390 return EFormatMONO; |
|
391 default: |
|
392 return EFormatNone; |
|
393 } |
|
394 } |
|
395 |
|
396 } // namespace GFX |
|
397 } // namespace Java |