Re: patch for gdk-pixbuf to read and write PNG tEXt chunks
- From: Sven Neumann <sven gimp org>
- To: Gtk+ Developers <gtk-devel-list gnome org>
- Cc: Jens Finke <jens triq net>
- Subject: Re: patch for gdk-pixbuf to read and write PNG tEXt chunks
- Date: 20 Sep 2001 12:27:00 +0200
Hi,
following up to myself, here's a reworked patch. It features better cleanup
on error, adds the proposed "tEXt::" prefix to the gdk_pixbuf_save parameters
and to the gobject data and gives some info about the new PNG parameter in
the inline docs.
There is one issue that I'm still unsure about: When a wrong parameter is
passed to the PNG saver it gives a warning and returns FALSE without setting
GError. This leads to a segfault later. I've copied this code from the
JPEG save routine, so if this is considered the wrong behaviour, we should
fix it in other places too. We'd probably need a new GDK_PIXBUF_ERROR value
then (GDK_PIXBUF_ERROR_BAD_OPTION ?!).
Salut, Sven
Index: gdk-pixbuf/gdk-pixbuf-io.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.c,v
retrieving revision 1.60
diff -u -r1.60 gdk-pixbuf-io.c
--- gdk-pixbuf/gdk-pixbuf-io.c 2001/09/14 22:04:55 1.60
+++ gdk-pixbuf/gdk-pixbuf-io.c 2001/09/20 10:17:59
@@ -731,8 +731,8 @@
* @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,11 @@
* "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 being strings.
*
* Return value: whether an error was set
**/
Index: gdk-pixbuf/io-png.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-png.c,v
retrieving revision 1.41
diff -u -r1.41 io-png.c
--- gdk-pixbuf/io-png.c 2001/08/30 07:21:13 1.41
+++ gdk-pixbuf/io-png.c 2001/09/20 10:17:59
@@ -186,13 +186,17 @@
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_text = 0;
+ gchar **texts = NULL;
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
error,
@@ -255,17 +259,43 @@
rows[i] = pixels + i * w * bpp;
png_read_image (png_ptr, rows);
+
+ if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_text)) {
+ texts = g_new (gchar*, 2 * num_text);
+ for (i = 0; i < num_text; i++) {
+ texts[2*i] = g_strconcat ("tEXt::", text_ptr[i].key, NULL);
+ texts[2*i+1] = g_strdup (text_ptr[i].text);
+ }
+ }
+
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);
+
+ /* Attach tEXt chunks as object data */
+
+ if (pixbuf) {
+ for (i = 0; i < num_text; i++) {
+ g_object_set_data_full (G_OBJECT (pixbuf),
+ texts[2*i], texts[2*i+1],
+ (GDestroyNotify) g_free);
+ g_free (texts[2*i]);
+ }
+ } else {
+ for (i = 0; i < 2*num_text; i++)
+ g_free (texts[i]);
+ }
+ g_free (texts);
+
+ return pixbuf;
}
/* I wish these avoided the setjmp()/longjmp() crap in libpng instead
@@ -501,7 +531,10 @@
{
LoadContext* lc;
png_uint_32 width, height;
+ png_textp png_text_ptr;
+ int num_text, i;
int color_type;
+ gchar *key;
gboolean have_alpha = FALSE;
gboolean failed = FALSE;
@@ -538,7 +571,20 @@
}
return;
}
+
+ /* Extract tEXt chunks and attach them as object data */
+ if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_text)) {
+ for (i = 0; i < num_text; i++) {
+ key = g_strconcat ("tEXt::", png_text_ptr[i].key, NULL);
+ g_object_set_data_full (G_OBJECT (lc->pixbuf),
+ key,
+ g_strdup (png_text_ptr[i].text),
+ (GDestroyNotify) g_free);
+ g_free (key);
+ }
+ }
+
/* Notify the client that we are ready to go */
if (lc->prepare_func)
@@ -653,6 +699,7 @@
{
png_structp png_ptr;
png_infop info_ptr;
+ png_textp text_ptr = NULL;
guchar *ptr;
guchar *pixels;
int x, y, j;
@@ -662,23 +709,30 @@
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;
+ int len;
+
+ for (kiter = keys; *kiter; kiter++) {
+ len = strlen (*kiter);
+ if (len < 6 || strncmp (*kiter, "tEXt::", 6)) {
+ g_warning ("Bad option name '%s' passed to PNG saver",
+ *kiter);
+ return FALSE;
+ }
+ len -= 6;
+ if (len < 1 || len > 79) {
+ g_warning ("tEXt keys passed as option to PNG saver must be of length 1-79");
+ return FALSE;
+ }
+ num_keys++;
}
-#endif
}
+
data = NULL;
bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
@@ -704,7 +758,21 @@
png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
return FALSE;
}
+
+ if (num_keys > 0) {
+ text_ptr = g_new0 (png_text, num_keys);
+ for (j = 0; j < num_keys; j++) {
+ text_ptr[j].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[j].key = keys[j]+6;
+ text_ptr[j].text = values[j];
+ text_ptr[j].text_length = (values[j] ?
+ strlen (values[j]) : 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,
@@ -762,6 +830,9 @@
png_write_end (png_ptr, info_ptr);
png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+
+ if (num_keys > 0)
+ g_free (text_ptr);
return TRUE;
}
Index: demos/testpixbuf-save.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/testpixbuf-save.c,v
retrieving revision 1.7
diff -u -r1.7 testpixbuf-save.c
--- demos/testpixbuf-save.c 2001/09/07 21:49:33 1.7
+++ demos/testpixbuf-save.c 2001/09/20 10:17:59
@@ -35,7 +35,10 @@
return;
}
- if (!gdk_pixbuf_save (pixbuf, "foo.png", "png", &err, NULL)) {
+ if (!gdk_pixbuf_save (pixbuf, "foo.png", "png",
+ &err,
+ "tEXt::Software", "testpixbuf-save",
+ NULL)) {
fprintf (stderr, "%s", err->message);
g_error_free (err);
}
Index: demos/testpixbuf-scale.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/testpixbuf-scale.c,v
retrieving revision 1.11
diff -u -r1.11 testpixbuf-scale.c
--- demos/testpixbuf-scale.c 2001/08/23 15:26:44 1.11
+++ demos/testpixbuf-scale.c 2001/09/20 10:17:59
@@ -63,6 +63,7 @@
GtkWidget *hbox, *label, *hscale;
GtkAdjustment *adjustment;
GtkRequisition scratch_requisition;
+ const gchar *creator;
GError *error;
pixbuf_init ();
@@ -82,6 +83,11 @@
g_error_free (error);
exit(1);
}
+
+ creator = (const gchar *) g_object_get_data (G_OBJECT (pixbuf),
+ "tEXt::Software");
+ if (creator)
+ g_print ("%s was created by '%s'\n", argv[1], creator);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "destroy",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]