1#include <gtk/gtk.h>
2
3static const char *format_name[] = {
4 "BGRAp", "ARGBp", "RGBAp",
5 "BGRA", "ARGB", "RGBA", "ABGR",
6 "RGB", "BGR", NULL
7};
8
9static const char *
10format_to_string (GdkMemoryFormat format)
11{
12 if (format < GDK_MEMORY_N_FORMATS)
13 return format_name[format];
14 else
15 return "ERROR";
16}
17
18/* Copied from gdkmemorytexture.c */
19
20static void
21convert_memcpy (guchar *dest_data,
22 gsize dest_stride,
23 const guchar *src_data,
24 gsize src_stride,
25 gsize width,
26 gsize height)
27{
28 gsize y;
29
30 for (y = 0; y < height; y++)
31 memcpy (dest: dest_data + y * dest_stride, src: src_data + y * src_stride, n: 4 * width);
32}
33
34static void
35convert_memcpy3 (guchar *dest_data,
36 gsize dest_stride,
37 const guchar *src_data,
38 gsize src_stride,
39 gsize width,
40 gsize height)
41{
42 gsize y;
43
44 for (y = 0; y < height; y++)
45 memcpy (dest: dest_data + y * dest_stride, src: src_data + y * src_stride, n: 3 * width);
46}
47
48#define SWIZZLE3(R,G,B) \
49static void \
50convert_swizzle ## R ## G ## B (guchar *dest_data, \
51 gsize dest_stride, \
52 const guchar *src_data, \
53 gsize src_stride, \
54 gsize width, \
55 gsize height) \
56{ \
57 gsize x, y; \
58\
59 for (y = 0; y < height; y++) \
60 { \
61 for (x = 0; x < width; x++) \
62 { \
63 dest_data[3 * x + R] = src_data[3 * x + 0]; \
64 dest_data[3 * x + G] = src_data[3 * x + 1]; \
65 dest_data[3 * x + B] = src_data[3 * x + 2]; \
66 } \
67\
68 dest_data += dest_stride; \
69 src_data += src_stride; \
70 } \
71}
72
73SWIZZLE3(2,1,0)
74
75#define SWIZZLE(A,R,G,B) \
76static void \
77convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \
78 gsize dest_stride, \
79 const guchar *src_data, \
80 gsize src_stride, \
81 gsize width, \
82 gsize height) \
83{ \
84 gsize x, y; \
85\
86 for (y = 0; y < height; y++) \
87 { \
88 for (x = 0; x < width; x++) \
89 { \
90 dest_data[4 * x + A] = src_data[4 * x + 0]; \
91 dest_data[4 * x + R] = src_data[4 * x + 1]; \
92 dest_data[4 * x + G] = src_data[4 * x + 2]; \
93 dest_data[4 * x + B] = src_data[4 * x + 3]; \
94 } \
95\
96 dest_data += dest_stride; \
97 src_data += src_stride; \
98 } \
99}
100
101SWIZZLE(3,2,1,0)
102SWIZZLE(2,1,0,3)
103SWIZZLE(3,0,1,2)
104SWIZZLE(1,2,3,0)
105
106#define SWIZZLE_OPAQUE(A,R,G,B) \
107static void \
108convert_swizzle_opaque_## A ## R ## G ## B (guchar *dest_data, \
109 gsize dest_stride, \
110 const guchar *src_data, \
111 gsize src_stride, \
112 gsize width, \
113 gsize height) \
114{ \
115 gsize x, y; \
116\
117 for (y = 0; y < height; y++) \
118 { \
119 for (x = 0; x < width; x++) \
120 { \
121 dest_data[4 * x + A] = 0xFF; \
122 dest_data[4 * x + R] = src_data[3 * x + 0]; \
123 dest_data[4 * x + G] = src_data[3 * x + 1]; \
124 dest_data[4 * x + B] = src_data[3 * x + 2]; \
125 } \
126\
127 dest_data += dest_stride; \
128 src_data += src_stride; \
129 } \
130}
131
132SWIZZLE_OPAQUE(3,2,1,0)
133SWIZZLE_OPAQUE(3,0,1,2)
134SWIZZLE_OPAQUE(0,1,2,3)
135SWIZZLE_OPAQUE(0,3,2,1)
136
137#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
138#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \
139static void \
140convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \
141 (guchar *dest_data, \
142 gsize dest_stride, \
143 const guchar *src_data, \
144 gsize src_stride, \
145 gsize width, \
146 gsize height) \
147{ \
148 gsize x, y; \
149\
150 for (y = 0; y < height; y++) \
151 { \
152 for (x = 0; x < width; x++) \
153 { \
154 dest_data[4 * x + A] = src_data[4 * x + A2]; \
155 PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \
156 PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \
157 PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \
158 } \
159\
160 dest_data += dest_stride; \
161 src_data += src_stride; \
162 } \
163}
164
165SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0)
166SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0)
167SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3)
168SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3)
169SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2)
170SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2)
171SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1)
172SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1)
173SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0)
174SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
175SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
176SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
177
178typedef void (* ConversionFunc) (guchar *dest_data,
179 gsize dest_stride,
180 const guchar *src_data,
181 gsize src_stride,
182 gsize width,
183 gsize height);
184
185static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_FORMATS] =
186{
187 { convert_memcpy, convert_swizzle3210, convert_swizzle2103, NULL, NULL, NULL, NULL, NULL, NULL },
188 { convert_swizzle3210, convert_memcpy, convert_swizzle3012, NULL, NULL, NULL, NULL, NULL, NULL },
189 { convert_swizzle2103, convert_swizzle1230, convert_memcpy, NULL, NULL, NULL, NULL, NULL, NULL },
190 { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, convert_memcpy, NULL, NULL, NULL, NULL, NULL },
191 { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123, NULL, convert_memcpy, NULL, NULL, NULL, NULL },
192 { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012, convert_swizzle2103, convert_swizzle1230, convert_memcpy, convert_swizzle3210, NULL, NULL },
193 { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321, NULL, NULL, NULL, convert_memcpy, NULL, NULL },
194 { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012, NULL, NULL, NULL, NULL, convert_memcpy3, convert_swizzle210 },
195 { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210, NULL, NULL, NULL, NULL, convert_swizzle210, convert_memcpy3 },
196};
197
198static void
199gdk_memory_convert (guchar *dest_data,
200 gsize dest_stride,
201 GdkMemoryFormat dest_format,
202 const guchar *src_data,
203 gsize src_stride,
204 GdkMemoryFormat src_format,
205 gsize width,
206 gsize height)
207{
208 g_assert (dest_format < GDK_MEMORY_N_FORMATS);
209 g_assert (src_format < GDK_MEMORY_N_FORMATS);
210
211 if (converters[src_format][dest_format] == NULL)
212 g_error ("Conversion from %s to %s not supported", format_to_string (src_format), format_to_string (dest_format));
213
214 converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
215}
216
217/* End of copied code */
218
219static GdkTexture *
220make_texture (GdkMemoryFormat format,
221 int padding,
222 int *out_stride,
223 int *out_bpp)
224{
225 GdkPixbuf *source;
226 GdkMemoryFormat source_format;
227 int width, height, stride, bpp;
228 guchar *data;
229 GBytes *bytes;
230 GdkTexture *texture;
231 GError *error = NULL;
232
233 width = height = 200;
234
235 source = gdk_pixbuf_new_from_file_at_scale (filename: "tests/portland-rose.jpg",
236 width, height, TRUE,
237 error: &error);
238 if (!source)
239 g_error ("%s", error->message);
240
241 source_format = GDK_MEMORY_R8G8B8;
242 bpp = 3;
243
244 if (format != GDK_MEMORY_R8G8B8 && format != GDK_MEMORY_B8G8R8)
245 {
246 bpp = 4;
247
248 /* add an alpha channel with 50% alpha */
249 GdkPixbuf *pb = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB, TRUE, bits_per_sample: 8, width, height);
250 gdk_pixbuf_composite (src: source, dest: pb, dest_x: 0, dest_y: 0, dest_width: width, dest_height: height, offset_x: 0, offset_y: 0, scale_x: 1, scale_y: 1, interp_type: GDK_INTERP_BILINEAR, overall_alpha: 128);
251 g_object_unref (object: source);
252 source = pb;
253
254 source_format = GDK_MEMORY_R8G8B8A8;
255 }
256
257 stride = bpp * width + padding;
258 data = g_new0 (guchar, stride * height);
259
260 gdk_memory_convert (dest_data: data, dest_stride: stride, dest_format: format,
261 src_data: gdk_pixbuf_get_pixels (pixbuf: source),
262 src_stride: gdk_pixbuf_get_rowstride (pixbuf: source),
263 src_format: source_format,
264 width, height);
265
266 g_object_unref (object: source);
267
268 bytes = g_bytes_new_take (data, size: stride * height);
269 texture = gdk_memory_texture_new (width, height, format, bytes, stride);
270 g_bytes_unref (bytes);
271
272 *out_stride = stride;
273 *out_bpp = bpp;
274
275 return texture;
276}
277
278static void
279update_picture (GtkWidget *picture)
280{
281 GdkMemoryFormat format;
282 int padding;
283 GdkTexture *texture;
284 GtkLabel *label;
285 char *text;
286 int stride;
287 int bpp;
288
289 format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (picture), "format"));
290 padding = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (picture), "padding"));
291
292 texture = make_texture (format, padding, out_stride: &stride, out_bpp: &bpp);
293 gtk_picture_set_paintable (self: GTK_PICTURE (ptr: picture), paintable: GDK_PAINTABLE (ptr: texture));
294
295 label = GTK_LABEL (g_object_get_data (G_OBJECT (picture), "size_label"));
296 text = g_strdup_printf (format: "%d x %d @ %d",
297 gdk_texture_get_width (texture),
298 gdk_texture_get_height (texture),
299 bpp);
300 gtk_label_set_label (self: label, str: text);
301 g_free (mem: text);
302
303 label = GTK_LABEL (g_object_get_data (G_OBJECT (picture), "stride_label"));
304 text = g_strdup_printf (format: "%d", stride);
305 gtk_label_set_label (self: label, str: text);
306 g_free (mem: text);
307
308 g_object_unref (object: texture);
309}
310
311static void
312update_format (GtkDropDown *dropdown,
313 GParamSpec *pspec,
314 GtkWidget *picture)
315{
316 g_object_set_data (G_OBJECT (picture), key: "format", GINT_TO_POINTER (gtk_drop_down_get_selected (dropdown)));
317 update_picture (picture);
318}
319
320static void
321update_padding (GtkSpinButton *spinbutton,
322 GParamSpec *pspec,
323 GtkWidget *picture)
324{
325 g_object_set_data (G_OBJECT (picture), key: "padding", GINT_TO_POINTER (gtk_spin_button_get_value_as_int (spinbutton)));
326 update_picture (picture);
327}
328
329static void
330add_to_grid (GtkWidget *grid,
331 int left,
332 int top,
333 GdkMemoryFormat format,
334 int padding)
335{
336 GtkWidget *dropdown, *spin, *picture, *label;
337
338 picture = gtk_picture_new ();
339 gtk_grid_attach (GTK_GRID (grid), child: picture, column: left + 2, row: top + 0, width: 1, height: 4);
340
341 g_object_set_data (G_OBJECT (picture), key: "format", GINT_TO_POINTER (format));
342 g_object_set_data (G_OBJECT (picture), key: "padding", GINT_TO_POINTER (padding));
343
344 dropdown = gtk_drop_down_new_from_strings (strings: format_name);
345 gtk_widget_set_valign (widget: dropdown, align: GTK_ALIGN_CENTER);
346 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dropdown), position: format);
347 g_signal_connect (dropdown, "notify::selected", G_CALLBACK (update_format), picture);
348
349 gtk_grid_attach (GTK_GRID (grid), child: gtk_label_new (str: "Format"), column: left, row: top, width: 1, height: 1);
350 gtk_grid_attach (GTK_GRID (grid), child: dropdown, column: left + 1, row: top, width: 1, height: 1);
351
352 spin = gtk_spin_button_new_with_range (min: 0, max: 10, step: 1);
353 gtk_widget_set_valign (widget: spin, align: GTK_ALIGN_CENTER);
354 gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), value: padding);
355 g_signal_connect (spin, "notify::value", G_CALLBACK (update_padding), picture);
356
357 gtk_grid_attach (GTK_GRID (grid), child: gtk_label_new (str: "Padding"), column: left, row: top + 1, width: 1, height: 1);
358 gtk_grid_attach (GTK_GRID (grid), child: spin, column: left + 1, row: top + 1, width: 1, height: 1);
359
360 label = gtk_label_new (str: "");
361 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0);
362 g_object_set_data (G_OBJECT (picture), key: "size_label", data: label);
363 gtk_grid_attach (GTK_GRID (grid), child: gtk_label_new (str: "Size"), column: left, row: top + 2, width: 1, height: 1);
364 gtk_grid_attach (GTK_GRID (grid), child: label, column: left + 1, row: top + 2, width: 1, height: 1);
365 label = gtk_label_new (str: "");
366 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0);
367 g_object_set_data (G_OBJECT (picture), key: "stride_label", data: label);
368 gtk_grid_attach (GTK_GRID (grid), child: gtk_label_new (str: "Stride"), column: left, row: top + 3, width: 1, height: 1);
369 gtk_grid_attach (GTK_GRID (grid), child: label, column: left + 1, row: top + 3, width: 1, height: 1);
370
371 update_picture (picture);
372}
373
374int
375main (int argc, char *argv[])
376{
377 GtkWidget *window, *grid;
378
379 gtk_init ();
380
381 window = gtk_window_new ();
382 grid = gtk_grid_new ();
383 gtk_widget_set_margin_top (widget: grid, margin: 10);
384 gtk_widget_set_margin_bottom (widget: grid, margin: 10);
385 gtk_widget_set_margin_start (widget: grid, margin: 10);
386 gtk_widget_set_margin_end (widget: grid, margin: 10);
387 gtk_grid_set_row_spacing (GTK_GRID (grid), spacing: 6);
388 gtk_grid_set_column_spacing (GTK_GRID (grid), spacing: 6);
389 gtk_window_set_child (GTK_WINDOW (window), child: grid);
390
391 add_to_grid (grid, left: 0, top: 0, format: GDK_MEMORY_R8G8B8, padding: 0);
392
393 gtk_window_present (GTK_WINDOW (window));
394
395 while (g_list_model_get_n_items (list: gtk_window_get_toplevels ()) > 0)
396 g_main_context_iteration (NULL, TRUE);
397
398 return 0;
399}
400

source code of gtk/tests/testupload.c