diff options
author | Havoc Pennington <hp@redhat.com> | 2000-10-18 18:42:54 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2000-10-18 18:42:54 +0000 |
commit | 7a4c68938789206bfec3c6d15cc4bb922daf6443 (patch) | |
tree | e5f031fc609e50a8b7b12e7d6abf63cc78cc88e7 /gdk-pixbuf | |
parent | 7420908815651a1ff2ceb1c0fb5e92fe9b260619 (diff) | |
download | gdk-pixbuf-7a4c68938789206bfec3c6d15cc4bb922daf6443.tar.gz |
Some updates
2000-10-18 Havoc Pennington <hp@redhat.com>
* gtk/gtk-sections.txt: Some updates
* gdk/gdk-sections.txt: remove GdkPixbufAlphaMode
* gdk-pixbuf/gdk-pixbuf-sections.txt: Add new API, remove
GdkPixbufClass/GdkAnimationClass since those are private
* gdk-pixbuf/Makefile.am (IGNORE_HFILES): ignore more headers
2000-10-18 Havoc Pennington <hp@redhat.com>
* gtk/gtktextiter.c (gtk_text_iter_forward_to_newline): Fix a bug
where any number of empty lines would get skipped
* gtk/gtktextiter.h: Remove padding from GtkTextIter; live on the
edge.
* gtk/gtktextiter.c (gtk_text_iter_make_surreal): enhance the
warning about invalid iterators (explain more thoroughly)
(gtk_text_iter_in_region): rename gtk_text_iter_in_range
* gtk/gtktextview.c (FOCUS_EDGE_WIDTH): Make focus rectangle less
big
* demos/*.c: Add error handling
* gtk/gtktextbuffer.c: don't modify const iterators
* gtk/gdk-pixbuf-loader.c: Add full error handling here
* gtk/gtkimage.c (gtk_image_set_from_file): ignore errors
on file load
* gtk/gtkiconfactory.c: Update to reflect addition of error
handling to gdk-pixbuf loaders
2000-10-16 Havoc Pennington <hp@redhat.com>
* gdk-pixbuf-io.c (gdk_pixbuf_get_module)
(gdk_pixbuf_get_named_module) (gdk_pixbuf_load_module):
add error reporting here also
* make-inline-pixbuf.c (main): use GError
* io-xpm.c: include unistd.h
* gdk-pixbuf-util.c: include string.h
* io-*.c: add error reporting
* gdk-pixbuf-animation.c (gdk_pixbuf_animation_new_from_file): add
error reporting
* gdk-pixbuf-io.c (gdk_pixbuf_new_from_file): Add error reporting
* gdk-pixbuf-io.h: Add GError** to load_increment and load
methods
* gdk-pixbuf-io.c (gdk_pixbuf_save) (gdk_pixbuf_savev): return
a G_FILE_ERROR if we fail to write or close the file.
* gdk-pixbuf.h: remove GDK_PIXBUF_ERROR_IO, instead we'll use
G_FILE_ERROR_*. Rename enum to GdkPixbufError, properly following
the GError naming rules. Add GError** to load functions.
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r-- | gdk-pixbuf/ChangeLog | 29 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-animation.c | 74 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-data.c | 130 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 199 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.h | 24 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-loader.c | 114 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-loader.h | 6 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-util.c | 1 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf.h | 31 | ||||
-rw-r--r-- | gdk-pixbuf/gnome-canvas-pixbuf.c | 841 | ||||
-rw-r--r-- | gdk-pixbuf/gnome-canvas-pixbuf.h | 64 | ||||
-rw-r--r-- | gdk-pixbuf/io-bmp.c | 34 | ||||
-rw-r--r-- | gdk-pixbuf/io-gif.c | 68 | ||||
-rw-r--r-- | gdk-pixbuf/io-ico.c | 27 | ||||
-rw-r--r-- | gdk-pixbuf/io-jpeg.c | 79 | ||||
-rw-r--r-- | gdk-pixbuf/io-png.c | 135 | ||||
-rw-r--r-- | gdk-pixbuf/io-pnm.c | 125 | ||||
-rw-r--r-- | gdk-pixbuf/io-ras.c | 25 | ||||
-rw-r--r-- | gdk-pixbuf/io-tiff.c | 3 | ||||
-rw-r--r-- | gdk-pixbuf/io-wbmp.c | 28 | ||||
-rw-r--r-- | gdk-pixbuf/io-xpm.c | 4 | ||||
-rw-r--r-- | gdk-pixbuf/make-inline-pixbuf.c | 9 |
22 files changed, 888 insertions, 1162 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index 321f5ad58..172bd5306 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,32 @@ +2000-10-16 Havoc Pennington <hp@redhat.com> + + * gdk-pixbuf-io.c (gdk_pixbuf_get_module) + (gdk_pixbuf_get_named_module) (gdk_pixbuf_load_module): + add error reporting here also + + * make-inline-pixbuf.c (main): use GError + + * io-xpm.c: include unistd.h + + * gdk-pixbuf-util.c: include string.h + + * io-*.c: add error reporting + + * gdk-pixbuf-animation.c (gdk_pixbuf_animation_new_from_file): add + error reporting + + * gdk-pixbuf-io.c (gdk_pixbuf_new_from_file): Add error reporting + + * gdk-pixbuf-io.h: Add GError** to load_increment and load + methods + + * gdk-pixbuf-io.c (gdk_pixbuf_save) (gdk_pixbuf_savev): return + a G_FILE_ERROR if we fail to write or close the file. + + * gdk-pixbuf.h: remove GDK_PIXBUF_ERROR_IO, instead we'll use + G_FILE_ERROR_*. Rename enum to GdkPixbufError, properly following + the GError naming rules. Add GError** to load functions. + 2000-10-06 Havoc Pennington <hp@redhat.com> * gdk-pixbuf.h: add GdkPixbufAlphaMode diff --git a/gdk-pixbuf/gdk-pixbuf-animation.c b/gdk-pixbuf/gdk-pixbuf-animation.c index 25f5d7d17..16dc26d6c 100644 --- a/gdk-pixbuf/gdk-pixbuf-animation.c +++ b/gdk-pixbuf/gdk-pixbuf-animation.c @@ -22,6 +22,7 @@ */ #include <config.h> +#include <errno.h> #include "gdk-pixbuf-io.h" #include "gdk-pixbuf-private.h" @@ -92,10 +93,12 @@ gdk_pixbuf_animation_finalize (GObject *object) /** * gdk_pixbuf_animation_new_from_file: * @filename: Name of file to load. + * @error: return location for error * * Creates a new animation by loading it from a file. The file format is * detected automatically. If the file's format does not support multi-frame - * images, then an animation with a single frame will be created. + * images, then an animation with a single frame will be created. Possible errors + * are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains. * * Return value: A newly created animation with a reference count of 1, or NULL * if any of several error conditions ocurred: the file could not be opened, @@ -103,7 +106,8 @@ gdk_pixbuf_animation_finalize (GObject *object) * allocate the image buffer, or the image file contained invalid data. **/ GdkPixbufAnimation * -gdk_pixbuf_animation_new_from_file (const char *filename) +gdk_pixbuf_animation_new_from_file (const char *filename, + GError **error) { GdkPixbufAnimation *animation; int size; @@ -114,25 +118,39 @@ gdk_pixbuf_animation_new_from_file (const char *filename) g_return_val_if_fail (filename != NULL, NULL); f = fopen (filename, "rb"); - if (!f) + if (!f) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Failed to open file '%s': %s"), + filename, g_strerror (errno)); return NULL; + } size = fread (&buffer, 1, sizeof (buffer), f); if (size == 0) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image file '%s' contains no data"), + filename); + fclose (f); return NULL; } - image_module = gdk_pixbuf_get_module (buffer, size); + image_module = gdk_pixbuf_get_module (buffer, size, filename, error); if (!image_module) { - g_warning ("Unable to find handler for file: %s", filename); fclose (f); return NULL; } if (image_module->module == NULL) - gdk_pixbuf_load_module (image_module); + if (!gdk_pixbuf_load_module (image_module, error)) { + fclose (f); + return NULL; + } if (image_module->load_animation == NULL) { GdkPixbuf *pixbuf; @@ -141,14 +159,35 @@ gdk_pixbuf_animation_new_from_file (const char *filename) /* Keep this logic in sync with gdk_pixbuf_new_from_file() */ if (image_module->load == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, + _("Don't know how to load the animation in file '%s'"), + filename); fclose (f); return NULL; } fseek (f, 0, SEEK_SET); - pixbuf = (* image_module->load) (f); + pixbuf = (* image_module->load) (f, error); fclose (f); + if (pixbuf == NULL && error != NULL && *error == NULL) { + /* I don't trust these crufty longjmp()'ing image libs + * to maintain proper error invariants, and I don't + * want user code to segfault as a result. We need to maintain + * the invariant that error gets set if NULL is returned. + */ + + g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", + image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Failed to load image '%s': reason not known, probably a corrupt image file"), + filename); + } + if (pixbuf == NULL) return NULL; @@ -167,7 +206,26 @@ gdk_pixbuf_animation_new_from_file (const char *filename) animation->height = gdk_pixbuf_get_height (pixbuf); } else { fseek (f, 0, SEEK_SET); - animation = (* image_module->load_animation) (f); + animation = (* image_module->load_animation) (f, error); + + if (animation == NULL && error != NULL && *error == NULL) { + /* I don't trust these crufty longjmp()'ing + * image libs to maintain proper error + * invariants, and I don't want user code to + * segfault as a result. We need to maintain + * the invariant that error gets set if NULL + * is returned. + */ + + g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", + image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Failed to load animation '%s': reason not known, probably a corrupt animation file"), + filename); + } + fclose (f); } diff --git a/gdk-pixbuf/gdk-pixbuf-data.c b/gdk-pixbuf/gdk-pixbuf-data.c index 94db20f37..a1b023240 100644 --- a/gdk-pixbuf/gdk-pixbuf-data.c +++ b/gdk-pixbuf/gdk-pixbuf-data.c @@ -23,6 +23,7 @@ #include <config.h> #include "gdk-pixbuf.h" #include "gdk-pixbuf-private.h" +#include "gdk-pixbuf-i18n.h" #include <stdlib.h> #include <string.h> @@ -106,7 +107,10 @@ read_bool (const guchar **p) } static GdkPixbuf* -read_raw_inline (const guchar *data, gboolean copy_pixels, int length) +read_raw_inline (const guchar *data, + gboolean copy_pixels, + int length, + GError **error) { GdkPixbuf *pixbuf; const guchar *p = data; @@ -116,6 +120,11 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) if (length >= 0 && length < 12) { /* Not enough buffer to hold the width/height/rowstride */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image data is partially missing")); + return NULL; } @@ -123,9 +132,14 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) width = read_int (&p); height = read_int (&p); - if (rowstride < width) + if (rowstride < width) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an incorrect pixel rowstride, perhaps the data was corrupted somehow.")); return NULL; /* bad data from untrusted source. */ - + } + /* rowstride >= width, so we can trust width */ length -= 12; @@ -133,37 +147,71 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) /* There's some better way like G_MAXINT/height > rowstride * but I'm not sure it works, so stick to this for now. */ - if (((double)height) * ((double)rowstride) > (double)G_MAXINT) + if (((double)height) * ((double)rowstride) > (double)G_MAXINT) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image size is impossibly large, perhaps the data was corrupted somehow")); + return NULL; /* overflow */ - + } + if (length >= 0 && length < (height * rowstride + 13)) { /* Not enough buffer to hold the remaining header * information plus the data. */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image data is partially missing, probably it was ocorrupted somehow.")); return NULL; } - + /* Read the remaining 13 bytes of header information */ has_alpha = read_bool (&p) != FALSE; colorspace = read_int (&p); n_channels = read_int (&p); bits_per_sample = read_int (&p); - - if (colorspace != GDK_COLORSPACE_RGB) + + if (colorspace != GDK_COLORSPACE_RGB) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an unknown colorspace code (%d), perhaps the image data was corrupted"), + colorspace); return NULL; + } - if (bits_per_sample != 8) + if (bits_per_sample != 8) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of bits per sample (%d), perhaps the image data was corrupted"), + bits_per_sample); return NULL; - - if (has_alpha && n_channels != 4) + } + + if (has_alpha && n_channels != 4) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of channels (%d), perhaps the image data was corrupted"), + n_channels); return NULL; - - if (!has_alpha && n_channels != 3) + } + + if (!has_alpha && n_channels != 3) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of channels (%d), perhaps the image data was corrupted"), + n_channels); return NULL; - + } + if (copy_pixels) { guchar *pixels; gint dest_rowstride; @@ -172,10 +220,19 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) pixbuf = gdk_pixbuf_new (colorspace, has_alpha, bits_per_sample, width, height); - + + if (pixbuf == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Not enough memory to store a %d by %d image; try exiting some applications to free memory."), + width, height); + return NULL; + } + pixels = gdk_pixbuf_get_pixels (pixbuf); dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - + for (row = 0; row < height; row++) { memcpy (pixels, p, rowstride); pixels += dest_rowstride; @@ -190,32 +247,42 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) rowstride, NULL, NULL); } - + return pixbuf; } /** * gdk_pixbuf_new_from_inline: - * @data: An inlined GdkPixbuf + * @inline_pixbuf: An inlined GdkPixbuf * @copy_pixels: whether to copy the pixels out of the inline data, or to use them in-place + * @length: length of the inline data + * @error: return location for error * * Create a #GdkPixbuf from a custom format invented to store pixbuf - * data in C program code. This library comes with a program called "make-inline-pixbuf" - * that can write out a variable definition containing an inlined pixbuf. - * This is useful if you want to ship a program with images, but - * don't want to depend on any external files. + * data in C program code. This library comes with a program called + * "make-inline-pixbuf" that can write out a variable definition + * containing an inlined pixbuf. This is useful if you want to ship a + * program with images, but don't want to depend on any external + * files. * * The inline data format contains the pixels in #GdkPixbuf's native * format. Since the inline pixbuf is read-only static data, you * don't need to copy it unless you intend to write to it. * + * If you create a pixbuf from const inline data compiled into your + * program, it's probably safe to ignore errors, since things will + * always succeed. For non-const inline data, you could get out of + * memory. For untrusted inline data located at runtime, you could + * have corrupt inline data in addition. + * * Return value: A newly-created #GdkPixbuf structure with a reference count of - * 1. + * 1, or NULL If error is set. **/ GdkPixbuf* gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, gboolean copy_pixels, - int length) + int length, + GError **error) { const guchar *p; GdkPixbuf *pixbuf; @@ -225,12 +292,20 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, /* not enough bytes to contain even the magic number * and format code. */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image contained no data.")); return NULL; } p = inline_pixbuf; if (read_int (&p) != GDK_PIXBUF_INLINE_MAGIC_NUMBER) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image isn't in the correct format (inline GdkPixbuf format)")); return NULL; } @@ -239,10 +314,15 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, switch (format) { case GDK_PIXBUF_INLINE_RAW: - pixbuf = read_raw_inline (p, copy_pixels, length - 8); + pixbuf = read_raw_inline (p, copy_pixels, length - 8, error); break; default: + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("This version of the software is unable to read images with type code %d"), + format); return NULL; } diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index d861c5611..02a517e43 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -275,8 +275,9 @@ get_libdir (void) /* actually load the image handler - gdk_pixbuf_get_module only get a */ /* reference to the module to load, it doesn't actually load it */ /* perhaps these actions should be combined in one function */ -void -gdk_pixbuf_load_module (GdkPixbufModule *image_module) +gboolean +gdk_pixbuf_load_module (GdkPixbufModule *image_module, + GError **error) { char *module_name; char *path; @@ -285,7 +286,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) gpointer save_sym; char *name; - g_return_if_fail (image_module->module == NULL); + g_return_val_if_fail (image_module->module == NULL, FALSE); name = image_module->module_name; @@ -304,10 +305,14 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) module = g_module_open (path, G_MODULE_BIND_LAZY); if (!module) { - g_warning ("Unable to load module: %s: %s", path, g_module_error ()); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Unable to load image-loading module: %s: %s"), + path, g_module_error ()); g_free (module_name); g_free (path); - return; + return FALSE; } g_free (path); } else { @@ -337,7 +342,9 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->load_animation = load_sym; if (pixbuf_module_symbol (module, name, "image_save", &save_sym)) - image_module->save = save_sym; + image_module->save = save_sym; + + return TRUE; } #else @@ -406,8 +413,9 @@ m_stop_load (tiff); m_load (xpm); m_load_xpm_data (xpm); -void -gdk_pixbuf_load_module (GdkPixbufModule *image_module) +gboolean +gdk_pixbuf_load_module (GdkPixbufModule *image_module, + GError **error) { image_module->module = (void *) 1; @@ -417,7 +425,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->load_increment = mname (png,load_increment); image_module->stop_load = mname (png,stop_load); image_module->save = mname (png,save); - return; + return TRUE; } if (strcmp (image_module->module_name, "bmp") == 0){ @@ -425,7 +433,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->begin_load = mname (bmp,begin_load); image_module->load_increment = mname (bmp,load_increment); image_module->stop_load = mname (bmp,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "wbmp") == 0){ @@ -433,7 +441,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->begin_load = mname (wbmp,begin_load); image_module->load_increment = mname (wbmp,load_increment); image_module->stop_load = mname (wbmp,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "gif") == 0){ @@ -442,7 +450,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->load_increment = mname (gif,load_increment); image_module->stop_load = mname (gif,stop_load); image_module->load_animation = mname (gif,load_animation); - return; + return TRUE; } if (strcmp (image_module->module_name, "ico") == 0){ @@ -450,7 +458,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->begin_load = mname (ico,begin_load); image_module->load_increment = mname (ico,load_increment); image_module->stop_load = mname (ico,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "jpeg") == 0){ @@ -459,34 +467,42 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->load_increment = mname (jpeg,load_increment); image_module->stop_load = mname (jpeg,stop_load); image_module->save = mname (jpeg,save); - return; + return TRUE; } if (strcmp (image_module->module_name, "pnm") == 0){ image_module->load = mname (pnm,load); image_module->begin_load = mname (pnm,begin_load); image_module->load_increment = mname (pnm,load_increment); image_module->stop_load = mname (pnm,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "ras") == 0){ image_module->load = mname (ras,load); image_module->begin_load = mname (ras,begin_load); image_module->load_increment = mname (ras,load_increment); image_module->stop_load = mname (ras,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "tiff") == 0){ image_module->load = mname (tiff,load); image_module->begin_load = mname (tiff,begin_load); image_module->load_increment = mname (tiff,load_increment); image_module->stop_load = mname (tiff,stop_load); - return; + return TRUE; } if (strcmp (image_module->module_name, "xpm") == 0){ image_module->load = mname (xpm,load); image_module->load_xpm_data = mname (xpm,load_xpm_data); - return; + return TRUE; } + + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Image type '%s' is not supported"), + image_module->module_name); + + return FALSE; } @@ -495,7 +511,8 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) GdkPixbufModule * -gdk_pixbuf_get_named_module (const char *name) +gdk_pixbuf_get_named_module (const char *name, + GError **error) { int i; @@ -504,11 +521,19 @@ gdk_pixbuf_get_named_module (const char *name) return &(file_formats[i]); } + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Image type '%s' is not supported"), + name); + return NULL; } GdkPixbufModule * -gdk_pixbuf_get_module (guchar *buffer, guint size) +gdk_pixbuf_get_module (guchar *buffer, guint size, + const gchar *filename, + GError **error) { int i; @@ -517,15 +542,30 @@ gdk_pixbuf_get_module (guchar *buffer, guint size) return &(file_formats[i]); } + if (filename) + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Couldn't recognize the image file format for file '%s'"), + filename); + else + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Unrecognized image file format")); + + return NULL; } /** * gdk_pixbuf_new_from_file: * @filename: Name of file to load. + * @error: Return location for an error * * Creates a new pixbuf by loading an image from a file. The file format is - * detected automatically. + * detected automatically. If NULL is returned, then @error will be set. + * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains. * * Return value: A newly-created pixbuf with a reference count of 1, or NULL if * any of several error conditions occurred: the file could not be opened, @@ -533,7 +573,8 @@ gdk_pixbuf_get_module (guchar *buffer, guint size) * allocate the image buffer, or the image file contained invalid data. **/ GdkPixbuf * -gdk_pixbuf_new_from_file (const char *filename) +gdk_pixbuf_new_from_file (const char *filename, + GError **error) { GdkPixbuf *pixbuf; int size; @@ -544,34 +585,82 @@ gdk_pixbuf_new_from_file (const char *filename) g_return_val_if_fail (filename != NULL, NULL); f = fopen (filename, "rb"); - if (!f) + if (!f) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Failed to open file '%s': %s"), + filename, g_strerror (errno)); return NULL; + } size = fread (&buffer, 1, sizeof (buffer), f); if (size == 0) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image file '%s' contains no data"), + filename); + fclose (f); return NULL; } - image_module = gdk_pixbuf_get_module (buffer, size); - if (!image_module) { - g_warning ("Unable to find handler for file: %s", filename); - fclose (f); - return NULL; - } + image_module = gdk_pixbuf_get_module (buffer, size, filename, error); + if (image_module == NULL) { + fclose (f); + return NULL; + } if (image_module->module == NULL) - gdk_pixbuf_load_module (image_module); + if (!gdk_pixbuf_load_module (image_module, error)) { + fclose (f); + return NULL; + } if (image_module->load == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, + _("Don't know how to load the image in file '%s'"), + filename); + fclose (f); return NULL; } fseek (f, 0, SEEK_SET); - pixbuf = (* image_module->load) (f); + pixbuf = (* image_module->load) (f, error); fclose (f); + if (pixbuf == NULL && error != NULL && *error == NULL) { + /* I don't trust these crufty longjmp()'ing image libs + * to maintain proper error invariants, and I don't + * want user code to segfault as a result. We need to maintain + * the invariant that error gets set if NULL is returned. + */ + + g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Failed to load image '%s': reason not known, probably a corrupt image file"), + filename); + + } else if (error != NULL && *error != NULL) { + + /* Add the filename to the error message */ + GError *e = *error; + gchar *old; + + old = e->message; + + e->message = g_strdup_printf (_("Failed to load image '%s': %s"), + filename, old); + + g_free (old); + } + return pixbuf; } @@ -591,7 +680,7 @@ gdk_pixbuf_new_from_xpm_data (const char **data) GdkPixbuf *pixbuf; if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) - gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX]); + gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX], NULL); if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) { g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data"); @@ -650,31 +739,26 @@ gdk_pixbuf_real_save (GdkPixbuf *pixbuf, gchar **values, GError **error) { - int i; GdkPixbufModule *image_module = NULL; + + image_module = gdk_pixbuf_get_named_module (type, error); + + if (image_module == NULL) + return FALSE; - for (i = 0; file_formats[i].module_name; i++) { - if (!strcmp (file_formats[i].module_name, type)) { - image_module = &(file_formats[i]); - break; - } - } - - if (!image_module) { + if (image_module->module == NULL) + if (!gdk_pixbuf_load_module (image_module, error)) + return FALSE; + + if (image_module->save == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNKNOWN_TYPE, - _("This build of gdk-pixbuf does not support saving the image format: %s"), type); + GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, + _("This build of gdk-pixbuf does not support saving the image format: %s"), + type); return FALSE; } - - if (image_module->module == NULL) - gdk_pixbuf_load_module (image_module); - - g_return_val_if_fail (image_module->save != NULL, FALSE); - - - + return (* image_module->save) (filehandle, pixbuf, keys, values, error); @@ -691,7 +775,7 @@ gdk_pixbuf_real_save (GdkPixbuf *pixbuf, * * Saves pixbuf to a file in @type, which is currently "jpeg" or * "png". If @error is set, FALSE will be returned. Possible errors include those - * from #GdkPixbufErrorType and those from #GFileErrorType. + * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain. * * The variable argument list should be NULL-terminated; if not empty, * it should contain pairs of strings that modify the save @@ -747,8 +831,7 @@ gdk_pixbuf_save (GdkPixbuf *pixbuf, * * Saves pixbuf to a file in @type, which is currently "jpeg" or "png". * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more - * details. Possible errors include those from #GdkPixbufErrorType and - * those from #GFileErrorType. + * details. * * Return value: whether an error was set **/ @@ -772,8 +855,8 @@ gdk_pixbuf_savev (GdkPixbuf *pixbuf, if (f == NULL) { g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_IO, + G_FILE_ERROR, + g_file_error_from_errno (errno), _("Failed to open '%s' for writing: %s"), filename, g_strerror (errno)); return FALSE; @@ -793,8 +876,8 @@ gdk_pixbuf_savev (GdkPixbuf *pixbuf, if (fclose (f) < 0) { g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_IO, + G_FILE_ERROR, + g_file_error_from_errno (errno), _("Failed to close '%s' while writing image, all data may not have been saved: %s"), filename, g_strerror (errno)); return FALSE; diff --git a/gdk-pixbuf/gdk-pixbuf-io.h b/gdk-pixbuf/gdk-pixbuf-io.h index 3ce4d2f73..60046b8e7 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.h +++ b/gdk-pixbuf/gdk-pixbuf-io.h @@ -55,7 +55,8 @@ struct _GdkPixbufModule { char *module_name; gboolean (* format_check) (guchar *buffer, int size); GModule *module; - GdkPixbuf *(* load) (FILE *f); + GdkPixbuf *(* load) (FILE *f, + GError **error); GdkPixbuf *(* load_xpm_data) (const char **data); /* Incremental loading */ @@ -64,26 +65,33 @@ struct _GdkPixbufModule { ModuleUpdatedNotifyFunc update_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data); + gpointer user_data, + GError **error); void (* stop_load) (gpointer context); gboolean (* load_increment) (gpointer context, const guchar *buf, - guint size); + guint size, + GError **error); /* Animation loading */ - GdkPixbufAnimation *(* load_animation) (FILE *f); + GdkPixbufAnimation *(* load_animation) (FILE *f, + GError **error); gboolean (* save) (FILE *f, GdkPixbuf *pixbuf, gchar **param_keys, gchar **param_values, - GError **err); + GError **error); }; -GdkPixbufModule *gdk_pixbuf_get_module (guchar *buffer, guint size); -GdkPixbufModule *gdk_pixbuf_get_named_module (const char *name); -void gdk_pixbuf_load_module (GdkPixbufModule *image_module); +GdkPixbufModule *gdk_pixbuf_get_module (guchar *buffer, guint size, + const gchar *filename, + GError **error); +GdkPixbufModule *gdk_pixbuf_get_named_module (const char *name, + GError **error); +gboolean gdk_pixbuf_load_module (GdkPixbufModule *image_module, + GError **error); diff --git a/gdk-pixbuf/gdk-pixbuf-loader.c b/gdk-pixbuf/gdk-pixbuf-loader.c index 5f4320f22..42aec5d4c 100644 --- a/gdk-pixbuf/gdk-pixbuf-loader.c +++ b/gdk-pixbuf/gdk-pixbuf-loader.c @@ -338,20 +338,32 @@ gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf, } static gint -gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type) +gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, + const char *image_type, + GError **error) { GdkPixbufLoaderPrivate *priv = loader->private; - if(image_type) - priv->image_module = gdk_pixbuf_get_named_module (image_type); + if (image_type) + { + priv->image_module = gdk_pixbuf_get_named_module (image_type, + error); + } else - priv->image_module = gdk_pixbuf_get_module (priv->header_buf, priv->header_buf_offset); + { + g_return_val_if_fail (priv->header_buf_offset > 0, 0); + priv->image_module = gdk_pixbuf_get_module (priv->header_buf, + priv->header_buf_offset, + NULL, + error); + } if (priv->image_module == NULL) return 0; if (priv->image_module->module == NULL) - gdk_pixbuf_load_module (priv->image_module); + if (!gdk_pixbuf_load_module (priv->image_module, error)) + return 0; if (priv->image_module->module == NULL) return 0; @@ -360,8 +372,12 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type) (priv->image_module->stop_load == NULL) || (priv->image_module->load_increment == NULL)) { - g_warning (G_STRLOC ": module %s does not support incremental loading.\n", - priv->image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, + _("Incremental loading of image type '%s' is not supported"), + image_type); + return 0; } @@ -369,16 +385,33 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type) gdk_pixbuf_loader_update, gdk_pixbuf_loader_frame_done, gdk_pixbuf_loader_animation_done, - loader); + loader, + error); if (priv->context == NULL) { - g_warning (G_STRLOC ": Failed to begin progressive load"); + /* Defense against broken loaders; DO NOT take this as a GError + * example + */ + if (error && *error == NULL) + { + g_warning ("Bug! loader '%s' didn't set an error on failure", + priv->image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Internal error: Image loader module '%s'" + " failed to begin loading an image, but didn't" + " give a reason for the failure"), + priv->image_module->module_name); + + } + return 0; } if (priv->header_buf_offset - && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset)) + && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error)) return priv->header_buf_offset; return 0; @@ -387,7 +420,8 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type) static int gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, const guchar *buf, - gsize count) + gsize count, + GError **error) { gint n_bytes; GdkPixbufLoaderPrivate *priv = loader->private; @@ -399,7 +433,7 @@ gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, if (priv->header_buf_offset >= LOADER_HEADER_SIZE) { - if (gdk_pixbuf_loader_load_module (loader, NULL) == 0) + if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0) return 0; } @@ -411,11 +445,14 @@ gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, * @loader: A pixbuf loader. * @buf: Pointer to image data. * @count: Length of the @buf buffer in bytes. + * @error: return location for errors * - * This will cause a pixbuf loader to parse the next @count bytes of an image. - * It will return TRUE if the data was loaded successfully, and FALSE if an - * error occurred. In the latter case, the loader will be closed, and will not - * accept further writes. + * This will cause a pixbuf loader to parse the next @count bytes of + * an image. It will return TRUE if the data was loaded successfully, + * and FALSE if an error occurred. In the latter case, the loader + * will be closed, and will not accept further writes. If FALSE is + * returned, @error will be set to an error from the #GDK_PIXBUF_ERROR + * domain. * * Return value: #TRUE if the write was successful, or #FALSE if the loader * cannot parse the buffer. @@ -423,7 +460,8 @@ gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, gboolean gdk_pixbuf_loader_write (GdkPixbufLoader *loader, const guchar *buf, - gsize count) + gsize count, + GError **error) { GdkPixbufLoaderPrivate *priv; @@ -442,7 +480,7 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader, { gint eaten; - eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count); + eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error); if (eaten <= 0) return FALSE; @@ -451,8 +489,27 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader, } if (count > 0 && priv->image_module->load_increment) - return priv->image_module->load_increment (priv->context, buf, count); - + { + gboolean retval; + retval = priv->image_module->load_increment (priv->context, buf, count, + error); + if (!retval && error && *error == NULL) + { + /* Fix up busted image loader */ + g_warning ("Bug! loader '%s' didn't set an error on failure", + priv->image_module->module_name); + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Internal error: Image loader module '%s'" + " failed to begin loading an image, but didn't" + " give a reason for the failure"), + priv->image_module->module_name); + } + + return retval; + } + return TRUE; } @@ -477,13 +534,22 @@ gdk_pixbuf_loader_new (void) * Return value: A newly-created pixbuf loader. **/ GdkPixbufLoader * -gdk_pixbuf_loader_new_with_type (const char *image_type) +gdk_pixbuf_loader_new_with_type (const char *image_type, + GError **error) { GdkPixbufLoader *retval; - + GError *tmp; + retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL); - gdk_pixbuf_loader_load_module(retval, image_type); + tmp = NULL; + gdk_pixbuf_loader_load_module(retval, image_type, &tmp); + if (tmp != NULL) + { + g_propagate_error (error, tmp); + g_object_unref (G_OBJECT (retval)); + return NULL; + } return retval; } @@ -579,7 +645,7 @@ gdk_pixbuf_loader_close (GdkPixbufLoader *loader) /* We have less the 128 bytes in the image. Flush it, and keep going. */ if (priv->image_module == NULL) - gdk_pixbuf_loader_load_module (loader, NULL); + gdk_pixbuf_loader_load_module (loader, NULL, NULL); if (priv->image_module && priv->image_module->stop_load) priv->image_module->stop_load (priv->context); diff --git a/gdk-pixbuf/gdk-pixbuf-loader.h b/gdk-pixbuf/gdk-pixbuf-loader.h index c3d6d6f95..402b69725 100644 --- a/gdk-pixbuf/gdk-pixbuf-loader.h +++ b/gdk-pixbuf/gdk-pixbuf-loader.h @@ -72,10 +72,12 @@ struct _GdkPixbufLoaderClass GtkType gdk_pixbuf_loader_get_type (void) G_GNUC_CONST; GdkPixbufLoader * gdk_pixbuf_loader_new (void); -GdkPixbufLoader * gdk_pixbuf_loader_new_with_type (const char *image_type); +GdkPixbufLoader * gdk_pixbuf_loader_new_with_type (const char *image_type, + GError **error); gboolean gdk_pixbuf_loader_write (GdkPixbufLoader *loader, const guchar *buf, - gsize count); + gsize count, + GError **error); GdkPixbuf * gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader); GdkPixbufAnimation * gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader); void gdk_pixbuf_loader_close (GdkPixbufLoader *loader); diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c index 36fc29750..bee4fb5bb 100644 --- a/gdk-pixbuf/gdk-pixbuf-util.c +++ b/gdk-pixbuf/gdk-pixbuf-util.c @@ -23,6 +23,7 @@ #include <config.h> #include "gdk-pixbuf-private.h" +#include <string.h> diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h index a61dc9366..e87737277 100644 --- a/gdk-pixbuf/gdk-pixbuf.h +++ b/gdk-pixbuf/gdk-pixbuf.h @@ -39,8 +39,8 @@ extern "C" { /* Alpha compositing mode */ typedef enum { - GDK_PIXBUF_ALPHA_BILEVEL, - GDK_PIXBUF_ALPHA_FULL + GDK_PIXBUF_ALPHA_BILEVEL, + GDK_PIXBUF_ALPHA_FULL } GdkPixbufAlphaMode; /* Color spaces; right now only RGB is supported. @@ -71,14 +71,18 @@ typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data); #define GDK_PIXBUF_ERROR gdk_pixbuf_error_quark () typedef enum { - /* some kind of failure reading or writing files */ - GDK_PIXBUF_ERROR_IO, + /* image data hosed */ + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + /* no mem to load image */ + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, /* bad option value passed to save routine */ GDK_PIXBUF_ERROR_BAD_OPTION_VALUE, /* unsupported image type (sort of an ENOSYS) */ GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + /* unsupported operation (load, save) for image type */ + GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, GDK_PIXBUF_ERROR_FAILED -} GdkPixbufErrorType; +} GdkPixbufError; GQuark gdk_pixbuf_error_quark () G_GNUC_CONST; @@ -114,7 +118,8 @@ GdkPixbuf *gdk_pixbuf_copy (const GdkPixbuf *pixbuf); /* Simple loading */ -GdkPixbuf *gdk_pixbuf_new_from_file (const char *filename); +GdkPixbuf *gdk_pixbuf_new_from_file (const char *filename, + GError **error); GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data, GdkColorspace colorspace, @@ -130,23 +135,24 @@ GdkPixbuf *gdk_pixbuf_new_from_xpm_data (const char **data); /* Read an inline pixbuf */ GdkPixbuf *gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, gboolean copy_pixels, - int length); + int length, + GError **error); /* Saving */ gboolean gdk_pixbuf_save (GdkPixbuf *pixbuf, const char *filename, - const char *format, - GError **err, + const char *type, + GError **error, ...); gboolean gdk_pixbuf_savev (GdkPixbuf *pixbuf, const char *filename, - const char *format, + const char *type, char **option_keys, char **option_values, - GError **err); + GError **error); /* Adding an alpha channel */ GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color, @@ -248,7 +254,8 @@ typedef enum { GType gdk_pixbuf_animation_get_type (void) G_GNUC_CONST; -GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename); +GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename, + GError **error); GdkPixbufAnimation *gdk_pixbuf_animation_ref (GdkPixbufAnimation *animation); void gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation); diff --git a/gdk-pixbuf/gnome-canvas-pixbuf.c b/gdk-pixbuf/gnome-canvas-pixbuf.c deleted file mode 100644 index a6372b997..000000000 --- a/gdk-pixbuf/gnome-canvas-pixbuf.c +++ /dev/null @@ -1,841 +0,0 @@ -/* GNOME libraries - GdkPixbuf item for the GNOME canvas - * - * Copyright (C) 1999 The Free Software Foundation - * - * Author: Federico Mena-Quintero <federico@gimp.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <config.h> -#include <math.h> -#include <libgnomeui/gnome-canvas.h> -#include <libgnomeui/gnome-canvas-util.h> -#include <libart_lgpl/art_rgb_affine.h> -#include <libart_lgpl/art_rgb_rgba_affine.h> -#include "gdk-pixbuf-private.h" -#include "gnome-canvas-pixbuf.h" - - - -/* Private part of the GnomeCanvasPixbuf structure */ -typedef struct { - /* Our gdk-pixbuf */ - GdkPixbuf *pixbuf; - - /* Width value */ - double width; - - /* Height value */ - double height; - - /* X translation */ - double x; - - /* Y translation */ - double y; - - /* Whether dimensions are set and whether they are in pixels or units */ - guint width_set : 1; - guint width_in_pixels : 1; - guint height_set : 1; - guint height_in_pixels : 1; - guint x_in_pixels : 1; - guint y_in_pixels : 1; - - /* Whether the pixbuf has changed */ - guint need_pixbuf_update : 1; - - /* Whether the transformation or size have changed */ - guint need_xform_update : 1; -} PixbufPrivate; - - - -/* Object argument IDs */ -enum { - ARG_0, - ARG_PIXBUF, - ARG_WIDTH, - ARG_WIDTH_SET, - ARG_WIDTH_IN_PIXELS, - ARG_HEIGHT, - ARG_HEIGHT_SET, - ARG_HEIGHT_IN_PIXELS, - ARG_X, - ARG_X_IN_PIXELS, - ARG_Y, - ARG_Y_IN_PIXELS -}; - -static void gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class); -static void gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *cpb); -static void gnome_canvas_pixbuf_destroy (GtkObject *object); -static void gnome_canvas_pixbuf_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void gnome_canvas_pixbuf_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); - -static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine, - ArtSVP *clip_path, int flags); -static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, - int x, int y, int width, int height); -static void gnome_canvas_pixbuf_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf); -static double gnome_canvas_pixbuf_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item); -static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, - double *x1, double *y1, double *x2, double *y2); - -static GnomeCanvasItemClass *parent_class; - - - -/** - * gnome_canvas_pixbuf_get_type: - * @void: - * - * Registers the #GnomeCanvasPixbuf class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #GnomeCanvasPixbuf class. - **/ -GtkType -gnome_canvas_pixbuf_get_type (void) -{ - static GtkType canvas_pixbuf_type = 0; - - if (!canvas_pixbuf_type) { - static const GtkTypeInfo canvas_pixbuf_info = { - "GnomeCanvasPixbuf", - sizeof (GnomeCanvasPixbuf), - sizeof (GnomeCanvasPixbufClass), - (GtkClassInitFunc) gnome_canvas_pixbuf_class_init, - (GtkObjectInitFunc) gnome_canvas_pixbuf_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - canvas_pixbuf_type = gtk_type_unique (gnome_canvas_item_get_type (), - &canvas_pixbuf_info); - } - - return canvas_pixbuf_type; -} - -/* Class initialization function for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class) -{ - GtkObjectClass *object_class; - GnomeCanvasItemClass *item_class; - - object_class = (GtkObjectClass *) class; - item_class = (GnomeCanvasItemClass *) class; - - parent_class = gtk_type_class (gnome_canvas_item_get_type ()); - - gtk_object_add_arg_type ("GnomeCanvasPixbuf::pixbuf", - GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::width", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::width_set", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_WIDTH_SET); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::width_in_pixels", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_WIDTH_IN_PIXELS); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::height", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::height_set", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HEIGHT_SET); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::height_in_pixels", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HEIGHT_IN_PIXELS); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::x", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::x_in_pixels", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_X_IN_PIXELS); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::y", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); - gtk_object_add_arg_type ("GnomeCanvasPixbuf::y_in_pixels", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_Y_IN_PIXELS); - - - object_class->destroy = gnome_canvas_pixbuf_destroy; - object_class->set_arg = gnome_canvas_pixbuf_set_arg; - object_class->get_arg = gnome_canvas_pixbuf_get_arg; - - item_class->update = gnome_canvas_pixbuf_update; - item_class->draw = gnome_canvas_pixbuf_draw; - item_class->render = gnome_canvas_pixbuf_render; - item_class->point = gnome_canvas_pixbuf_point; - item_class->bounds = gnome_canvas_pixbuf_bounds; -} - -/* Object initialization function for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp) -{ - PixbufPrivate *priv; - - priv = g_new0 (PixbufPrivate, 1); - gcp->priv = priv; - - priv->width = 0.0; - priv->height = 0.0; - priv->x = 0.0; - priv->y = 0.0; -} - -/* Destroy handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_destroy (GtkObject *object) -{ - GnomeCanvasItem *item; - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object)); - - item = GNOME_CANVAS_ITEM (object); - gcp = (GNOME_CANVAS_PIXBUF (object)); - priv = gcp->priv; - - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - - if (priv->pixbuf) - gdk_pixbuf_unref (priv->pixbuf); - - g_free (priv); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - - - -/* Set_arg handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) -{ - GnomeCanvasItem *item; - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - GdkPixbuf *pixbuf; - double val; - - item = GNOME_CANVAS_ITEM (object); - gcp = GNOME_CANVAS_PIXBUF (object); - priv = gcp->priv; - - switch (arg_id) { - case ARG_PIXBUF: - pixbuf = GTK_VALUE_POINTER (*arg); - if (pixbuf != priv->pixbuf) { - if (pixbuf) { - g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); - g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); - g_return_if_fail (pixbuf->bits_per_sample == 8); - - gdk_pixbuf_ref (pixbuf); - } - - if (priv->pixbuf) - gdk_pixbuf_unref (priv->pixbuf); - - priv->pixbuf = pixbuf; - } - - priv->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_WIDTH: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - priv->width = val; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_WIDTH_SET: - priv->width_set = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_WIDTH_IN_PIXELS: - priv->width_in_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_HEIGHT: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - priv->height = val; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_HEIGHT_SET: - priv->height_set = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_HEIGHT_IN_PIXELS: - priv->height_in_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_X: - priv->x = GTK_VALUE_DOUBLE (*arg); - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_X_IN_PIXELS: - priv->x_in_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_Y: - priv->y = GTK_VALUE_DOUBLE (*arg); - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_Y_IN_PIXELS: - priv->y_in_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE; - priv->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - default: - break; - } -} - -/* Get_arg handler for the pixbuf canvasi item */ -static void -gnome_canvas_pixbuf_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - - gcp = GNOME_CANVAS_PIXBUF (object); - priv = gcp->priv; - - switch (arg_id) { - case ARG_PIXBUF: - GTK_VALUE_POINTER (*arg) = priv->pixbuf; - break; - - case ARG_WIDTH: - GTK_VALUE_DOUBLE (*arg) = priv->width; - break; - - case ARG_WIDTH_SET: - GTK_VALUE_BOOL (*arg) = priv->width_set; - break; - - case ARG_WIDTH_IN_PIXELS: - GTK_VALUE_BOOL (*arg) = priv->width_in_pixels; - break; - - case ARG_HEIGHT: - GTK_VALUE_DOUBLE (*arg) = priv->height; - break; - - case ARG_HEIGHT_SET: - GTK_VALUE_BOOL (*arg) = priv->height_set; - break; - - case ARG_HEIGHT_IN_PIXELS: - GTK_VALUE_BOOL (*arg) = priv->height_in_pixels; - break; - - case ARG_X: - GTK_VALUE_DOUBLE (*arg) = priv->x; - break; - - case ARG_X_IN_PIXELS: - GTK_VALUE_BOOL (*arg) = priv->x_in_pixels; - break; - - case ARG_Y: - GTK_VALUE_DOUBLE (*arg) = priv->y; - break; - - case ARG_Y_IN_PIXELS: - GTK_VALUE_BOOL (*arg) = priv->y_in_pixels; - break; - - default: - arg->type = GTK_TYPE_INVALID; - break; - } -} - - - -/* Bounds and utilities */ - -/* Computes the amount by which the unit horizontal and vertical vectors will be - * scaled by an affine transformation. - */ -static void -compute_xform_scaling (double *affine, ArtPoint *i_c, ArtPoint *j_c) -{ - ArtPoint orig, orig_c; - ArtPoint i, j; - - /* Origin */ - - orig.x = 0.0; - orig.y = 0.0; - art_affine_point (&orig_c, &orig, affine); - - /* Horizontal and vertical vectors */ - - i.x = 1.0; - i.y = 0.0; - art_affine_point (i_c, &i, affine); - i_c->x -= orig_c.x; - i_c->y -= orig_c.y; - - j.x = 0.0; - j.y = 1.0; - art_affine_point (j_c, &j, affine); - j_c->x -= orig_c.x; - j_c->y -= orig_c.y; -} - -/* computes the addtional resolution dependent affine needed to - * fit the image within its viewport defined by x,y,width and height - * args - */ -static void -compute_viewport_affine (GnomeCanvasPixbuf *gcp, double *viewport_affine, double *i2c) -{ - PixbufPrivate *priv; - ArtPoint i_c, j_c; - double i_len, j_len; - double si_len, sj_len; - double ti_len, tj_len; - double scale[6], translate[6]; - double w, h; - - priv = gcp->priv; - - /* Compute scaling vectors and required width/height */ - - compute_xform_scaling (i2c, &i_c, &j_c); - - i_len = sqrt (i_c.x * i_c.x + i_c.y * i_c.y); - j_len = sqrt (j_c.x * j_c.x + j_c.y * j_c.y); - - if (priv->width_set) - w = priv->width; - else - w = priv->pixbuf->width; - - if (priv->height_set) - h = priv->height; - else - h = priv->pixbuf->height; - - /* Convert i_len and j_len into scaling factors */ - - if (priv->width_in_pixels) { - if (i_len > GNOME_CANVAS_EPSILON) - si_len = 1.0 / i_len; - else - si_len = 0.0; - } else - si_len = 1.0; - - si_len *= w / priv->pixbuf->width; - - if (priv->height_in_pixels) { - if (j_len > GNOME_CANVAS_EPSILON) - sj_len = 1.0 / j_len; - else - sj_len = 0.0; - } else - sj_len = 1.0; - - sj_len *= h / priv->pixbuf->height; - - /* Calculate translation offsets */ - - if (priv->x_in_pixels) { - if (i_len > GNOME_CANVAS_EPSILON) - ti_len = 1.0 / i_len; - else - ti_len = 0.0; - } else - ti_len = 1.0; - - ti_len *= priv->x; - - if (priv->y_in_pixels) { - if (j_len > GNOME_CANVAS_EPSILON) - tj_len = 1.0 / j_len; - else - tj_len = 0.0; - } else - tj_len = 1.0; - - tj_len *= priv->y; - - /* Compute the final affine */ - - art_affine_scale (scale, si_len, sj_len); - art_affine_translate (translate, ti_len, tj_len); - art_affine_multiply (viewport_affine, scale, translate); -} - -/* Computes the affine transformation with which the pixbuf needs to be - * transformed to render it on the canvas. This is not the same as the - * item_to_canvas transformation because we may need to scale the pixbuf - * by some other amount. - */ -static void -compute_render_affine (GnomeCanvasPixbuf *gcp, double *render_affine, double *i2c) -{ - double viewport_affine[6]; - - compute_viewport_affine (gcp, viewport_affine, i2c); - art_affine_multiply (render_affine, viewport_affine, i2c); -} - -/* Recomputes the bounding box of a pixbuf canvas item. The horizontal and - * vertical dimensions may be specified in units or pixels, separately, so we - * have to compute the components individually for each dimension. - */ -static void -recompute_bounding_box (GnomeCanvasPixbuf *gcp) -{ - GnomeCanvasItem *item; - PixbufPrivate *priv; - double i2c[6], render_affine[6]; - ArtDRect rect; - - item = GNOME_CANVAS_ITEM (gcp); - priv = gcp->priv; - - if (!priv->pixbuf) { - item->x1 = item->y1 = item->x2 = item->y2 = 0.0; - return; - } - - rect.x0 = 0.0; - rect.x1 = priv->pixbuf->width; - - rect.y0 = 0.0; - rect.y1 = priv->pixbuf->height; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (gcp, render_affine, i2c); - art_drect_affine_transform (&rect, &rect, render_affine); - - item->x1 = floor (rect.x0); - item->y1 = floor (rect.y0); - item->x2 = ceil (rect.x1); - item->y2 = ceil (rect.y1); -} - - - -/* Update sequence */ - -/* Update handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - - gcp = GNOME_CANVAS_PIXBUF (item); - priv = gcp->priv; - - if (parent_class->update) - (* parent_class->update) (item, affine, clip_path, flags); - - if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE) - || priv->need_pixbuf_update - || priv->need_xform_update) - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - - /* If we need a pixbuf update, or if the item changed visibility to - * shown, recompute the bounding box. - */ - if (priv->need_pixbuf_update - || priv->need_xform_update - || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && (GTK_OBJECT_FLAGS (gcp) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE)) { - recompute_bounding_box (gcp); - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - priv->need_pixbuf_update = FALSE; - priv->need_xform_update = FALSE; - } -} - - - -/* Rendering */ - -/* This is private to libart, but we need it. Sigh. */ -extern void art_rgb_affine_run (int *p_x0, int *p_x1, int y, int src_width, int src_height, - const double affine[6]); - -/* Fills the specified buffer with the transformed version of a pixbuf */ -static void -transform_pixbuf (guchar *dest, int x, int y, int width, int height, int rowstride, - GdkPixbuf *pixbuf, double *affine) -{ - int xx, yy; - double inv[6]; - guchar *src, *d; - ArtPoint src_p, dest_p; - int run_x1, run_x2; - int src_x, src_y; - int i; - - art_affine_invert (inv, affine); - - for (yy = 0; yy < height; yy++) { - dest_p.y = y + yy + 0.5; - - run_x1 = x; - run_x2 = x + width; - art_rgb_affine_run (&run_x1, &run_x2, yy + y, - pixbuf->width, pixbuf->height, - inv); - - d = dest + yy * rowstride + (run_x1 - x) * 4; - - for (xx = run_x1; xx < run_x2; xx++) { - dest_p.x = xx + 0.5; - art_affine_point (&src_p, &dest_p, inv); - src_x = floor (src_p.x); - src_y = floor (src_p.y); - - src = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * pixbuf->n_channels; - - for (i = 0; i < pixbuf->n_channels; i++) - *d++ = *src++; - - if (!pixbuf->has_alpha) - *d++ = 255; /* opaque */ - } - } -} - -/* Draw handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, - int x, int y, int width, int height) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - double i2c[6], render_affine[6]; - guchar *buf; - GdkPixbuf *pixbuf; - ArtIRect p_rect, a_rect, d_rect; - int w, h; - - gcp = GNOME_CANVAS_PIXBUF (item); - priv = gcp->priv; - - if (!priv->pixbuf) - return; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (gcp, render_affine, i2c); - - /* Compute the area we need to repaint */ - - p_rect.x0 = item->x1; - p_rect.y0 = item->y1; - p_rect.x1 = item->x2; - p_rect.y1 = item->y2; - - a_rect.x0 = x; - a_rect.y0 = y; - a_rect.x1 = x + width; - a_rect.y1 = y + height; - - art_irect_intersect (&d_rect, &p_rect, &a_rect); - if (art_irect_empty (&d_rect)) - return; - - /* Create a temporary buffer and transform the pixbuf there */ - - w = d_rect.x1 - d_rect.x0; - h = d_rect.y1 - d_rect.y0; - - buf = g_new0 (guchar, w * h * 4); - transform_pixbuf (buf, - d_rect.x0, d_rect.y0, - w, h, - w * 4, - priv->pixbuf, render_affine); - - pixbuf = gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, TRUE, 8, w, h, w * 4, NULL, NULL); - - gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawable, - 0, 0, - d_rect.x0 - x, d_rect.y0 - y, - w, h, - GDK_PIXBUF_ALPHA_BILEVEL, - 128, - GDK_RGB_DITHER_MAX, - d_rect.x0, d_rect.y0); - - gdk_pixbuf_unref (pixbuf); - g_free (buf); -} - -/* Render handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - double i2c[6], render_affine[6]; - - gcp = GNOME_CANVAS_PIXBUF (item); - priv = gcp->priv; - - if (!priv->pixbuf) - return; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (gcp, render_affine, i2c); - gnome_canvas_buf_ensure_buf (buf); - - if (priv->pixbuf->has_alpha) - art_rgb_rgba_affine (buf->buf, - buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, - buf->buf_rowstride, - priv->pixbuf->pixels, - priv->pixbuf->width, priv->pixbuf->height, - priv->pixbuf->rowstride, - render_affine, - ART_FILTER_NEAREST, - NULL); - else - art_rgb_affine (buf->buf, - buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, - buf->buf_rowstride, - priv->pixbuf->pixels, - priv->pixbuf->width, priv->pixbuf->height, - priv->pixbuf->rowstride, - render_affine, - ART_FILTER_NEAREST, - NULL); - - buf->is_bg = FALSE; -} - - - -/* Point handler for the pixbuf canvas item */ -static double -gnome_canvas_pixbuf_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - double i2c[6], render_affine[6], inv[6]; - ArtPoint c, p; - int px, py; - double no_hit; - guchar *src; - - gcp = GNOME_CANVAS_PIXBUF (item); - priv = gcp->priv; - - *actual_item = item; - - no_hit = item->canvas->pixels_per_unit * 2 + 10; - - if (!priv->pixbuf) - return no_hit; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (gcp, render_affine, i2c); - art_affine_invert (inv, render_affine); - - c.x = cx; - c.y = cy; - art_affine_point (&p, &c, inv); - px = p.x; - py = p.y; - - if (px < 0 || px >= priv->pixbuf->width || py < 0 || py >= priv->pixbuf->height) - return no_hit; - - if (!priv->pixbuf->has_alpha) - return 0.0; - - src = priv->pixbuf->pixels + py * priv->pixbuf->rowstride + px * priv->pixbuf->n_channels; - - if (src[3] < 128) - return no_hit; - else - return 0.0; -} - - - -/* Bounds handler for the pixbuf canvas item */ -static void -gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) -{ - GnomeCanvasPixbuf *gcp; - PixbufPrivate *priv; - double i2c[6], viewport_affine[6]; - ArtDRect rect; - - gcp = GNOME_CANVAS_PIXBUF (item); - priv = gcp->priv; - - if (!priv->pixbuf) { - *x1 = *y1 = *x2 = *y2 = 0.0; - return; - } - - rect.x0 = 0.0; - rect.x1 = priv->pixbuf->width; - - rect.y0 = 0.0; - rect.y1 = priv->pixbuf->height; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_viewport_affine (gcp, viewport_affine, i2c); - art_drect_affine_transform (&rect, &rect, viewport_affine); - - *x1 = rect.x0; - *y1 = rect.y0; - *x2 = rect.x1; - *y2 = rect.y1; -} diff --git a/gdk-pixbuf/gnome-canvas-pixbuf.h b/gdk-pixbuf/gnome-canvas-pixbuf.h deleted file mode 100644 index 822f5899f..000000000 --- a/gdk-pixbuf/gnome-canvas-pixbuf.h +++ /dev/null @@ -1,64 +0,0 @@ -/* GNOME libraries - GdkPixbuf item for the GNOME canvas - * - * Copyright (C) 1999 The Free Software Foundation - * - * Author: Federico Mena-Quintero <federico@gimp.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef GNOME_CANVAS_PIXBUF_H -#define GNOME_CANVAS_PIXBUF_H - -#include <libgnome/gnome-defs.h> -#include <libgnomeui/gnome-canvas.h> - -BEGIN_GNOME_DECLS - - - -#define GNOME_TYPE_CANVAS_PIXBUF (gnome_canvas_pixbuf_get_type ()) -#define GNOME_CANVAS_PIXBUF(obj) (GTK_CHECK_CAST ((obj), \ - GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbuf)) -#define GNOME_CANVAS_PIXBUF_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \ - GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbufClass)) -#define GNOME_IS_CANVAS_PIXBUF(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_PIXBUF)) -#define GNOME_IS_CANVAS_PIXBUF_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), \ - GNOME_TYPE_CANVAS_PIXBUF)) - - -typedef struct _GnomeCanvasPixbuf GnomeCanvasPixbuf; -typedef struct _GnomeCanvasPixbufClass GnomeCanvasPixbufClass; - -struct _GnomeCanvasPixbuf { - GnomeCanvasItem item; - - /* Private data */ - gpointer priv; -}; - -struct _GnomeCanvasPixbufClass { - GnomeCanvasItemClass parent_class; -}; - - -GtkType gnome_canvas_pixbuf_get_type (void) G_GNUC_CONST; - - - -END_GNOME_DECLS - -#endif diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c index 18ef7bc90..b090957be 100644 --- a/gdk-pixbuf/io-bmp.c +++ b/gdk-pixbuf/io-bmp.c @@ -176,17 +176,19 @@ gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc - anim_done_func, gpointer user_data); + anim_done_func, gpointer user_data, + GError **error); void gdk_pixbuf__bmp_image_stop_load(gpointer data); gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf, - guint size); + guint size, + GError **error); /* Shared library entry point --> This should be removed when generic_image_load enters gdk-pixbuf-io. */ -GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f) +GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error) { guchar membuf[4096]; size_t length; @@ -195,15 +197,22 @@ GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f) GdkPixbuf *pb; State = - gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL); + gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL, + error); + if (State == NULL) + return NULL; + while (feof(f) == 0) { length = fread(membuf, 1, 4096, f); if (length > 0) - (void) - gdk_pixbuf__bmp_image_load_increment(State, - membuf, - length); + if (!gdk_pixbuf__bmp_image_load_increment(State, + membuf, + length, + error)) { + gdk_pixbuf__bmp_image_stop_load (State); + return NULL; + } } if (State->pixbuf != NULL) @@ -309,7 +318,8 @@ gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc - anim_done_func, gpointer user_data) + anim_done_func, gpointer user_data, + GError **error) { struct bmp_progressive_state *context; @@ -695,8 +705,10 @@ void DoCompressedByte(struct bmp_progressive_state *context, guchar ** buf, * * append image data onto inrecrementally built output image */ -gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf, - guint size) +gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, + guchar * buf, + guint size, + GError **error) { struct bmp_progressive_state *context = (struct bmp_progressive_state *) data; diff --git a/gdk-pixbuf/io-gif.c b/gdk-pixbuf/io-gif.c index 681e915da..e61f41fb8 100644 --- a/gdk-pixbuf/io-gif.c +++ b/gdk-pixbuf/io-gif.c @@ -180,6 +180,9 @@ struct _GifContext gint draw_xpos; gint draw_ypos; gint draw_pass; + + /* error pointer */ + GError **error; }; static int GetDataBlock (GifContext *, unsigned char *); @@ -204,7 +207,7 @@ gif_read (GifContext *context, guchar *buffer, size_t len) count += len; g_print ("Fsize :%d\tcount :%d\t", len, count); #endif - retval = (fread(buffer, len, 1, context->file) != 0); + retval = (fread(buffer, len, 1, context->file) != 0); #ifdef IO_GIFDEBUG if (len < 100) { for (i = 0; i < len; i++) @@ -212,6 +215,7 @@ gif_read (GifContext *context, guchar *buffer, size_t len) } g_print ("\n"); #endif + return retval; } else { #ifdef IO_GIFDEBUG @@ -416,10 +420,21 @@ gif_lzw_fill_buffer (GifContext *context) if (context->code_done) { if (context->code_curbit >= context->code_lastbit) { - g_message ("GIF: ran off the end of by bits\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("GIF file was missing some data (perhaps it was truncated somehow?)")); + return -2; } - g_message ("trying to read more data after we've done stuff\n"); + /* Is this supposed to be an error or what? */ + /* g_message ("trying to read more data after we've done stuff\n"); */ + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Internal error in the GIF loader (%s)"), + G_STRLOC); + return -2; } @@ -563,8 +578,10 @@ lzw_read_byte (GifContext *context) *(context->lzw_sp)++ = context->lzw_table[1][code]; if (code == context->lzw_table[0][code]) { - /*g_message (_("GIF: circular table entry BIG ERROR\n"));*/ - /*gimp_quit ();*/ + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Circular table entry in GIF file")); return -2; } code = context->lzw_table[0][code]; @@ -890,12 +907,18 @@ gif_init (GifContext *context) char version[4]; if (!gif_read (context, buf, 6)) { - /* Unable to read magic number */ + /* Unable to read magic number, + * gif_read() should have set error + */ return -1; } if (strncmp ((char *) buf, "GIF", 3) != 0) { /* Not a GIF file */ + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("File does not appear to be a GIF file")); return -1; } @@ -904,12 +927,17 @@ gif_init (GifContext *context) if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) { /* bad version number, not '87a' or '89a' */ + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Version %s of the GIF file format is not supported"), + version); return -1; } /* read the screen descriptor */ if (!gif_read (context, buf, 7)) { - /* Failed to read screen descriptor */ + /* Failed to read screen descriptor, error set */ return -1; } @@ -950,6 +978,12 @@ gif_get_frame_info (GifContext *context) if (context->frame_height > context->height) { /* we don't want to resize things. So we exit */ context->state = GIF_DONE; + + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("GIF animation contained a frame with an incorrect size")); + return -2; } @@ -1092,7 +1126,7 @@ new_context (void) } /* Shared library entry point */ GdkPixbuf * -gdk_pixbuf__gif_image_load (FILE *file) +gdk_pixbuf__gif_image_load (FILE *file, GError **error) { GifContext *context; GdkPixbuf *pixbuf; @@ -1101,7 +1135,8 @@ gdk_pixbuf__gif_image_load (FILE *file) context = new_context (); context->file = file; - + context->error = error; + gif_main_loop (context); pixbuf = context->pixbuf; @@ -1115,7 +1150,8 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func, ModuleUpdatedNotifyFunc update_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { GifContext *context; @@ -1123,6 +1159,7 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func, count = 0; #endif context = new_context (); + context->error = error; context->prepare_func = prepare_func; context->update_func = update_func; context->frame_done_func = frame_done_func; @@ -1148,11 +1185,14 @@ gdk_pixbuf__gif_image_stop_load (gpointer data) } gboolean -gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size) +gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size, + GError **error) { gint retval; GifContext *context = (GifContext *) data; + context->error = error; + if (context->amount_needed == 0) { /* we aren't looking for some bytes. */ /* we can use buf now, but we don't want to keep it around at all. @@ -1206,7 +1246,8 @@ gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size) } GdkPixbufAnimation * -gdk_pixbuf__gif_image_load_animation (FILE *file) +gdk_pixbuf__gif_image_load_animation (FILE *file, + GError **error) { GifContext *context; GdkPixbufAnimation *animation; @@ -1214,6 +1255,9 @@ gdk_pixbuf__gif_image_load_animation (FILE *file) g_return_val_if_fail (file != NULL, NULL); context = new_context (); + + context->error = error; + context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL); context->animation->n_frames = 0; diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c index 83e2cf93b..a85fee280 100644 --- a/gdk-pixbuf/io-ico.c +++ b/gdk-pixbuf/io-ico.c @@ -158,16 +158,18 @@ gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data); + gpointer user_data, + GError **error); void gdk_pixbuf__ico_image_stop_load(gpointer data); -gboolean gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size); +gboolean gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size, + GError **error); /* Shared library entry point --> Can go when generic_image_load enters gdk-pixbuf-io */ GdkPixbuf * -gdk_pixbuf__ico_image_load(FILE * f) +gdk_pixbuf__ico_image_load(FILE * f, GError **error) { guchar *membuf; size_t length; @@ -175,7 +177,11 @@ gdk_pixbuf__ico_image_load(FILE * f) GdkPixbuf *pb; - State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, NULL, NULL); + State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, + NULL, NULL, error); + if (State == NULL) + return NULL; + membuf = g_malloc(4096); g_assert(membuf != NULL); @@ -183,8 +189,11 @@ gdk_pixbuf__ico_image_load(FILE * f) while (feof(f) == 0) { length = fread(membuf, 1, 4096, f); if (length > 0) - gdk_pixbuf__ico_image_load_increment(State, membuf, length); - + if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length, + error)) { + gdk_pixbuf__ico_image_stop_load (State); + return NULL; + } } g_free(membuf); if (State->pixbuf != NULL) @@ -370,7 +379,8 @@ gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { struct ico_progressive_state *context; @@ -633,7 +643,8 @@ static void OneLine(struct ico_progressive_state *context) * append image data onto inrecrementally built output image */ gboolean -gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size) +gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size, + GError **error) { struct ico_progressive_state *context = (struct ico_progressive_state *) data; diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c index 623077738..332de30c9 100644 --- a/gdk-pixbuf/io-jpeg.c +++ b/gdk-pixbuf/io-jpeg.c @@ -74,6 +74,7 @@ typedef my_source_mgr * my_src_ptr; struct error_handler_data { struct jpeg_error_mgr pub; sigjmp_buf setjmp_buffer; + GError **error; }; /* progressive loader context */ @@ -92,30 +93,51 @@ typedef struct { struct error_handler_data jerr; } JpegProgContext; -GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f); +GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error); gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func, ModuleUpdatedNotifyFunc func2, ModuleFrameDoneNotifyFunc func3, ModuleAnimationDoneNotifyFunc func4, - gpointer user_data); + gpointer user_data, + GError **error); void gdk_pixbuf__jpeg_image_stop_load (gpointer context); -gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context, guchar *buf, guint size); +gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context, guchar *buf, guint size, + GError **error); static void fatal_error_handler (j_common_ptr cinfo) { - /* FIXME: - * We should somehow signal what error occurred to the caller so the - * caller can handle the error message */ struct error_handler_data *errmgr; - + char buffer[JMSG_LENGTH_MAX]; + errmgr = (struct error_handler_data *) cinfo->err; - cinfo->err->output_message (cinfo); + + /* Create the message */ + (* cinfo->err->format_message) (cinfo, buffer); + + /* broken check for *error == NULL for robustness against + * crappy JPEG library + */ + if (errmgr->error && *errmgr->error == NULL) { + g_set_error (errmgr->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Error interpreting JPEG image file (%s)"), + buffer); + } + siglongjmp (errmgr->setjmp_buffer, 1); - /* incase the jmp buf isn't initted? */ - exit(1); + g_assert_not_reached (); +} + +static void +output_message_handler (j_common_ptr cinfo) +{ + /* This method keeps libjpeg from dumping crap to stderr */ + + /* do nothing */ } /* Destroy notification function for the pixbuf */ @@ -158,7 +180,7 @@ explode_gray_into_buf (struct jpeg_decompress_struct *cinfo, /* Shared library entry point */ GdkPixbuf * -gdk_pixbuf__jpeg_image_load (FILE *f) +gdk_pixbuf__jpeg_image_load (FILE *f, GError **error) { gint w, h, i; guchar *pixels = NULL; @@ -175,7 +197,10 @@ gdk_pixbuf__jpeg_image_load (FILE *f) /* setup error handler */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = fatal_error_handler; + jerr.pub.output_message = output_message_handler; + jerr.error = error; + if (sigsetjmp (jerr.setjmp_buffer, 1)) { /* Whoops there was a jpeg error */ if (pixels) @@ -199,6 +224,17 @@ gdk_pixbuf__jpeg_image_load (FILE *f) pixels = malloc (h * w * 3); if (!pixels) { jpeg_destroy_decompress (&cinfo); + + /* broken check for *error == NULL for robustness against + * crappy JPEG library + */ + if (error && *error == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Insufficient memory to load image, try exiting some applications to free memory")); + } + return NULL; } @@ -286,7 +322,8 @@ gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { JpegProgContext *context; my_source_mgr *src; @@ -308,7 +345,9 @@ gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, context->cinfo.err = jpeg_std_error (&context->jerr.pub); context->jerr.pub.error_exit = fatal_error_handler; - + context->jerr.pub.output_message = output_message_handler; + context->jerr.error = error; + src = (my_src_ptr) context->cinfo.src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; @@ -318,6 +357,8 @@ gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, src->pub.bytes_in_buffer = 0; src->pub.next_input_byte = NULL; + context->jerr.error = NULL; + return (gpointer) context; } @@ -364,7 +405,8 @@ gdk_pixbuf__jpeg_image_stop_load (gpointer data) * append image data onto inrecrementally built output image */ gboolean -gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size) +gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size, + GError **error) { JpegProgContext *context = (JpegProgContext *)data; struct jpeg_decompress_struct *cinfo; @@ -382,6 +424,8 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size) cinfo = &context->cinfo; + context->jerr.error = error; + /* XXXXXXX (drmike) - loop(s) below need to be recoded now I * have a grasp of what the flow needs to be! */ @@ -641,12 +685,13 @@ gdk_pixbuf__jpeg_image_save (FILE *f, g_return_val_if_fail (pixels != NULL, FALSE); /* allocate a small buffer to convert image data */ - buf = malloc (w * 3 * sizeof (guchar)); - g_return_val_if_fail (buf != NULL, FALSE); + buf = g_malloc (w * 3 * sizeof (guchar)); /* set up error handling */ jerr.pub.error_exit = fatal_error_handler; - + jerr.pub.output_message = output_message_handler; + jerr.error = error; + cinfo.err = jpeg_std_error (&(jerr.pub)); if (sigsetjmp (jerr.setjmp_buffer, 1)) { jpeg_destroy_compress (&cinfo); diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c index 33fa2cf68..bd945f794 100644 --- a/gdk-pixbuf/io-png.c +++ b/gdk-pixbuf/io-png.c @@ -140,6 +140,38 @@ setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr, #endif } +static void +png_simple_error_callback(png_structp png_save_ptr, + png_const_charp error_msg) +{ + GError **error; + + error = png_get_error_ptr(png_save_ptr); + + /* I don't trust libpng to call the error callback only once, + * so check for already-set error + */ + if (error && *error == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Fatal error saving PNG image file: %s"), + error_msg); + } +} + +static void +png_simple_warning_callback(png_structp png_save_ptr, + png_const_charp warning_msg) +{ + /* Don't print anything; we should not be dumping junk to + * stderr, since that may be bad for some apps. If it's + * important enough to display, we need to add a GError + * **warning return location wherever we have an error return + * location. + */ +} + /* Destroy notification function for the pixbuf */ static void free_buffer (guchar *pixels, gpointer data) @@ -149,7 +181,7 @@ free_buffer (guchar *pixels, gpointer data) /* Shared library entry point */ GdkPixbuf * -gdk_pixbuf__png_image_load (FILE *f) +gdk_pixbuf__png_image_load (FILE *f, GError **error) { png_structp png_ptr; png_infop info_ptr, end_info; @@ -159,7 +191,10 @@ gdk_pixbuf__png_image_load (FILE *f) png_bytepp rows; guchar *pixels; - png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, + error, + png_simple_error_callback, + png_simple_warning_callback); if (!png_ptr) return NULL; @@ -197,6 +232,16 @@ gdk_pixbuf__png_image_load (FILE *f) pixels = malloc (w * h * bpp); if (!pixels) { + /* Check error NULL, normally this would be broken, + * but libpng makes me want to code defensively. + */ + if (error && *error == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Insufficient memory to load PNG file")); + } + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); return NULL; } @@ -273,6 +318,7 @@ struct _LoadContext { guint fatal_error_occurred : 1; + GError **error; }; gpointer @@ -280,7 +326,8 @@ gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, ModuleUpdatedNotifyFunc update_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { LoadContext* lc; @@ -297,6 +344,7 @@ gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, lc->first_pass_seen_in_chunk = -1; lc->last_pass_seen_in_chunk = -1; lc->max_row_seen_in_chunk = -1; + lc->error = error; /* Create the main PNG context struct */ @@ -308,13 +356,15 @@ gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, if (lc->png_read_ptr == NULL) { g_free(lc); + /* error callback should have set the error */ return NULL; } - + if (setjmp (lc->png_read_ptr->jmpbuf)) { if (lc->png_info_ptr) png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL); g_free(lc); + /* error callback should have set the error */ return NULL; } @@ -325,6 +375,7 @@ gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, if (lc->png_info_ptr == NULL) { png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL); g_free(lc); + /* error callback should have set the error */ return NULL; } @@ -335,6 +386,11 @@ gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, png_end_callback); + /* We don't want to keep modifying error after returning here, + * it may no longer be valid. + */ + lc->error = NULL; + return lc; } @@ -352,7 +408,8 @@ gdk_pixbuf__png_image_stop_load (gpointer context) } gboolean -gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size) +gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size, + GError **error) { LoadContext* lc = context; @@ -364,17 +421,20 @@ gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size) lc->first_pass_seen_in_chunk = -1; lc->last_pass_seen_in_chunk = -1; lc->max_row_seen_in_chunk = -1; + lc->error = error; /* Invokes our callbacks as needed */ if (setjmp (lc->png_read_ptr->jmpbuf)) { + lc->error = NULL; return FALSE; } else { png_process_data(lc->png_read_ptr, lc->png_info_ptr, buf, size); } - if (lc->fatal_error_occurred) + if (lc->fatal_error_occurred) { + lc->error = NULL; return FALSE; - else { + } else { if (lc->first_row_seen_in_chunk >= 0) { /* We saw at least one row */ gint pass_diff = lc->last_pass_seen_in_chunk - lc->first_pass_seen_in_chunk; @@ -417,6 +477,8 @@ gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size) lc->notify_user_data); } } + + lc->error = NULL; return TRUE; } @@ -437,7 +499,6 @@ png_info_callback (png_structp png_read_ptr, if (lc->fatal_error_occurred) return; - setup_png_transformations(lc->png_read_ptr, lc->png_info_ptr, @@ -458,6 +519,13 @@ png_info_callback (png_structp png_read_ptr, if (lc->pixbuf == NULL) { /* Failed to allocate memory */ lc->fatal_error_occurred = TRUE; + if (lc->error && *lc->error == NULL) { + g_set_error (lc->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Insufficient memory to store a %ld by %ld image; try exiting some applications to reduce memory usage"), + width, height); + } return; } @@ -521,8 +589,17 @@ png_error_callback(png_structp png_read_ptr, lc = png_get_error_ptr(png_read_ptr); lc->fatal_error_occurred = TRUE; - - fprintf(stderr, "Fatal error loading PNG: %s\n", error_msg); + + /* I don't trust libpng to call the error callback only once, + * so check for already-set error + */ + if (lc->error && *lc->error == NULL) { + g_set_error (lc->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Fatal error reading PNG image file: %s"), + error_msg); + } } static void @@ -532,12 +609,18 @@ png_warning_callback(png_structp png_read_ptr, LoadContext* lc; lc = png_get_error_ptr(png_read_ptr); - - fprintf(stderr, "Warning loading PNG: %s\n", warning_msg); + + /* Don't print anything; we should not be dumping junk to + * stderr, since that may be bad for some apps. If it's + * important enough to display, we need to add a GError + * **warning return location wherever we have an error return + * location. + */ } /* Save */ + gboolean gdk_pixbuf__png_image_save (FILE *f, GdkPixbuf *pixbuf, @@ -545,8 +628,6 @@ gdk_pixbuf__png_image_save (FILE *f, gchar **values, GError **error) { - /* FIXME error handling is broken */ - png_structp png_ptr; png_infop info_ptr; guchar *ptr; @@ -583,7 +664,9 @@ gdk_pixbuf__png_image_save (FILE *f, pixels = gdk_pixbuf_get_pixels (pixbuf); png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); + error, + png_simple_error_callback, + png_simple_warning_callback); g_return_val_if_fail (png_ptr != NULL, FALSE); @@ -599,8 +682,8 @@ gdk_pixbuf__png_image_save (FILE *f, png_init_io (png_ptr, f); if (has_alpha) { png_set_IHDR (png_ptr, info_ptr, w, h, bpc, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #ifdef WORDS_BIGENDIAN png_set_swap_alpha (png_ptr); #else @@ -608,9 +691,23 @@ gdk_pixbuf__png_image_save (FILE *f, #endif } else { png_set_IHDR (png_ptr, info_ptr, w, h, bpc, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); data = malloc (w * 3 * sizeof (char)); + + if (data == NULL) { + /* Check error NULL, normally this would be broken, + * but libpng makes me want to code defensively. + */ + if (error && *error == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Insufficient memory to save PNG file")); + } + png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + return FALSE; + } } sig_bit.red = bpc; sig_bit.green = bpc; diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c index c91658cfd..c352d611f 100644 --- a/gdk-pixbuf/io-pnm.c +++ b/gdk-pixbuf/io-pnm.c @@ -76,17 +76,21 @@ typedef struct { gboolean got_header; /* have we loaded pnm header? */ guint scan_state; + + GError **error; } PnmLoaderContext; -GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f); +GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error); gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func, ModuleUpdatedNotifyFunc func2, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data); + gpointer user_data, + GError **error); void gdk_pixbuf__pnm_image_stop_load (gpointer context); -gboolean gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size); +gboolean gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size, + GError **error); static void explode_bitmap_into_buf (PnmLoaderContext *context); static void explode_gray_into_buf (PnmLoaderContext *context); @@ -178,7 +182,7 @@ explode_gray_into_buf (PnmLoaderContext *context) /* skip over whitespace and comments in input buffer */ static gint -pnm_skip_whitespace (PnmIOBuffer *inbuf) +pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error) { register guchar *inptr; guchar *inend; @@ -208,7 +212,7 @@ pnm_skip_whitespace (PnmIOBuffer *inbuf) /* read next number from buffer */ static gint -pnm_read_next_value (PnmIOBuffer *inbuf, guint *value) +pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error) { register guchar *inptr, *word, *p; guchar *inend, buf[128]; @@ -220,7 +224,7 @@ pnm_read_next_value (PnmIOBuffer *inbuf, guint *value) g_return_val_if_fail (value != NULL, PNM_FATAL_ERR); /* skip white space */ - if ((retval = pnm_skip_whitespace (inbuf)) != PNM_OK) + if ((retval = pnm_skip_whitespace (inbuf, error)) != PNM_OK) return retval; inend = inbuf->byte + inbuf->nbytes; @@ -237,8 +241,13 @@ pnm_read_next_value (PnmIOBuffer *inbuf, guint *value) /* get the value */ *value = strtol (buf, &endptr, 10); - if (*endptr != '\0') + if (*endptr != '\0') { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM loader expected to find an integer, but didn't")); return PNM_FATAL_ERR; + } inbuf->byte = p; inbuf->nbytes = (guint) (inend - p); @@ -263,8 +272,13 @@ pnm_read_header (PnmLoaderContext *context) if (inbuf->nbytes < 2) return PNM_SUSPEND; - if (*inbuf->byte != 'P') + if (*inbuf->byte != 'P') { + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM file has an incorrect initial byte")); return PNM_FATAL_ERR; + } inbuf->byte++; inbuf->nbytes--; @@ -289,6 +303,10 @@ pnm_read_header (PnmLoaderContext *context) context->type = PNM_FORMAT_PPM_RAW; break; default: + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM file is not in a recognized PNM subformat")); return PNM_FATAL_ERR; } @@ -303,13 +321,19 @@ pnm_read_header (PnmLoaderContext *context) /* read the pixmap width */ guint width = 0; - retval = pnm_read_next_value (inbuf, &width); + retval = pnm_read_next_value (inbuf, &width, + context->error); - if (retval != PNM_OK) + if (retval != PNM_OK) return retval; - if (!width) + if (!width) { + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM file has an image width of 0")); return PNM_FATAL_ERR; + } context->width = width; } @@ -318,13 +342,19 @@ pnm_read_header (PnmLoaderContext *context) /* read the pixmap height */ guint height = 0; - retval = pnm_read_next_value (inbuf, &height); + retval = pnm_read_next_value (inbuf, &height, + context->error); if (retval != PNM_OK) return retval; - if (!height) + if (!height) { + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM file has an image height of 0")); return PNM_FATAL_ERR; + } context->height = height; } @@ -335,13 +365,19 @@ pnm_read_header (PnmLoaderContext *context) case PNM_FORMAT_PGM: case PNM_FORMAT_PGM_RAW: if (!context->maxval) { - retval = pnm_read_next_value (inbuf, &context->maxval); + retval = pnm_read_next_value (inbuf, &context->maxval, + context->error); if (retval != PNM_OK) return retval; - if (context->maxval == 0) + if (context->maxval == 0) { + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Maximum color value in PNM file is 0")); return PNM_FATAL_ERR; + } } break; default: @@ -375,7 +411,10 @@ pnm_read_raw_scanline (PnmLoaderContext *context) numpix = inbuf->nbytes / 3; break; default: - g_warning ("io-pnm.c: Illegal raw pnm type!\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Raw PNM image type is invalid")); return PNM_FATAL_ERR; } @@ -400,7 +439,10 @@ pnm_read_raw_scanline (PnmLoaderContext *context) offset = context->output_col * 3; break; default: - g_warning ("io-pnm.c: Illegal raw pnm type!\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Raw PNM image type is invalid")); return PNM_FATAL_ERR; } @@ -429,7 +471,11 @@ pnm_read_raw_scanline (PnmLoaderContext *context) } break; default: - g_warning ("Invalid raw pnm format!"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Raw PNM image type is invalid")); + return PNM_FATAL_ERR; } inbuf->byte += numbytes; @@ -485,7 +531,11 @@ pnm_read_ascii_scanline (PnmLoaderContext *context) break; default: - g_warning ("Can't happen\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM image format is invalid")); + return PNM_FATAL_ERR; } @@ -499,7 +549,8 @@ pnm_read_ascii_scanline (PnmLoaderContext *context) } for (i = context->scan_state; i < numval; i++) { - retval = pnm_read_next_value (inbuf, &value); + retval = pnm_read_next_value (inbuf, &value, + context->error); if (retval != PNM_OK) { /* save state and return */ context->scan_state = i; @@ -522,7 +573,11 @@ pnm_read_ascii_scanline (PnmLoaderContext *context) *dptr++ = (guchar)(255 * value / context->maxval); break; default: - g_warning ("io-pnm.c: Illegal ascii pnm type!\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("PNM image format is invalid")); + return PNM_FATAL_ERR; break; } } @@ -577,7 +632,11 @@ pnm_read_scanline (PnmLoaderContext *context) return retval; break; default: - g_warning ("Cannot load these image types (yet)\n"); + g_set_error (context->error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("PNM image loader does not support this PNM subformat")); + return PNM_FATAL_ERR; } @@ -586,7 +645,7 @@ pnm_read_scanline (PnmLoaderContext *context) /* Shared library entry point */ GdkPixbuf * -gdk_pixbuf__pnm_image_load (FILE *f) +gdk_pixbuf__pnm_image_load (FILE *f, GError **error) { PnmLoaderContext context; PnmIOBuffer *inbuf; @@ -608,6 +667,7 @@ gdk_pixbuf__pnm_image_load (FILE *f) context.got_header = FALSE; context.did_prescan = FALSE; context.scan_state = 0; + context.error = error; inbuf = &context.inbuf; @@ -647,7 +707,8 @@ gdk_pixbuf__pnm_image_load (FILE *f) /* scan until we hit image data */ if (!context.did_prescan) { - retval = pnm_skip_whitespace (inbuf); + retval = pnm_skip_whitespace (inbuf, + context.error); if (retval == PNM_FATAL_ERR) return NULL; else if (retval == PNM_SUSPEND) @@ -675,7 +736,7 @@ gdk_pixbuf__pnm_image_load (FILE *f) } else if (retval == PNM_FATAL_ERR) { if (context.pixbuf) gdk_pixbuf_unref (context.pixbuf); - g_warning ("io-pnm.c: error reading rows..\n"); + return NULL; } } @@ -703,7 +764,8 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { PnmLoaderContext *context; @@ -722,6 +784,8 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, context->inbuf.nbytes = 0; context->inbuf.byte = NULL; + + context->error = error; return (gpointer) context; } @@ -752,7 +816,8 @@ gdk_pixbuf__pnm_image_stop_load (gpointer data) * append image data onto inrecrementally built output image */ gboolean -gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) +gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size, + GError **error) { PnmLoaderContext *context = (PnmLoaderContext *)data; PnmIOBuffer *inbuf; @@ -764,6 +829,8 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) g_return_val_if_fail (context != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); + + context->error = error; bufhd = buf; inbuf = &context->inbuf; @@ -811,7 +878,8 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) /* scan until we hit image data */ if (!context->did_prescan) { - retval = pnm_skip_whitespace (inbuf); + retval = pnm_skip_whitespace (inbuf, + context->error); if (retval == PNM_FATAL_ERR) return FALSE; @@ -850,7 +918,6 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) } else if (retval == PNM_FATAL_ERR) { if (context->pixbuf) gdk_pixbuf_unref (context->pixbuf); - g_warning ("io-pnm.c: error reading rows.\n"); return FALSE; } else if (retval == PNM_OK) { /* send updated signal */ diff --git a/gdk-pixbuf/io-ras.c b/gdk-pixbuf/io-ras.c index e70f4c9e0..dbcf7bc14 100644 --- a/gdk-pixbuf/io-ras.c +++ b/gdk-pixbuf/io-ras.c @@ -98,14 +98,16 @@ gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data); + gpointer user_data, + GError **error); void gdk_pixbuf__ras_image_stop_load(gpointer data); -gboolean gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size); +gboolean gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size, + GError **error); /* Shared library entry point */ -GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f) +GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error) { guchar *membuf; size_t length; @@ -113,7 +115,8 @@ GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f) GdkPixbuf *pb; - State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, NULL, NULL); + State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, + NULL, NULL, error); membuf = g_malloc(4096); @@ -121,8 +124,12 @@ GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f) while (feof(f) == 0) { length = fread(membuf, 1, 4096, f); - (void)gdk_pixbuf__ras_image_load_increment(State, membuf, length); - } + if (!gdk_pixbuf__ras_image_load_increment(State, membuf, length, + error)) { + gdk_pixbuf__ras_image_stop_load (State); + return NULL; + } + } g_free(membuf); if (State->pixbuf != NULL) gdk_pixbuf_ref(State->pixbuf); @@ -213,7 +220,8 @@ gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { struct ras_progressive_state *context; @@ -385,7 +393,8 @@ static void OneLine(struct ras_progressive_state *context) * append image data onto inrecrementally built output image */ gboolean -gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size) +gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size, + GError **error) { struct ras_progressive_state *context = (struct ras_progressive_state *) data; diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c index fdf517463..615714742 100644 --- a/gdk-pixbuf/io-tiff.c +++ b/gdk-pixbuf/io-tiff.c @@ -148,7 +148,8 @@ gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func, ModuleUpdatedNotifyFunc update_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { TiffData *context; gint fd; diff --git a/gdk-pixbuf/io-wbmp.c b/gdk-pixbuf/io-wbmp.c index f8411ae26..bbca3e1a1 100644 --- a/gdk-pixbuf/io-wbmp.c +++ b/gdk-pixbuf/io-wbmp.c @@ -67,16 +67,18 @@ gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, ModuleUpdatedNotifyFunc updated_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc - anim_done_func, gpointer user_data); + anim_done_func, gpointer user_data, + GError **error); void gdk_pixbuf__wbmp_image_stop_load(gpointer data); gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf, - guint size); + guint size, + GError **error); /* Shared library entry point --> This should be removed when generic_image_load enters gdk-pixbuf-io. */ -GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f) +GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error) { size_t length; char membuf[4096]; @@ -84,14 +86,19 @@ GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f) GdkPixbuf *pb; - State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL); + State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL, + error); + if (State == NULL) + return NULL; + while (feof(f) == 0) { length = fread(membuf, 1, 4096, f); if (length > 0) gdk_pixbuf__wbmp_image_load_increment(State, membuf, - length); + length, + error); } if (State->pixbuf != NULL) @@ -111,10 +118,11 @@ GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f) gpointer gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, - ModuleUpdatedNotifyFunc updated_func, - ModuleFrameDoneNotifyFunc frame_done_func, - ModuleAnimationDoneNotifyFunc - anim_done_func, gpointer user_data) + ModuleUpdatedNotifyFunc updated_func, + ModuleFrameDoneNotifyFunc frame_done_func, + ModuleAnimationDoneNotifyFunc + anim_done_func, gpointer user_data, + GError **error) { struct wbmp_progressive_state *context; @@ -221,7 +229,7 @@ get_mbi(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, i * append image data onto inrecrementally built output image */ gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf, - guint size) + guint size, GError **error) { struct wbmp_progressive_state *context = (struct wbmp_progressive_state *) data; diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c index 17e2a43f4..b762c8705 100644 --- a/gdk-pixbuf/io-xpm.c +++ b/gdk-pixbuf/io-xpm.c @@ -27,6 +27,7 @@ #include <stdlib.h> #include <string.h> #include <glib.h> +#include <unistd.h> #include "gdk-pixbuf-private.h" #include "gdk-pixbuf-io.h" @@ -1400,7 +1401,8 @@ gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func, ModuleUpdatedNotifyFunc update_func, ModuleFrameDoneNotifyFunc frame_done_func, ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data) + gpointer user_data, + GError **error) { XPMContext *context; gint fd; diff --git a/gdk-pixbuf/make-inline-pixbuf.c b/gdk-pixbuf/make-inline-pixbuf.c index daf0a7e20..445fbd88a 100644 --- a/gdk-pixbuf/make-inline-pixbuf.c +++ b/gdk-pixbuf/make-inline-pixbuf.c @@ -187,15 +187,16 @@ main (int argc, char **argv) while (i < argc) { GdkPixbuf *pixbuf; + GError *error; g_assert ((i + 1) < argc); - - pixbuf = gdk_pixbuf_new_from_file (argv[i+1]); + + error = NULL; + pixbuf = gdk_pixbuf_new_from_file (argv[i+1], &error); if (pixbuf == NULL) { - fprintf (stderr, "Failed to open image file `%s': %s\n", - argv[i+1], strerror (errno)); + fprintf (stderr, "%s\n", error->message); exit (1); } |