summaryrefslogtreecommitdiff
path: root/gdk-pixbuf
diff options
context:
space:
mode:
authorSven Neumann <sven@gimp.org>2001-10-05 18:51:47 +0000
committerSven Neumann <neo@src.gnome.org>2001-10-05 18:51:47 +0000
commit40c29264820f2cf1db0d6e2836ae827ef9a5d05c (patch)
tree3a0a76e969c1b154cc677d553371e7f08390a2b5 /gdk-pixbuf
parent58a5467a4529526a08ef570c8451bf4eef35df22 (diff)
downloadgdk-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/ChangeLog13
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.c13
-rw-r--r--gdk-pixbuf/gdk-pixbuf-private.h10
-rw-r--r--gdk-pixbuf/gdk-pixbuf.c88
-rw-r--r--gdk-pixbuf/gdk-pixbuf.h10
-rw-r--r--gdk-pixbuf/io-jpeg.c4
-rw-r--r--gdk-pixbuf/io-png.c160
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;
}