diff --git a/demos/Makefile.am b/demos/Makefile.am
index c8c9bbb..81e07f4 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -24,6 +24,7 @@ LDADDS = 								\
 noinst_PROGRAMS = 		\
 	testpixbuf-drawable 	\
 	testanimation 		\
+	testpixbuf-color	\
 	testpixbuf-save		\
 	testpixbuf-scale 	\
 	pixbuf-demo
@@ -52,6 +53,7 @@ test-inline-pixbufs.h: $(pixbuf_csource_deps) apple-red.png gnome-foot.png
 testpixbuf_DEPENDENCIES = $(DEPS)
 testpixbuf_drawable_DEPENDENCIES = $(DEPS)
 testpixbuf_save_DEPENDENCIES = $(DEPS)
+testpixbuf_color_DEPENDENCIES = $(DEPS)
 testpixbuf_scale_DEPENDENCIES = $(DEPS)
 testanimation_DEPENDENCIES = $(DEPS)
 pixbuf_demo_DEPENDENCIES = $(DEPS)
@@ -59,6 +61,7 @@ pixbuf_demo_DEPENDENCIES = $(DEPS)
 testpixbuf_LDADD = $(LDADDS)
 testpixbuf_drawable_LDADD = $(LDADDS)
 testpixbuf_save_LDADD = $(LDADDS)
+testpixbuf_color_LDADD = $(LDADDS)
 testpixbuf_scale_LDADD = $(LDADDS)
 testanimation_LDADD = $(LDADDS)
 pixbuf_demo_LDADD = $(LDADDS)
@@ -66,6 +69,7 @@ pixbuf_demo_LDADD = $(LDADDS)
 testpixbuf_SOURCES = testpixbuf.c pixbuf-init.c
 testpixbuf_drawable_SOURCES = testpixbuf-drawable.c pixbuf-init.c
 testpixbuf_save_SOURCES = testpixbuf-save.c
+testpixbuf_color_SOURCES = testpixbuf-color.c
 testpixbuf_scale_SOURCES = testpixbuf-scale.c pixbuf-init.c
 testanimation_SOURCES = testanimation.c pixbuf-init.c
 pixbuf_demo_SOURCES = pixbuf-demo.c pixbuf-init.c
