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 | |
25 | const gchar * |
26 | get_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 | |
31 | static gboolean |
32 | pixels_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 | |
65 | static void |
66 | run_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 | |
183 | int |
184 | main (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 | |