diff options
author | Havoc Pennington <hp@pobox.com> | 1999-10-27 18:55:00 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 1999-10-27 18:55:00 +0000 |
commit | 54f017171fefee078ad36a4d2a6c67622c8f57de (patch) | |
tree | 0bb7951e213bc386a7bb7cff841c729e402eba84 /gdk-pixbuf/io-png.c | |
parent | 2ec115ea801002eb68b7881433a17c5810605a80 (diff) | |
download | gtk+-54f017171fefee078ad36a4d2a6c67622c8f57de.tar.gz |
Check properly whether the XPM module has already been loaded
1999-10-27 Havoc Pennington <hp@pobox.com>
* src/gdk-pixbuf-io.c (gdk_pixbuf_new_from_xpm_data): Check
properly whether the XPM module has already been loaded
(gdk_pixbuf_new_from_file): Check properly if loader module
was already loaded (was checking if load symbol was present
in order to decide whether to re-load; should check module !=
NULL, then load != NULL)
(image_handler_load): Check in present working directory,
makes it easier to debug for now
(file_formats): This array initializer was seriously on crack,
was assigning a function pointer to a GModule*
* src/testpixbuf.c (main): Change type of pixbuf_loader to GdkPixbufLoader*
* src/io-png.c: Progressive loading stuff compiles, untested.
Diffstat (limited to 'gdk-pixbuf/io-png.c')
-rw-r--r-- | gdk-pixbuf/io-png.c | 296 |
1 files changed, 294 insertions, 2 deletions
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c index a60adfbdc4..fed2e7e806 100644 --- a/gdk-pixbuf/io-png.c +++ b/gdk-pixbuf/io-png.c @@ -26,6 +26,7 @@ #include <stdio.h> #include <png.h> #include "gdk-pixbuf.h" +#include "gdk-pixbuf-io.h" @@ -135,8 +136,299 @@ image_load (FILE *f) free_buffer, NULL); } +/* These avoid the setjmp()/longjmp() crap in libpng */ +static void png_error_callback (png_structp png_read_ptr, + png_const_charp error_msg); + +static void png_warning_callback(png_structp png_read_ptr, + png_const_charp warning_msg); + +/* Called at the start of the progressive load */ +static void png_info_callback (png_structp png_read_ptr, + png_infop png_info_ptr); + +/* Called for each row; note that you will get duplicate row numbers + for interlaced PNGs */ +static void png_row_callback (png_structp png_read_ptr, + png_bytep new_row, + png_uint_32 row_num, + int pass_num); + +/* Called after reading the entire image */ +static void png_end_callback (png_structp png_read_ptr, + png_infop png_info_ptr); + +typedef struct _LoadContext LoadContext; + +struct _LoadContext { + png_structp png_read_ptr; + png_infop png_info_ptr; + + ModulePreparedNotifyFunc notify_func; + gpointer notify_user_data; + + GdkPixbuf* pixbuf; + + guint fatal_error_occurred : 1; + +}; + +gpointer +image_begin_load (ModulePreparedNotifyFunc func, gpointer user_data) +{ + LoadContext* lc; + + lc = g_new0(LoadContext, 1); + + lc->fatal_error_occurred = FALSE; + + lc->notify_func = func; + lc->notify_user_data = user_data; + + /* Create the main PNG context struct */ + + lc->png_read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + lc, /* error/warning callback data */ + png_error_callback, + png_warning_callback); + + if (lc->png_read_ptr == NULL) { + g_free(lc); + return NULL; + } + + /* Create the two auxiliary context structs */ + + lc->png_info_ptr = png_create_info_struct(lc->png_read_ptr); + + if (lc->png_info_ptr == NULL) { + png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL); + g_free(lc); + return NULL; + } + + png_set_progressive_read_fn(lc->png_read_ptr, + lc, /* callback data */ + png_info_callback, + png_row_callback, + png_end_callback); + + + return lc; +} + +void +image_stop_load (gpointer context) +{ + LoadContext* lc = context; + + g_return_if_fail(lc != NULL); + + gdk_pixbuf_unref(lc->pixbuf); + + png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL); + g_free(lc); +} + gboolean -image_load_by_data (void *data, size_t count) +image_load_increment(gpointer context, guchar *buf, guint size) +{ + LoadContext* lc = context; + + g_return_val_if_fail(lc != NULL, FALSE); + + /* Invokes our callbacks as needed */ + png_process_data(lc->png_read_ptr, lc->png_info_ptr, buf, size); + + if (lc->fatal_error_occurred) + return FALSE; + else + return TRUE; +} + +/* Called at the start of the progressive load, once we have image info */ +static void +png_info_callback (png_structp png_read_ptr, + png_infop png_info_ptr) +{ + LoadContext* lc; + png_uint_32 width, height; + int bit_depth, color_type, filter_type, + compression_type, interlace_type, channels; + gboolean have_alpha = FALSE; + + lc = png_get_progressive_ptr(png_read_ptr); + + if (lc->fatal_error_occurred) + return; + + /* Get the image info */ + + png_get_IHDR (lc->png_read_ptr, lc->png_info_ptr, + &width, &height, + &bit_depth, + &color_type, + &interlace_type, + &compression_type, + &filter_type); + + /* set_expand() basically needs to be called unless + we are already in RGB/RGBA mode + */ + if (color_type == PNG_COLOR_TYPE_PALETTE && + bit_depth <= 8) { + + /* Convert indexed images to RGB */ + png_set_expand (lc->png_read_ptr); + + } else if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) { + + /* Convert grayscale to RGB */ + png_set_expand (lc->png_read_ptr); + + } else if (png_get_valid (lc->png_read_ptr, + lc->png_info_ptr, PNG_INFO_tRNS)) { + + /* If we have transparency header, convert it to alpha + channel */ + png_set_expand(lc->png_read_ptr); + + } else if (bit_depth < 8) { + + /* If we have < 8 scale it up to 8 */ + png_set_expand(lc->png_read_ptr); + + + /* Conceivably, png_set_packing() is a better idea; + * God only knows how libpng works + */ + } + + /* If we are 16-bit, convert to 8-bit */ + if (bit_depth == 16) { + png_set_strip_16(lc->png_read_ptr); + } + + /* If gray scale, convert to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + png_set_gray_to_rgb(lc->png_read_ptr); + } + + /* If we have alpha, set a flag */ + if (color_type & PNG_COLOR_MASK_ALPHA) + have_alpha = TRUE; + + /* Update the info the reflect our transformations */ + png_read_update_info(lc->png_read_ptr, lc->png_info_ptr); + + png_get_IHDR (lc->png_read_ptr, lc->png_info_ptr, + &width, &height, + &bit_depth, + &color_type, + &interlace_type, + &compression_type, + &filter_type); + +#ifndef G_DISABLE_CHECKS + /* Check that the new info is what we want */ + + if (bit_depth != 8) { + g_warning("Bits per channel of transformed PNG is %d, not 8.", bit_depth); + lc->fatal_error_occurred = TRUE; + return; + } + + if ( ! (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) { + g_warning("Transformed PNG not RGB or RGBA."); + lc->fatal_error_occurred = TRUE; + return; + } + + channels = png_get_channels(lc->png_read_ptr, lc->png_info_ptr); + if ( ! (channels == 3 || channels == 4) ) { + g_warning("Transformed PNG has %d channels, must be 3 or 4.", channels); + lc->fatal_error_occurred = TRUE; + return; + } +#endif + + lc->pixbuf = gdk_pixbuf_new(have_alpha, width, height); + + if (lc->pixbuf == NULL) { + /* Failed to allocate memory */ + lc->fatal_error_occurred = TRUE; + return; + } + + /* Notify the client that we are ready to go */ + + if (lc->notify_func) + (* lc->notify_func) (lc->pixbuf, lc->notify_user_data); + + return; +} + +/* Called for each row; note that you will get duplicate row numbers + for interlaced PNGs */ +static void +png_row_callback (png_structp png_read_ptr, + png_bytep new_row, + png_uint_32 row_num, + int pass_num) +{ + LoadContext* lc; + guchar* old_row = NULL; + + lc = png_get_progressive_ptr(png_read_ptr); + + if (lc->fatal_error_occurred) + return; + + old_row = lc->pixbuf->art_pixbuf->pixels + (row_num * lc->pixbuf->art_pixbuf->rowstride); + + png_progressive_combine_row(lc->png_read_ptr, old_row, new_row); +} + +/* Called after reading the entire image */ +static void +png_end_callback (png_structp png_read_ptr, + png_infop png_info_ptr) { - return TRUE; + LoadContext* lc; + + lc = png_get_progressive_ptr(png_read_ptr); + + if (lc->fatal_error_occurred) + return; + + /* Doesn't do anything for now */ } + + +static void +png_error_callback(png_structp png_read_ptr, + png_const_charp error_msg) +{ + LoadContext* lc; + + lc = png_get_error_ptr(png_read_ptr); + + lc->fatal_error_occurred = TRUE; + + fprintf(stderr, "Fatal error loading PNG: %s\n", error_msg); +} + +static void +png_warning_callback(png_structp png_read_ptr, + png_const_charp warning_msg) +{ + LoadContext* lc; + + lc = png_get_error_ptr(png_read_ptr); + + fprintf(stderr, "Warning loading PNG: %s\n", warning_msg); +} + |