diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index f8ce73d..816da9a 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -1902,6 +1902,25 @@ gdk_pixbuf_real_save_to_callback (GdkPixbuf         *pixbuf,
  * be specified using the "compression" parameter; it's value is in an
  * integer in the range of [0,9].
  *
+ * ICC profiles can also be attached to PNG images where the profile is known.
+ * The "color-profile" value should be the complete display ICC profile encoded
+ * into base64.
+ * The other parameters are optional, but reccomended, as decoding the profile
+ * is only supported on some applications. The other options are easy to obtain
+ * if the appplication is willing to depend on a CMS, such as lcms.
+ *
+ * <informalexample><programlisting>
+ * gdk_pixbuf_save (pixbuf, handle, "png", &amp;error,
+ *                  "color-profile", icc_profile,
+ *                  "color-title", "Acme Display Adaptor",
+ *                  "color-gamma", "2.2",
+ *                  "color-white", "0.145,0.245f",
+ *                  "color-red", "0.345,0.445f",
+ *                  "color-green", "0.545,0.645f",
+ *                  "color-blue", "0.745,0.145f",
+ *                  NULL);
+ * </programlisting></informalexample>
+ *
  * TIFF images recognize a "compression" option which acceps an integer value.
  * Among the codecs are 1 None, 2 Huffman, 5 LZW, 7 JPEG and 8 Deflate, see
  * the libtiff documentation and tiff.h for all supported codec values.
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index eecdd0f..6c90cee 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -782,6 +782,30 @@ png_save_to_callback_flush_func (png_structp png_ptr)
         ;
 }
 
+/* decodes "0.1234,0.56789" into two floating point numbers, aborting on error */
+static gboolean
+png_save_parse_xy_values (const gchar *value, gdouble *x, gdouble *y)
+{
+        gchar *endptr = NULL;
+
+        /* get first number */
+        *x = g_ascii_strtod (value, &endptr);
+        if (endptr == value)
+                return FALSE;
+
+        /* nothing left */
+        if (endptr == NULL)
+                return FALSE;
+
+        /* get second number, ignoring seporator */
+        value = endptr + 1;
+        *y = g_ascii_strtod (value, &endptr);
+        if (endptr == value)
+                return FALSE;
+
+        return TRUE;
+}
+
 static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                                gchar           **keys,
                                gchar           **values,
@@ -791,7 +815,7 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
                                GdkPixbufSaveFunc save_func,
                                gpointer          user_data)
 {
-       png_structp png_ptr;
+       png_structp png_ptr = NULL;
        png_infop info_ptr;
        png_textp text_ptr = NULL;
        guchar *ptr;
@@ -806,6 +830,18 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
        int num_keys;
        int compression = -1;
        gboolean success = TRUE;
+       guchar *color_profile = NULL;
+       gchar *color_title = NULL;
+       gsize color_profile_size = 0;
+       gdouble color_gamma = 0.0f;
+       gdouble color_white_x = 0.0f;
+       gdouble color_white_y = 0.0f;
+       gdouble color_red_x = 0.0f;
+       gdouble color_red_y = 0.0f;
+       gdouble color_green_x = 0.0f;
+       gdouble color_green_y = 0.0f;
+       gdouble color_blue_x = 0.0f;
+       gdouble color_blue_y = 0.0f;
        SaveToFunctionIoPtr to_callback_ioptr;
 
        num_keys = 0;
@@ -823,7 +859,8 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
                                                             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;
+                                       success = FALSE;
+                                       goto cleanup;
                                }
                                for (i = 0; i < len; i++) {
                                        if ((guchar) key[i] > 127) {
@@ -831,10 +868,140 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
                                                                     GDK_PIXBUF_ERROR,
                                                                     GDK_PIXBUF_ERROR_BAD_OPTION,
                                                                     _("Keys for PNG text chunks must be ASCII characters."));
-                                               return FALSE;
+                                               success = FALSE;
+                                               goto cleanup;
                                        }
                                }
                                num_keys++;
