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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 typedef struct _LoadContext LoadContext;
35 GdkPixbufLoader *pixbuf_loader;
41 destroy_context (gpointer data)
43 LoadContext *lc = data;
45 g_free (lc->filename);
48 g_source_remove (lc->load_timeout);
51 fclose (lc->image_stream);
53 if (lc->pixbuf_loader)
55 gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
56 g_object_unref (lc->pixbuf_loader);
63 get_load_context (GtkWidget *image)
67 lc = g_object_get_data (G_OBJECT (image), "lc");
71 lc = g_new0 (LoadContext, 1);
73 g_object_set_data_full (G_OBJECT (image),
83 progressive_prepared_callback (GdkPixbufLoader* loader,
89 image = GTK_WIDGET (data);
91 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
93 /* Avoid displaying random memory contents, since the pixbuf
94 * isn't filled in yet.
96 gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
98 /* Could set the pixbuf instead, if we only wanted to display
101 gtk_image_set_from_animation (GTK_IMAGE (image),
102 gdk_pixbuf_loader_get_animation (loader));
106 progressive_updated_callback (GdkPixbufLoader* loader,
107 gint x, gint y, gint width, gint height,
112 image = GTK_WIDGET (data);
114 /* We know the pixbuf inside the GtkImage has changed, but the image
115 * itself doesn't know this; so queue a redraw. If we wanted to be
116 * really efficient, we could use a drawing area or something
117 * instead of a GtkImage, so we could control the exact position of
118 * the pixbuf on the display, then we could queue a draw for only
119 * the updated area of the image.
122 /* We only really need to redraw if the image's animation iterator
123 * is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
127 gtk_widget_queue_draw (image);
131 progressive_timeout (gpointer data)
136 image = GTK_WIDGET (data);
137 lc = get_load_context (image);
139 /* This shows off fully-paranoid error handling, so looks scary.
140 * You could factor out the error handling code into a nice separate
141 * function to make things nicer.
144 if (lc->image_stream)
148 GError *error = NULL;
150 bytes_read = fread (buf, 1, 256, lc->image_stream);
152 if (ferror (lc->image_stream))
156 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
157 GTK_DIALOG_DESTROY_WITH_PARENT,
160 "Failure reading image file 'alphatest.png': %s",
163 g_signal_connect (dialog, "response",
164 G_CALLBACK (gtk_widget_destroy), NULL);
166 fclose (lc->image_stream);
167 lc->image_stream = NULL;
169 gtk_widget_show (dialog);
171 lc->load_timeout = 0;
173 return FALSE; /* uninstall the timeout */
176 if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
182 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
183 GTK_DIALOG_DESTROY_WITH_PARENT,
186 "Failed to load image: %s",
189 g_error_free (error);
191 g_signal_connect (dialog, "response",
192 G_CALLBACK (gtk_widget_destroy), NULL);
194 fclose (lc->image_stream);
195 lc->image_stream = NULL;
197 gtk_widget_show (dialog);
199 lc->load_timeout = 0;
201 return FALSE; /* uninstall the timeout */
204 if (feof (lc->image_stream))
206 fclose (lc->image_stream);
207 lc->image_stream = NULL;
209 /* Errors can happen on close, e.g. if the image
210 * file was truncated we'll know on close that
214 if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
219 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
220 GTK_DIALOG_DESTROY_WITH_PARENT,
223 "Failed to load image: %s",
226 g_error_free (error);
228 g_signal_connect (dialog, "response",
229 G_CALLBACK (gtk_widget_destroy), NULL);
231 gtk_widget_show (dialog);
233 g_object_unref (lc->pixbuf_loader);
234 lc->pixbuf_loader = NULL;
236 lc->load_timeout = 0;
238 return FALSE; /* uninstall the timeout */
241 g_object_unref (lc->pixbuf_loader);
242 lc->pixbuf_loader = NULL;
247 lc->image_stream = fopen (lc->filename, "r");
249 if (lc->image_stream == NULL)
253 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
254 GTK_DIALOG_DESTROY_WITH_PARENT,
257 "Unable to open image file '%s': %s",
261 g_signal_connect (dialog, "response",
262 G_CALLBACK (gtk_widget_destroy), NULL);
264 gtk_widget_show (dialog);
266 lc->load_timeout = 0;
268 return FALSE; /* uninstall the timeout */
271 if (lc->pixbuf_loader)
273 gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
274 g_object_unref (lc->pixbuf_loader);
275 lc->pixbuf_loader = NULL;
278 lc->pixbuf_loader = gdk_pixbuf_loader_new ();
280 g_signal_connect (lc->pixbuf_loader, "area_prepared",
281 G_CALLBACK (progressive_prepared_callback), image);
282 g_signal_connect (lc->pixbuf_loader, "area_updated",
283 G_CALLBACK (progressive_updated_callback), image);
286 /* leave timeout installed */
291 start_progressive_loading (GtkWidget *image)
295 lc = get_load_context (image);
297 /* This is obviously totally contrived (we slow down loading
298 * on purpose to show how incremental loading works).
299 * The real purpose of incremental loading is the case where
300 * you are reading data from a slow source such as the network.
301 * The timeout simply simulates a slow data source by inserting
302 * pauses in the reading process.
304 lc->load_timeout = g_timeout_add (100,
310 do_image (const char *filename)
318 gchar *str, *escaped;
321 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
322 gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
324 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
326 vbox = gtk_vbox_new (FALSE, 8);
327 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
328 gtk_container_add (GTK_CONTAINER (window), vbox);
330 label = gtk_label_new (NULL);
331 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
332 escaped = g_markup_escape_text (filename, -1);
333 str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
334 gtk_label_set_markup (GTK_LABEL (label),
339 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
341 frame = gtk_frame_new (NULL);
342 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
343 /* The alignment keeps the frame from growing when users resize
346 align = gtk_alignment_new (0.5, 0.5, 0, 0);
347 gtk_container_add (GTK_CONTAINER (align), frame);
348 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
350 image = gtk_image_new_from_pixbuf (NULL);
351 gtk_container_add (GTK_CONTAINER (frame), image);
353 lc = get_load_context (image);
356 lc->filename = g_strdup (filename);
358 start_progressive_loading (image);
360 g_signal_connect (window, "destroy",
361 G_CALLBACK (gtk_main_quit), NULL);
363 g_signal_connect (window, "delete_event",
364 G_CALLBACK (gtk_main_quit), NULL);
366 gtk_widget_show_all (window);
372 do_nonprogressive (const gchar *filename)
380 gchar *str, *escaped;
382 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
383 gtk_window_set_title (GTK_WINDOW (window), "Animation");
385 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
387 vbox = gtk_vbox_new (FALSE, 8);
388 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
389 gtk_container_add (GTK_CONTAINER (window), vbox);
391 label = gtk_label_new (NULL);
392 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
393 escaped = g_markup_escape_text (filename, -1);
394 str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
395 gtk_label_set_markup (GTK_LABEL (label),
400 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
402 frame = gtk_frame_new (NULL);
403 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
404 /* The alignment keeps the frame from growing when users resize
407 align = gtk_alignment_new (0.5, 0.5, 0, 0);
408 gtk_container_add (GTK_CONTAINER (align), frame);
409 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
411 image = gtk_image_new_from_file (filename);
412 gtk_container_add (GTK_CONTAINER (frame), image);
414 g_signal_connect (window, "destroy",
415 G_CALLBACK (gtk_main_quit), NULL);
417 g_signal_connect (window, "delete_event",
418 G_CALLBACK (gtk_main_quit), NULL);
420 gtk_widget_show_all (window);
429 gtk_init (&argc, &argv);
435 do_nonprogressive (argv[i]);