|
1 /* Copyright (c) 2009 The Khronos Group Inc. |
|
2 * |
|
3 * Permission is hereby granted, free of charge, to any person obtaining a |
|
4 * copy of this software and/or associated documentation files (the |
|
5 * "Materials"), to deal in the Materials without restriction, including |
|
6 * without limitation the rights to use, copy, modify, merge, publish, |
|
7 * distribute, sublicense, and/or sell copies of the Materials, and to |
|
8 * permit persons to whom the Materials are furnished to do so, subject to |
|
9 * the following conditions: |
|
10 * |
|
11 * The above copyright notice and this permission notice shall be included |
|
12 * in all copies or substantial portions of the Materials. |
|
13 * |
|
14 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
20 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
21 */ |
|
22 |
|
23 #ifdef __cplusplus |
|
24 extern "C" |
|
25 { |
|
26 #endif |
|
27 |
|
28 #include <string.h> |
|
29 #include <stdlib.h> |
|
30 #include <stdio.h> |
|
31 #include <math.h> |
|
32 |
|
33 #include "owfobject.h" |
|
34 #include "owfimage.h" |
|
35 #include "owfutils.h" |
|
36 #include "owfmemory.h" |
|
37 #include "owfdebug.h" |
|
38 #include "owfdisplaycontextgeneral.h" |
|
39 |
|
40 #ifdef OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT |
|
41 #define roundSubPixel(p) ((OWFuint32)((p) + 0.5f)) |
|
42 #else |
|
43 #define roundSubPixel(p) (p) |
|
44 #endif |
|
45 |
|
46 |
|
47 /*----------------------------------------------------------------------------*/ |
|
48 OWF_API_CALL void |
|
49 OWF_IMAGE_Ctor(void* self) |
|
50 { |
|
51 self = self; |
|
52 } |
|
53 |
|
54 /*----------------------------------------------------------------------------*/ |
|
55 OWF_API_CALL void |
|
56 OWF_IMAGE_Dtor(void* self) |
|
57 { |
|
58 OWF_IMAGE* image; |
|
59 |
|
60 image = (OWF_IMAGE*)self; |
|
61 |
|
62 if (image && image->data) |
|
63 { |
|
64 if (!image->foreign) |
|
65 { |
|
66 OWF_Image_FreeData(0, &image->data); |
|
67 } |
|
68 } |
|
69 |
|
70 if (image) |
|
71 { |
|
72 memset(image, 0, sizeof(OWF_IMAGE)); |
|
73 } |
|
74 } |
|
75 |
|
76 /*----------------------------------------------------------------------------*/ |
|
77 static OWFfloat |
|
78 NonLinear(OWFfloat x) |
|
79 { |
|
80 if (x <= 0.00304f) |
|
81 { |
|
82 return 12.92f * x; |
|
83 } |
|
84 return 1.0556f * pow(x, 1.f/2.4f) - 0.0556f; |
|
85 } |
|
86 |
|
87 /*----------------------------------------------------------------------------*/ |
|
88 static OWFfloat |
|
89 Linear(OWFfloat x) |
|
90 { |
|
91 if (x <= 0.03928) |
|
92 { |
|
93 return x / 12.92f; |
|
94 } |
|
95 return pow((x + 0.0556f) / 1.0556f, 2.4f); |
|
96 } |
|
97 |
|
98 /*----------------------------------------------------------------------------*/ |
|
99 OWF_API_CALL void |
|
100 OWF_Image_NonLinearizeData(OWF_IMAGE* image)\ |
|
101 { |
|
102 OWFpixel* ptr; |
|
103 OWFint count; |
|
104 |
|
105 OWF_ASSERT(image != NULL && image->data != NULL); |
|
106 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
107 |
|
108 if (!image->format.linear) |
|
109 { |
|
110 return; |
|
111 } |
|
112 |
|
113 ptr = (OWFpixel*) image->data; |
|
114 count = image->width * image->height; |
|
115 |
|
116 while (count > 0) |
|
117 { |
|
118 ptr->color.red = (OWFsubpixel) NonLinear(ptr->color.red / |
|
119 OWF_RED_MAX_VALUE) * OWF_RED_MAX_VALUE; |
|
120 ptr->color.green = (OWFsubpixel) NonLinear(ptr->color.green / |
|
121 OWF_GREEN_MAX_VALUE) * OWF_GREEN_MAX_VALUE; |
|
122 ptr->color.blue = (OWFsubpixel) NonLinear(ptr->color.blue / |
|
123 OWF_BLUE_MAX_VALUE) * OWF_BLUE_MAX_VALUE; |
|
124 |
|
125 --count; |
|
126 ptr++; |
|
127 } |
|
128 |
|
129 image->format.linear = OWF_FALSE; |
|
130 } |
|
131 |
|
132 /*----------------------------------------------------------------------------*/ |
|
133 OWF_API_CALL void |
|
134 OWF_Image_LinearizeData(OWF_IMAGE* image) |
|
135 { |
|
136 OWFpixel* ptr; |
|
137 OWFuint count; |
|
138 |
|
139 OWF_ASSERT(image != NULL && image->data != NULL); |
|
140 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
141 |
|
142 if (image->format.linear) |
|
143 { |
|
144 return; |
|
145 } |
|
146 |
|
147 ptr = (OWFpixel*) image->data; |
|
148 count = image->width * image->height; |
|
149 |
|
150 while (count > 0) |
|
151 { |
|
152 ptr->color.red = (OWFsubpixel) Linear(ptr->color.red / |
|
153 OWF_RED_MAX_VALUE) * OWF_RED_MAX_VALUE; |
|
154 ptr->color.green = (OWFsubpixel) Linear(ptr->color.green / |
|
155 OWF_GREEN_MAX_VALUE) * OWF_GREEN_MAX_VALUE; |
|
156 ptr->color.blue = (OWFsubpixel) Linear(ptr->color.blue / |
|
157 OWF_BLUE_MAX_VALUE) * OWF_BLUE_MAX_VALUE; |
|
158 |
|
159 --count; |
|
160 ptr += image->pixelSize; |
|
161 } |
|
162 |
|
163 image->format.linear = OWF_TRUE; |
|
164 |
|
165 } |
|
166 |
|
167 /*----------------------------------------------------------------------------*/ |
|
168 #define GAMMA(color, max, gamma) (max * pow(color/max, gamma)) |
|
169 |
|
170 OWF_API_CALL void |
|
171 OWF_Image_Gamma(OWF_IMAGE* image, OWFfloat gamma) |
|
172 { |
|
173 OWFpixel* ptr; |
|
174 OWFint count; |
|
175 |
|
176 OWF_ASSERT(image != NULL && image->data != NULL); |
|
177 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
178 |
|
179 if (gamma == 1.0f) |
|
180 { |
|
181 return; |
|
182 } |
|
183 |
|
184 ptr = (OWFpixel*) image->data; |
|
185 count = image->width * image->height; |
|
186 |
|
187 while (count > 0) |
|
188 { |
|
189 ptr->color.red = |
|
190 (OWFsubpixel) GAMMA(ptr->color.red, OWF_RED_MAX_VALUE, gamma); |
|
191 ptr->color.green = |
|
192 (OWFsubpixel) GAMMA(ptr->color.green, OWF_GREEN_MAX_VALUE, gamma); |
|
193 ptr->color.blue = |
|
194 (OWFsubpixel) GAMMA(ptr->color.blue, OWF_BLUE_MAX_VALUE, gamma); |
|
195 |
|
196 --count; |
|
197 ptr++; |
|
198 } |
|
199 } |
|
200 |
|
201 /*----------------------------------------------------------------------------*/ |
|
202 OWF_API_CALL void |
|
203 OWF_Image_EdgeReplication(OWF_IMAGE* image) |
|
204 { |
|
205 OWFint y; |
|
206 OWFint copyStride; |
|
207 OWFuint8* srcPtr = NULL; |
|
208 OWFuint8* dstPtr = NULL; |
|
209 |
|
210 OWF_ASSERT(image); |
|
211 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
212 OWF_ASSERT(image->width >= 3 && image->height >= 3); |
|
213 |
|
214 copyStride = image->width * image->pixelSize; |
|
215 |
|
216 /* top side replication */ |
|
217 srcPtr = (OWFuint8*) image->data; |
|
218 srcPtr += 1 * image->stride + 0 * image->pixelSize; |
|
219 dstPtr = (OWFuint8*) image->data; |
|
220 |
|
221 memcpy(dstPtr, srcPtr, copyStride); |
|
222 |
|
223 /* bottom side replication */ |
|
224 srcPtr = (OWFuint8*) image->data; |
|
225 srcPtr += (image->height-2) * image->stride + 0 * image->pixelSize; |
|
226 dstPtr = (OWFuint8*) image->data; |
|
227 dstPtr += (image->height-1) * image->stride + 0 * image->pixelSize; |
|
228 |
|
229 memcpy(dstPtr, srcPtr, copyStride); |
|
230 |
|
231 /* left side replication */ |
|
232 for (y = 0; y < image->height; y++) |
|
233 { |
|
234 OWF_Image_SetPixel(image, 0, y, OWF_Image_GetPixelPtr(image, 1, y)); |
|
235 } |
|
236 |
|
237 /* right side replication */ |
|
238 for (y = 0; y < image->height; y++) |
|
239 { |
|
240 OWF_Image_SetPixel(image, image->width-1, y, OWF_Image_GetPixelPtr(image, |
|
241 image->width-2, |
|
242 y)); |
|
243 } |
|
244 |
|
245 } |
|
246 |
|
247 /*----------------------------------------------------------------------------*/ |
|
248 OWF_API_CALL OWFboolean |
|
249 OWF_Image_SourceFormatConversion(OWF_IMAGE* dst, OWF_IMAGE* src) |
|
250 { |
|
251 OWFint countY, widthDiff, heightDiff; |
|
252 void* srcLinePtr; |
|
253 OWFpixel* dstLinePtr; |
|
254 OWFboolean replicateEdges = OWF_FALSE; |
|
255 |
|
256 |
|
257 OWF_ASSERT(dst != 0 && dst->data != NULL); |
|
258 OWF_ASSERT(src != 0 && src->data != NULL); |
|
259 OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
260 |
|
261 srcLinePtr = src->data; |
|
262 dstLinePtr = (OWFpixel*) dst->data; |
|
263 |
|
264 /* dst image must either be the same size as the src image or 2 pixels |
|
265 bigger (enough space to perform edge replication) */ |
|
266 if (dst->width != src->width || dst->height != src->height) |
|
267 { |
|
268 widthDiff = dst->width - src->width; |
|
269 heightDiff = dst->height - src->height; |
|
270 |
|
271 if (widthDiff == 2 && heightDiff == 2) |
|
272 { |
|
273 replicateEdges = OWF_TRUE; |
|
274 /* start of the destination buffer should have a 1 pixel offset */ |
|
275 dstLinePtr = (OWFpixel*) dst->data + 1 * dst->width + 1; |
|
276 } |
|
277 else |
|
278 { |
|
279 return OWF_FALSE; |
|
280 } |
|
281 } |
|
282 |
|
283 if (dst->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) |
|
284 { |
|
285 return OWF_FALSE; |
|
286 } |
|
287 |
|
288 for (countY = src->height; countY; countY--) |
|
289 { |
|
290 OWFint count = src->width; |
|
291 OWFpixel* dstPtr = dstLinePtr; |
|
292 |
|
293 switch (src->format.pixelFormat) |
|
294 { |
|
295 case OWF_IMAGE_ARGB8888: |
|
296 { |
|
297 OWFuint32* srcPtr = (OWFuint32*) srcLinePtr; |
|
298 |
|
299 while (count > 0) |
|
300 { |
|
301 dstPtr->color.alpha = (OWFsubpixel) |
|
302 OWF_ALPHA_MAX_VALUE * ((*srcPtr & ARGB8888_ALPHA_MASK) >> ARGB8888_ALPHA_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
303 dstPtr->color.red = (OWFsubpixel) |
|
304 OWF_RED_MAX_VALUE * ((*srcPtr & ARGB8888_RED_MASK) >> ARGB8888_RED_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
305 dstPtr->color.green = (OWFsubpixel) |
|
306 OWF_GREEN_MAX_VALUE * ((*srcPtr & ARGB8888_GREEN_MASK)>> ARGB8888_GREEN_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
307 dstPtr->color.blue = (OWFsubpixel) |
|
308 OWF_BLUE_MAX_VALUE * ((*srcPtr & ARGB8888_BLUE_MASK) >> ARGB8888_BLUE_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
309 dstPtr ++; |
|
310 srcPtr ++; |
|
311 count--; |
|
312 } |
|
313 break; |
|
314 } |
|
315 |
|
316 case OWF_IMAGE_XRGB8888: |
|
317 { |
|
318 OWFuint32* srcPtr = (OWFuint32*) srcLinePtr; |
|
319 |
|
320 while (count > 0) |
|
321 { |
|
322 dstPtr->color.alpha = OWF_FULLY_OPAQUE; |
|
323 dstPtr->color.red = (OWFsubpixel) |
|
324 OWF_RED_MAX_VALUE * ((*srcPtr & ARGB8888_RED_MASK) >> ARGB8888_RED_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
325 dstPtr->color.green = (OWFsubpixel) |
|
326 OWF_GREEN_MAX_VALUE * ((*srcPtr & ARGB8888_GREEN_MASK) >> ARGB8888_GREEN_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
327 dstPtr->color.blue = (OWFsubpixel) |
|
328 OWF_BLUE_MAX_VALUE * ((*srcPtr & ARGB8888_BLUE_MASK) >> ARGB8888_BLUE_SHIFT) / OWF_BYTE_MAX_VALUE; |
|
329 dstPtr ++; |
|
330 srcPtr ++; |
|
331 count--; |
|
332 } |
|
333 break; |
|
334 } |
|
335 |
|
336 case OWF_IMAGE_RGB565: |
|
337 { |
|
338 OWFfloat tmp; |
|
339 OWFuint16* srcPtr = (OWFuint16*) srcLinePtr; |
|
340 |
|
341 while (count > 0) |
|
342 { |
|
343 /* |
|
344 * Formula for converting channel value is: |
|
345 * Each channel is multiplied by (2^d - 1)/(2^s -1) |
|
346 * where d is dest channel bits and s is source channel bits. |
|
347 */ |
|
348 dstPtr->color.alpha = (OWFsubpixel) OWF_FULLY_OPAQUE; |
|
349 |
|
350 tmp = (OWFfloat)((*srcPtr & RGB565_RED_MASK) >> RGB565_RED_SHIFT); |
|
351 dstPtr->color.red = (OWFsubpixel)OWF_RED_MAX_VALUE * tmp / 31.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; |
|
352 |
|
353 tmp = (OWFfloat)((*srcPtr & RGB565_GREEN_MASK) >> RGB565_GREEN_SHIFT); |
|
354 dstPtr->color.green = (OWFsubpixel)OWF_GREEN_MAX_VALUE * tmp / 63.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; |
|
355 |
|
356 tmp = (OWFfloat)(*srcPtr & RGB565_BLUE_MASK); |
|
357 dstPtr->color.blue = (OWFsubpixel)OWF_BLUE_MAX_VALUE * tmp / 31.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; |
|
358 |
|
359 dstPtr ++; |
|
360 srcPtr ++; |
|
361 count--; |
|
362 } |
|
363 break; |
|
364 } |
|
365 |
|
366 default: |
|
367 { |
|
368 return OWF_FALSE; /* source format not supported */ |
|
369 } |
|
370 } |
|
371 |
|
372 dstLinePtr+=dst->width; |
|
373 srcLinePtr=(OWFuint8*)srcLinePtr+src->stride; |
|
374 } |
|
375 |
|
376 if (replicateEdges) |
|
377 { |
|
378 OWF_Image_EdgeReplication(dst); |
|
379 } |
|
380 |
|
381 return OWF_TRUE; |
|
382 } |
|
383 |
|
384 /*----------------------------------------------------------------------------*/ |
|
385 OWF_PUBLIC OWFint |
|
386 OWF_Image_GetStride(OWFint width, const OWF_IMAGE_FORMAT* format, OWFint minimumStride) |
|
387 { |
|
388 OWFint size; |
|
389 OWFint pixelSize; |
|
390 |
|
391 OWF_ASSERT(format); |
|
392 |
|
393 pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); |
|
394 |
|
395 if (pixelSize < 0) |
|
396 { |
|
397 /* negative pixelSize means that pixel size is a fraction |
|
398 * (1/-pixelSize) of a byte, e.g. -8 means pixel has size |
|
399 * of one bit. */ |
|
400 |
|
401 size = (width + 1) / -pixelSize; |
|
402 } |
|
403 else |
|
404 { |
|
405 size = width * pixelSize; |
|
406 } |
|
407 if (size<minimumStride) |
|
408 { |
|
409 size=minimumStride; |
|
410 } |
|
411 if (format->rowPadding) |
|
412 { |
|
413 size += format->rowPadding - 1; |
|
414 size -= size % format->rowPadding; |
|
415 } |
|
416 return size; |
|
417 } |
|
418 |
|
419 /*----------------------------------------------------------------------------*/ |
|
420 OWF_API_CALL OWFboolean |
|
421 OWF_Image_IsValidDestinationFormat(OWF_IMAGE_FORMAT* format) |
|
422 { |
|
423 switch (format->pixelFormat) |
|
424 { |
|
425 case OWF_IMAGE_ARGB8888: |
|
426 { |
|
427 return OWF_TRUE; |
|
428 } |
|
429 case OWF_IMAGE_XRGB8888: |
|
430 { |
|
431 return OWF_TRUE; |
|
432 } |
|
433 #ifdef SUPPORT_565_OUTPUT |
|
434 case OWF_IMAGE_RGB565: |
|
435 { |
|
436 return OWF_TRUE; |
|
437 } |
|
438 #endif |
|
439 default: |
|
440 { |
|
441 return OWF_FALSE; /* destination format not supported */ |
|
442 } |
|
443 } |
|
444 } |
|
445 |
|
446 /*----------------------------------------------------------------------------*/ |
|
447 OWF_API_CALL OWFboolean |
|
448 OWF_Image_DestinationFormatConversion(OWF_IMAGE* dst, OWF_IMAGE* src) |
|
449 { |
|
450 OWFint countY; |
|
451 OWFuint32* dstPtr; |
|
452 OWFpixel* srcPtr; |
|
453 |
|
454 OWF_ASSERT(dst != 0 && dst->data != NULL); |
|
455 OWF_ASSERT(src != 0 && src->data != NULL); |
|
456 OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
457 |
|
458 if (src->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) |
|
459 { |
|
460 return OWF_FALSE; |
|
461 } |
|
462 |
|
463 /* src and data must have equal amount of pixels */ |
|
464 if (dst->width != src->width || dst->height != src->height) |
|
465 { |
|
466 return OWF_FALSE; |
|
467 } |
|
468 |
|
469 dstPtr = (OWFuint32*) dst->data; |
|
470 srcPtr = (OWFpixel*) src->data; |
|
471 |
|
472 if (dst->format.premultiplied && !src->format.premultiplied) |
|
473 { |
|
474 OWF_Image_PremultiplyAlpha(src); |
|
475 } |
|
476 else if (!dst->format.premultiplied && src->format.premultiplied) |
|
477 { |
|
478 OWF_Image_UnpremultiplyAlpha(src); |
|
479 } |
|
480 |
|
481 for (countY = 0; countY < src->height; countY++) |
|
482 { |
|
483 OWFuint8* destination = (OWFuint8*) dst->data; |
|
484 destination += countY*dst->stride; |
|
485 dstPtr = (OWFuint32*) destination; |
|
486 |
|
487 switch (dst->format.pixelFormat) |
|
488 { |
|
489 case OWF_IMAGE_ARGB8888: |
|
490 { |
|
491 OWFint countX; |
|
492 OWFuint32 dstPixel = 0; |
|
493 |
|
494 for (countX = 0; countX < src->width; countX++) |
|
495 { |
|
496 dstPixel = ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.alpha / OWF_ALPHA_MAX_VALUE)) << |
|
497 ARGB8888_ALPHA_SHIFT); |
|
498 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.red / OWF_RED_MAX_VALUE)) << |
|
499 ARGB8888_RED_SHIFT); |
|
500 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.green / OWF_GREEN_MAX_VALUE)) << |
|
501 ARGB8888_GREEN_SHIFT); |
|
502 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.blue / OWF_BLUE_MAX_VALUE)) << |
|
503 ARGB8888_BLUE_SHIFT); |
|
504 *dstPtr = dstPixel; |
|
505 dstPtr ++; |
|
506 srcPtr ++; |
|
507 } |
|
508 break; |
|
509 } |
|
510 |
|
511 case OWF_IMAGE_XRGB8888: |
|
512 { |
|
513 OWFint countX; |
|
514 OWFuint32 dstPixel = 0; |
|
515 |
|
516 for (countX = 0; countX < src->width; countX++) |
|
517 { |
|
518 dstPixel = ARGB8888_ALPHA_MASK; |
|
519 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.red / OWF_RED_MAX_VALUE)) << |
|
520 ARGB8888_RED_SHIFT); |
|
521 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.green / OWF_GREEN_MAX_VALUE)) << |
|
522 ARGB8888_GREEN_SHIFT); |
|
523 dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.blue / OWF_BLUE_MAX_VALUE)) << |
|
524 ARGB8888_BLUE_SHIFT); |
|
525 *dstPtr = dstPixel; |
|
526 dstPtr ++; |
|
527 srcPtr ++; |
|
528 } |
|
529 break; |
|
530 } |
|
531 |
|
532 default: |
|
533 { |
|
534 return OWF_FALSE; /* destination format not supported */ |
|
535 } |
|
536 } |
|
537 } |
|
538 |
|
539 return OWF_TRUE; |
|
540 } |
|
541 |
|
542 /*----------------------------------------------------------------------------*/ |
|
543 OWF_API_CALL void |
|
544 OWF_Image_Init(OWF_IMAGE* image) |
|
545 { |
|
546 OWF_ASSERT(NULL != image); |
|
547 memset(image, 0, sizeof(OWF_IMAGE)); |
|
548 } |
|
549 |
|
550 /*----------------------------------------------------------------------------*/ |
|
551 OWF_PUBLIC OWF_IMAGE* |
|
552 OWF_Image_Create(OWFint width, |
|
553 OWFint height, |
|
554 const OWF_IMAGE_FORMAT* format, |
|
555 void* buffer, |
|
556 OWFint minimumStride |
|
557 ) |
|
558 { |
|
559 OWF_IMAGE* image; |
|
560 |
|
561 image = CREATE(OWF_IMAGE); |
|
562 |
|
563 if (image) |
|
564 { |
|
565 |
|
566 image->format.pixelFormat = format->pixelFormat; |
|
567 image->format.linear = format->linear; |
|
568 image->format.premultiplied = format->premultiplied; |
|
569 image->format.rowPadding = format->rowPadding; |
|
570 |
|
571 image->pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); |
|
572 image->width = width; |
|
573 image->height = height; |
|
574 |
|
575 /* stride is row length in bytes (aligned according to image format) */ |
|
576 image->stride = OWF_Image_GetStride(width, &image->format, minimumStride); |
|
577 image->foreign = (buffer) ? OWF_TRUE : OWF_FALSE; |
|
578 image->dataMax = image->stride * height; |
|
579 |
|
580 DPRINT(("OWF_Image_Create:")); |
|
581 DPRINT((" Pixel format = %x", format->pixelFormat)); |
|
582 DPRINT((" Linear = %d", format->linear)); |
|
583 DPRINT((" Premultiplied = %d", format->premultiplied)); |
|
584 DPRINT((" Row alignment = %d bytes", format->rowPadding)); |
|
585 DPRINT((" Pixel size = %d", image->pixelSize)); |
|
586 DPRINT((" Width = %d", image->width)); |
|
587 DPRINT((" Height = %d", image->height)); |
|
588 DPRINT((" Stride = %d", image->stride)); |
|
589 DPRINT((" Foreign data = %d", image->foreign)); |
|
590 DPRINT((" Data size = %d", image->dataMax)); |
|
591 if (image->dataMax > 0) |
|
592 { |
|
593 image->data = (image->foreign) ? (buffer) : |
|
594 OWF_Image_AllocData(0, width, height, format->pixelFormat); |
|
595 } |
|
596 else |
|
597 { |
|
598 /* either overflow occured or width/height is zero */ |
|
599 if (width && height) |
|
600 { |
|
601 DPRINT(("OWF_Image_Create: Overflow in image size calculation.")); |
|
602 } |
|
603 else |
|
604 { |
|
605 DPRINT(("OWF_Image_Create: width or height is zero.")); |
|
606 } |
|
607 } |
|
608 } |
|
609 |
|
610 if (!(image && image->data && (image->dataMax > 0))) |
|
611 { |
|
612 DPRINT(("OWF_Image_Create: Image creation failed (image = %p, " |
|
613 "data = %p, dataSize = %d)", |
|
614 image, image ? (void*)(image->data) : (void*)NULL, image?image->dataMax:-1)); |
|
615 DESTROY(image); |
|
616 return NULL; |
|
617 } |
|
618 return image; |
|
619 } |
|
620 |
|
621 /*----------------------------------------------------------------------------*/ |
|
622 OWF_PUBLIC void OWF_Image_Destroy(OWF_IMAGE* image) |
|
623 { |
|
624 if (image) |
|
625 { |
|
626 DESTROY(image); |
|
627 } |
|
628 } |
|
629 |
|
630 |
|
631 /*----------------------------------------------------------------------------*/ |
|
632 OWF_API_CALL OWF_IMAGE* |
|
633 OWF_Image_Copy(const OWF_IMAGE* image) |
|
634 { |
|
635 OWF_IMAGE* newImage = NULL; |
|
636 |
|
637 OWF_ASSERT(image); |
|
638 |
|
639 newImage = CREATE(OWF_IMAGE); |
|
640 if (newImage) |
|
641 { |
|
642 memcpy(newImage, image, sizeof(*newImage)); |
|
643 if (!image->foreign) |
|
644 { |
|
645 newImage->data = xalloc(1, image->dataMax); |
|
646 if (newImage->data) |
|
647 { |
|
648 memcpy(newImage->data, |
|
649 image->data, |
|
650 image->height*image->stride); |
|
651 } |
|
652 } |
|
653 } |
|
654 |
|
655 return newImage; |
|
656 } |
|
657 |
|
658 /*----------------------------------------------------------------------------*/ |
|
659 OWF_API_CALL OWFboolean |
|
660 OWF_Image_SetSize(OWF_IMAGE* image, |
|
661 OWFint width, |
|
662 OWFint height) |
|
663 { |
|
664 OWFint size; |
|
665 OWFint stride; |
|
666 |
|
667 OWF_ASSERT(image); |
|
668 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL || |
|
669 image->format.pixelFormat==OWF_IMAGE_L32); |
|
670 |
|
671 /** note that this setsize ignores any specialised stride **/ |
|
672 stride = OWF_Image_GetStride(width, &image->format, 0); |
|
673 size = height * stride; |
|
674 |
|
675 /* change source size if buffer have enough space */ |
|
676 if (size > 0 && size <= image->dataMax) |
|
677 { |
|
678 image->height = height; |
|
679 image->width = width; |
|
680 image->stride = stride; |
|
681 return OWF_TRUE; |
|
682 } |
|
683 return OWF_FALSE; |
|
684 } |
|
685 /*----------------------------------------------------------------------------*/ |
|
686 OWF_API_CALL void |
|
687 OWF_Image_SetFlags(OWF_IMAGE* image, |
|
688 OWFboolean premultiply, |
|
689 OWFboolean linear) |
|
690 { |
|
691 OWF_ASSERT(image); |
|
692 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL || |
|
693 image->format.pixelFormat==OWF_IMAGE_L32); |
|
694 image->format.linear=linear; |
|
695 image->format.premultiplied=premultiply; |
|
696 } |
|
697 |
|
698 /*----------------------------------------------------------------------------*/ |
|
699 OWF_API_CALL void |
|
700 OWF_Image_SetPixelBuffer(OWF_IMAGE* image, void* buffer) |
|
701 { |
|
702 OWF_ASSERT(image); |
|
703 OWF_ASSERT(buffer); |
|
704 OWF_ASSERT(image->foreign); |
|
705 if (image->foreign) |
|
706 { |
|
707 image->data=buffer; |
|
708 } |
|
709 } |
|
710 /*----------------------------------------------------------------------------*/ |
|
711 /* NEVER USED |
|
712 OWF_API_CALL OWFboolean |
|
713 OWF_Image_SetPixelData(OWF_IMAGE* image, |
|
714 OWFint width, |
|
715 OWFint height, |
|
716 const OWF_IMAGE_FORMAT* format, |
|
717 void* buffer) |
|
718 { |
|
719 OWFint size = 0, |
|
720 stride = 0; |
|
721 |
|
722 OWF_ASSERT(image && format); |
|
723 |
|
724 stride = OWF_Image_GetStride(width, format); |
|
725 size = height * stride; |
|
726 |
|
727 if (size <= 0) |
|
728 { |
|
729 return OWF_FALSE; |
|
730 } |
|
731 |
|
732 if (!image->foreign) |
|
733 { |
|
734 OWF_Image_FreeData(0, &image->data); |
|
735 } |
|
736 |
|
737 image->format.pixelFormat = format->pixelFormat; |
|
738 image->format.linear = format->linear; |
|
739 image->format.premultiplied = format->premultiplied; |
|
740 image->format.rowPadding = format->rowPadding; |
|
741 |
|
742 image->pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); |
|
743 image->width = width; |
|
744 image->height = height; |
|
745 image->stride = stride; |
|
746 image->foreign = OWF_TRUE; |
|
747 image->dataMax = size; |
|
748 image->data = buffer; |
|
749 |
|
750 return OWF_TRUE; |
|
751 } |
|
752 */ |
|
753 /*----------------------------------------------------------------------------*/ |
|
754 OWF_API_CALL OWFboolean |
|
755 OWF_Image_Blit(OWF_IMAGE* dst, |
|
756 OWF_RECTANGLE const* dstRect, |
|
757 OWF_IMAGE const* src, |
|
758 OWF_RECTANGLE const* srcRect) |
|
759 { |
|
760 OWF_RECTANGLE bounds, rect, drect, srect; |
|
761 OWFint lineCount = 0; |
|
762 OWFint copyStride = 0; |
|
763 OWFuint8* srcPtr = NULL; |
|
764 OWFuint8* dstPtr = NULL; |
|
765 |
|
766 OWF_ASSERT(dst != 0 && dst->data != NULL); |
|
767 OWF_ASSERT(src != 0 && src->data != NULL); |
|
768 OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
769 OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
770 |
|
771 OWF_Rect_Set(&bounds, 0, 0, dst->width, dst->height); |
|
772 OWF_Rect_Set(&rect, |
|
773 dstRect->x, dstRect->y, |
|
774 srcRect->width, srcRect->height); |
|
775 OWF_Rect_Set(&srect, |
|
776 srcRect->x, srcRect->y, |
|
777 srcRect->width, srcRect->height); |
|
778 |
|
779 /* clip destination rectangle against bounds */ |
|
780 if (!OWF_Rect_Clip(&drect, &rect, &bounds)) |
|
781 { |
|
782 return OWF_FALSE; |
|
783 } |
|
784 |
|
785 if (src->pixelSize != dst->pixelSize) |
|
786 { |
|
787 DPRINT(("OWF_Image_Blit(): pixels sizes differ\n")); |
|
788 return OWF_FALSE; |
|
789 } |
|
790 |
|
791 lineCount = srect.height; |
|
792 copyStride = srect.width * src->pixelSize; |
|
793 |
|
794 /* use bytepointers in copy - generic */ |
|
795 srcPtr = (OWFuint8*) src->data; |
|
796 srcPtr += srect.y * src->stride + srect.x * src->pixelSize; |
|
797 dstPtr = (OWFuint8*)dst->data; |
|
798 dstPtr += drect.y * dst->stride + drect.x * src->pixelSize; |
|
799 |
|
800 while (lineCount > 0) |
|
801 { |
|
802 --lineCount; |
|
803 |
|
804 memcpy(dstPtr, srcPtr, copyStride); |
|
805 |
|
806 srcPtr += src->stride; |
|
807 dstPtr += dst->stride; |
|
808 } |
|
809 |
|
810 return OWF_TRUE; |
|
811 } |
|
812 |
|
813 /*----------------------------------------------------------------------------*/ |
|
814 OWF_API_CALL OWFpixel* |
|
815 OWF_Image_GetPixelPtr(OWF_IMAGE* image, |
|
816 OWFint x, |
|
817 OWFint y) |
|
818 { |
|
819 OWF_ASSERT(image && image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
820 if (!(image && image->data)) |
|
821 { |
|
822 return 0; |
|
823 } |
|
824 |
|
825 x = CLAMP(x, 0, image->width-1); |
|
826 y = CLAMP(y, 0, image->height-1); |
|
827 |
|
828 return (OWFpixel*)image->data + y * image->width + x ; |
|
829 } |
|
830 |
|
831 /*----------------------------------------------------------------------------*/ |
|
832 OWF_API_CALL void |
|
833 OWF_Image_GetPixel(OWF_IMAGE* image, |
|
834 OWFint x, |
|
835 OWFint y, |
|
836 OWFpixel* pixel) |
|
837 { |
|
838 OWFpixel* temp = NULL; |
|
839 |
|
840 OWF_ASSERT(pixel); |
|
841 |
|
842 if (!(image && image->data)) |
|
843 { |
|
844 return; |
|
845 } |
|
846 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
847 |
|
848 pixel->color.alpha = 0; |
|
849 pixel->color.red = 0; |
|
850 pixel->color.green = 0; |
|
851 pixel->color.blue = 0; |
|
852 |
|
853 if (x < 0 || y < 0 || x >= image->width || y >= image->height) |
|
854 { |
|
855 return; |
|
856 } |
|
857 |
|
858 temp = (OWFpixel*)image->data + y * image->width + x; |
|
859 |
|
860 pixel->color.alpha = temp->color.alpha; |
|
861 pixel->color.red = temp->color.red; |
|
862 pixel->color.green = temp->color.green; |
|
863 pixel->color.blue = temp->color.blue; |
|
864 } |
|
865 |
|
866 /*----------------------------------------------------------------------------*/ |
|
867 OWF_API_CALL void |
|
868 OWF_Image_SetPixel(OWF_IMAGE* image, |
|
869 OWFint x, |
|
870 OWFint y, |
|
871 OWFpixel const* pixel) |
|
872 { |
|
873 OWFpixel* data = NULL; |
|
874 |
|
875 if (!(image && image->data)) |
|
876 { |
|
877 return; |
|
878 } |
|
879 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
880 |
|
881 if(x < 0 || y < 0 || x >= image->width || y >= image->height) |
|
882 { |
|
883 return; |
|
884 } |
|
885 |
|
886 |
|
887 data = (OWFpixel*)image->data + y * image->width + x; |
|
888 |
|
889 data->color.red = pixel->color.red; |
|
890 data->color.green = pixel->color.green; |
|
891 data->color.blue = pixel->color.blue; |
|
892 data->color.alpha = pixel->color.alpha; |
|
893 } |
|
894 |
|
895 /*----------------------------------------------------------------------------*/ |
|
896 OWF_API_CALL OWFboolean |
|
897 OWF_Image_PointSamplingStretchBlit(OWF_IMAGE* dst, |
|
898 OWF_RECTANGLE* dstRect, |
|
899 OWF_IMAGE* src, |
|
900 OWFfloat* srcRect) |
|
901 { |
|
902 OWFint ox = 0, oy = 0; |
|
903 OWFfloat dx = 0.f, dy = 0.f; |
|
904 OWFint x, y; |
|
905 |
|
906 /* images must be valid */ |
|
907 if (!((src != NULL) && (src->data != NULL) && |
|
908 (dst != NULL) && (dst->data != NULL))) |
|
909 { |
|
910 return OWF_FALSE; |
|
911 } |
|
912 OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
913 OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
914 |
|
915 /* ditto with rectangles, too */ |
|
916 if (!((dstRect != NULL) && (dstRect->width && dstRect->height) && |
|
917 (srcRect != NULL) && (srcRect[2] && srcRect[3]))) |
|
918 { |
|
919 return OWF_FALSE; |
|
920 } |
|
921 |
|
922 /* Note: bounds check missing */ |
|
923 |
|
924 if (src->pixelSize != dst->pixelSize) |
|
925 { |
|
926 return OWF_FALSE; |
|
927 } |
|
928 |
|
929 /* solve scaling ratios for image */ |
|
930 dx = (OWFfloat) srcRect[2] / (OWFfloat) dstRect->width; |
|
931 dy = (OWFfloat) srcRect[3] / (OWFfloat) dstRect->height; |
|
932 |
|
933 for (y = 0; y < dstRect->height; y++) |
|
934 { |
|
935 for (x = 0; x < dstRect->width; x++) |
|
936 { |
|
937 OWFpixel* pixel; |
|
938 |
|
939 /* NOTE This code uses pixel center points to calculate distances |
|
940 and factors. Results can differ slightly when pixel corner |
|
941 coordinates are used */ |
|
942 |
|
943 /* coordinates of nearest pixel in original image */ |
|
944 ox = (int) floor((((OWFfloat) x + 0.5) * dx) + srcRect[0]); |
|
945 oy = (int) floor((((OWFfloat) y + 0.5) * dy) + srcRect[1]); |
|
946 |
|
947 pixel = OWF_Image_GetPixelPtr(src, |
|
948 ox, |
|
949 oy); |
|
950 |
|
951 OWF_Image_SetPixel(dst, |
|
952 dstRect->x + x, |
|
953 dstRect->y + y, |
|
954 pixel); |
|
955 |
|
956 } |
|
957 } |
|
958 return OWF_TRUE; |
|
959 } |
|
960 |
|
961 /*----------------------------------------------------------------------------*/ |
|
962 OWF_API_CALL OWFboolean |
|
963 OWF_Image_BilinearStretchBlit(OWF_IMAGE* dst, |
|
964 OWF_RECTANGLE* dstRect, |
|
965 OWF_IMAGE* src, |
|
966 OWFfloat* srcRect) |
|
967 { |
|
968 OWFint x = 0, y = 0; |
|
969 OWFint ox = 0, oy = 0; |
|
970 OWFfloat dx = 0.f, dy = 0.f, wx = 0.f, wy = 0.f; |
|
971 OWFfloat w[2 * 2]; |
|
972 OWFpixel* sample[4]; |
|
973 OWFpixel* pixel = NULL; |
|
974 |
|
975 /* images must be valid */ |
|
976 if (!((src != NULL) && (src->data != NULL) && |
|
977 (dst != NULL) && (dst->data != NULL))) |
|
978 { |
|
979 return OWF_FALSE; |
|
980 } |
|
981 OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
982 OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
983 |
|
984 /* ditto with rectangles, too */ |
|
985 if (!((dstRect != NULL) && (dstRect->width && dstRect->height) && |
|
986 (srcRect != NULL) && (srcRect[2] && srcRect[3]))) |
|
987 { |
|
988 return OWF_FALSE; |
|
989 } |
|
990 |
|
991 if (src->pixelSize != dst->pixelSize) |
|
992 { |
|
993 return OWF_FALSE; |
|
994 } |
|
995 |
|
996 /* solve scaling ratios for image */ |
|
997 dx = (OWFfloat) srcRect[2] / (OWFfloat) dstRect->width; |
|
998 dy = (OWFfloat) srcRect[3] / (OWFfloat) dstRect->height; |
|
999 |
|
1000 for (y = 0; y < dstRect->height; y++) |
|
1001 { |
|
1002 for (x = 0; x < dstRect->width; x++) |
|
1003 { |
|
1004 OWFfloat tempOx, tempOy; |
|
1005 |
|
1006 /* NOTE This code uses pixel center points to calculate distances |
|
1007 and factors. Results can differ slightly when pixel corner |
|
1008 coordinates are used */ |
|
1009 |
|
1010 /* coordinates of nearest pixel in original image */ |
|
1011 tempOx = (((OWFfloat) x + 0.5) * dx) + srcRect[0]; |
|
1012 tempOy = (((OWFfloat) y + 0.5) * dy) + srcRect[1]; |
|
1013 |
|
1014 ox = (int) floor((((OWFfloat) x + 0.5) * dx) + srcRect[0]); |
|
1015 oy = (int) floor((((OWFfloat) y + 0.5) * dy) + srcRect[1]); |
|
1016 |
|
1017 /* Distances to nearest pixel, eg. fractional part of coordinate */ |
|
1018 wx = (OWFfloat) ox + 0.5 - tempOx; |
|
1019 wy = (OWFfloat) oy + 0.5 - tempOy; |
|
1020 |
|
1021 /* If distance is positive, we should use left or upper pixel for |
|
1022 * second nearest pixel. */ |
|
1023 if (wx > 0.0) |
|
1024 { |
|
1025 ox--; |
|
1026 wx = 1.0 - wx; |
|
1027 } |
|
1028 else |
|
1029 { |
|
1030 wx = -wx; /* abs */ |
|
1031 } |
|
1032 |
|
1033 if (wy > 0.0) |
|
1034 { |
|
1035 oy--; |
|
1036 wy = 1.0 - wy; |
|
1037 } |
|
1038 else |
|
1039 { |
|
1040 wy = -wy; |
|
1041 } |
|
1042 |
|
1043 /* Calculate weights for samples */ |
|
1044 w[0] = (1.0 - wx) * (1.0 - wy); |
|
1045 w[1] = wx * (1.0 - wy); |
|
1046 w[2] = (1.0 - wx) * wy; |
|
1047 w[3] = wx * wy; |
|
1048 |
|
1049 /* get sample */ |
|
1050 sample[0] = OWF_Image_GetPixelPtr(src, ox + 0, oy + 0); |
|
1051 sample[1] = OWF_Image_GetPixelPtr(src, ox + 1, oy + 0); |
|
1052 sample[2] = OWF_Image_GetPixelPtr(src, ox + 0, oy + 1); |
|
1053 sample[3] = OWF_Image_GetPixelPtr(src, ox + 1, oy + 1); |
|
1054 |
|
1055 |
|
1056 /* get result pixel */ |
|
1057 pixel = OWF_Image_GetPixelPtr(dst, x, y); |
|
1058 |
|
1059 /* calculate final color */ |
|
1060 pixel->color.red = |
|
1061 sample[0]->color.red * w[0] + sample[1]->color.red * w[1] + |
|
1062 sample[2]->color.red * w[2] + sample[3]->color.red * w[3] + OWF_BILINEAR_ROUNDING_VALUE; |
|
1063 |
|
1064 pixel->color.green = |
|
1065 sample[0]->color.green * w[0] + sample[1]->color.green * w[1] + |
|
1066 sample[2]->color.green * w[2] + sample[3]->color.green * w[3] + OWF_BILINEAR_ROUNDING_VALUE; |
|
1067 |
|
1068 pixel->color.blue = |
|
1069 sample[0]->color.blue * w[0] + sample[1]->color.blue * w[1] + |
|
1070 sample[2]->color.blue * w[2] + sample[3]->color.blue * w[3] + OWF_BILINEAR_ROUNDING_VALUE; |
|
1071 |
|
1072 pixel->color.alpha = |
|
1073 sample[0]->color.alpha * w[0] + sample[1]->color.alpha * w[1] + |
|
1074 sample[2]->color.alpha * w[2] + sample[3]->color.alpha * w[3] + OWF_BILINEAR_ROUNDING_VALUE; |
|
1075 } |
|
1076 } |
|
1077 return OWF_TRUE; |
|
1078 |
|
1079 } |
|
1080 |
|
1081 /*----------------------------------------------------------------------------*/ |
|
1082 OWF_API_CALL OWFboolean |
|
1083 OWF_Image_Stretch(OWF_IMAGE* dst, |
|
1084 OWF_RECTANGLE* dstRect, |
|
1085 OWF_IMAGE* src, |
|
1086 OWFfloat* srcRect, |
|
1087 OWF_FILTERING filter) |
|
1088 { |
|
1089 OWFboolean result = OWF_FALSE; |
|
1090 |
|
1091 switch (filter) |
|
1092 { |
|
1093 case OWF_FILTER_POINT_SAMPLING: |
|
1094 { |
|
1095 result = OWF_Image_PointSamplingStretchBlit(dst, dstRect, src, |
|
1096 srcRect); |
|
1097 break; |
|
1098 } |
|
1099 case OWF_FILTER_BILINEAR: |
|
1100 { |
|
1101 result = OWF_Image_BilinearStretchBlit(dst, dstRect, src, srcRect); |
|
1102 break; |
|
1103 } |
|
1104 } |
|
1105 |
|
1106 return result; |
|
1107 } |
|
1108 |
|
1109 /*----------------------------------------------------------------------------*/ |
|
1110 OWF_API_CALL void |
|
1111 OWF_Image_Clear(OWF_IMAGE* image, |
|
1112 OWFsubpixel red, |
|
1113 OWFsubpixel green, |
|
1114 OWFsubpixel blue, |
|
1115 OWFsubpixel alpha) |
|
1116 { |
|
1117 OWFint i, numPixels; |
|
1118 OWFpixel* pixels; |
|
1119 |
|
1120 OWF_ASSERT(image != 0); |
|
1121 OWF_ASSERT(image->data != 0); |
|
1122 OWF_ASSERT(image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); |
|
1123 |
|
1124 numPixels = image->width * image->height; |
|
1125 pixels = (OWFpixel*) image->data; |
|
1126 |
|
1127 for (i = 0; i < numPixels; i++) |
|
1128 { |
|
1129 pixels[i].color.red = (OWFsubpixel) red; |
|
1130 pixels[i].color.green = (OWFsubpixel) green; |
|
1131 pixels[i].color.blue = (OWFsubpixel) blue; |
|
1132 pixels[i].color.alpha = (OWFsubpixel) alpha; |
|
1133 } |
|
1134 } |
|
1135 |
|
1136 /*----------------------------------------------------------------------------*/ |
|
1137 OWF_API_CALL void |
|
1138 OWF_Image_PremultiplyAlpha(OWF_IMAGE* image) |
|
1139 { |
|
1140 OWFint x, y; |
|
1141 |
|
1142 OWF_ASSERT(image != 0); |
|
1143 |
|
1144 if (image->format.premultiplied) |
|
1145 { |
|
1146 return; |
|
1147 } |
|
1148 |
|
1149 /* only for internal format */ |
|
1150 if (image->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) |
|
1151 { |
|
1152 return; |
|
1153 } |
|
1154 |
|
1155 for (y = 0; y < image->height; y++) |
|
1156 { |
|
1157 for (x = 0; x < image->width; x++) |
|
1158 { |
|
1159 OWFpixel* pixel; |
|
1160 OWFsubpixel alpha; |
|
1161 |
|
1162 pixel = OWF_Image_GetPixelPtr(image, x, y); |
|
1163 |
|
1164 alpha = pixel->color.alpha; |
|
1165 |
|
1166 if (0 == alpha) |
|
1167 { |
|
1168 pixel->color.red = |
|
1169 pixel->color.green = |
|
1170 pixel->color.blue = 0; |
|
1171 } |
|
1172 else |
|
1173 { |
|
1174 pixel->color.red = (pixel->color.red * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / |
|
1175 OWF_ALPHA_MAX_VALUE; |
|
1176 pixel->color.green = (pixel->color.green * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / |
|
1177 OWF_ALPHA_MAX_VALUE; |
|
1178 pixel->color.blue = (pixel->color.blue * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / |
|
1179 OWF_ALPHA_MAX_VALUE; |
|
1180 } |
|
1181 } |
|
1182 } |
|
1183 |
|
1184 image->format.premultiplied = OWF_TRUE; |
|
1185 } |
|
1186 |
|
1187 /*----------------------------------------------------------------------------*/ |
|
1188 OWF_API_CALL void |
|
1189 OWF_Image_UnpremultiplyAlpha(OWF_IMAGE* image) |
|
1190 { |
|
1191 OWFint count; |
|
1192 OWFpixel* pixelPtr; |
|
1193 |
|
1194 OWF_ASSERT(image != 0); |
|
1195 |
|
1196 if (!image->format.premultiplied) |
|
1197 { |
|
1198 return; |
|
1199 } |
|
1200 |
|
1201 /* only for internal format */ |
|
1202 if (image->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) |
|
1203 { |
|
1204 return; |
|
1205 } |
|
1206 |
|
1207 count = image->width * image->height; |
|
1208 pixelPtr = (OWFpixel*)image->data; |
|
1209 |
|
1210 while (count > 0) |
|
1211 { |
|
1212 |
|
1213 OWFsubpixel a = pixelPtr->color.alpha; |
|
1214 |
|
1215 #ifdef OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT |
|
1216 OWF_ASSERT(a <= OWF_ALPHA_MAX_VALUE && a >= OWF_ALPHA_MIN_VALUE); |
|
1217 #endif |
|
1218 |
|
1219 if (a > OWF_ALPHA_MIN_VALUE) |
|
1220 { |
|
1221 OWFsubpixel r = pixelPtr->color.red * OWF_RED_MAX_VALUE / a; |
|
1222 OWFsubpixel g = pixelPtr->color.green * OWF_GREEN_MAX_VALUE / a; |
|
1223 OWFsubpixel b = pixelPtr->color.blue * OWF_BLUE_MAX_VALUE / a; |
|
1224 |
|
1225 pixelPtr->color.red = r; |
|
1226 pixelPtr->color.green = g; |
|
1227 pixelPtr->color.blue = b; |
|
1228 |
|
1229 --count; |
|
1230 pixelPtr++; |
|
1231 } |
|
1232 } |
|
1233 |
|
1234 image->format.premultiplied = OWF_TRUE; |
|
1235 } |
|
1236 |
|
1237 /*----------------------------------------------------------------------------*/ |
|
1238 OWF_API_CALL void |
|
1239 OWF_Image_Rotate(OWF_IMAGE* dst, |
|
1240 OWF_IMAGE* src, |
|
1241 OWF_ROTATION rotation) |
|
1242 { |
|
1243 OWFint ox = 0, oy = 0, |
|
1244 w = 0, h = 0, |
|
1245 x = 0, y = 0; |
|
1246 OWFint xx = 0, xy = 0, |
|
1247 yx = 0, yy = 0; |
|
1248 |
|
1249 OWF_ASSERT(src && src->data); |
|
1250 OWF_ASSERT(dst && dst->data); |
|
1251 OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
1252 OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
1253 |
|
1254 w = src->width; |
|
1255 h = src->height; |
|
1256 |
|
1257 switch (rotation) |
|
1258 { |
|
1259 case OWF_ROTATION_0: |
|
1260 { |
|
1261 /* |
|
1262 * origin: (0, 0) |
|
1263 * x-axis: (1, 0) |
|
1264 * y-axis: (0, 1) |
|
1265 */ |
|
1266 ox = 0; |
|
1267 oy = 0; |
|
1268 xx = 1; |
|
1269 xy = 0; |
|
1270 yx = 0; |
|
1271 yy = 1; |
|
1272 break; |
|
1273 } |
|
1274 case OWF_ROTATION_90: |
|
1275 { |
|
1276 /* |
|
1277 * origin: (height-1, 0) |
|
1278 * x-axis: (0, 1) |
|
1279 * y-axis: (-1, 0) |
|
1280 */ |
|
1281 ox = h - 1; |
|
1282 oy = 0; |
|
1283 xx = 0; |
|
1284 xy = 1; |
|
1285 yx = -1; |
|
1286 yy = 0; |
|
1287 break; |
|
1288 } |
|
1289 case OWF_ROTATION_180: |
|
1290 { |
|
1291 /* |
|
1292 * origin: (width-1, height-1) |
|
1293 * x-axis: (-1, 0) |
|
1294 * y-axis: (0, -1) |
|
1295 */ |
|
1296 ox = w - 1; |
|
1297 oy = h - 1; |
|
1298 xx = -1; |
|
1299 xy = 0; |
|
1300 yx = 0; |
|
1301 yy = -1; |
|
1302 break; |
|
1303 } |
|
1304 case OWF_ROTATION_270: |
|
1305 { |
|
1306 /* |
|
1307 * origin: (0, height-1) |
|
1308 * x-axis: (0, -1) |
|
1309 * y-axis: (1, 0) |
|
1310 */ |
|
1311 ox = 0; |
|
1312 oy = w - 1; |
|
1313 xx = 0; |
|
1314 xy = -1; |
|
1315 yx = 1; |
|
1316 yy = 0; |
|
1317 break; |
|
1318 |
|
1319 } |
|
1320 } |
|
1321 |
|
1322 for (y = 0; y < h; y++) |
|
1323 { |
|
1324 for (x = 0; x < w; x++) |
|
1325 { |
|
1326 /* |
|
1327 * O = [ox oy]' X = [xx xy]' Y = [yx yy]' |
|
1328 * |
|
1329 * p_dst(x_src,y_src) = O + x_src*X + y_src*Y |
|
1330 */ |
|
1331 OWF_Image_SetPixel(dst, |
|
1332 ox + x * xx + y * yx, |
|
1333 oy + x * xy + y * yy, |
|
1334 OWF_Image_GetPixelPtr(src, x, y)); |
|
1335 } |
|
1336 } |
|
1337 } |
|
1338 |
|
1339 /*----------------------------------------------------------------------------*/ |
|
1340 OWF_API_CALL void |
|
1341 OWF_Image_Flip(OWF_IMAGE* image, |
|
1342 OWF_FLIP_DIRECTION dir) |
|
1343 { |
|
1344 OWFint x, y; |
|
1345 |
|
1346 if (!image) |
|
1347 { |
|
1348 return; |
|
1349 } |
|
1350 OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); |
|
1351 |
|
1352 if (dir & OWF_FLIP_VERTICALLY) |
|
1353 { |
|
1354 OWFint h = image->height/2; |
|
1355 |
|
1356 for (y = 0; y < h; y++) |
|
1357 { |
|
1358 for (x = 0; x < image->width; x++) |
|
1359 { |
|
1360 OWFpixel pix; |
|
1361 |
|
1362 OWF_Image_GetPixel(image, x, y, &pix); |
|
1363 OWF_Image_SetPixel(image, x, y, |
|
1364 OWF_Image_GetPixelPtr(image, |
|
1365 x, |
|
1366 image->height - 1 - y |
|
1367 )); |
|
1368 OWF_Image_SetPixel(image, x, image->height - 1 - y, &pix); |
|
1369 } |
|
1370 } |
|
1371 } |
|
1372 |
|
1373 if (dir & OWF_FLIP_HORIZONTALLY) |
|
1374 { |
|
1375 OWFint w = image->width/2; |
|
1376 |
|
1377 for (y = 0; y < image->height; y++) |
|
1378 { |
|
1379 for (x = 0; x < w; x++) |
|
1380 { |
|
1381 OWFpixel pix; |
|
1382 |
|
1383 OWF_Image_GetPixel(image, x, y, &pix); |
|
1384 OWF_Image_SetPixel(image, x, y, |
|
1385 OWF_Image_GetPixelPtr(image, |
|
1386 image->width - 1 - x, |
|
1387 y |
|
1388 )); |
|
1389 OWF_Image_SetPixel(image, image->width - 1 - x, y, &pix); |
|
1390 } |
|
1391 } |
|
1392 } |
|
1393 } |
|
1394 |
|
1395 /*----------------------------------------------------------------------------*/ |
|
1396 #define BLENDER_INNER_LOOP_BEGIN \ |
|
1397 OWFint rowCount = drect.height; \ |
|
1398 while (rowCount > 0) { \ |
|
1399 OWFint colCount = drect.width; \ |
|
1400 while (colCount > 0) { \ |
|
1401 if (!(blend->tsColor && COLOR_MATCH(SC, TSC))) \ |
|
1402 { \ |
|
1403 |
|
1404 #define BLENDER_INNER_LOOP_END \ |
|
1405 DA = blend->destinationFullyOpaque ? OWF_FULLY_OPAQUE : DA; \ |
|
1406 } /* end tsColor check */ \ |
|
1407 srcPtr ++; \ |
|
1408 dstPtr ++; \ |
|
1409 maskPtr++; \ |
|
1410 --colCount; \ |
|
1411 } \ |
|
1412 srcPtr += srcLineDelta; \ |
|
1413 dstPtr += dstLineDelta; \ |
|
1414 maskPtr += maskLineDelta; \ |
|
1415 --rowCount; \ |
|
1416 } |
|
1417 |
|
1418 #define TSC blend->tsColor->color |
|
1419 #define SC srcPtr->color |
|
1420 |
|
1421 /* Note: actually would be better to compare integer values |
|
1422 * for TSC match -> eliminate float arithmetic pitfalls |
|
1423 */ |
|
1424 #define COLOR_MATCH(x, y) (x.red==y.red && x.green==y.green && x.blue==y.blue) |
|
1425 |
|
1426 #define SA srcPtr->color.alpha |
|
1427 #define SR srcPtr->color.red |
|
1428 #define SG srcPtr->color.green |
|
1429 #define SB srcPtr->color.blue |
|
1430 |
|
1431 #define DA dstPtr->color.alpha |
|
1432 #define DR dstPtr->color.red |
|
1433 #define DG dstPtr->color.green |
|
1434 #define DB dstPtr->color.blue |
|
1435 |
|
1436 #define MA *maskPtr |
|
1437 #define GA blend->globalAlpha |
|
1438 |
|
1439 OWF_API_CALL void |
|
1440 OWF_Image_Blend(OWF_BLEND_INFO* blend, |
|
1441 OWF_TRANSPARENCY transparency) |
|
1442 { |
|
1443 OWF_IMAGE* dst; |
|
1444 OWF_IMAGE* src; |
|
1445 OWF_IMAGE* mask; |
|
1446 OWF_RECTANGLE* srcRect; |
|
1447 OWF_RECTANGLE* dstRect; |
|
1448 OWF_RECTANGLE bounds, srect, drect, rect; |
|
1449 OWFint srcLineDelta, dstLineDelta, maskLineDelta; |
|
1450 OWFpixel* srcPtr; |
|
1451 OWFpixel* dstPtr; |
|
1452 OWFsubpixel* maskPtr; |
|
1453 |
|
1454 |
|
1455 /* preparation */ |
|
1456 OWF_ASSERT(blend); |
|
1457 DPRINT(("OWF_Image_Blend: transparency = %d", transparency)); |
|
1458 /* Mask must be set if mask-transparency is used */ |
|
1459 OWF_ASSERT(((transparency & OWF_TRANSPARENCY_MASK) && blend->mask) || |
|
1460 !(transparency & OWF_TRANSPARENCY_MASK)); |
|
1461 |
|
1462 OWF_ASSERT(blend->source.image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); |
|
1463 OWF_ASSERT(blend->destination.image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); |
|
1464 if (blend->mask) |
|
1465 { |
|
1466 OWF_ASSERT(blend->mask->format.pixelFormat == OWF_IMAGE_L32); |
|
1467 } |
|
1468 |
|
1469 dst = blend->destination.image; |
|
1470 src = blend->source.image; |
|
1471 mask = blend->mask; |
|
1472 dstRect = blend->destination.rectangle; |
|
1473 srcRect = blend->source.rectangle; |
|
1474 |
|
1475 /* this is actually asserted above */ |
|
1476 if (OWF_TRANSPARENCY_MASK == (transparency & OWF_TRANSPARENCY_MASK) && |
|
1477 NULL == mask) |
|
1478 { |
|
1479 return; |
|
1480 } |
|
1481 |
|
1482 OWF_Rect_Set(&bounds, 0, 0, dst->width, dst->height); |
|
1483 /* NOTE: src and dst rects should be of same size!!! */ |
|
1484 OWF_Rect_Set(&rect, |
|
1485 dstRect->x, dstRect->y, |
|
1486 dstRect->width, dstRect->height); |
|
1487 OWF_Rect_Set(&srect, |
|
1488 srcRect->x, srcRect->y, |
|
1489 srcRect->width, srcRect->height); |
|
1490 |
|
1491 /* clip destination rectangle against bounds */ |
|
1492 if (!OWF_Rect_Clip(&drect, &rect, &bounds)) |
|
1493 { |
|
1494 return; |
|
1495 } |
|
1496 |
|
1497 /* adjust source rectangle if needed */ |
|
1498 if (drect.x > rect.x) |
|
1499 { |
|
1500 OWFint dx = drect.x - rect.x; |
|
1501 srect.x += dx; |
|
1502 srect.width -= dx; |
|
1503 } |
|
1504 |
|
1505 if (drect.y > rect.y) |
|
1506 { |
|
1507 OWFint dy = drect.y - rect.y; |
|
1508 srect.y += dy; |
|
1509 srect.height -= dy; |
|
1510 } |
|
1511 |
|
1512 if (drect.width < srect.width) |
|
1513 { |
|
1514 srect.width = drect.width; |
|
1515 } |
|
1516 |
|
1517 if (drect.height < srect.height) |
|
1518 { |
|
1519 srect.height = drect.height; |
|
1520 } |
|
1521 |
|
1522 |
|
1523 srcPtr = (OWFpixel*) src->data; |
|
1524 srcPtr += srect.y * src->width + srect.x; |
|
1525 dstPtr = (OWFpixel*) dst->data; |
|
1526 dstPtr += drect.y * dst->width + drect.x; |
|
1527 |
|
1528 if (mask) |
|
1529 { |
|
1530 maskPtr = (OWFsubpixel*) mask->data + srect.y * mask->width + srect.x; |
|
1531 maskLineDelta = mask->width - drect.width; |
|
1532 } |
|
1533 else |
|
1534 { |
|
1535 maskPtr = 0; |
|
1536 maskLineDelta = 0; |
|
1537 } |
|
1538 srcLineDelta = src->width - srect.width; |
|
1539 dstLineDelta = dst->width - drect.width; |
|
1540 |
|
1541 /* inner loops */ |
|
1542 switch (transparency) |
|
1543 { |
|
1544 case OWF_TRANSPARENCY_NONE: |
|
1545 { |
|
1546 /* |
|
1547 rgb = src.rgb |
|
1548 alpha = 1 |
|
1549 */ |
|
1550 BLENDER_INNER_LOOP_BEGIN; |
|
1551 DR = SR; |
|
1552 DG = SG; |
|
1553 DB = SB; |
|
1554 DA = OWF_FULLY_OPAQUE; |
|
1555 BLENDER_INNER_LOOP_END; |
|
1556 break; |
|
1557 } |
|
1558 |
|
1559 case OWF_TRANSPARENCY_GLOBAL_ALPHA: |
|
1560 { |
|
1561 /* |
|
1562 rgb = src.rgb * elem.alpha + dst.rgb * (1 - elem.alpha) |
|
1563 alpha = elem.alpha + dst.alpha * (1 - elem.alpha) |
|
1564 */ |
|
1565 BLENDER_INNER_LOOP_BEGIN; |
|
1566 DR = (SR * GA + DR * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1567 OWF_ALPHA_MAX_VALUE; |
|
1568 DG = (SG * GA + DG * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1569 OWF_ALPHA_MAX_VALUE; |
|
1570 DB = (SB * GA + DB * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1571 OWF_ALPHA_MAX_VALUE; |
|
1572 DA = GA + (DA * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1573 OWF_ALPHA_MAX_VALUE; |
|
1574 BLENDER_INNER_LOOP_END; |
|
1575 break; |
|
1576 } |
|
1577 |
|
1578 case OWF_TRANSPARENCY_SOURCE_ALPHA: |
|
1579 { |
|
1580 /* |
|
1581 rgb = src.rgb + dst.rgb * (1 - src.alpha) |
|
1582 alpha = src.alpha + dst.alpha * (1 - src.alpha) |
|
1583 */ |
|
1584 BLENDER_INNER_LOOP_BEGIN; |
|
1585 DR = SR + (DR * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; |
|
1586 DG = SG + (DG * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; |
|
1587 DB = SB + (DB * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; |
|
1588 DA = SA + (DA * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; |
|
1589 BLENDER_INNER_LOOP_END; |
|
1590 break; |
|
1591 } |
|
1592 |
|
1593 case OWF_TRANSPARENCY_MASK: |
|
1594 { |
|
1595 /* |
|
1596 rgb = src.rgb * mask.alpha + dst.rgb * (1 - mask.alpha) |
|
1597 alpha = mask.alpha + dst.alpha * (1 - mask.alpha) |
|
1598 */ |
|
1599 BLENDER_INNER_LOOP_BEGIN; |
|
1600 DR = (SR * MA + DR * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1601 OWF_ALPHA_MAX_VALUE; |
|
1602 DG = (SG * MA + DG * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1603 OWF_ALPHA_MAX_VALUE; |
|
1604 DB = (SB * MA + DB * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1605 OWF_ALPHA_MAX_VALUE; |
|
1606 DA = MA + (DA * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1607 OWF_ALPHA_MAX_VALUE; |
|
1608 BLENDER_INNER_LOOP_END; |
|
1609 break; |
|
1610 } |
|
1611 |
|
1612 case OWF_TRANSPARENCY_GLOBAL_ALPHA | OWF_TRANSPARENCY_SOURCE_ALPHA: |
|
1613 { |
|
1614 /* |
|
1615 rgb = src.rgb * elem.a + dst.rgb * (1 - src.a * elem.a) |
|
1616 a = src.a * elem.a + dst.a * (1 - src.a * elem.a) |
|
1617 */ |
|
1618 OWFsubpixel SAEA; |
|
1619 |
|
1620 BLENDER_INNER_LOOP_BEGIN; |
|
1621 SAEA = SA * GA / OWF_ALPHA_MAX_VALUE; |
|
1622 DR = (SR * GA + DR * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1623 OWF_ALPHA_MAX_VALUE; |
|
1624 DG = (SG * GA + DG * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1625 OWF_ALPHA_MAX_VALUE; |
|
1626 DB = (SB * GA + DB * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1627 OWF_ALPHA_MAX_VALUE; |
|
1628 DA = SAEA + (DA * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1629 OWF_ALPHA_MAX_VALUE; |
|
1630 BLENDER_INNER_LOOP_END; |
|
1631 break; |
|
1632 } |
|
1633 |
|
1634 case OWF_TRANSPARENCY_GLOBAL_ALPHA | OWF_TRANSPARENCY_MASK: |
|
1635 { |
|
1636 /* |
|
1637 rgb = src.rgb * mask.a * elem.a + dst.rgb * (1 - mask.a * elem.a) |
|
1638 a = mask.a * elem.a + dest.a * (1 - mask.a * elem.a) |
|
1639 */ |
|
1640 OWFsubpixel MAEA; |
|
1641 |
|
1642 BLENDER_INNER_LOOP_BEGIN; |
|
1643 MAEA = MA * GA / OWF_ALPHA_MAX_VALUE; |
|
1644 DR = (SR * MAEA + DR * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1645 OWF_ALPHA_MAX_VALUE; |
|
1646 DG = (SG * MAEA + DG * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1647 OWF_ALPHA_MAX_VALUE; |
|
1648 DB = (SB * MAEA + DB * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1649 OWF_ALPHA_MAX_VALUE; |
|
1650 DA = MAEA + (DA * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / |
|
1651 OWF_ALPHA_MAX_VALUE; |
|
1652 //No need to check with OWF_ALPHA_MIN_VALUE as it is zero |
|
1653 OWF_ASSERT(GA <= OWF_ALPHA_MAX_VALUE); |
|
1654 BLENDER_INNER_LOOP_END; |
|
1655 break; |
|
1656 } |
|
1657 |
|
1658 default: |
|
1659 { |
|
1660 DPRINT(("OWF_Image_Blend: whooops. invalid blending mode\n")); |
|
1661 abort(); |
|
1662 break; |
|
1663 } |
|
1664 } |
|
1665 } |
|
1666 |
|
1667 /*----------------------------------------------------------------------------*/ |
|
1668 OWF_API_CALL void* |
|
1669 OWF_Image_AllocData(OWF_DISPCTX dc, OWFint width, OWFint height, OWF_PIXEL_FORMAT pixelFormat) |
|
1670 { |
|
1671 OWF_IMAGE_FORMAT imgf; |
|
1672 OWFint stride; |
|
1673 |
|
1674 /* kludge. GetStride need pixelFormat. */ |
|
1675 imgf.pixelFormat = pixelFormat; |
|
1676 imgf.rowPadding = OWF_Image_GetFormatPadding(pixelFormat); |
|
1677 stride = OWF_Image_GetStride(width, &imgf, 0); |
|
1678 |
|
1679 OWF_ASSERT (width > 0 && height > 0); |
|
1680 |
|
1681 if (stride == 0) |
|
1682 { |
|
1683 return NULL; |
|
1684 } |
|
1685 |
|
1686 if (dc) |
|
1687 { |
|
1688 return OWF_DisplayContext_ScratchBuffer_Allocate(dc, height * stride); |
|
1689 } |
|
1690 |
|
1691 return xalloc(1, height * stride); |
|
1692 } |
|
1693 |
|
1694 /*----------------------------------------------------------------------------*/ |
|
1695 OWF_API_CALL void |
|
1696 OWF_Image_FreeData(OWF_DISPCTX dc, void** data) |
|
1697 { |
|
1698 if (*data) |
|
1699 { |
|
1700 if (dc) |
|
1701 { |
|
1702 OWF_DisplayContext_ScratchBuffer_Destroy(dc, *data); |
|
1703 } |
|
1704 else |
|
1705 { |
|
1706 xfree(*data); |
|
1707 } |
|
1708 } |
|
1709 *data = NULL; |
|
1710 } |
|
1711 |
|
1712 /*----------------------------------------------------------------------------*/ |
|
1713 OWF_API_CALL OWFint |
|
1714 OWF_Image_GetFormatPixelSize(OWF_PIXEL_FORMAT format) |
|
1715 { |
|
1716 switch (format) |
|
1717 { |
|
1718 case OWF_IMAGE_ARGB_INTERNAL: |
|
1719 { |
|
1720 return sizeof(OWFpixel); |
|
1721 } |
|
1722 |
|
1723 case OWF_IMAGE_ARGB8888: |
|
1724 case OWF_IMAGE_XRGB8888: |
|
1725 case OWF_IMAGE_L32: |
|
1726 { |
|
1727 return 4; |
|
1728 } |
|
1729 |
|
1730 case OWF_IMAGE_RGB888: |
|
1731 { |
|
1732 return 3; |
|
1733 } |
|
1734 |
|
1735 case OWF_IMAGE_RGB565: |
|
1736 case OWF_IMAGE_L16: |
|
1737 { |
|
1738 return 2; |
|
1739 } |
|
1740 |
|
1741 case OWF_IMAGE_L8: |
|
1742 { |
|
1743 return 1; |
|
1744 } |
|
1745 |
|
1746 case OWF_IMAGE_L1: |
|
1747 { |
|
1748 /* Use negative numbers for divisor, e.g., -8 = 1/8. */ |
|
1749 /* L1 is 1 bit alpha, LSB->MSB, each row padded to 32-bit |
|
1750 * boundary. */ |
|
1751 return -8; |
|
1752 } |
|
1753 default: |
|
1754 { |
|
1755 return 0; |
|
1756 } |
|
1757 } |
|
1758 } |
|
1759 |
|
1760 /*----------------------------------------------------------------------------*/ |
|
1761 OWF_API_CALL OWFint |
|
1762 OWF_Image_GetFormatPadding(OWF_PIXEL_FORMAT format) |
|
1763 { |
|
1764 OWFint padding = 1; |
|
1765 |
|
1766 switch (format) |
|
1767 { |
|
1768 case OWF_IMAGE_ARGB_INTERNAL: |
|
1769 { |
|
1770 padding = sizeof(OWFpixel); |
|
1771 break; |
|
1772 } |
|
1773 |
|
1774 case OWF_IMAGE_ARGB8888: |
|
1775 case OWF_IMAGE_XRGB8888: |
|
1776 case OWF_IMAGE_L32: |
|
1777 { |
|
1778 padding = 4; |
|
1779 break; |
|
1780 } |
|
1781 |
|
1782 /* |
|
1783 case OWF_IMAGE_RGB888: |
|
1784 { |
|
1785 return 3; |
|
1786 } |
|
1787 */ |
|
1788 |
|
1789 case OWF_IMAGE_RGB565: |
|
1790 case OWF_IMAGE_L16: |
|
1791 { |
|
1792 padding = 2; |
|
1793 break; |
|
1794 } |
|
1795 |
|
1796 case OWF_IMAGE_L8: |
|
1797 { |
|
1798 padding = 1; |
|
1799 break; |
|
1800 } |
|
1801 |
|
1802 case OWF_IMAGE_L1: |
|
1803 { |
|
1804 /* Use negative numbers for divisor, e.g., -8 = 1/8. */ |
|
1805 /* L1 is 1 bit alpha, LSB->MSB, each row padded to 32-bit |
|
1806 * boundary. */ |
|
1807 padding = 4; |
|
1808 break; |
|
1809 } |
|
1810 default: |
|
1811 { |
|
1812 break; |
|
1813 } |
|
1814 } |
|
1815 |
|
1816 OWF_ASSERT(padding); |
|
1817 |
|
1818 return padding; |
|
1819 } |
|
1820 |
|
1821 /*----------------------------------------------------------------------------*/ |
|
1822 OWF_API_CALL void |
|
1823 OWF_Image_SwapWidthAndHeight(OWF_IMAGE* image) |
|
1824 { |
|
1825 /* swap w & h. Note that original stride is not restored if swap back. */ |
|
1826 image->width ^= image->height; |
|
1827 image->height ^= image->width; |
|
1828 image->width ^= image->height; |
|
1829 |
|
1830 image->stride = OWF_Image_GetStride(image->width, &image->format, 0); |
|
1831 } |
|
1832 |
|
1833 /*----------------------------------------------------------------------------*/ |
|
1834 OWF_API_CALL OWFboolean |
|
1835 OWF_Image_ConvertMask(OWF_IMAGE* output, OWF_IMAGE* input) |
|
1836 { |
|
1837 OWFboolean result = OWF_TRUE; |
|
1838 void* srcLinePtr; |
|
1839 OWFsubpixel* dstLinePtr; |
|
1840 OWFint countY; |
|
1841 |
|
1842 DPRINT(("OWF_Image_ConvertMask:")); |
|
1843 DPRINT((" Converting mask from stream format to internal 8-bit")); |
|
1844 |
|
1845 OWF_ASSERT(input); |
|
1846 OWF_ASSERT(output); |
|
1847 |
|
1848 srcLinePtr = input->data; |
|
1849 dstLinePtr = (OWFsubpixel*) output->data; |
|
1850 |
|
1851 for (countY = input->height; countY; countY--) |
|
1852 { |
|
1853 OWFsubpixel* dstData = dstLinePtr; |
|
1854 |
|
1855 switch (input->format.pixelFormat) |
|
1856 { |
|
1857 case OWF_IMAGE_L1: |
|
1858 { |
|
1859 OWFint countX; |
|
1860 OWFuint8* srcData = (OWFuint8*) srcLinePtr; |
|
1861 |
|
1862 DPRINT(("1-bit alpha, width = %d, height = %d", |
|
1863 input->width, input->height)); |
|
1864 |
|
1865 for (countX = 0; countX < input->width; countX++) |
|
1866 { |
|
1867 /* |
|
1868 * alpha pixel ordering is LSB -> MSB |
|
1869 * |
|
1870 * byte# |----- byte 0 ----|----- byte 1-----|-- |
|
1871 * bit# | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | |
|
1872 * pix# | 7 6 5 4 3 2 1 0 | f e d c b a 9 8 | ... |
|
1873 */ |
|
1874 if (srcData[countX >> 3] & (1 << (countX & 7))) |
|
1875 { |
|
1876 dstData[countX] = OWF_FULLY_OPAQUE; |
|
1877 } |
|
1878 else |
|
1879 { |
|
1880 dstData[countX] = OWF_FULLY_TRANSPARENT; |
|
1881 } |
|
1882 } |
|
1883 break; |
|
1884 } |
|
1885 case OWF_IMAGE_L8: |
|
1886 { |
|
1887 OWFint countX; |
|
1888 OWFuint8* srcData = (OWFuint8*) srcLinePtr; |
|
1889 |
|
1890 DPRINT(("8-bit alpha, width = %d, height = %d", |
|
1891 input->width, input->height)); |
|
1892 |
|
1893 for (countX = 0; countX < input->width; countX++) |
|
1894 { |
|
1895 dstData[countX] = srcData[countX] * OWF_FULLY_OPAQUE / |
|
1896 (OWFfloat) OWF_BYTE_MAX_VALUE; |
|
1897 } |
|
1898 break; |
|
1899 } |
|
1900 case OWF_IMAGE_ARGB8888: |
|
1901 { |
|
1902 /* ARGB image - take the alpha channel and discard |
|
1903 * everything else */ |
|
1904 OWFint countX; |
|
1905 OWFuint32* srcData = (OWFuint32*) srcLinePtr; |
|
1906 |
|
1907 DPRINT(("32-bit ARGB, width = %d, height = %d", |
|
1908 input->width, input->height)); |
|
1909 |
|
1910 for (countX = 0; countX < input->width; countX++) |
|
1911 { |
|
1912 dstData[countX] = (srcData[countX] >> 24) * OWF_FULLY_OPAQUE / |
|
1913 (OWFfloat) OWF_BYTE_MAX_VALUE; |
|
1914 } |
|
1915 break; |
|
1916 } |
|
1917 default: |
|
1918 { |
|
1919 DPRINT(("Unsupported alpha format, ignoring mask")); |
|
1920 |
|
1921 result = OWF_FALSE; |
|
1922 break; |
|
1923 } |
|
1924 } |
|
1925 |
|
1926 dstLinePtr+=output->width; |
|
1927 /* Presumes that the stride is always whole bytes - eg. a 2x2-pixel mono |
|
1928 * image takes at least 2 bytes */ |
|
1929 srcLinePtr=(OWFuint8*)srcLinePtr+input->stride; |
|
1930 } |
|
1931 return result; |
|
1932 } |
|
1933 |
|
1934 #ifdef __cplusplus |
|
1935 } |
|
1936 #endif |