From 60e0183ac9a56fa0d05971a8cf90798053b430c7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 21 Dec 2009 08:53:28 +0000 Subject: [PATCH] Add icc-profile option to gdk-pixbuf for the TIFF image format --- demos/testpixbuf-color.c | 43 +++++++++++++++++++++++++++ gdk-pixbuf/gdk-pixbuf-io.c | 2 +- gdk-pixbuf/io-tiff.c | 59 ++++++++++++++++++++++++++------------ 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/demos/testpixbuf-color.c b/demos/testpixbuf-color.c index b87d850a0..9eb4ec5e0 100644 --- a/demos/testpixbuf-color.c +++ b/demos/testpixbuf-color.c @@ -35,6 +35,31 @@ out: return ret; } +static gboolean +save_image_tiff (const gchar *filename, GdkPixbuf *pixbuf, GError **error) +{ + gchar *contents = NULL; + gchar *contents_encode = NULL; + gsize length; + gboolean ret; + gint len; + + /* get icc file */ + ret = g_file_get_contents (ICC_PROFILE, &contents, &length, error); + if (!ret) + goto out; + contents_encode = g_base64_encode ((const guchar *) contents, length); + ret = gdk_pixbuf_save (pixbuf, filename, "tiff", error, + "icc-profile", contents_encode, + NULL); + len = strlen (contents_encode); + g_debug ("ICC profile was %i bytes", len); +out: + g_free (contents); + g_free (contents_encode); + return ret; +} + static gboolean save_image_verify (const gchar *filename, GError **error) { @@ -99,6 +124,15 @@ main (int argc, char **argv) goto out; } + /* PASS */ + g_debug ("try to save TIFF with a profile"); + ret = save_image_tiff ("icc-profile.tiff", pixbuf, &error); + if (!ret) { + g_warning ("FAILED: did not save image: %s", error->message); + g_error_free (error); + goto out; + } + /* PASS */ g_debug ("try to load PNG and get color attributes"); ret = save_image_verify ("icc-profile.png", &error); @@ -108,6 +142,15 @@ main (int argc, char **argv) goto out; } + /* PASS */ + g_debug ("try to load TIFF and get color attributes"); + ret = save_image_verify ("icc-profile.tiff", &error); + if (!ret) { + g_warning ("FAILED: did not load image: %s", error->message); + g_error_free (error); + goto out; + } + /* success */ retval = 0; g_debug ("ALL OKAY!"); diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index ed765ed40..205ff5686 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -1902,7 +1902,7 @@ gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf, * be specified using the "compression" parameter; it's value is in an * integer in the range of [0,9]. * - * ICC color profiles can also be embedded into PNG images. + * ICC color profiles can also be embedded into PNG and TIFF images. * The "icc-profile" value should be the complete ICC profile encoded * into base64. * diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c index 7f8b79318..221bcac62 100644 --- a/gdk-pixbuf/io-tiff.c +++ b/gdk-pixbuf/io-tiff.c @@ -150,6 +150,10 @@ tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error) uint16 orientation = 0; uint16 transform = 0; uint16 codec; + gchar *icc_profile_base64; + const gchar *icc_profile; + guint icc_profile_size; + gint retval; /* We're called with the lock held. */ @@ -274,6 +278,14 @@ tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error) gdk_pixbuf_set_option (pixbuf, "compression", str); } + /* Extract embedded ICC profile */ + retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile); + if (retval == 1) { + 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); + } + if (context && context->prepare_func) (* context->prepare_func) (pixbuf, NULL, context->user_data); @@ -662,6 +674,8 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func, int y; TiffSaveContext *context; gboolean retval; + guchar *icc_profile = NULL; + gsize icc_profile_size = 0; tiff_push_handlers (); @@ -710,13 +724,22 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func, else { tiff_set_error (error, GDK_PIXBUF_ERROR_FAILED, - _("TIFF compression doesn't refer to a valid codec.")); - - tiff_pop_handlers (); - - free_save_context (context); - return FALSE; + _("TIFF compression doesn't refer to a valid codec.")); + retval = FALSE; + goto cleanup; } + } else if (g_str_equal (keys[i], "icc-profile")) { + /* decode from base64 */ + icc_profile = g_base64_decode (values[i], &icc_profile_size); + if (icc_profile_size < 127) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_BAD_OPTION, + _("Color profile has invalid length '%d'."), + icc_profile_size); + retval = FALSE; + goto cleanup; + } } i++; } @@ -729,6 +752,9 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func, TIFFSetField (tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField (tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + if (icc_profile != NULL) + TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile); + for (y = 0; y < height; y++) { if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1 || global_error) @@ -741,11 +767,8 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func, _("Failed to write TIFF data")); TIFFClose (tiff); - - free_save_context (context); - tiff_pop_handlers (); - - return FALSE; + retval = FALSE; + goto cleanup; } TIFFClose (tiff); @@ -753,20 +776,18 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func, tiff_set_error (error, GDK_PIXBUF_ERROR_FAILED, _("TIFFClose operation failed")); - - free_save_context (context); - tiff_pop_handlers (); - - return FALSE; + retval = FALSE; + goto cleanup; } - tiff_pop_handlers (); /* Now call the callback */ retval = save_func (context->buffer, context->used, error, user_data); - free_save_context (context); - +cleanup: + g_free (icc_profile); + tiff_pop_handlers (); + free_save_context (context); return retval; } -- 2.43.2