2 /* testpixbuf -- test program for gdk-pixbuf code
3 * Copyright (C) 1999 Mark Crichton, Larry Ewing
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
27 typedef struct _LoadContext LoadContext;
33 GdkPixbufLoader *pixbuf_loader;
39 destroy_context (gpointer data)
41 LoadContext *lc = data;
43 g_free (lc->filename);
46 g_source_remove (lc->load_timeout);
49 fclose (lc->image_stream);
51 if (lc->pixbuf_loader)
53 gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
54 g_object_unref (lc->pixbuf_loader);
61 get_load_context (GtkWidget *image)
65 lc = g_object_get_data (G_OBJECT (image), "lc");
69 lc = g_new0 (LoadContext, 1);
71 g_object_set_data_full (G_OBJECT (image),
81 progressive_prepared_callback (GdkPixbufLoader* loader,
87 image = GTK_WIDGET (data);
89 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
91 /* Avoid displaying random memory contents, since the pixbuf
92 * isn't filled in yet.
94 gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
96 /* Could set the pixbuf instead, if we only wanted to display
99 gtk_image_set_from_animation (GTK_IMAGE (image),
100 gdk_pixbuf_loader_get_animation (loader));
104 progressive_updated_callback (GdkPixbufLoader* loader,
105 gint x, gint y, gint width, gint height,
110 image = GTK_WIDGET (data);
112 /* We know the pixbuf inside the GtkImage has changed, but the image
113 * itself doesn't know this; so queue a redraw. If we wanted to be
114 * really efficient, we could use a drawing area or something
115 * instead of a GtkImage, so we could control the exact position of
116 * the pixbuf on the display, then we could queue a draw for only
117 * the updated area of the image.
120 /* We only really need to redraw if the image's animation iterator
121 * is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
125 gtk_widget_queue_draw (image);
129 progressive_timeout (gpointer data)
134 image = GTK_WIDGET (data);
135 lc = get_load_context (image);
137 /* This shows off fully-paranoid error handling, so looks scary.
138 * You could factor out the error handling code into a nice separate
139 * function to make things nicer.
142 if (lc->image_stream)
146 GError *error = NULL;
148 bytes_read = fread (buf, 1, 256, lc->image_stream);
150 if (ferror (lc->image_stream))
154 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
155 GTK_DIALOG_DESTROY_WITH_PARENT,
158 "Failure reading image file 'alphatest.png': %s",
161 g_signal_connect (dialog, "response",
162 G_CALLBACK (gtk_widget_destroy), NULL);
164 fclose (lc->image_stream);
165 lc->image_stream = NULL;
167 gtk_widget_show (dialog);
169 lc->load_timeout = 0;
171 return FALSE; /* uninstall the timeout */
174 if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
180 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
181 GTK_DIALOG_DESTROY_WITH_PARENT,
184 "Failed to load image: %s",
187 g_error_free (error);
189 g_signal_connect (dialog, "response",
190 G_CALLBACK (gtk_widget_destroy), NULL);
192 fclose (lc->image_stream);
193 lc->image_stream = NULL;
195 gtk_widget_show (dialog);
197 lc->load_timeout = 0;
199 return FALSE; /* uninstall the timeout */
202 if (feof (lc->image_stream))
204 fclose (lc->image_stream);
205 lc->image_stream = NULL;
207 /* Errors can happen on close, e.g. if the image
208 * file was truncated we'll know on close that
212 if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
217 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
218 GTK_DIALOG_DESTROY_WITH_PARENT,
221 "Failed to load image: %s",
224 g_error_free (error);
226 g_signal_connect (dialog, "response",
227 G_CALLBACK (gtk_widget_destroy), NULL);
229 gtk_widget_show (dialog);
231 g_object_unref (lc->pixbuf_loader);
232 lc->pixbuf_loader = NULL;
234 lc->load_timeout = 0;
236 return FALSE; /* uninstall the timeout */
239 g_object_unref (lc->pixbuf_loader);
240 lc->pixbuf_loader = NULL;
245 lc->image_stream = fopen (lc->filename, "r");
247 if (lc->image_stream == NULL)
251 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
252 GTK_DIALOG_DESTROY_WITH_PARENT,
255 "Unable to open image file '%s': %s",
259 g_signal_connect (dialog, "response",
260 G_CALLBACK (gtk_widget_destroy), NULL);
262 gtk_widget_show (dialog);
264 lc->load_timeout = 0;
266 return FALSE; /* uninstall the timeout */
269 if (lc->pixbuf_loader)
271 gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
272 g_object_unref (lc->pixbuf_loader);
273 lc->pixbuf_loader = NULL;
276 lc->pixbuf_loader = gdk_pixbuf_loader_new ();
278 g_signal_connect (lc->pixbuf_loader, "area_prepared",
279 G_CALLBACK (progressive_prepared_callback), image);
280 g_signal_connect (lc->pixbuf_loader, "area_updated",
281 G_CALLBACK (progressive_updated_callback), image);
284 /* leave timeout installed */
289 start_progressive_loading (GtkWidget *image)
293 lc = get_load_context (image);
295 /* This is obviously totally contrived (we slow down loading
296 * on purpose to show how incremental loading works).
297 * The real purpose of incremental loading is the case where
298 * you are reading data from a slow source such as the network.
299 * The timeout simply simulates a slow data source by inserting
300 * pauses in the reading process.
302 lc->load_timeout = gdk_threads_add_timeout (100,
308 do_image (const char *filename)
316 gchar *str, *escaped;
319 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
320 gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
322 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
324 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
325 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
326 gtk_container_add (GTK_CONTAINER (window), vbox);
328 label = gtk_label_new (NULL);
329 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
330 escaped = g_markup_escape_text (filename, -1);
331 str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
332 gtk_label_set_markup (GTK_LABEL (label),
337 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
339 frame = gtk_frame_new (NULL);
340 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
341 /* The alignment keeps the frame from growing when users resize
344 align = gtk_alignment_new (0.5, 0.5, 0, 0);
345 gtk_container_add (GTK_CONTAINER (align), frame);
346 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
348 image = gtk_image_new_from_pixbuf (NULL);
349 gtk_container_add (GTK_CONTAINER (frame), image);
351 lc = get_load_context (image);
354 lc->filename = g_strdup (filename);
356 start_progressive_loading (image);
358 g_signal_connect (window, "destroy",
359 G_CALLBACK (gtk_main_quit), NULL);
361 g_signal_connect (window, "delete_event",
362 G_CALLBACK (gtk_main_quit), NULL);
364 gtk_widget_show_all (window);
370 do_nonprogressive (const gchar *filename)
378 gchar *str, *escaped;
380 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
381 gtk_window_set_title (GTK_WINDOW (window), "Animation");
383 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
385 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
386 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
387 gtk_container_add (GTK_CONTAINER (window), vbox);
389 label = gtk_label_new (NULL);
390 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
391 escaped = g_markup_escape_text (filename, -1);
392 str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
393 gtk_label_set_markup (GTK_LABEL (label),
398 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
400 frame = gtk_frame_new (NULL);
401 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
402 /* The alignment keeps the frame from growing when users resize
405 align = gtk_alignment_new (0.5, 0.5, 0, 0);
406 gtk_container_add (GTK_CONTAINER (align), frame);
407 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
409 image = gtk_image_new_from_file (filename);
410 gtk_container_add (GTK_CONTAINER (frame), image);
412 g_signal_connect (window, "destroy",
413 G_CALLBACK (gtk_main_quit), NULL);
415 g_signal_connect (window, "delete_event",
416 G_CALLBACK (gtk_main_quit), NULL);
418 gtk_widget_show_all (window);
427 gtk_init (&argc, &argv);
433 do_nonprogressive (argv[i]);