1/* -*- Mode: C; c-basic-offset: 2; -*- */
2/* GdkPixbuf library - test loaders
3 *
4 * Copyright (C) 2018 Canonical Ltd.
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, see <http://www.gnu.org/licenses/>.
18 */
19
20#define GLIB_DISABLE_DEPRECATION_WARNINGS
21#include "gdk-pixbuf/gdk-pixbuf.h"
22#include "test-common.h"
23#include <string.h>
24
25const gchar *
26get_test_path (const gchar *filename)
27{
28 return g_test_get_filename (file_type: G_TEST_DIST, first_path: "test-images", "gif-test-suite", filename, NULL);
29}
30
31static gboolean
32pixels_match (GBytes *pixels0, GBytes *pixels1)
33{
34 gsize size0, size1, i;
35 guint8 *data0, *data1;
36
37 data0 = g_bytes_get_data (bytes: pixels0, size: &size0);
38 data1 = g_bytes_get_data (bytes: pixels1, size: &size1);
39
40 if (size0 != size1)
41 return FALSE;
42
43 for (i = 0; i < size0; i += 4)
44 {
45 guint8 red0, green0, blue0, alpha0;
46 guint8 red1, green1, blue1, alpha1;
47
48 red0 = data0[i + 0];
49 green0 = data0[i + 1];
50 blue0 = data0[i + 2];
51 alpha0 = data0[i + 3];
52 red1 = data1[i + 0];
53 green1 = data1[i + 1];
54 blue1 = data1[i + 2];
55 alpha1 = data1[i + 3];
56 if (alpha0 == 0 && alpha1 == 0)
57 ; /* Transparent, don't care what the RGB is set to */
58 else if (red0 != red1 || blue0 != blue1 || green0 != green1 || alpha0 != alpha1)
59 return FALSE;
60 }
61
62 return TRUE;
63}
64
65static void
66run_gif_test (gconstpointer data)
67{
68 const gchar *name = data;
69 GKeyFile *config_file;
70 gchar *config_filename, *input_filename;
71 gint width, height;
72 GFile *input_file;
73 GBytes *input_bytes;
74 GdkPixbufLoader *loader;
75 GdkPixbufAnimation *animation = NULL;
76 GdkPixbufAnimationIter *iter = NULL;
77 GTimeVal animation_time;
78 GStrv frames;
79 int i;
80 GError *error = NULL;
81
82 if (!format_supported (filename: "gif"))
83 {
84 g_test_skip (msg: "GIF format not supported");
85 return;
86 }
87
88 config_file = g_key_file_new ();
89 g_key_file_set_list_separator (key_file: config_file, separator: ',');
90 config_filename = g_strdup_printf (format: "%s.conf", name);
91 g_key_file_load_from_file (key_file: config_file, file: get_test_path (filename: config_filename), flags: G_KEY_FILE_NONE, error: &error);
92 g_free (mem: config_filename);
93 g_assert_no_error (error);
94
95 input_filename = g_key_file_get_string (key_file: config_file, group_name: "config", key: "input", error: &error);
96 g_assert_no_error (error);
97 input_file = g_file_new_for_path (path: get_test_path (filename: input_filename));
98 g_free (mem: input_filename);
99 input_bytes = g_file_load_bytes (file: input_file, NULL, NULL, error: &error);
100 g_clear_object (&input_file);
101 g_assert_no_error (error);
102
103 width = g_key_file_get_integer (key_file: config_file, group_name: "config", key: "width", error: &error);
104 g_assert_no_error (error);
105 height = g_key_file_get_integer (key_file: config_file, group_name: "config", key: "height", error: &error);
106 g_assert_no_error (error);
107
108 loader = gdk_pixbuf_loader_new ();
109 gdk_pixbuf_loader_write_bytes (loader, buffer: input_bytes, error: &error);
110 g_clear_pointer (&input_bytes, g_bytes_unref);
111 g_assert_no_error (error);
112
113 gdk_pixbuf_loader_close (loader, error: &error);
114 if (width == 0 || height == 0) {
115 g_assert_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE);
116 g_clear_error (err: &error);
117 }
118 else {
119 g_assert_no_error (error);
120 animation = gdk_pixbuf_loader_get_animation (loader);
121 g_assert_nonnull (animation);
122 }
123
124 frames = g_key_file_get_string_list (key_file: config_file, group_name: "config", key: "frames", NULL, error: &error);
125 g_assert_no_error (error);
126 animation_time.tv_sec = 0;
127 animation_time.tv_usec = 0;
128 for (i = 0; frames[i]; i++)
129 {
130 const gchar *frame = frames[i];
131 GdkPixbuf *pixbuf;
132 gint delay_time, expected_delay_time = 100;
133 gchar *pixels_filename;
134 GFile *pixels_file;
135 GBytes *expected_pixels, *pixels;
136
137 g_assert_nonnull (animation);
138
139 if (iter == NULL)
140 iter = gdk_pixbuf_animation_get_iter (animation, start_time: &animation_time);
141 else
142 gdk_pixbuf_animation_iter_advance (iter, current_time: &animation_time);
143 delay_time = gdk_pixbuf_animation_iter_get_delay_time (iter);
144 g_time_val_add (time_: &animation_time, microseconds: gdk_pixbuf_animation_iter_get_delay_time (iter) * 1000);
145
146 if (g_key_file_has_key (key_file: config_file, group_name: frame, key: "delay", error: &error))
147 expected_delay_time = g_key_file_get_integer (key_file: config_file, group_name: frame, key: "delay", error: &error) * 10;
148 g_assert_no_error (error);
149
150 g_assert_cmpint (delay_time, ==, expected_delay_time);
151
152 pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (iter);
153
154 g_assert_cmpint (width, ==, gdk_pixbuf_get_width (pixbuf));
155 g_assert_cmpint (height, ==, gdk_pixbuf_get_height (pixbuf));
156
157 pixels_filename = g_key_file_get_string (key_file: config_file, group_name: frame, key: "pixels", error: &error);
158 g_assert_no_error (error);
159 pixels_file = g_file_new_for_path (path: get_test_path (filename: pixels_filename));
160 g_free (mem: pixels_filename);
161 expected_pixels = g_file_load_bytes (file: pixels_file, NULL, NULL, error: &error);
162 g_clear_object (&pixels_file);
163 g_assert_no_error (error);
164
165 g_assert_cmpint (gdk_pixbuf_get_colorspace (pixbuf), ==, GDK_COLORSPACE_RGB);
166 g_assert_cmpint (gdk_pixbuf_get_n_channels (pixbuf), ==, 4);
167 g_assert_true (gdk_pixbuf_get_has_alpha (pixbuf));
168 g_assert_cmpint (gdk_pixbuf_get_rowstride (pixbuf), ==, width * 4);
169 pixels = g_bytes_new_static (data: gdk_pixbuf_read_pixels (pixbuf), size: gdk_pixbuf_get_byte_length (pixbuf));
170 g_assert_true (pixels_match (pixels, expected_pixels));
171 g_clear_pointer (&pixels, g_bytes_unref);
172 g_clear_pointer (&expected_pixels, g_bytes_unref);
173 }
174 g_strfreev (str_array: frames);
175 g_clear_object (&iter);
176
177 /* FIXME: We should check here if there's more frames than we were expecting, but gdk-pixbuf doesn't return this information */
178
179 g_clear_object (&loader);
180 g_clear_pointer (&config_file, g_key_file_unref);
181}
182
183int
184main (int argc, char **argv)
185{
186 gchar *path, *contents;
187 GStrv lines;
188 int i, result;
189 GError *error = NULL;
190
191 g_test_init (argc: &argc, argv: &argv, NULL);
192
193 path = g_build_filename (first_element: g_test_get_dir (file_type: G_TEST_DIST), "test-images", "gif-test-suite", "TESTS", NULL);
194 g_file_get_contents (filename: path, contents: &contents, NULL, error: &error);
195 g_free (mem: path);
196 g_assert_no_error (error);
197 lines = g_strsplit (string: contents, delimiter: "\n", max_tokens: -1);
198 g_free (mem: contents);
199 for (i = 0; lines[i]; i++)
200 {
201 const gchar *name = g_strstrip (lines[i]);
202 gchar *test_name;
203
204 if (g_strcmp0 (str1: name, str2: "") == 0 || name[0] == '#')
205 continue;
206
207 test_name = g_strdup_printf (format: "/pixbuf/gif/%s", name);
208 g_test_add_data_func (testpath: test_name, test_data: name, test_func: run_gif_test);
209 g_free (mem: test_name);
210 }
211
212 result = g_test_run ();
213
214 g_strfreev (str_array: lines);
215
216 return result;
217}
218

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