[gdk-pixbuf] Add PNG image density metadata support
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gdk-pixbuf] Add PNG image density metadata support
- Date: Wed, 22 Oct 2014 15:38:22 +0000 (UTC)
commit 299b0219f20b99d8de4e9ca634b4df0133246b1b
Author: Robert Ancell <robert ancell canonical com>
Date: Wed Oct 22 10:56:47 2014 -0400
Add PNG image density metadata support
https://bugzilla.gnome.org/show_bug.cgi?id=466372
gdk-pixbuf/gdk-pixbuf-io.c | 2 +-
gdk-pixbuf/gdk-pixbuf.c | 4 +-
gdk-pixbuf/io-png.c | 67 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 70 insertions(+), 3 deletions(-)
---
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index 43d283f..e197acf 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -2358,7 +2358,7 @@ gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf,
*
* Currently only few parameters exist. JPEG images can be saved with a
* "quality" parameter; its value should be in the range [0,100]. JPEG
- * density can be set by setting the "x-dpi" and "y-dpi" parameters
+ * and PNG density can be set by setting the "x-dpi" and "y-dpi" parameters
* to the appropriate values in dots per inch.
*
* Text chunks can be attached to PNG images by specifying parameters of
diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c
index feeb605..9f127ae 100644
--- a/gdk-pixbuf/gdk-pixbuf.c
+++ b/gdk-pixbuf/gdk-pixbuf.c
@@ -897,8 +897,8 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf,
* return an "orientation" option string that corresponds to the embedded
* TIFF/Exif orientation tag (if present). Since 2.32, the TIFF loader sets
* the "multipage" option string to "yes" when a multi-page TIFF is loaded.
- * Since 2.32 the JPEG loader sets "x-dpi" and "y-dpi" if the file contains
- * image density information in dots per inch.
+ * Since 2.32 the JPEG and PNG loaders set "x-dpi" and "y-dpi" if the file
+ * contains image density information in dots per inch.
*
* 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.
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index ae0fafe..35708e9 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -26,10 +26,14 @@
#include <stdlib.h>
#include <string.h>
#include <png.h>
+#include <math.h>
#include "gdk-pixbuf-private.h"
+#define DPI_TO_DPM(value) ((int) round ((value) * 1000 / 25.4))
+#define DPM_TO_DPI(value) ((int) round ((value) * 25.4 / 1000))
+
static gboolean
setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr,
GError **error,
@@ -260,6 +264,10 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error)
const gchar *icc_profile_title;
const gchar *icc_profile;
png_uint_32 icc_profile_size;
+ png_uint_32 x_resolution;
+ png_uint_32 y_resolution;
+ int unit_type;
+ gchar *density_str;
guint32 retval;
gint compression_type;
@@ -348,6 +356,18 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error)
}
#endif
+#ifdef PNG_pHYs_SUPPORTED
+ retval = png_get_pHYs (png_ptr, info_ptr, &x_resolution, &y_resolution, &unit_type);
+ if (retval != 0 && unit_type == PNG_RESOLUTION_METER) {
+ density_str = g_strdup_printf ("%d", DPM_TO_DPI (x_resolution));
+ gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
+ g_free (density_str);
+ density_str = g_strdup_printf ("%d", DPM_TO_DPI (y_resolution));
+ gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
+ g_free (density_str);
+ }
+#endif
+
g_free (rows);
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
@@ -844,6 +864,8 @@ static gboolean real_save_png (GdkPixbuf *pixbuf,
int bpc;
int num_keys;
int compression = -1;
+ int x_density = 0;
+ int y_density = 0;
gboolean success = TRUE;
guchar *icc_profile = NULL;
gsize icc_profile_size = 0;
@@ -917,6 +939,46 @@ static gboolean real_save_png (GdkPixbuf *pixbuf,
success = FALSE;
goto cleanup;
}
+ } else if (strcmp (*kiter, "x-dpi") == 0) {
+ char *endptr = NULL;
+ x_density = strtol (*viter, &endptr, 10);
+ if (endptr == *viter)
+ x_density = -1;
+
+ if (x_density <= 0) {
+ /* This is a user-visible error;
+ * lets people skip the range-checking
+ * in their app.
+ */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("PNG x-dpi must be greater than zero; value '%s' is
not allowed."),
+ *viter);
+
+ success = FALSE;
+ goto cleanup;
+ }
+ } else if (strcmp (*kiter, "y-dpi") == 0) {
+ char *endptr = NULL;
+ y_density = strtol (*viter, &endptr, 10);
+ if (endptr == *viter)
+ y_density = -1;
+
+ if (y_density <= 0) {
+ /* This is a user-visible error;
+ * lets people skip the range-checking
+ * in their app.
+ */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("PNG y-dpi must be greater than zero; value '%s' is
not allowed."),
+ *viter);
+
+ success = FALSE;
+ goto cleanup;
+ }
} else {
g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
}
@@ -1016,6 +1078,11 @@ static gboolean real_save_png (GdkPixbuf *pixbuf,
if (compression >= 0)
png_set_compression_level (png_ptr, compression);
+#ifdef PNG_pHYs_SUPPORTED
+ if (x_density > 0 && y_density > 0)
+ png_set_pHYs (png_ptr, info_ptr, DPI_TO_DPM (x_density), DPI_TO_DPM (y_density),
PNG_RESOLUTION_METER);
+#endif
+
#if defined(PNG_iCCP_SUPPORTED)
/* the proper ICC profile title is encoded in the profile */
if (icc_profile != NULL) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]