1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - Progressive loader object
4 * Copyright (C) 1999 The Free Software Foundation
6 * Authors: Mark Crichton <crichton@gimp.org>
7 * Miguel de Icaza <miguel@gnu.org>
8 * Federico Mena-Quintero <federico@gimp.org>
9 * Jonathan Blandford <jrb@redhat.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
29 #include "gdk-pixbuf-private.h"
30 #include "gdk-pixbuf-animation.h"
31 #include "gdk-pixbuf-io.h"
32 #include "gdk-pixbuf-loader.h"
33 #include "gdk-pixbuf-marshal.h"
44 static void gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *klass);
45 static void gdk_pixbuf_loader_init (GdkPixbufLoader *loader);
46 static void gdk_pixbuf_loader_finalize (GObject *loader);
48 static gpointer parent_class = NULL;
49 static guint pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
54 #define LOADER_HEADER_SIZE 128
58 GdkPixbufAnimation *animation;
60 guchar header_buf[LOADER_HEADER_SIZE];
61 gint header_buf_offset;
62 GdkPixbufModule *image_module;
68 } GdkPixbufLoaderPrivate;
72 * gdk_pixbuf_loader_get_type:
74 * Registers the #GdkPixbufLoader class if necessary, and returns the type ID
77 * Return value: The type ID of the #GdkPixbufLoader class.
80 gdk_pixbuf_loader_get_type (void)
82 static GType loader_type = 0;
86 static const GTypeInfo loader_info = {
87 sizeof (GdkPixbufLoaderClass),
89 (GBaseFinalizeFunc) NULL,
90 (GClassInitFunc) gdk_pixbuf_loader_class_init,
91 NULL, /* class_finalize */
92 NULL, /* class_data */
93 sizeof (GdkPixbufLoader),
95 (GInstanceInitFunc) gdk_pixbuf_loader_init
98 loader_type = g_type_register_static (G_TYPE_OBJECT,
108 gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
110 GObjectClass *object_class;
112 object_class = (GObjectClass *) class;
114 parent_class = g_type_class_peek_parent (class);
116 object_class->finalize = gdk_pixbuf_loader_finalize;
119 * GdkPixbufLoader::size-prepared:
120 * @loader: the object which received the signal.
121 * @width: the original width of the image
122 * @height: the original height of the image
124 * This signal is emitted when the pixbuf loader has been fed the
125 * initial amount of data that is required to figure out the size
126 * of the image that it will create. Applications can call
127 * gdk_pixbuf_loader_set_size() in response to this signal to set
128 * the desired size to which the image should be scaled.
130 pixbuf_loader_signals[SIZE_PREPARED] =
131 g_signal_new ("size_prepared",
132 G_TYPE_FROM_CLASS (object_class),
134 G_STRUCT_OFFSET (GdkPixbufLoaderClass, size_prepared),
136 gdk_pixbuf_marshal_VOID__INT_INT,
142 * GdkPixbufLoader::area-prepared:
143 * @loader: the object which received the signal.
145 * This signal is emitted when the pixbuf loader has allocated the
146 * pixbuf in the desired size. After this signal is emitted,
147 * applications can call gdk_pixbuf_loader_get_pixbuf() to fetch
148 * the partially-loaded pixbuf.
150 pixbuf_loader_signals[AREA_PREPARED] =
151 g_signal_new ("area_prepared",
152 G_TYPE_FROM_CLASS (object_class),
154 G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_prepared),
156 gdk_pixbuf_marshal_VOID__VOID,
160 * GdkPixbufLoader::area-updated:
161 * @loader: the object which received the signal.
162 * @x: X offset of upper-left corner of the updated area.
163 * @y: Y offset of upper-left corner of the updated area.
164 * @width: Width of updated area.
165 * @height: Height of updated area.
167 * This signal is emitted when a significant area of the image being
168 * loaded has been updated. Normally it means that a complete
169 * scanline has been read in, but it could be a different area as
170 * well. Applications can use this signal to know when to repaint
171 * areas of an image that is being loaded.
173 pixbuf_loader_signals[AREA_UPDATED] =
174 g_signal_new ("area_updated",
175 G_TYPE_FROM_CLASS (object_class),
177 G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_updated),
179 gdk_pixbuf_marshal_VOID__INT_INT_INT_INT,
187 * GdkPixbufLoader::closed:
188 * @loader: the object which received the signal.
190 * This signal is emitted when gdk_pixbuf_loader_close() is called.
191 * It can be used by different parts of an application to receive
192 * notification when an image loader is closed by the code that
195 pixbuf_loader_signals[CLOSED] =
196 g_signal_new ("closed",
197 G_TYPE_FROM_CLASS (object_class),
199 G_STRUCT_OFFSET (GdkPixbufLoaderClass, closed),
201 gdk_pixbuf_marshal_VOID__VOID,
206 gdk_pixbuf_loader_init (GdkPixbufLoader *loader)
208 GdkPixbufLoaderPrivate *priv;
210 priv = g_new0 (GdkPixbufLoaderPrivate, 1);
215 gdk_pixbuf_loader_finalize (GObject *object)
217 GdkPixbufLoader *loader;
218 GdkPixbufLoaderPrivate *priv = NULL;
220 loader = GDK_PIXBUF_LOADER (object);
224 g_warning ("GdkPixbufLoader finalized without calling gdk_pixbuf_loader_close() - this is not allowed. You must explicitly end the data stream to the loader before dropping the last reference.");
227 g_object_unref (priv->animation);
231 G_OBJECT_CLASS (parent_class)->finalize (object);
235 * gdk_pixbuf_loader_set_size:
236 * @loader: A pixbuf loader.
237 * @width: The desired width of the image being loaded.
238 * @height: The desired height of the image being loaded.
240 * Causes the image to be scaled while it is loaded. The desired
241 * image size can be determined relative to the original size of
242 * the image by calling gdk_pixbuf_loader_set_size() from a
243 * signal handler for the ::size_prepared signal.
245 * Attempts to set the desired image size are ignored after the
246 * emission of the ::size_prepared signal.
251 gdk_pixbuf_loader_set_size (GdkPixbufLoader *loader,
255 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
256 g_return_if_fail (width > 0 && height > 0);
258 if (!priv->size_fixed)
261 priv->height = height;
266 gdk_pixbuf_loader_size_func (gint *width, gint *height, gpointer loader)
268 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
270 /* allow calling gdk_pixbuf_loader_set_size() before the signal */
271 if (priv->width == 0 && priv->height == 0)
273 priv->width = *width;
274 priv->height = *height;
277 g_signal_emit (loader, pixbuf_loader_signals[SIZE_PREPARED], 0, *width, *height);
278 priv->size_fixed = TRUE;
280 *width = priv->width;
281 *height = priv->height;
285 gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
286 GdkPixbufAnimation *anim,
289 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
290 g_return_if_fail (pixbuf != NULL);
292 if (!priv->size_fixed)
294 /* Defend against lazy loaders which don't call size_func */
295 gint width = gdk_pixbuf_get_width (pixbuf);
296 gint height = gdk_pixbuf_get_height (pixbuf);
298 gdk_pixbuf_loader_size_func (&width, &height, loader);
301 priv->needs_scale = FALSE;
302 if (priv->width > 0 && priv->height > 0 &&
303 (priv->width != gdk_pixbuf_get_width (pixbuf) ||
304 priv->height != gdk_pixbuf_get_height (pixbuf)))
305 priv->needs_scale = TRUE;
310 anim = gdk_pixbuf_non_anim_new (pixbuf);
312 priv->animation = anim;
314 if (!priv->needs_scale)
315 g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
319 gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
326 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
328 if (!priv->needs_scale)
329 g_signal_emit (loader,
330 pixbuf_loader_signals[AREA_UPDATED],
333 /* sanity check in here. Defend against an errant loader */
334 MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
335 MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
339 gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
340 const char *image_type,
343 GdkPixbufLoaderPrivate *priv = loader->priv;
347 priv->image_module = _gdk_pixbuf_get_named_module (image_type,
352 priv->image_module = _gdk_pixbuf_get_module (priv->header_buf,
353 priv->header_buf_offset,
358 if (priv->image_module == NULL)
361 if (priv->image_module->module == NULL)
362 if (!_gdk_pixbuf_load_module (priv->image_module, error))
365 if (priv->image_module->module == NULL)
368 if ((priv->image_module->begin_load == NULL) ||
369 (priv->image_module->stop_load == NULL) ||
370 (priv->image_module->load_increment == NULL))
374 GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
375 _("Incremental loading of image type '%s' is not supported"),
376 priv->image_module->module_name);
381 priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_size_func,
382 gdk_pixbuf_loader_prepare,
383 gdk_pixbuf_loader_update,
387 if (priv->context == NULL)
389 /* Defense against broken loaders; DO NOT take this as a GError
392 if (error && *error == NULL)
394 g_warning ("Bug! loader '%s' didn't set an error on failure",
395 priv->image_module->module_name);
398 GDK_PIXBUF_ERROR_FAILED,
399 _("Internal error: Image loader module '%s'"
400 " failed to begin loading an image, but didn't"
401 " give a reason for the failure"),
402 priv->image_module->module_name);
409 if (priv->header_buf_offset
410 && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error))
411 return priv->header_buf_offset;
417 gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader,
423 GdkPixbufLoaderPrivate *priv = loader->priv;
425 n_bytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
426 memcpy (priv->header_buf + priv->header_buf_offset, buf, n_bytes);
428 priv->header_buf_offset += n_bytes;
430 if (priv->header_buf_offset >= LOADER_HEADER_SIZE)
432 if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0)
440 * gdk_pixbuf_loader_write:
441 * @loader: A pixbuf loader.
442 * @buf: Pointer to image data.
443 * @count: Length of the @buf buffer in bytes.
444 * @error: return location for errors
446 * This will cause a pixbuf loader to parse the next @count bytes of
447 * an image. It will return %TRUE if the data was loaded successfully,
448 * and %FALSE if an error occurred. In the latter case, the loader
449 * will be closed, and will not accept further writes. If %FALSE is
450 * returned, @error will be set to an error from the #GDK_PIXBUF_ERROR
451 * or #G_FILE_ERROR domains.
453 * Return value: %TRUE if the write was successful, or %FALSE if the loader
454 * cannot parse the buffer.
457 gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
462 GdkPixbufLoaderPrivate *priv;
464 g_return_val_if_fail (loader != NULL, FALSE);
465 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), FALSE);
467 g_return_val_if_fail (buf != NULL, FALSE);
468 g_return_val_if_fail (count >= 0, FALSE);
469 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
473 /* we expect it's not to be closed */
474 g_return_val_if_fail (priv->closed == FALSE, FALSE);
476 if (priv->image_module == NULL)
480 eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
488 if (count > 0 && priv->image_module->load_increment)
491 retval = priv->image_module->load_increment (priv->context, buf, count,
493 if (!retval && error && *error == NULL)
495 /* Fix up busted image loader */
496 g_warning ("Bug! loader '%s' didn't set an error on failure",
497 priv->image_module->module_name);
500 GDK_PIXBUF_ERROR_FAILED,
501 _("Internal error: Image loader module '%s'"
502 " failed to begin loading an image, but didn't"
503 " give a reason for the failure"),
504 priv->image_module->module_name);
514 * gdk_pixbuf_loader_new:
516 * Creates a new pixbuf loader object.
518 * Return value: A newly-created pixbuf loader.
521 gdk_pixbuf_loader_new (void)
523 return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
527 * gdk_pixbuf_loader_new_with_type:
528 * @image_type: name of the image format to be loaded with the image
529 * @error: return location for an allocated #GError, or %NULL to ignore errors
531 * Creates a new pixbuf loader object that always attempts to parse
532 * image data as if it were an image of type @image_type, instead of
533 * identifying the type automatically. Useful if you want an error if
534 * the image isn't the expected type, for loading image formats
535 * that can't be reliably identified by looking at the data, or if
536 * the user manually forces a specific type.
538 * Return value: A newly-created pixbuf loader.
541 gdk_pixbuf_loader_new_with_type (const char *image_type,
544 GdkPixbufLoader *retval;
546 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
548 retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
551 gdk_pixbuf_loader_load_module (retval, image_type, &tmp);
554 g_propagate_error (error, tmp);
555 g_object_unref (retval);
563 * gdk_pixbuf_loader_new_with_mime_type:
564 * @mime_type: the mime type to be loaded
565 * @error: return location for an allocated #GError, or %NULL to ignore errors
567 * Creates a new pixbuf loader object that always attempts to parse
568 * image data as if it were an image of mime type @mime_type, instead of
569 * identifying the type automatically. Useful if you want an error if
570 * the image isn't the expected mime type, for loading image formats
571 * that can't be reliably identified by looking at the data, or if
572 * the user manually forces a specific mime type.
574 * Return value: A newly-created pixbuf loader.
578 gdk_pixbuf_loader_new_with_mime_type (const char *mime_type,
581 const char * image_type = NULL;
584 GdkPixbufLoader *retval;
588 GdkPixbufFormat *info;
591 formats = gdk_pixbuf_get_formats ();
592 length = g_slist_length (formats);
594 for (i = 0; i < length && image_type == NULL; i++) {
595 info = (GdkPixbufFormat *)g_slist_nth_data (formats, i);
596 mimes = info->mime_types;
598 for (j = 0; mimes[j] != NULL; j++)
599 if (g_ascii_strcasecmp (mimes[i], mime_type)) {
600 image_type = info->name;
605 g_slist_free (formats);
607 retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
610 gdk_pixbuf_loader_load_module(retval, image_type, &tmp);
613 g_propagate_error (error, tmp);
614 g_object_unref (retval);
622 * gdk_pixbuf_loader_get_pixbuf:
623 * @loader: A pixbuf loader.
625 * Queries the #GdkPixbuf that a pixbuf loader is currently creating.
626 * In general it only makes sense to call this function after the
627 * "area_prepared" signal has been emitted by the loader; this means
628 * that enough data has been read to know the size of the image that
629 * will be allocated. If the loader has not received enough data via
630 * gdk_pixbuf_loader_write(), then this function returns %NULL. The
631 * returned pixbuf will be the same in all future calls to the loader,
632 * so simply calling g_object_ref() should be sufficient to continue
633 * using it. Additionally, if the loader is an animation, it will
634 * return the "static image" of the animation
635 * (see gdk_pixbuf_animation_get_static_image()).
637 * Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
638 * enough data has been read to determine how to create the image buffer.
641 gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
643 GdkPixbufLoaderPrivate *priv;
645 g_return_val_if_fail (loader != NULL, NULL);
646 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
651 return gdk_pixbuf_animation_get_static_image (priv->animation);
657 * gdk_pixbuf_loader_get_animation:
658 * @loader: A pixbuf loader
660 * Queries the #GdkPixbufAnimation that a pixbuf loader is currently creating.
661 * In general it only makes sense to call this function after the "area_prepared"
662 * signal has been emitted by the loader. If the loader doesn't have enough
663 * bytes yet (hasn't emitted the "area_prepared" signal) this function will
666 * Return value: The #GdkPixbufAnimation that the loader is loading, or %NULL if
667 not enough data has been read to determine the information.
670 gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader)
672 GdkPixbufLoaderPrivate *priv;
674 g_return_val_if_fail (loader != NULL, NULL);
675 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
679 return priv->animation;
683 * gdk_pixbuf_loader_close:
684 * @loader: A pixbuf loader.
685 * @error: return location for a #GError, or %NULL to ignore errors
687 * Informs a pixbuf loader that no further writes with
688 * gdk_pixbuf_loader_write() will occur, so that it can free its
689 * internal loading structures. Also, tries to parse any data that
690 * hasn't yet been parsed; if the remaining data is partial or
691 * corrupt, an error will be returned. If %FALSE is returned, @error
692 * will be set to an error from the #GDK_PIXBUF_ERROR or #G_FILE_ERROR
693 * domains. If you're just cancelling a load rather than expecting it
694 * to be finished, passing %NULL for @error to ignore it is
697 * Returns: %TRUE if all image data written so far was successfully
698 passed out via the update_area signal
701 gdk_pixbuf_loader_close (GdkPixbufLoader *loader,
704 GdkPixbufLoaderPrivate *priv;
705 gboolean retval = TRUE;
707 g_return_val_if_fail (loader != NULL, TRUE);
708 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), TRUE);
709 g_return_val_if_fail (error == NULL || *error == NULL, TRUE);
713 /* we expect it's not closed */
714 g_return_val_if_fail (priv->closed == FALSE, TRUE);
716 /* We have less the 128 bytes in the image. Flush it, and keep going. */
717 if (priv->image_module == NULL)
720 gdk_pixbuf_loader_load_module (loader, NULL, &tmp);
723 g_propagate_error (error, tmp);
728 if (priv->image_module && priv->image_module->stop_load && priv->context)
730 if (!priv->image_module->stop_load (priv->context, error))
736 if (priv->needs_scale)
738 GdkPixbuf *tmp, *pixbuf;
740 tmp = gdk_pixbuf_animation_get_static_image (priv->animation);
742 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, tmp->has_alpha, 8, priv->width, priv->height);
743 g_object_unref (priv->animation);
744 priv->animation = gdk_pixbuf_non_anim_new (pixbuf);
745 g_object_unref (pixbuf);
746 g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
747 gdk_pixbuf_scale (tmp, pixbuf, 0, 0, priv->width, priv->height, 0, 0,
748 (double) priv->width / tmp->width,
749 (double) priv->height / tmp->height,
750 GDK_INTERP_BILINEAR);
751 g_object_unref (tmp);
753 g_signal_emit (loader, pixbuf_loader_signals[AREA_UPDATED], 0,
754 0, 0, priv->width, priv->height);
758 g_signal_emit (loader, pixbuf_loader_signals[CLOSED], 0);
764 * gdk_pixbuf_loader_get_format:
765 * @loader: A pixbuf loader.
767 * Obtains the available information about the format of the
768 * currently loading image file.
770 * Returns: A #GdkPixbufFormat or %NULL. The return value is owned
771 * by GdkPixbuf and should not be freed.
776 gdk_pixbuf_loader_get_format (GdkPixbufLoader *loader)
778 GdkPixbufLoaderPrivate *priv;
780 g_return_val_if_fail (loader != NULL, NULL);
781 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
785 if (priv->image_module)
786 return _gdk_pixbuf_get_format (priv->image_module);