+                       } else if (strcmp (*kiter, "color-title") == 0) {
+                               int len;
+                               len = strlen (*viter);
+                               if (len <= 1 || len > 79) {
+                                       g_set_error_literal (error,
+                                                            GDK_PIXBUF_ERROR,
+                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                            _("Titles for color profiles must have at least 1 and at most 79 characters."));
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               color_title = g_strdup (*viter);
+                       } else if (strcmp (*kiter, "color-profile") == 0) {
+                               /* decode from base64 */
+                               color_profile = g_base64_decode (*viter, &color_profile_size);
+                               if (color_profile_size < 127) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Color profile has invalid length '%d'."),
+                                                    color_profile_size);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "color-gamma") == 0) {
+                               color_gamma = atof (*viter);
+                               if (color_gamma < 0.1f || color_gamma > 5.0f) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Color gamma must be a value between 0.1 and 5.0; value '%f' is not allowed."),
+                                                    color_gamma);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "color-white") == 0) {
+                               success = png_save_parse_xy_values (*viter, &color_white_x, &color_white_y);
+                               if (!success) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Could not parse white point, must be formatted '0.8,0.8'; value '%s' is not allowed."),
+                                                    *viter);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               if (color_white_x < 0.0f || color_white_x > 0.8f ||
+                                   color_white_y < 0.0f || color_white_y > 0.8f) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("White point must be a value between 0.0 and 0.8; value '%f' is not allowed."),
+                                                    color_white_x);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "color-red") == 0) {
+                               success = png_save_parse_xy_values (*viter, &color_red_x, &color_red_y);
+                               if (!success) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Could not parse red point, must be formatted '0.8,0.8'; value '%s' is not allowed."),
+                                                    *viter);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               if (color_red_x < 0.0f || color_red_x > 0.8f ||
+                                   color_red_y < 0.0f || color_red_y > 0.8f) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("red point must be a value between 0.0 and 0.8; value '%f' is not allowed."),
+                                                    color_red_x);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "color-green") == 0) {
+                               success = png_save_parse_xy_values (*viter, &color_green_x, &color_green_y);
+                               if (!success) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Could not parse green point, must be formatted '0.8,0.8'; value '%s' is not allowed."),
+                                                    *viter);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               if (color_green_x < 0.0f || color_green_x > 0.8f ||
+                                   color_green_y < 0.0f || color_green_y > 0.8f) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("green point must be a value between 0.0 and 0.8; value '%f' is not allowed."),
+                                                    color_green_x);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "color-blue") == 0) {
+                               success = png_save_parse_xy_values (*viter, &color_blue_x, &color_blue_y);
+                               if (!success) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Could not parse blue point, must be formatted '0.8,0.8'; value '%s' is not allowed."),
+                                                    *viter);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               if (color_blue_x < 0.0f || color_blue_x > 0.8f ||
+                                   color_blue_y < 0.0f || color_blue_y > 0.8f) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("blue point must be a value between 0.0 and 0.8; value '%f' is not allowed."),
+                                                    color_blue_x);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
                        } else if (strcmp (*kiter, "compression") == 0) {
                                char *endptr = NULL;
                                compression = strtol (*viter, &endptr, 10);
@@ -845,7 +1012,8 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
                                                     GDK_PIXBUF_ERROR_BAD_OPTION,
                                                     _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
                                                     *viter);
-                                       return FALSE;
+                                       success = FALSE;
+                                       goto cleanup;
                                }
                                if (compression < 0 || compression > 9) {
                                        /* This is a user-visible error;
@@ -857,7 +1025,8 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
                                                     GDK_PIXBUF_ERROR_BAD_OPTION,
                                                     _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
                                                     compression);
-                                       return FALSE;
+                                       success = FALSE;
+                                       goto cleanup;
                                }
                        } else {
                                g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
@@ -947,6 +1116,35 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
        if (compression >= 0)
                png_set_compression_level (png_ptr, compression);
 
+#if defined(PNG_gAMA_SUPPORTED)
+        if (color_gamma >= 0.0f) {
+                png_set_gAMA (png_ptr, info_ptr, color_gamma);
+        }
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+        if (color_white_x > 0.0f) {
+                png_set_cHRM (png_ptr, info_ptr,
+                              color_white_x, color_white_y,
+                              color_red_x, color_red_y,
+                              color_green_x, color_green_y,
+                              color_blue_x, color_blue_y);
+       }
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+        if (color_profile != NULL) {
+
+                /* fallback to a default value if this is not provided */
+                if (color_title == NULL)
+                        color_title = g_strdup ("display ICC profile");
+
+                png_set_iCCP (png_ptr, info_ptr,
+                              color_title, PNG_COMPRESSION_TYPE_BASE,
+                              (gchar*) color_profile, color_profile_size);
+        }
+#endif
+
        if (has_alpha) {
                png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                              PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
@@ -975,13 +1173,16 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
        png_write_end (png_ptr, info_ptr);
 
 cleanup:
-       png_destroy_write_struct (&png_ptr, &info_ptr);
+        if (png_ptr != NULL)
+                png_destroy_write_struct (&png_ptr, &info_ptr);
 
-       if (num_keys > 0) {
-               for (i = 0; i < num_keys; i++)
-                       g_free (text_ptr[i].text);
-               g_free (text_ptr);
-       }
+        g_free (color_profile);
+
+        if (text_ptr != NULL) {
+                for (i = 0; i < num_keys; i++)
+                        g_free (text_ptr[i].text);
+                g_free (text_ptr);
+        }
 
        return success;
 }
