1 | /* |
2 | * Copyright © 2021 Benjamin Otte |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Benjamin Otte <otte@gnome.org> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include "gdkmemoryformatprivate.h" |
23 | |
24 | #include "gsk/gl/fp16private.h" |
25 | |
26 | #include <epoxy/gl.h> |
27 | |
28 | typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription; |
29 | |
30 | #define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \ |
31 | static void \ |
32 | name ## _to_float (float *dest, \ |
33 | const guchar *src_data, \ |
34 | gsize n) \ |
35 | { \ |
36 | for (gsize i = 0; i < n; i++) \ |
37 | { \ |
38 | T *src = (T *) (src_data + i * bpp); \ |
39 | dest[0] = (float) src[R] / scale; \ |
40 | dest[1] = (float) src[G] / scale; \ |
41 | dest[2] = (float) src[B] / scale; \ |
42 | if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \ |
43 | dest += 4; \ |
44 | } \ |
45 | } \ |
46 | \ |
47 | static void \ |
48 | name ## _from_float (guchar *dest_data, \ |
49 | const float *src, \ |
50 | gsize n) \ |
51 | { \ |
52 | for (gsize i = 0; i < n; i++) \ |
53 | { \ |
54 | T *dest = (T *) (dest_data + i * bpp); \ |
55 | dest[R] = CLAMP (src[0] * scale + 0.5, 0, scale); \ |
56 | dest[G] = CLAMP (src[1] * scale + 0.5, 0, scale); \ |
57 | dest[B] = CLAMP (src[2] * scale + 0.5, 0, scale); \ |
58 | if (A >= 0) dest[A] = CLAMP (src[3] * scale + 0.5, 0, scale); \ |
59 | src += 4; \ |
60 | } \ |
61 | } |
62 | |
63 | TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255) |
64 | TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255) |
65 | TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255) |
66 | TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255) |
67 | TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255) |
68 | TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255) |
69 | TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255) |
70 | TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255) |
71 | TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255) |
72 | TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535) |
73 | TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535) |
74 | |
75 | static void |
76 | r16g16b16_float_to_float (float *dest, |
77 | const guchar *src_data, |
78 | gsize n) |
79 | { |
80 | guint16 *src = (guint16 *) src_data; |
81 | for (gsize i = 0; i < n; i++) |
82 | { |
83 | half_to_float (h: src, f: dest, n: 3); |
84 | dest[3] = 1.0; |
85 | dest += 4; |
86 | src += 3; |
87 | } |
88 | } |
89 | |
90 | static void |
91 | r16g16b16_float_from_float (guchar *dest_data, |
92 | const float *src, |
93 | gsize n) |
94 | { |
95 | guint16 *dest = (guint16 *) dest_data; |
96 | for (gsize i = 0; i < n; i++) |
97 | { |
98 | float_to_half (f: src, h: dest, n: 3); |
99 | dest += 3; |
100 | src += 4; |
101 | } |
102 | } |
103 | |
104 | static void |
105 | r16g16b16a16_float_to_float (float *dest, |
106 | const guchar *src, |
107 | gsize n) |
108 | { |
109 | half_to_float (h: (const guint16 *) src, f: dest, n: 4 * n); |
110 | } |
111 | |
112 | static void |
113 | r16g16b16a16_float_from_float (guchar *dest, |
114 | const float *src, |
115 | gsize n) |
116 | { |
117 | float_to_half (f: src, h: (guint16 *) dest, n: 4 * n); |
118 | } |
119 | |
120 | static void |
121 | r32g32b32_float_to_float (float *dest, |
122 | const guchar *src_data, |
123 | gsize n) |
124 | { |
125 | float *src = (float *) src_data; |
126 | for (gsize i = 0; i < n; i++) |
127 | { |
128 | dest[0] = src[0]; |
129 | dest[1] = src[1]; |
130 | dest[2] = src[2]; |
131 | dest[3] = 1.0; |
132 | dest += 4; |
133 | src += 3; |
134 | } |
135 | } |
136 | |
137 | static void |
138 | r32g32b32_float_from_float (guchar *dest_data, |
139 | const float *src, |
140 | gsize n) |
141 | { |
142 | float *dest = (float *) dest_data; |
143 | for (gsize i = 0; i < n; i++) |
144 | { |
145 | dest[0] = src[0]; |
146 | dest[1] = src[1]; |
147 | dest[2] = src[2]; |
148 | dest += 3; |
149 | src += 4; |
150 | } |
151 | } |
152 | |
153 | static void |
154 | r32g32b32a32_float_to_float (float *dest, |
155 | const guchar *src, |
156 | gsize n) |
157 | { |
158 | memcpy (dest: dest, src: src, n: sizeof (float) * n * 4); |
159 | } |
160 | |
161 | static void |
162 | r32g32b32a32_float_from_float (guchar *dest, |
163 | const float *src, |
164 | gsize n) |
165 | { |
166 | memcpy (dest: dest, src: src, n: sizeof (float) * n * 4); |
167 | } |
168 | |
169 | #define PREMULTIPLY_FUNC(name, R1, G1, B1, A1, R2, G2, B2, A2) \ |
170 | static void \ |
171 | name (guchar *dest, \ |
172 | const guchar *src, \ |
173 | gsize n) \ |
174 | { \ |
175 | for (; n > 0; n--) \ |
176 | { \ |
177 | guchar a = src[A1]; \ |
178 | guint16 r = (guint16)src[R1] * a + 127; \ |
179 | guint16 g = (guint16)src[G1] * a + 127; \ |
180 | guint16 b = (guint16)src[B1] * a + 127; \ |
181 | dest[R2] = (r + (r >> 8) + 1) >> 8; \ |
182 | dest[G2] = (g + (g >> 8) + 1) >> 8; \ |
183 | dest[B2] = (b + (b >> 8) + 1) >> 8; \ |
184 | dest[A2] = a; \ |
185 | dest += 4; \ |
186 | src += 4; \ |
187 | } \ |
188 | } |
189 | |
190 | PREMULTIPLY_FUNC(r8g8b8a8_to_r8g8b8a8_premultiplied, 0, 1, 2, 3, 0, 1, 2, 3) |
191 | PREMULTIPLY_FUNC(r8g8b8a8_to_b8g8r8a8_premultiplied, 0, 1, 2, 3, 2, 1, 0, 3) |
192 | PREMULTIPLY_FUNC(r8g8b8a8_to_a8r8g8b8_premultiplied, 0, 1, 2, 3, 1, 2, 3, 0) |
193 | PREMULTIPLY_FUNC(r8g8b8a8_to_a8b8g8r8_premultiplied, 0, 1, 2, 3, 3, 2, 1, 0) |
194 | |
195 | #define ADD_ALPHA_FUNC(name, R1, G1, B1, R2, G2, B2, A2) \ |
196 | static void \ |
197 | name (guchar *dest, \ |
198 | const guchar *src, \ |
199 | gsize n) \ |
200 | { \ |
201 | for (; n > 0; n--) \ |
202 | { \ |
203 | dest[R2] = src[R1]; \ |
204 | dest[G2] = src[G1]; \ |
205 | dest[B2] = src[B1]; \ |
206 | dest[A2] = 255; \ |
207 | dest += 4; \ |
208 | src += 3; \ |
209 | } \ |
210 | } |
211 | |
212 | ADD_ALPHA_FUNC(r8g8b8_to_r8g8b8a8, 0, 1, 2, 0, 1, 2, 3) |
213 | ADD_ALPHA_FUNC(r8g8b8_to_b8g8r8a8, 0, 1, 2, 2, 1, 0, 3) |
214 | ADD_ALPHA_FUNC(r8g8b8_to_a8r8g8b8, 0, 1, 2, 1, 2, 3, 0) |
215 | ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0) |
216 | |
217 | struct _GdkMemoryFormatDescription |
218 | { |
219 | GdkMemoryAlpha alpha; |
220 | gsize bytes_per_pixel; |
221 | gsize alignment; |
222 | gboolean prefers_high_depth; |
223 | gboolean supports_gles; |
224 | struct { |
225 | guint internal_format; |
226 | guint format; |
227 | guint type; |
228 | } gl; |
229 | /* no premultiplication going on here */ |
230 | void (* to_float) (float *, const guchar*, gsize); |
231 | void (* from_float) (guchar *, const float *, gsize); |
232 | }; |
233 | |
234 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN |
235 | # define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8 |
236 | #elif G_BYTE_ORDER == G_BIG_ENDIAN |
237 | # define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8_REV |
238 | #else |
239 | # error "Define the right GL flags here" |
240 | #endif |
241 | |
242 | static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { |
243 | [GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = { |
244 | GDK_MEMORY_ALPHA_PREMULTIPLIED, |
245 | 4, |
246 | G_ALIGNOF (guchar), |
247 | FALSE, |
248 | FALSE, |
249 | { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, |
250 | b8g8r8a8_premultiplied_to_float, |
251 | b8g8r8a8_premultiplied_from_float, |
252 | }, |
253 | [GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = { |
254 | .alpha: GDK_MEMORY_ALPHA_PREMULTIPLIED, |
255 | .bytes_per_pixel: 4, |
256 | G_ALIGNOF (guchar), |
257 | FALSE, |
258 | FALSE, |
259 | .gl: { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, |
260 | .to_float: a8r8g8b8_premultiplied_to_float, |
261 | .from_float: a8r8g8b8_premultiplied_from_float, |
262 | }, |
263 | [GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = { |
264 | .alpha: GDK_MEMORY_ALPHA_PREMULTIPLIED, |
265 | .bytes_per_pixel: 4, |
266 | G_ALIGNOF (guchar), |
267 | FALSE, |
268 | TRUE, |
269 | .gl: { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, |
270 | .to_float: r8g8b8a8_premultiplied_to_float, |
271 | .from_float: r8g8b8a8_premultiplied_from_float, |
272 | }, |
273 | [GDK_MEMORY_B8G8R8A8] = { |
274 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
275 | .bytes_per_pixel: 4, |
276 | G_ALIGNOF (guchar), |
277 | FALSE, |
278 | FALSE, |
279 | .gl: { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, |
280 | .to_float: b8g8r8a8_to_float, |
281 | .from_float: b8g8r8a8_from_float, |
282 | }, |
283 | [GDK_MEMORY_A8R8G8B8] = { |
284 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
285 | .bytes_per_pixel: 4, |
286 | G_ALIGNOF (guchar), |
287 | FALSE, |
288 | FALSE, |
289 | .gl: { GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, |
290 | .to_float: a8r8g8b8_to_float, |
291 | .from_float: a8r8g8b8_from_float, |
292 | }, |
293 | [GDK_MEMORY_R8G8B8A8] = { |
294 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
295 | .bytes_per_pixel: 4, |
296 | G_ALIGNOF (guchar), |
297 | FALSE, |
298 | TRUE, |
299 | .gl: { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, |
300 | .to_float: r8g8b8a8_to_float, |
301 | .from_float: r8g8b8a8_from_float, |
302 | }, |
303 | [GDK_MEMORY_A8B8G8R8] = { |
304 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
305 | .bytes_per_pixel: 4, |
306 | G_ALIGNOF (guchar), |
307 | FALSE, |
308 | FALSE, |
309 | .gl: { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, |
310 | .to_float: a8b8g8r8_to_float, |
311 | .from_float: a8b8g8r8_from_float, |
312 | }, |
313 | [GDK_MEMORY_R8G8B8] = { |
314 | .alpha: GDK_MEMORY_ALPHA_OPAQUE, |
315 | .bytes_per_pixel: 3, |
316 | G_ALIGNOF (guchar), |
317 | FALSE, |
318 | TRUE, |
319 | .gl: { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE }, |
320 | .to_float: r8g8b8_to_float, |
321 | .from_float: r8g8b8_from_float, |
322 | }, |
323 | [GDK_MEMORY_B8G8R8] = { |
324 | .alpha: GDK_MEMORY_ALPHA_OPAQUE, |
325 | .bytes_per_pixel: 3, |
326 | G_ALIGNOF (guchar), |
327 | FALSE, |
328 | FALSE, |
329 | .gl: { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, |
330 | .to_float: b8g8r8_to_float, |
331 | .from_float: b8g8r8_from_float, |
332 | }, |
333 | [GDK_MEMORY_R16G16B16] = { |
334 | .alpha: GDK_MEMORY_ALPHA_OPAQUE, |
335 | .bytes_per_pixel: 6, |
336 | G_ALIGNOF (guint16), |
337 | TRUE, |
338 | TRUE, |
339 | .gl: { GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT }, |
340 | .to_float: r16g16b16_to_float, |
341 | .from_float: r16g16b16_from_float, |
342 | }, |
343 | [GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = { |
344 | .alpha: GDK_MEMORY_ALPHA_PREMULTIPLIED, |
345 | .bytes_per_pixel: 8, |
346 | G_ALIGNOF (guint16), |
347 | TRUE, |
348 | TRUE, |
349 | .gl: { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, |
350 | .to_float: r16g16b16a16_to_float, |
351 | .from_float: r16g16b16a16_from_float, |
352 | }, |
353 | [GDK_MEMORY_R16G16B16A16] = { |
354 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
355 | .bytes_per_pixel: 8, |
356 | G_ALIGNOF (guint16), |
357 | TRUE, |
358 | TRUE, |
359 | .gl: { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, |
360 | .to_float: r16g16b16a16_to_float, |
361 | .from_float: r16g16b16a16_from_float, |
362 | }, |
363 | [GDK_MEMORY_R16G16B16_FLOAT] = { |
364 | .alpha: GDK_MEMORY_ALPHA_OPAQUE, |
365 | .bytes_per_pixel: 6, |
366 | G_ALIGNOF (guint16), |
367 | TRUE, |
368 | TRUE, |
369 | .gl: { GL_RGB16F, GL_RGB, GL_HALF_FLOAT }, |
370 | .to_float: r16g16b16_float_to_float, |
371 | .from_float: r16g16b16_float_from_float, |
372 | }, |
373 | [GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = { |
374 | .alpha: GDK_MEMORY_ALPHA_PREMULTIPLIED, |
375 | .bytes_per_pixel: 8, |
376 | G_ALIGNOF (guint16), |
377 | TRUE, |
378 | TRUE, |
379 | .gl: { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, |
380 | .to_float: r16g16b16a16_float_to_float, |
381 | .from_float: r16g16b16a16_float_from_float, |
382 | }, |
383 | [GDK_MEMORY_R16G16B16A16_FLOAT] = { |
384 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
385 | .bytes_per_pixel: 8, |
386 | G_ALIGNOF (guint16), |
387 | TRUE, |
388 | TRUE, |
389 | .gl: { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, |
390 | .to_float: r16g16b16a16_float_to_float, |
391 | .from_float: r16g16b16a16_float_from_float, |
392 | }, |
393 | [GDK_MEMORY_R32G32B32_FLOAT] = { |
394 | .alpha: GDK_MEMORY_ALPHA_OPAQUE, |
395 | .bytes_per_pixel: 12, |
396 | G_ALIGNOF (float), |
397 | TRUE, |
398 | TRUE, |
399 | .gl: { GL_RGB32F, GL_RGB, GL_FLOAT }, |
400 | .to_float: r32g32b32_float_to_float, |
401 | .from_float: r32g32b32_float_from_float, |
402 | }, |
403 | [GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = { |
404 | .alpha: GDK_MEMORY_ALPHA_PREMULTIPLIED, |
405 | .bytes_per_pixel: 16, |
406 | G_ALIGNOF (float), |
407 | TRUE, |
408 | TRUE, |
409 | .gl: { GL_RGBA32F, GL_RGBA, GL_FLOAT }, |
410 | .to_float: r32g32b32a32_float_to_float, |
411 | .from_float: r32g32b32a32_float_from_float, |
412 | }, |
413 | [GDK_MEMORY_R32G32B32A32_FLOAT] = { |
414 | .alpha: GDK_MEMORY_ALPHA_STRAIGHT, |
415 | .bytes_per_pixel: 16, |
416 | G_ALIGNOF (float), |
417 | TRUE, |
418 | TRUE, |
419 | .gl: { GL_RGBA32F, GL_RGBA, GL_FLOAT }, |
420 | .to_float: r32g32b32a32_float_to_float, |
421 | .from_float: r32g32b32a32_float_from_float, |
422 | } |
423 | }; |
424 | |
425 | gsize |
426 | gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) |
427 | { |
428 | return memory_formats[format].bytes_per_pixel; |
429 | } |
430 | |
431 | GdkMemoryAlpha |
432 | gdk_memory_format_alpha (GdkMemoryFormat format) |
433 | { |
434 | return memory_formats[format].alpha; |
435 | } |
436 | |
437 | gsize |
438 | gdk_memory_format_alignment (GdkMemoryFormat format) |
439 | { |
440 | return memory_formats[format].alignment; |
441 | } |
442 | |
443 | /*<private> |
444 | * gdk_memory_format_prefers_high_depth: |
445 | * @format: a memory format |
446 | * |
447 | * Checks if the given format benefits from being rendered |
448 | * in bit depths higher than 8bits per pixel. See |
449 | * gsk_render_node_prefers_high_depth() for more information |
450 | * on this. |
451 | * Usually this is the case when |
452 | * gdk_memory_format_bytes_per_pixel() is larger than 4. |
453 | * |
454 | * Returns: %TRUE if the format benefits from being |
455 | * composited in hgiher bit depths. |
456 | **/ |
457 | gboolean |
458 | gdk_memory_format_prefers_high_depth (GdkMemoryFormat format) |
459 | { |
460 | return memory_formats[format].prefers_high_depth; |
461 | } |
462 | |
463 | gboolean |
464 | gdk_memory_format_gl_format (GdkMemoryFormat format, |
465 | gboolean gles, |
466 | guint *out_internal_format, |
467 | guint *out_format, |
468 | guint *out_type) |
469 | { |
470 | *out_internal_format = memory_formats[format].gl.internal_format; |
471 | *out_format = memory_formats[format].gl.format; |
472 | *out_type = memory_formats[format].gl.type; |
473 | |
474 | if (memory_formats[format].alpha == GDK_MEMORY_ALPHA_STRAIGHT) |
475 | return FALSE; |
476 | |
477 | if (gles && !memory_formats[format].supports_gles) |
478 | return FALSE; |
479 | |
480 | return TRUE; |
481 | } |
482 | |
483 | static void |
484 | premultiply (float *rgba, |
485 | gsize n) |
486 | { |
487 | for (gsize i = 0; i < n; i++) |
488 | { |
489 | rgba[0] *= rgba[3]; |
490 | rgba[1] *= rgba[3]; |
491 | rgba[2] *= rgba[3]; |
492 | rgba += 4; |
493 | } |
494 | } |
495 | |
496 | static void |
497 | unpremultiply (float *rgba, |
498 | gsize n) |
499 | { |
500 | for (gsize i = 0; i < n; i++) |
501 | { |
502 | if (rgba[3] > 1/255.0) |
503 | { |
504 | rgba[0] /= rgba[3]; |
505 | rgba[1] /= rgba[3]; |
506 | rgba[2] /= rgba[3]; |
507 | } |
508 | rgba += 4; |
509 | } |
510 | } |
511 | |
512 | void |
513 | gdk_memory_convert (guchar *dest_data, |
514 | gsize dest_stride, |
515 | GdkMemoryFormat dest_format, |
516 | const guchar *src_data, |
517 | gsize src_stride, |
518 | GdkMemoryFormat src_format, |
519 | gsize width, |
520 | gsize height) |
521 | { |
522 | const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format]; |
523 | const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format]; |
524 | float *tmp; |
525 | gsize y; |
526 | void (*func) (guchar *, const guchar *, gsize) = NULL; |
527 | |
528 | g_assert (dest_format < GDK_MEMORY_N_FORMATS); |
529 | g_assert (src_format < GDK_MEMORY_N_FORMATS); |
530 | |
531 | if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) |
532 | func = r8g8b8a8_to_r8g8b8a8_premultiplied; |
533 | else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) |
534 | func = r8g8b8a8_to_b8g8r8a8_premultiplied; |
535 | else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED) |
536 | func = r8g8b8a8_to_b8g8r8a8_premultiplied; |
537 | else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED) |
538 | func = r8g8b8a8_to_r8g8b8a8_premultiplied; |
539 | else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED) |
540 | func = r8g8b8a8_to_a8r8g8b8_premultiplied; |
541 | else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED) |
542 | func = r8g8b8a8_to_a8b8g8r8_premultiplied; |
543 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) |
544 | func = r8g8b8_to_r8g8b8a8; |
545 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) |
546 | func = r8g8b8_to_b8g8r8a8; |
547 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED) |
548 | func = r8g8b8_to_b8g8r8a8; |
549 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED) |
550 | func = r8g8b8_to_r8g8b8a8; |
551 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED) |
552 | func = r8g8b8_to_a8r8g8b8; |
553 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED) |
554 | func = r8g8b8_to_a8b8g8r8; |
555 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8) |
556 | func = r8g8b8_to_r8g8b8a8; |
557 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8) |
558 | func = r8g8b8_to_b8g8r8a8; |
559 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8) |
560 | func = r8g8b8_to_b8g8r8a8; |
561 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8) |
562 | func = r8g8b8_to_r8g8b8a8; |
563 | else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8) |
564 | func = r8g8b8_to_a8r8g8b8; |
565 | else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8) |
566 | func = r8g8b8_to_a8b8g8r8; |
567 | |
568 | if (func != NULL) |
569 | { |
570 | for (y = 0; y < height; y++) |
571 | { |
572 | func (dest_data, src_data, width); |
573 | src_data += src_stride; |
574 | dest_data += dest_stride; |
575 | } |
576 | return; |
577 | } |
578 | |
579 | tmp = g_new (float, width * 4); |
580 | |
581 | for (y = 0; y < height; y++) |
582 | { |
583 | src_desc->to_float (tmp, src_data, width); |
584 | if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT) |
585 | unpremultiply (rgba: tmp, n: width); |
586 | else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT) |
587 | premultiply (rgba: tmp, n: width); |
588 | dest_desc->from_float (dest_data, tmp, width); |
589 | src_data += src_stride; |
590 | dest_data += dest_stride; |
591 | } |
592 | |
593 | g_free (mem: tmp); |
594 | } |
595 | |