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
28typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
29
30#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \
31static void \
32name ## _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\
47static void \
48name ## _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
63TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255)
64TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255)
65TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255)
66TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255)
67TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255)
68TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255)
69TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255)
70TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255)
71TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255)
72TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535)
73TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535)
74
75static void
76r16g16b16_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
90static void
91r16g16b16_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
104static void
105r16g16b16a16_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
112static void
113r16g16b16a16_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
120static void
121r32g32b32_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
137static void
138r32g32b32_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
153static void
154r32g32b32a32_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
161static void
162r32g32b32a32_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) \
170static void \
171name (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
190PREMULTIPLY_FUNC(r8g8b8a8_to_r8g8b8a8_premultiplied, 0, 1, 2, 3, 0, 1, 2, 3)
191PREMULTIPLY_FUNC(r8g8b8a8_to_b8g8r8a8_premultiplied, 0, 1, 2, 3, 2, 1, 0, 3)
192PREMULTIPLY_FUNC(r8g8b8a8_to_a8r8g8b8_premultiplied, 0, 1, 2, 3, 1, 2, 3, 0)
193PREMULTIPLY_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) \
196static void \
197name (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
212ADD_ALPHA_FUNC(r8g8b8_to_r8g8b8a8, 0, 1, 2, 0, 1, 2, 3)
213ADD_ALPHA_FUNC(r8g8b8_to_b8g8r8a8, 0, 1, 2, 2, 1, 0, 3)
214ADD_ALPHA_FUNC(r8g8b8_to_a8r8g8b8, 0, 1, 2, 1, 2, 3, 0)
215ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0)
216
217struct _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
242static 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
425gsize
426gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
427{
428 return memory_formats[format].bytes_per_pixel;
429}
430
431GdkMemoryAlpha
432gdk_memory_format_alpha (GdkMemoryFormat format)
433{
434 return memory_formats[format].alpha;
435}
436
437gsize
438gdk_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 **/
457gboolean
458gdk_memory_format_prefers_high_depth (GdkMemoryFormat format)
459{
460 return memory_formats[format].prefers_high_depth;
461}
462
463gboolean
464gdk_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
483static void
484premultiply (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
496static void
497unpremultiply (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
512void
513gdk_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

source code of gtk/gdk/gdkmemoryformat.c