[gdk-pixbuf] Add PNG image density metadata support



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]