summaryrefslogtreecommitdiff
path: root/gdk-pixbuf/io-png.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2000-10-18 18:42:54 +0000
committerHavoc Pennington <hp@src.gnome.org>2000-10-18 18:42:54 +0000
commit7a4c68938789206bfec3c6d15cc4bb922daf6443 (patch)
treee5f031fc609e50a8b7b12e7d6abf63cc78cc88e7 /gdk-pixbuf/io-png.c
parent7420908815651a1ff2ceb1c0fb5e92fe9b260619 (diff)
downloadgtk+-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/io-png.c')
-rw-r--r--gdk-pixbuf/io-png.c135
1 files changed, 116 insertions, 19 deletions
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index 33fa2cf68f..bd945f7943 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;