diff --git a/demos/testpixbuf-color.c b/demos/testpixbuf-color.c
new file mode 100644
index 0000000..31e9687
--- /dev/null
+++ b/demos/testpixbuf-color.c
@@ -0,0 +1,136 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#define ICC_PROFILE     "/usr/share/color/icc/bluish.icc"
+
+/* all icc data */
+static gboolean
+save_image_good (const gchar *filename, GdkPixbuf *pixbuf, GError **error)
+{
+        gchar *contents = NULL;
+        gchar *contents_encode = NULL;
+        gsize length;
+        gboolean ret;
+        gint len;
+
+        /* get icc file */
+        ret = g_file_get_contents (ICC_PROFILE, &contents, &length, error);
+        if (!ret)
+                goto out;
+        contents_encode = g_base64_encode ((const guchar *) contents, length);
+        ret = gdk_pixbuf_save (pixbuf, filename, "png", error,
+                               "tEXt::Software", "Hello my name is dave",
+                               "color-profile", contents_encode,
+                               "color-title", "Acme Display Adaptor",
+                               NULL);
+        len = strlen (contents_encode);
+        g_debug ("ICC profile was %i bytes", len);
+out:
+        g_free (contents);
+        g_free (contents_encode);
+        return ret;
+}
+
+/* bad title */
+static gboolean
+save_image_invalid_title (const gchar *filename, GdkPixbuf *pixbuf, GError **error)
+{
+        gboolean ret;
+        ret = gdk_pixbuf_save (pixbuf, filename, "png", error,
+                               "color-title", "Acme  Display Adaptor",
+                               NULL);
+        return ret;
+}
+
+/* all icc data */
+static gboolean
+save_image_verify (const gchar *filename, GError **error)
+{
+        gboolean ret = FALSE;
+        GdkPixbuf *pixbuf = NULL;
+        const gchar *option;
+        gint len;
+
+        /* load */
+        pixbuf = gdk_pixbuf_new_from_file (filename, error);
+        if (pixbuf == NULL)
+                goto out;
+
+        /* check values */
+        option = gdk_pixbuf_get_option (pixbuf, "color-profile");
+        len = strlen (option);
+        if (len != 5288) {
+                *error = g_error_new (1, 0, "profile length invalid, got %i", len);
+                goto out;
+        }
+        option = gdk_pixbuf_get_option (pixbuf, "color-title");
+        if (g_strcmp0 (option, "Acme Display Adaptor") != 0) {
+                *error = g_error_new (1, 0, "profile title invalid, got %s", option);
+                goto out;
+        }
+
+        /* success */
+        ret = TRUE;
+out:
+        if (pixbuf != NULL)
+                g_object_unref (pixbuf);
+        return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+        GdkWindow *root;
+        GdkPixbuf *pixbuf;
+        gboolean ret;
+        gint retval = 1;
+        GError *error = NULL;
+
+        gtk_init (&argc, &argv);
+
+        gtk_widget_set_default_colormap (gdk_rgb_get_colormap ());
+
+        root = gdk_get_default_root_window ();
+        pixbuf = gdk_pixbuf_get_from_drawable (NULL, root, NULL,
+                                               0, 0, 0, 0, 150, 160);
+
+        /* PASS */
+        g_debug ("try to save with a profile");
+        ret = save_image_good ("color-profile.png", pixbuf, &error);
+        if (!ret) {
+                g_warning ("FAILED: did not save image: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* FAIL */
+        g_debug ("try to save with invalid profile title");
+        ret = save_image_invalid_title ("color-bad.png", pixbuf, &error);
+        if (!ret) {
+                g_debug ("PASSED: did not save bad image: %s", error->message);
+                g_clear_error (&error);
+        } else {
+                g_warning ("FAILED: did not fail");
+                goto out;
+        }
+
+        /* PASS */
+        g_debug ("try to load filename and get color attributes");
+        ret = save_image_verify ("color-profile.png", &error);
+        if (!ret) {
+                g_warning ("FAILED: did not load image: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* success */
+        retval = 0;
+        g_debug ("ALL OKAY!");
+out:
+        return retval;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index f8ce73d..f0a378d 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -1902,6 +1902,46 @@ 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 color profiles can also be embedded into PNG images.
+ * The "color-profile" value should be the complete ICC profile encoded
+ * into base64.
+ *
+ * <informalexample><programlisting>
+ * gchar *contents;
+ * gchar *contents_encode;
+ * gsize length;
+ * g_file_get_contents ("/home/hughsie/.color/icc/L225W.icm", &contents, &length, NULL);
+ * contents_encode = g_base64_encode ((const guchar *) contents, length);
+ * gdk_pixbuf_save (pixbuf, handle, "png", &amp;error,
+ *                  "color-profile", contents_encode,
+ *                  "color-title", "Acme Display Adaptor",
+ *                  NULL);
+ * </programlisting></informalexample>
+ *
+ * The following program listing shows how to get the profile description easily
+ * from lcms.
+ *
+ * <informalexample><programlisting>
+ * #include <lcms.h>
+ * {
+ * cmsHPROFILE lcms_profile;
+ * const gchar *color_title;
+ * lcms_profile = cmsOpenProfileFromMem ((LPVOID)contents, length);
+ * if (lcms_profile == NULL)
+ * 	g_error ("failed to load: not an ICC profile");
+ * color_title = cmsTakeProductName (lcms_profile);
+ * gdk_pixbuf_save (pixbuf, handle, "png", &amp;error,
+ *                  "color-profile", contents_encode,
+ *                  "color-title", color_title,
+ *                  NULL);
+ * cmsCloseProfile (lcms_profile);
+ * }
+ * </programlisting></informalexample>
+ *
+ * Care must be taken with the color-title string, as this has to be less than
+ * 80 characters in length, and can contain only printable Latin-1 characters
+ * and spaces. Leading, trailing, and consecutive spaces are also not permitted.
+ *
  * 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..ae7b603 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -258,6 +258,12 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error)
         gint    num_texts;
         gchar *key;
         gchar *value;
+        gchar *color_profile_base64 = NULL;
+        const gchar *color_title;
+        const gchar *color_profile;
+        guint color_profile_size;
+        guint32 retval;
+        gint compression_type;
 
 #ifdef PNG_USER_MEM_SUPPORTED
 	png_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
@@ -332,6 +338,18 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error)
                 }
         }
 
+#if defined(PNG_cHRM_SUPPORTED)
+        retval = png_get_iCCP (png_ptr, info_ptr,
+                               (png_charpp) &color_title, &compression_type,
+                               (png_charpp) &color_profile, (png_uint_32*) &color_profile_size);
+        if (retval != 0) {
+                gdk_pixbuf_set_option (pixbuf, "color-title", color_title);
+                color_profile_base64 = g_base64_encode ((const guchar *) color_profile, color_profile_size);
+                gdk_pixbuf_set_option (pixbuf, "color-profile", color_profile_base64);
+        }
+#endif
+
+        g_free (color_profile_base64);
 	g_free (rows);
 	png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
 
@@ -782,6 +800,44 @@ png_save_to_callback_flush_func (png_structp png_ptr)
         ;
 }
 
+static gboolean
+png_check_profile_title (const gchar *title)
+{
+        gint len;
+        guint i;
+
+        /* it has to have a title */
+        if (title == NULL)
+                return FALSE;
+
+        /* has to be < 79 chars */
+        len = strlen (title);
+        if (len <= 1 || len > 79)
+                return FALSE;
+
+        /* check for non latin-1 chars */
+        for (i=0; i<len; i++) {
+                if (title[i] < 32 ||
+                    (title[i] > 126 && title[i] < 161))
+                        return FALSE;
+        }
+
+        /* check for leading or trailing spaces */
+        if (title[i] == ' ' || title[len-1] == ' ')
+                return FALSE;
+
+        /* check for consecutive spaces */
+        for (i=1; i<len; i++) {
+                if (title[i] != ' ')
+                        continue;
+                if (title[i] == title[i-1])
+                        return FALSE;
+        }
+
+        /* all okay */
+        return TRUE;
+}
+
 static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                                gchar           **keys,
                                gchar           **values,
@@ -791,7 +847,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 +862,9 @@ 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;
        SaveToFunctionIoPtr to_callback_ioptr;
 
        num_keys = 0;
@@ -823,7 +882,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 +891,37 @@ 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) {
+                               gboolean ret;
+                               ret = png_check_profile_title (*viter);
+                               if (!ret) {
+                                       g_set_error_literal (error,
+                                                            GDK_PIXBUF_ERROR,
+                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                            _("Profile names shall be less than 80 characters, and can contain only printable Latin-1 characters and spaces."
+                                                              "Leading, trailing, and consecutive spaces are not permitted."));
+                                       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, "compression") == 0) {
                                char *endptr = NULL;
                                compression = strtol (*viter, &endptr, 10);
@@ -845,7 +932,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 +945,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 +1036,19 @@ static gboolean real_save_png (GdkPixbuf        *pixbuf,
        if (compression >= 0)
                png_set_compression_level (png_ptr, compression);
 
+#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 ("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 +1077,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;
 }
