1/* -*- Mode: C; c-basic-offset: 2; -*- */
2/* GdkPixbuf library - test loaders
3 *
4 * Copyright (C) 2014 Red Hat, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Author: Matthias Clasen
21 */
22
23#include "config.h"
24#include "test-common.h"
25#include "gdk-pixbuf/gdk-pixbuf.h"
26
27#include <string.h>
28
29/* Checkerboard of black and white pxels (actually (1,1,1) and (255,255,255)
30 * so they average to (128,128,128)) */
31GdkPixbuf *
32make_checkerboard (int width, int height)
33{
34 GdkPixbuf *checkerboard;
35 guint x, y;
36 guchar *row; /* Pointer to start of row of pixels within the image */
37 guchar *pixel; /* Pointer to current pixel data in row */
38
39 checkerboard = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB, has_alpha: 0, bits_per_sample: 8, width, height);
40 g_assert_nonnull (checkerboard);
41
42 for (y = 0, row = gdk_pixbuf_get_pixels (pixbuf: checkerboard);
43 y < height;
44 y++, row += gdk_pixbuf_get_rowstride (pixbuf: checkerboard))
45 {
46 for (x = 0, pixel = row;
47 x < width;
48 x++, pixel += gdk_pixbuf_get_n_channels (pixbuf: checkerboard))
49 {
50 pixel[0] = pixel[1] = pixel[2] = (x ^ y) & 1 ? 1 : 255;
51 }
52 }
53
54 return checkerboard;
55}
56
57/* Image where all the pixels have different colours */
58GdkPixbuf *
59make_rg (int width, int height)
60{
61 GdkPixbuf *pixbuf;
62 guint x, y;
63 guchar *row; /* Pointer to start of row of pixels within the image */
64 guchar *pixel; /* Pointer to current pixel data in row */
65
66 /* Make a source image whose pixels are all of different colors */
67 pixbuf = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB, has_alpha: 0, bits_per_sample: 8, width, height);
68 g_assert_nonnull (pixbuf);
69
70 for (y = 0, row = gdk_pixbuf_get_pixels (pixbuf);
71 y < height;
72 y++, row += gdk_pixbuf_get_rowstride (pixbuf))
73 {
74 for (x = 0, pixel = row;
75 x < width;
76 x++, pixel += gdk_pixbuf_get_n_channels (pixbuf))
77 {
78 pixel[0] = x & 255; pixel[1] = y & 255;
79 /* If image > 256 pixels wide/high put the extra bits in the last pixel */
80 pixel[2] = ((x >> 8) & 15) | ((( y >> 8) & 15) << 4);
81 }
82 }
83
84 return pixbuf;
85}
86
87gboolean
88find_format (const gchar *filename, gchar **found_format)
89{
90 GSList *formats, *l;
91 gboolean retval;
92
93 retval = FALSE;
94 formats = gdk_pixbuf_get_formats ();
95 for (l = formats; l; l = l->next)
96 {
97 GdkPixbufFormat *format = l->data;
98 char **extensions = gdk_pixbuf_format_get_extensions (format);
99 gint i;
100
101 for (i = 0; extensions[i]; i++)
102 {
103 if (g_str_has_suffix (str: filename, suffix: extensions[i]))
104 {
105 if (found_format != NULL)
106 *found_format = gdk_pixbuf_format_get_name (format);
107 retval = TRUE;
108 break;
109 }
110 }
111
112 g_strfreev (str_array: extensions);
113 if (retval)
114 break;
115 }
116 g_slist_free (list: formats);
117
118 return retval;
119}
120
121gboolean
122format_supported (const gchar *filename)
123{
124 return find_format(filename, NULL);
125}
126
127gboolean
128file_supported (GFile *file)
129{
130 char *uri;
131 gboolean result;
132
133 uri = g_file_get_uri (file);
134
135 result = format_supported (filename: uri);
136
137 g_free (mem: uri);
138
139 return result;
140}
141
142gboolean
143skip_if_insufficient_memory (GError **err)
144{
145 if (*err && g_error_matches (error: *err, GDK_PIXBUF_ERROR, code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY))
146 {
147 g_test_skip (msg: (*err)->message);
148 g_error_free (error: *err);
149 *err = NULL;
150 return TRUE;
151 }
152
153 return FALSE;
154}
155
156gboolean
157pixdata_equal (GdkPixbuf *test,
158 GdkPixbuf *ref,
159 GError **error)
160{
161 if (gdk_pixbuf_get_colorspace (pixbuf: test) != gdk_pixbuf_get_colorspace (pixbuf: ref))
162 {
163 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0, format: "Image colorspace is %d but should be %d",
164 gdk_pixbuf_get_colorspace (pixbuf: test), gdk_pixbuf_get_colorspace (pixbuf: ref));
165 return FALSE;
166 }
167
168 if (gdk_pixbuf_get_n_channels (pixbuf: test) != gdk_pixbuf_get_n_channels (pixbuf: ref))
169 {
170 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0,
171 format: "has %u channels but should have %u",
172 gdk_pixbuf_get_n_channels (pixbuf: test), gdk_pixbuf_get_n_channels (pixbuf: ref));
173 return FALSE;
174 }
175
176 if (gdk_pixbuf_get_bits_per_sample (pixbuf: test) != gdk_pixbuf_get_bits_per_sample (pixbuf: ref))
177 {
178 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0,
179 format: "Image is %u bits per sample but should be %u bits per sample",
180 gdk_pixbuf_get_bits_per_sample (pixbuf: test), gdk_pixbuf_get_bits_per_sample (pixbuf: ref));
181 return FALSE;
182 }
183
184 if (gdk_pixbuf_get_width (pixbuf: test) != gdk_pixbuf_get_width (pixbuf: ref) ||
185 gdk_pixbuf_get_height (pixbuf: test) != gdk_pixbuf_get_height (pixbuf: ref))
186 {
187 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0,
188 format: "Image size is %dx%d but should be %dx%d",
189 gdk_pixbuf_get_width (pixbuf: test), gdk_pixbuf_get_height (pixbuf: test),
190 gdk_pixbuf_get_width (pixbuf: ref), gdk_pixbuf_get_height (pixbuf: ref));
191 return FALSE;
192 }
193
194 if (gdk_pixbuf_get_rowstride (pixbuf: test) != gdk_pixbuf_get_rowstride (pixbuf: ref))
195 {
196 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0,
197 format: "Image rowstrides is %u bytes but should be %u bytes",
198 gdk_pixbuf_get_rowstride (pixbuf: test), gdk_pixbuf_get_rowstride (pixbuf: ref));
199 return FALSE;
200 }
201
202 if (memcmp (s1: gdk_pixbuf_get_pixels (pixbuf: test), s2: gdk_pixbuf_get_pixels (pixbuf: ref),
203 n: gdk_pixbuf_get_byte_length (pixbuf: test)) != 0)
204 {
205 gint x, y, width, height, n_channels, rowstride;
206 const guchar *test_pixels, *ref_pixels;
207
208 rowstride = gdk_pixbuf_get_rowstride (pixbuf: test);
209 n_channels = gdk_pixbuf_get_n_channels (pixbuf: test);
210 width = gdk_pixbuf_get_width (pixbuf: test);
211 height = gdk_pixbuf_get_height (pixbuf: test);
212 test_pixels = gdk_pixbuf_get_pixels (pixbuf: test);
213 ref_pixels = gdk_pixbuf_get_pixels (pixbuf: ref);
214
215 g_assert_cmpint (width, >=, 0);
216 g_assert_cmpint (height, >=, 0);
217 g_assert_cmpint (n_channels, >=, 0);
218
219 for (y = 0; y < height; y++)
220 {
221 for (x = 0; x < width; x++)
222 {
223 if (memcmp (s1: &test_pixels[x * n_channels], s2: &ref_pixels[x * n_channels], n: n_channels) != 0)
224 {
225 if (n_channels == 4)
226 {
227 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0, format: "Image data at %ux%u is #%02X%02X%02X%02X, but should be #%02X%02X%02X%02X",
228 x, y,
229 test_pixels[x * n_channels + 0], test_pixels[x * n_channels + 1], test_pixels[x * n_channels + 2], test_pixels[x * n_channels + 3],
230 ref_pixels[x * n_channels + 0], ref_pixels[x * n_channels + 1], ref_pixels[x * n_channels + 2], ref_pixels[x * n_channels + 3]);
231 }
232 else if (n_channels == 3)
233 {
234 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0, format: "Image data at %ux%u is #%02X%02X%02X, but should be #%02X%02X%02X",
235 x, y,
236 test_pixels[x * n_channels + 0], test_pixels[x * n_channels + 1], test_pixels[x * n_channels + 2],
237 ref_pixels[x * n_channels + 0], ref_pixels[x * n_channels + 1], ref_pixels[x * n_channels + 2]);
238 }
239 else
240 {
241 g_set_error (err: error, GDK_PIXBUF_ERROR, code: 0, format: "Image data differ at %ux%u", x, y);
242 }
243 return FALSE;
244 }
245 }
246 test_pixels += rowstride;
247 ref_pixels += rowstride;
248 }
249 }
250
251 return TRUE;
252}
253
254static int
255compare_files (gconstpointer a, gconstpointer b)
256{
257 GFile *file1 = G_FILE (a);
258 GFile *file2 = G_FILE (b);
259 char *uri1, *uri2;
260 int result;
261
262 uri1 = g_file_get_uri (file: file1);
263 uri2 = g_file_get_uri (file: file2);
264
265 result = strcmp (s1: uri1, s2: uri2);
266
267 g_free (mem: uri1);
268 g_free (mem: uri2);
269
270 return result;
271}
272
273void
274add_test_for_all_images (const gchar *prefix,
275 GFile *base,
276 GFile *file,
277 GTestDataFunc test_func,
278 AddTestFunc add_test_func)
279{
280 GFileEnumerator *enumerator;
281 GFileInfo *info;
282 GList *l, *files;
283 GError *error = NULL;
284
285
286 if (g_file_query_file_type (file, flags: 0, NULL) != G_FILE_TYPE_DIRECTORY)
287 {
288 gchar *test_path;
289 gchar *relative_path;
290
291 if (base)
292 relative_path = g_file_get_relative_path (parent: base, descendant: file);
293 else
294 relative_path = g_file_get_path (file);
295
296 test_path = g_strconcat (string1: prefix, "/", relative_path, NULL);
297
298 g_test_add_data_func_full (testpath: test_path, g_object_ref (file), test_func, data_free_func: g_object_unref);
299 g_free (mem: relative_path);
300 g_free (mem: test_path);
301 return;
302 }
303
304
305 enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, flags: 0, NULL, error: &error);
306 g_assert_no_error (error);
307 files = NULL;
308
309 while ((info = g_file_enumerator_next_file (enumerator, NULL, error: &error)))
310 {
311 GFile *next_file = g_file_get_child (file, name: g_file_info_get_name (info));
312
313 if (add_test_func == NULL || add_test_func (next_file))
314 {
315 files = g_list_prepend (list: files, g_object_ref (next_file));
316 }
317
318 g_object_unref (object: next_file);
319 g_object_unref (object: info);
320 }
321
322 g_assert_no_error (error);
323 g_object_unref (object: enumerator);
324
325 files = g_list_sort (list: files, compare_func: compare_files);
326
327 for (l = files; l; l = l->next)
328 {
329 add_test_for_all_images (prefix, base, file: l->data, test_func, add_test_func);
330 }
331
332 g_list_free_full (list: files, free_func: g_object_unref);
333}
334

source code of gtk/subprojects/gdk-pixbuf/tests/test-common.c