* Boston, MA 02111-1307, USA.
*/
-#include <config.h>
+#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
*/
bit_depth = png_get_bit_depth (png_read_ptr, png_info_ptr);
if (bit_depth < 1 || bit_depth > 16) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Bits per channel of PNG image is invalid."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Bits per channel of PNG image is invalid."));
return FALSE;
}
png_get_IHDR (png_read_ptr, png_info_ptr,
/* Check that the new info is what we want */
if (width == 0 || height == 0) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Transformed PNG has zero width or height."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Transformed PNG has zero width or height."));
return FALSE;
}
if (bit_depth != 8) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Bits per channel of transformed PNG is not 8."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Bits per channel of transformed PNG is not 8."));
return FALSE;
}
if ( ! (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Transformed PNG not RGB or RGBA."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Transformed PNG not RGB or RGBA."));
return FALSE;
}
channels = png_get_channels(png_read_ptr, png_info_ptr);
if ( ! (channels == 3 || channels == 4) ) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Transformed PNG has unsupported number of channels, must be 3 or 4."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Transformed PNG has unsupported number of channels, must be 3 or 4."));
return FALSE;
}
return TRUE;
gint num_texts;
gchar *key;
gchar *value;
+ gchar *icc_profile_base64;
+ const gchar *icc_profile_title;
+ const gchar *icc_profile;
+ guint icc_profile_size;
+ guint32 retval;
+ gint compression_type;
#ifdef PNG_USER_MEM_SUPPORTED
png_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
}
if (setjmp (png_ptr->jmpbuf)) {
- if (rows)
- g_free (rows);
+ g_free (rows);
if (pixbuf)
g_object_unref (pixbuf);
if (!pixbuf) {
if (error && *error == NULL) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Insufficient memory to load PNG file"));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to load PNG file"));
}
}
}
+#if defined(PNG_cHRM_SUPPORTED)
+ /* Extract embedded ICC profile */
+ retval = png_get_iCCP (png_ptr, info_ptr,
+ (png_charpp) &icc_profile_title, &compression_type,
+ (png_charpp) &icc_profile, (png_uint_32*) &icc_profile_size);
+ if (retval != 0) {
+ icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
+ gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
+ g_free (icc_profile_base64);
+ }
+#endif
+
g_free (rows);
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
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);
+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,
int i, num_texts;
int color_type;
gboolean have_alpha = FALSE;
-
+ gchar *icc_profile_base64;
+ const gchar *icc_profile_title;
+ const gchar *icc_profile;
+ guint icc_profile_size;
+ guint32 retval;
+ gint compression_type;
+
lc = png_get_progressive_ptr(png_read_ptr);
if (lc->fatal_error_occurred)
if (w == 0 || h == 0) {
lc->fatal_error_occurred = TRUE;
if (lc->error && *lc->error == NULL) {
- g_set_error (lc->error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_FAILED,
- _("Transformed PNG has zero width or height."));
+ g_set_error_literal (lc->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Transformed PNG has zero width or height."));
}
return;
}
}
}
+#if defined(PNG_cHRM_SUPPORTED)
+ /* Extract embedded ICC profile */
+ retval = png_get_iCCP (png_read_ptr, png_info_ptr,
+ (png_charpp) &icc_profile_title, &compression_type,
+ (png_charpp) &icc_profile, (png_uint_32*) &icc_profile_size);
+ if (retval != 0) {
+ icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
+ gdk_pixbuf_set_option (lc->pixbuf, "icc-profile", icc_profile_base64);
+ g_free (icc_profile_base64);
+ }
+#endif
+
/* Notify the client that we are ready to go */
if (lc->prepare_func)
(* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
-
+
return;
}
if (row_num >= lc->pixbuf->height) {
lc->fatal_error_occurred = TRUE;
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"));
+ g_set_error_literal (lc->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Fatal error reading PNG image file"));
}
return;
}
}
static void
-png_warning_callback(png_structp png_read_ptr,
- png_const_charp warning_msg)
+png_warning_callback (png_structp png_read_ptr,
+ png_const_charp warning_msg)
{
LoadContext* lc;
GdkPixbufSaveFunc save_func,
gpointer user_data)
{
- png_structp png_ptr;
+ png_structp png_ptr = NULL;
png_infop info_ptr;
png_textp text_ptr = NULL;
guchar *ptr;
int num_keys;
int compression = -1;
gboolean success = TRUE;
+ guchar *icc_profile = NULL;
+ gsize icc_profile_size = 0;
SaveToFunctionIoPtr to_callback_ioptr;
num_keys = 0;
gchar *key = *kiter + 6;
int len = strlen (key);
if (len <= 1 || len > 79) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_BAD_OPTION,
- _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
- return FALSE;
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
+ success = FALSE;
+ goto cleanup;
}
for (i = 0; i < len; i++) {
if ((guchar) key[i] > 127) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_BAD_OPTION,
- _("Keys for PNG text chunks must be ASCII characters."));
- return FALSE;
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("Keys for PNG text chunks must be ASCII characters."));
+ success = FALSE;
+ goto cleanup;
}
}
num_keys++;
+ } else if (strcmp (*kiter, "icc-profile") == 0) {
+ /* decode from base64 */
+ icc_profile = g_base64_decode (*viter, &icc_profile_size);
+ if (icc_profile_size < 127) {
+ /* This is a user-visible error */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("Color profile has invalid length '%d'."),
+ icc_profile_size);
+ success = FALSE;
+ goto cleanup;
+ }
} else if (strcmp (*kiter, "compression") == 0) {
char *endptr = NULL;
compression = strtol (*viter, &endptr, 10);
GDK_PIXBUF_ERROR_BAD_OPTION,
_("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
*viter);
- return FALSE;
+ success = FALSE;
+ goto cleanup;
}
if (compression < 0 || compression > 9) {
/* This is a user-visible error;
GDK_PIXBUF_ERROR_BAD_OPTION,
_("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
compression);
- return FALSE;
+ success = FALSE;
+ goto cleanup;
}
} else {
- g_warning ("Bad option name '%s' passed to PNG saver",
- *kiter);
- return FALSE;
+ g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
}
++kiter;
error,
png_simple_error_callback,
png_simple_warning_callback);
-
- g_return_val_if_fail (png_ptr != NULL, FALSE);
+ if (png_ptr == NULL) {
+ success = FALSE;
+ goto cleanup;
+ }
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
if (compression >= 0)
png_set_compression_level (png_ptr, compression);
+#if defined(PNG_iCCP_SUPPORTED)
+ /* the proper ICC profile title is encoded in the profile */
+ if (icc_profile != NULL) {
+ png_set_iCCP (png_ptr, info_ptr,
+ "ICC profile", PNG_COMPRESSION_TYPE_BASE,
+ (gchar*) icc_profile, icc_profile_size);
+ }
+#endif
+
if (has_alpha) {
png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
png_write_end (png_ptr, info_ptr);
cleanup:
- png_destroy_write_struct (&png_ptr, &info_ptr);
+ if (png_ptr != NULL)
+ png_destroy_write_struct (&png_ptr, &info_ptr);
- if (num_keys > 0) {
- for (i = 0; i < num_keys; i++)
- g_free (text_ptr[i].text);
- g_free (text_ptr);
- }
+ g_free (icc_profile);
+
+ if (text_ptr != NULL) {
+ for (i = 0; i < num_keys; i++)
+ g_free (text_ptr[i].text);
+ g_free (text_ptr);
+ }
return success;
}
}
#ifndef INCLUDE_png
-#define MODULE_ENTRY(type,function) function
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
#else
-#define MODULE_ENTRY(type,function) _gdk_pixbuf__ ## type ## _ ## function
+#define MODULE_ENTRY(function) void _gdk_pixbuf__png_ ## function
#endif
-void
-MODULE_ENTRY (png, fill_vtable) (GdkPixbufModule *module)
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
{
module->load = gdk_pixbuf__png_image_load;
module->begin_load = gdk_pixbuf__png_image_begin_load;
module->save_to_callback = gdk_pixbuf__png_image_save_to_callback;
}
-void
-MODULE_ENTRY (png, fill_info) (GdkPixbufFormat *info)
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
{
static GdkPixbufModulePattern signature[] = {
{ "\x89PNG\r\n\x1a\x0a", NULL, 100 },