diff options
author | Sven Neumann <sven@gimp.org> | 2001-10-05 18:51:47 +0000 |
---|---|---|
committer | Sven Neumann <neo@src.gnome.org> | 2001-10-05 18:51:47 +0000 |
commit | 40c29264820f2cf1db0d6e2836ae827ef9a5d05c (patch) | |
tree | 3a0a76e969c1b154cc677d553371e7f08390a2b5 /gdk-pixbuf | |
parent | 58a5467a4529526a08ef570c8451bf4eef35df22 (diff) | |
download | gdk-pixbuf-40c29264820f2cf1db0d6e2836ae827ef9a5d05c.tar.gz |
gdk-pixbuf/gdk-pixbuf-io.c gdk-pixbuf/gdk-pixbuf-private.h
2001-10-05 Sven Neumann <sven@gimp.org>
* gdk-pixbuf/gdk-pixbuf-io.c
* gdk-pixbuf/gdk-pixbuf-private.h
* gdk-pixbuf/gdk-pixbuf.c
* gdk-pixbuf/gdk-pixbuf.h
* gdk-pixbuf/io-jpeg.c
* gdk-pixbuf/io-png.c: changed GDK_PIXBUF_ERROR_BAD_OPTION_VALUE to
GDK_PIXBUF_ERROR_BAD_OPTION to we can use it for bad keys too. Added
new public API gdk_pixbuf_get_option() to retrieve key/value pairs
set by an image loader. Added support for saving and reading PNG tEXt
chunks in PNG images.
* demos/testpixbuf-save.c
* demos/testpixbuf-scale.c: simple tests for the new PNG tEXt chunk
feature.
* gdk-pixbuf/tmpl/gdk-pixbuf.sgml: adapt to changes in GDK_PIXBUF_ERROR
enum.
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r-- | gdk-pixbuf/ChangeLog | 13 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 13 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-private.h | 10 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf.c | 88 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf.h | 10 | ||||
-rw-r--r-- | gdk-pixbuf/io-jpeg.c | 4 | ||||
-rw-r--r-- | gdk-pixbuf/io-png.c | 160 |
7 files changed, 269 insertions, 29 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index bb93b87d8..5f40de330 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,16 @@ +2001-10-05 Sven Neumann <sven@gimp.org> + + * gdk-pixbuf/gdk-pixbuf-io.c + * gdk-pixbuf/gdk-pixbuf-private.h + * gdk-pixbuf/gdk-pixbuf.c + * gdk-pixbuf/gdk-pixbuf.h + * gdk-pixbuf/io-jpeg.c + * gdk-pixbuf/io-png.c: changed GDK_PIXBUF_ERROR_BAD_OPTION_VALUE to + GDK_PIXBUF_ERROR_BAD_OPTION to we can use it for bad keys too. Added + new public API gdk_pixbuf_get_option() to retrieve key/value pairs + set by an image loader. Added support for saving and reading PNG tEXt + chunks in PNG images. + Tue Oct 2 11:29:50 2001 Owen Taylor <otaylor@redhat.com> * gdk-pixdata.c (gdk_pixdata_to_csource): Fix indentation diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index 5558ef657..e97036ac1 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -731,8 +731,8 @@ gdk_pixbuf_real_save (GdkPixbuf *pixbuf, * @Varargs: list of key-value save options * * 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 - * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain. + * "png". If @error is set, FALSE will be returned. Possible errors include + * those 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 @@ -743,8 +743,13 @@ gdk_pixbuf_real_save (GdkPixbuf *pixbuf, * "quality", "100", NULL); * </programlisting> * - * The only save parameter that currently exists is the "quality" field - * for JPEG images; its value should be in the range [0,100]. + * Currently only few parameters exist. JPEG images can be saved with a + * "quality" parameter; its value should be in the range [0,100]. + * Text chunks can be attached to PNG images by specifying parameters of + * the form "tEXt::key", where key is an ASCII string of length 1-79. + * The values are UTF-8 encoded strings. Note however that PNG text + * chunks are stored in ISO-8859-1 encoding, so you can only set texts + * that can be represented in this encoding. * * Return value: whether an error was set **/ diff --git a/gdk-pixbuf/gdk-pixbuf-private.h b/gdk-pixbuf/gdk-pixbuf-private.h index 4393cbe33..db13af805 100644 --- a/gdk-pixbuf/gdk-pixbuf-private.h +++ b/gdk-pixbuf/gdk-pixbuf-private.h @@ -128,8 +128,16 @@ struct _GdkPixbufAnimationIterClass { const GTimeVal *current_time); }; - GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf); + + +/* key/value pairs that can be attached by the pixbuf loader */ + +gboolean gdk_pixbuf_set_option (GdkPixbuf *pixbuf, + const gchar *key, + const gchar *value); + + #endif diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c index 60750f4a0..17df45fc7 100644 --- a/gdk-pixbuf/gdk-pixbuf.c +++ b/gdk-pixbuf/gdk-pixbuf.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* GdkPixbuf library - Basic memory management * * Copyright (C) 1999 The Free Software Foundation @@ -479,6 +480,93 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf, } } + + +/** + * gdk_pixbuf_get_option: + * @pixbuf: a #GdkPixbuf + * @key: a nul-terminated string. + * + * Looks up @key in the list of options that may have been attached to the + * @pixbuf when it was loaded. + * + * Return value: the value associated with @key. This is a nul-terminated + * string that should not be freed or %NULL if @key was not found. + **/ +G_CONST_RETURN gchar * +gdk_pixbuf_get_option (GdkPixbuf *pixbuf, + const gchar *key) +{ + gchar **options; + gint i; + + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); + g_return_val_if_fail (key != NULL, NULL); + + options = g_object_get_qdata (G_OBJECT (pixbuf), + g_quark_from_static_string ("gdk_pixbuf_options")); + if (options) { + for (i = 0; options[2*i]; i++) { + if (strcmp (options[2*i], key) == 0) + return options[2*i+1]; + } + } + + return NULL; +} + +/** + * gdk_pixbuf_set_option: + * @pixbuf: a #GdkPixbuf + * @key: a nul-terminated string. + * @value: a nul-terminated string. + * + * Attaches a key/value pair as an option to a #GdkPixbuf. If %key already + * exists in the list of options attached to @pixbuf, the new value is + * ignored and %FALSE is returned. + * + * Return value: %TRUE on success. + **/ +gboolean +gdk_pixbuf_set_option (GdkPixbuf *pixbuf, + const gchar *key, + const gchar *value) +{ + GQuark quark; + gchar **options; + gint n = 0; + + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + quark = g_quark_from_static_string ("gdk_pixbuf_options"); + + options = g_object_get_qdata (G_OBJECT (pixbuf), quark); + + if (options) { + for (n = 0; options[2*n]; n++) { + if (strcmp (options[2*n], key) == 0) + return FALSE; + } + + g_object_steal_qdata (G_OBJECT (pixbuf), quark); + options = g_renew (gchar *, options, 2*(n+1) + 1); + } else { + options = g_new (gchar *, 3); + } + + options[2*n] = g_strdup (key); + options[2*n+1] = g_strdup (value); + options[2*n+2] = NULL; + + g_object_set_qdata_full (G_OBJECT (pixbuf), quark, + options, (GDestroyNotify) g_strfreev); + + return TRUE; +} + + /* Include the marshallers */ #include <glib-object.h> diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h index 7d274d9d7..d0263bdc2 100644 --- a/gdk-pixbuf/gdk-pixbuf.h +++ b/gdk-pixbuf/gdk-pixbuf.h @@ -85,8 +85,8 @@ typedef enum { 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, + /* bad option passed to save routine */ + GDK_PIXBUF_ERROR_BAD_OPTION, /* unsupported image type (sort of an ENOSYS) */ GDK_PIXBUF_ERROR_UNKNOWN_TYPE, /* unsupported operation (load, save) for image type */ @@ -286,6 +286,12 @@ gboolean gdk_pixbuf_animation_iter_advance (Gd const GTimeVal *current_time); + + +G_CONST_RETURN gchar * gdk_pixbuf_get_option (GdkPixbuf *pixbuf, + const gchar *key); + + #include <gdk-pixbuf/gdk-pixbuf-loader.h> #include <gdk-pixbuf/gdk-pixbuf-enum-types.h> diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c index f04c954f9..ec054dd2c 100644 --- a/gdk-pixbuf/io-jpeg.c +++ b/gdk-pixbuf/io-jpeg.c @@ -660,7 +660,7 @@ gdk_pixbuf__jpeg_image_save (FILE *f, if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_BAD_OPTION_VALUE, + GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."), *viter); @@ -675,7 +675,7 @@ gdk_pixbuf__jpeg_image_save (FILE *f, */ g_set_error (error, GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_BAD_OPTION_VALUE, + GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."), quality); diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c index f434e699d..b531a75d2 100644 --- a/gdk-pixbuf/io-png.c +++ b/gdk-pixbuf/io-png.c @@ -182,17 +182,39 @@ free_buffer (guchar *pixels, gpointer data) g_free (pixels); } +static gboolean +png_text_to_pixbuf_option (png_text text_ptr, + gchar **key, + gchar **value) +{ + *value = g_convert (text_ptr.text, -1, + "UTF-8", "ISO-8859-1", + NULL, NULL, NULL); + if (*value) { + *key = g_strconcat ("tEXt::", text_ptr.key, NULL); + return TRUE; + } else { + g_warning ("Couldn't convert tEXt chunk value to UTF-8."); + *key = NULL; + return FALSE; + } +} + /* Shared library entry point */ static GdkPixbuf * gdk_pixbuf__png_image_load (FILE *f, GError **error) { + GdkPixbuf *pixbuf; png_structp png_ptr; png_infop info_ptr, end_info; + png_textp text_ptr; gboolean failed = FALSE; gint i, ctype, bpp; png_uint_32 w, h; png_bytepp rows; guchar *pixels; + gint num_texts; + gchar **options = NULL; png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, error, @@ -255,17 +277,42 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error) rows[i] = pixels + i * w * bpp; png_read_image (png_ptr, rows); + + if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_texts)) { + options = g_new (gchar *, num_texts * 2); + for (i = 0; i < num_texts; i++) { + png_text_to_pixbuf_option (text_ptr[i], + options + 2*i, + options + 2*i + 1); + } + } png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); g_free (rows); if (ctype & PNG_COLOR_MASK_ALPHA) - return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, - w, h, w * 4, - free_buffer, NULL); + pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, + w, h, w * 4, + free_buffer, NULL); else - return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, FALSE, 8, - w, h, w * 3, - free_buffer, NULL); + pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, FALSE, 8, + w, h, w * 3, + free_buffer, NULL); + + if (options) { + for (i = 0; i < num_texts; i++) { + if (pixbuf) { + if (!gdk_pixbuf_set_option (pixbuf, + options[2*i], + options[2*i+1])) + g_warning ("Got multiple tEXt chunks for the same key."); + } + g_free (options[2*i]); + g_free (options[2*i+1]); + } + g_free (options); + } + + return pixbuf; } /* I wish these avoided the setjmp()/longjmp() crap in libpng instead @@ -501,6 +548,8 @@ png_info_callback (png_structp png_read_ptr, { LoadContext* lc; png_uint_32 width, height; + png_textp png_text_ptr; + int i, num_texts; int color_type; gboolean have_alpha = FALSE; gboolean failed = FALSE; @@ -538,7 +587,22 @@ png_info_callback (png_structp png_read_ptr, } return; } + + /* Extract tEXt chunks and attach them as pixbuf options */ + if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_texts)) { + for (i = 0; i < num_texts; i++) { + gchar *key, *value; + + if (png_text_to_pixbuf_option (png_text_ptr[i], + &key, &value)) { + gdk_pixbuf_set_option (lc->pixbuf, key, value); + g_free (key); + g_free (value); + } + } + } + /* Notify the client that we are ready to go */ if (lc->prepare_func) @@ -653,32 +717,76 @@ gdk_pixbuf__png_image_save (FILE *f, { png_structp png_ptr; png_infop info_ptr; + png_textp text_ptr = NULL; guchar *ptr; guchar *pixels; - int x, y, j; + int x, y; + int i, j; png_bytep row_ptr; png_bytep data; png_color_8 sig_bit; int w, h, rowstride; int has_alpha; int bpc; + int num_keys; + + num_keys = 0; if (keys && *keys) { - g_warning ("Bad option name '%s' passed to PNG saver", - *keys); - return FALSE; -#if 0 - gchar **kiter = keys; - gchar **viter = values; - - - while (*kiter) { - - ++kiter; - ++viter; + gchar **kiter; + gchar *key; + int len; + + for (kiter = keys; *kiter; kiter++) { + if (strncmp (*kiter, "tEXt::", 6) != 0) { + g_warning ("Bad option name '%s' passed to PNG saver", *kiter); + return FALSE; + } + key = *kiter + 6; + 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; + } + 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; + } + } + num_keys++; + } + } + + if (num_keys > 0) { + text_ptr = g_new0 (png_text, num_keys); + for (i = 0; i < num_keys; i++) { + text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[i].key = keys[i] + 6; + text_ptr[i].text = g_convert (values[i], -1, + "ISO-8859-1", "UTF-8", + NULL, &text_ptr[i].text_length, + NULL); + if (!text_ptr[i].text) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_BAD_OPTION, + _("Value for PNG tEXt chunk can not be converted to ISO-8859-1 encoding.")); + num_keys = i; + for (i = 0; i < num_keys; i++) + g_free (text_ptr[i].text); + g_free (text_ptr); + return FALSE; + } } -#endif } + data = NULL; bpc = gdk_pixbuf_get_bits_per_sample (pixbuf); @@ -704,7 +812,13 @@ gdk_pixbuf__png_image_save (FILE *f, png_destroy_write_struct (&png_ptr, (png_infopp) NULL); return FALSE; } + + if (num_keys > 0) { + png_set_text (png_ptr, info_ptr, text_ptr, num_keys); + } + 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, @@ -763,6 +877,12 @@ gdk_pixbuf__png_image_save (FILE *f, png_write_end (png_ptr, info_ptr); png_destroy_write_struct (&png_ptr, (png_infopp) NULL); + if (num_keys > 0) { + for (i = 0; i < num_keys; i++) + g_free (text_ptr[i].text); + g_free (text_ptr); + } + return TRUE; } |