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 (G_OBJECT (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 gtk_signal_connect (GTK_OBJECT (dialog),
165 GTK_SIGNAL_FUNC (gtk_widget_destroy),
168 fclose (lc->image_stream);
169 lc->image_stream = NULL;
171 gtk_widget_show (dialog);
173 lc->load_timeout = 0;
175 return FALSE; /* uninstall the timeout */
178 if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
184 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
185 GTK_DIALOG_DESTROY_WITH_PARENT,
188 "Failed to load image: %s",
191 g_error_free (error);
193 gtk_signal_connect (GTK_OBJECT (dialog),
195 GTK_SIGNAL_FUNC (gtk_widget_destroy),
198 fclose (lc->image_stream);
199 lc->image_stream = NULL;
201 gtk_widget_show (dialog);
203 lc->load_timeout = 0;
205 return FALSE; /* uninstall the timeout */
208 if (feof (lc->image_stream))
210 fclose (lc->image_stream);
211 lc->image_stream = NULL;
213 /* Errors can happen on close, e.g. if the image
214 * file was truncated we'll know on close that
218 if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
223 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
224 GTK_DIALOG_DESTROY_WITH_PARENT,
227 "Failed to load image: %s",
230 g_error_free (error);
232 gtk_signal_connect (GTK_OBJECT (dialog),
234 GTK_SIGNAL_FUNC (gtk_widget_destroy),
237 gtk_widget_show (dialog);
239 g_object_unref (G_OBJECT (lc->pixbuf_loader));
240 lc->pixbuf_loader = NULL;
242 lc->load_timeout = 0;
244 return FALSE; /* uninstall the timeout */
247 g_object_unref (G_OBJECT (lc->pixbuf_loader));
248 lc->pixbuf_loader = NULL;
253 lc->image_stream = fopen (lc->filename, "r");
255 if (lc->image_stream == NULL)
259 dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
260 GTK_DIALOG_DESTROY_WITH_PARENT,
263 "Unable to open image file '%s': %s",
267 gtk_signal_connect (GTK_OBJECT (dialog),
269 GTK_SIGNAL_FUNC (gtk_widget_destroy),
272 gtk_widget_show (dialog);
274 lc->load_timeout = 0;
276 return FALSE; /* uninstall the timeout */
279 if (lc->pixbuf_loader)
281 gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
282 g_object_unref (G_OBJECT (lc->pixbuf_loader));
283 lc->pixbuf_loader = NULL;
286 lc->pixbuf_loader = gdk_pixbuf_loader_new ();
288 g_signal_connect (G_OBJECT (lc->pixbuf_loader),
290 G_CALLBACK (progressive_prepared_callback),
292 g_signal_connect (G_OBJECT (lc->pixbuf_loader),
294 G_CALLBACK (progressive_updated_callback),
298 /* leave timeout installed */
303 start_progressive_loading (GtkWidget *image)
307 lc = get_load_context (image);
309 /* This is obviously totally contrived (we slow down loading
310 * on purpose to show how incremental loading works).
311 * The real purpose of incremental loading is the case where
312 * you are reading data from a slow source such as the network.
313 * The timeout simply simulates a slow data source by inserting
314 * pauses in the reading process.
316 lc->load_timeout = g_timeout_add (100,
322 do_image (const char *filename)
330 gchar *str, *escaped;
333 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
334 gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
336 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
338 vbox = gtk_vbox_new (FALSE, 8);
339 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
340 gtk_container_add (GTK_CONTAINER (window), vbox);
342 label = gtk_label_new (NULL);
343 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
344 escaped = g_markup_escape_text (filename, -1);
345 str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
346 gtk_label_set_markup (GTK_LABEL (label),
351 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
353 frame = gtk_frame_new (NULL);
354 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
355 /* The alignment keeps the frame from growing when users resize
358 align = gtk_alignment_new (0.5, 0.5, 0, 0);
359 gtk_container_add (GTK_CONTAINER (align), frame);
360 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
362 image = gtk_image_new_from_pixbuf (NULL);
363 gtk_container_add (GTK_CONTAINER (frame), image);
365 lc = get_load_context (image);
368 lc->filename = g_strdup (filename);
370 start_progressive_loading (image);
372 gtk_widget_show_all (window);
378 do_nonprogressive (const gchar *filename)
386 gchar *str, *escaped;
388 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
389 gtk_window_set_title (GTK_WINDOW (window), "Animation");
391 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
393 vbox = gtk_vbox_new (FALSE, 8);
394 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
395 gtk_container_add (GTK_CONTAINER (window), vbox);
397 label = gtk_label_new (NULL);
398 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
399 escaped = g_markup_escape_text (filename, -1);
400 str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
401 gtk_label_set_markup (GTK_LABEL (label),
406 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
408 frame = gtk_frame_new (NULL);
409 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
410 /* The alignment keeps the frame from growing when users resize
413 align = gtk_alignment_new (0.5, 0.5, 0, 0);
414 gtk_container_add (GTK_CONTAINER (align), frame);
415 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
417 image = gtk_image_new_from_file (filename);
418 gtk_container_add (GTK_CONTAINER (frame), image);
420 gtk_widget_show_all (window);
429 gtk_init (&argc, &argv);
435 do_nonprogressive (argv[i]);