diff --git a/configure.in b/configure.in
index e835274..e41e5a1 100644
--- a/configure.in
+++ b/configure.in
@@ -1950,6 +1950,33 @@ AC_ARG_ENABLE(test-print-backend,
               [enable_test_print_backend=no])
 AM_CONDITIONAL(TEST_PRINT_BACKEND, test "x$enable_test_print_backend" != "xno")
 
+################################################################
+# CMS system checks
+################################################################
+
+AC_ARG_ENABLE(lcms,
+              [AC_HELP_STRING([--disable-lcms]
+                              [disable lcms color backend])],,
+              [enable_lcms=auto])
+
+if test "x$enable_lcms" = "xno"; then
+  AM_CONDITIONAL(HAVE_LCMS, false)
+else
+  PKG_CHECK_MODULES(LCMS, lcms, have_lcms=yes, have_lcms=no)
+  if test "x$have_lcms" = "xno"; then
+    if test "x$enable_lcms" = "xauto"; then
+      AM_CONDITIONAL(HAVE_LCMS, false)
+    else
+      AC_MSG_ERROR([
+*** lcms not found.
+])
+    fi
+  else
+    AC_SUBST(LCMS_CFLAGS)
+    AC_SUBST(LCMS_LIBS)
+    AM_CONDITIONAL(HAVE_LCMS, true)
+  fi
+fi
 
 ################################################################
 # Strip -export-dynamic from the link lines of various libraries
@@ -2148,6 +2175,8 @@ gtk/theme-bits/Makefile
 gtk/tests/Makefile
 modules/Makefile
 modules/other/Makefile
+modules/giomodules/Makefile
+modules/giomodules/lcms/Makefile
 modules/other/gail/Makefile
 modules/other/gail/libgail-util/Makefile
 modules/other/gail/tests/Makefile
diff --git a/demos/icc-profile-fish.png b/demos/icc-profile-fish.png
new file mode 100644
index 0000000..7f8b64b
Binary files /dev/null and b/demos/icc-profile-fish.png differ
diff --git a/demos/testpixbuf-color.c b/demos/testpixbuf-color.c
index 78fa939..9e68736 100644
--- a/demos/testpixbuf-color.c
+++ b/demos/testpixbuf-color.c
@@ -100,6 +100,77 @@ out:
 	return ret;
 }
 
+static gboolean
+transform_image (const gchar *filename, GError **error)
+{
+	GtkWidget *image_test;
+	GtkWidget *dialog;
+	GtkWidget *vbox;
+	gint response;
+	GdkPixbuf *pixbuf;
+	GtkColorEngine *engine = NULL;
+	GtkColorProfile *profile = NULL;
+	GtkColorTransform *transform = NULL;
+	gchar *icc_profile = NULL;
+	gsize len = 0;
+	gboolean ret;
+	const gchar *option;
+
+	image_test = gtk_image_new_from_file (filename);
+	pixbuf = gtk_image_get_pixbuf (GTK_IMAGE(image_test));
+
+	/* check values */
+	option = gdk_pixbuf_get_option (pixbuf, "icc-profile");
+	if (option == NULL) {
+		*error = g_error_new (1, 0, "no profile set");
+		goto out;
+	}
+
+	/* decode base64 */
+	icc_profile = (gchar *) g_base64_decode (option, &len);
+	if (len == 0) {
+		*error = g_error_new (1, 0, "no embedded profile");
+		goto out;
+	}
+
+        /* transform this image with the embedded profile */
+        engine = gtk_color_engine_get_default ();
+        profile = gtk_color_engine_create_profile (engine, (const guint8 *)icc_profile, len, error);
+        if (profile == NULL) {
+                ret = FALSE;
+                goto out;
+        }
+        transform = gtk_color_engine_create_transform_from_profiles (engine, profile, NULL);
+        ret = gtk_color_transform_apply_pixbuf_in_place (transform, pixbuf, error);
+        if (!ret)
+                goto out;
+
+	/* show in a dialog as an example */
+	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Are the fish yellow?");
+	vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+	gtk_box_pack_end (GTK_BOX(vbox), image_test, TRUE, TRUE, 12);
+	gtk_widget_set_size_request (GTK_WIDGET(image_test), 300, 300);
+	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+	gtk_widget_show (image_test);
+
+        /* ask the user to ensure the image was converted */
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	if (response != GTK_RESPONSE_YES) {
+		ret = FALSE;
+		*error = g_error_new (1, 0, "failed to convert fish");
+		goto out;
+	}
+out:
+        if (transform != NULL)
+                g_object_unref (transform);
+        if (profile != NULL)
+                g_object_unref (profile);
+        if (engine != NULL)
+                g_object_unref (engine);
+	g_free (icc_profile);
+	return ret;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -118,6 +189,15 @@ main (int argc, char **argv)
 					       0, 0, 0, 0, 150, 160);
 
 	/* PASS */
+	g_debug ("try to render color corrected image");
+	ret = transform_image ("icc-profile-fish.png", &error);
+	if (!ret) {
+		g_warning ("FAILED: did not load image: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* PASS */
 	g_debug ("try to save PNG with a profile");
 	ret = save_image_png ("icc-profile.png", pixbuf, &error);
 	if (!ret) {
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index c3d950f..9a0fab7 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -196,8 +196,11 @@ gtk_public_h_sources =          \
 	gtkcheckmenuitem.h	\
 	gtkclipboard.h		\
 	gtkcolorbutton.h	\
-	gtkcolorsel.h		\
+	gtkcolorengine.h	\
+	gtkcolorprofile.h	\
 	gtkcolorseldialog.h	\
+	gtkcolorsel.h		\
+	gtkcolortransform.h	\
 	gtkcombobox.h		\
 	gtkcomboboxentry.h	\
 	gtkcontainer.h		\
@@ -380,6 +383,7 @@ gtk_private_h_sources =		\
 	gtkfilesystem.h		\
 	gtkfilesystemmodel.h	\
 	gtkiconcache.h		\
+	gtkcolorenginefallback.h	\
 	gtkintl.h		\
 	gtkkeyhash.h		\
 	gtkmnemonichash.h	\
@@ -455,6 +459,10 @@ gtk_base_c_sources =            \
 	gtkcolorbutton.c	\
 	gtkcolorsel.c		\
 	gtkcolorseldialog.c	\
+	gtkcolorengine.c	\
+	gtkcolorprofile.c	\
+	gtkcolortransform.c	\
+	gtkcolorenginefallback.c	\
 	gtkcombobox.c		\
 	gtkcomboboxentry.c	\
 	gtkcontainer.c		\
diff --git a/gtk/gtk.h b/gtk/gtk.h
index bbeabae..d8b8015 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -67,8 +67,11 @@
 #include <gtk/gtkcheckmenuitem.h>
 #include <gtk/gtkclipboard.h>
 #include <gtk/gtkcolorbutton.h>
-#include <gtk/gtkcolorsel.h>
+#include <gtk/gtkcolorengine.h>
+#include <gtk/gtkcolorprofile.h>
 #include <gtk/gtkcolorseldialog.h>
+#include <gtk/gtkcolorsel.h>
+#include <gtk/gtkcolortransform.h>
 #include <gtk/gtkcombobox.h>
 #include <gtk/gtkcomboboxentry.h>
 #include <gtk/gtkcontainer.h>
diff --git a/gtk/gtkcolorengine.c b/gtk/gtkcolorengine.c
new file mode 100644
index 0000000..b4f30ea
--- /dev/null
+++ b/gtk/gtkcolorengine.c
@@ -0,0 +1,212 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gtk-color-engine
+ * @short_description: Creates #GtkColorProfile and #GtkColorTransform objects
+ * @include: gtk/gtk.h
+ * @title: GtkColorEngine
+ * @see_also: #GtkColorProfile, #GtkColorTransform
+ *
+ * Color management is an important part of a modern desktop experience.
+ * It is basically the transformation of images between the color
+ * representations of various devices, such as cameras, scanners, displays
+ * and printers.
+ *
+ * The goal of a color management system is to obtain the best match across
+ * these different devices.
+ * This means that photgraphs taken on a digital camera should match as closely
+ * as possible what is observed on the computer screen and what is printed out
+ * on paper.
+ *
+ * Output devices may be capable of representing more or less colors than
+ * the input device, and part of the color management system is to define a
+ * rendering intent when mapping one device gamut to another.
+ *
+ * #GtkColorEngine is an object that manages the default color management system
+ * (CMS) which may or may not be installed as plugins.
+ * The #GtkColorEngine object automatically loads the default CMS the first time
+ * that it is required.
+ * If no CMM is available then a fallback is used, which does no color
+ * correction to the image whatsoever.
+ *
+ * A #GtkColorEngine allows the user to create a #GtkColorProfile objects using
+ * gtk_color_engine_create_profile(). Profiles are used to represent device
+ * colorspaces.
+ *
+ * A #GtkColorEngine also allows creation of #GtkColorTransform objects by using
+ * either gtk_color_engine_create_transform() or
+ * gtk_color_engine_create_transform_from_profiles().
+ * Transforms are used to represent the mapping of one colorspace to another.
+ *
+ * On way you can use #GtkColorEngine is the following code snippet, where a
+ * #GtkImage is being converted from one defined colorspace into the internal
+ * sRGB space.
+ * |[
+ *  GdkPixbuf *pixbuf;
+ *  GtkColorEngine *engine;
+ *  GtkColorProfile *profile;
+ *  GtkColorTransform *transform;
+ *  engine = gtk_color_engine_get_default ();
+ *  profile = gtk_color_engine_create_profile (engine, icc_profile, len, error);
+ *  transform = gtk_color_engine_create_transform_from_profiles (engine, profile, NULL);
+ *  pixbuf = gtk_image_get_pixbuf (image);
+ *  ret = gtk_color_transform_apply_pixbuf_in_place (transform, pixbuf, error);
+ *  g_object_unref (transform);
+ *  g_object_unref (profile);
+ * ]|
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "gtkprivate.h"
+#include "gtkcolorengine.h"
+#include "gtkcolorenginefallback.h"
+
+G_DEFINE_INTERFACE (GtkColorEngine, gtk_color_engine, G_TYPE_OBJECT)
+
+static void
+gtk_color_engine_default_init (GtkColorEngineInterface *iface)
+{
+}
+
+/**
+ * gtk_color_engine_create_transform:
+ * @color_engine: a #GtkColorEngine
+ *
+ * Gets a new transform from the engine, which allows you to modify an image.
+ * You will still need to call gtk_color_transform_set_input_profile() and/or
+ * gtk_color_transform_set_output_profile() before the transform will be useful.
+ *
+ * Return value: a new #GtkColorTransform instance, free with g_object_unref()
+ *
+ * Since: 2.20
+ **/
+GtkColorTransform *
+gtk_color_engine_create_transform (GtkColorEngine *color_engine)
+{
+  GtkColorEngineInterface *iface = GTK_COLOR_ENGINE_GET_IFACE (color_engine);
+
+  g_return_val_if_fail (GTK_IS_COLOR_ENGINE (color_engine), NULL);
+  g_return_val_if_fail ((*iface->create_transform) != NULL, NULL);
+
+  return (*iface->create_transform) (color_engine);
+}
+
+/**
+ * gtk_color_engine_create_transform_from_profiles:
+ * @color_engine: a #GtkColorEngine
+ * @input_profile: a #GtkColorProfile, or %NULL
+ * @output_profile: a #GtkColorProfile, or %NULL
+ *
+ * Gets a new transform from the engine which is preset with two profiles.
+ * This saves you calling gtk_color_engine_create_transform() and then
+ * gtk_color_transform_set_input_profile() and/or
+ * gtk_color_transform_set_output_profile().
+ *
+ * Return value: a new #GtkColorTransform instance, free with g_object_unref()
+ *
+ * Since: 2.20
+ **/
+GtkColorTransform *
+gtk_color_engine_create_transform_from_profiles (GtkColorEngine  *color_engine,
+                                                 GtkColorProfile *input_profile,
+                                                 GtkColorProfile *output_profile)
+{
+  GtkColorTransform *color_transform;
+
+  g_return_val_if_fail (GTK_IS_COLOR_ENGINE (color_engine), NULL);
+  g_return_val_if_fail (GTK_IS_COLOR_PROFILE (input_profile) || input_profile == NULL, NULL);
+  g_return_val_if_fail (GTK_IS_COLOR_PROFILE (output_profile) || output_profile == NULL, NULL);
+
+  color_transform = gtk_color_engine_create_transform (color_engine);
+  gtk_color_transform_set_input_profile (color_transform, input_profile);
+  gtk_color_transform_set_output_profile (color_transform, output_profile);
+  return color_transform;
+}
+
+/**
+ * gtk_color_engine_create_profile:
+ * @color_engine: a #GtkColorEngine
+ * @data: the COLOR engine data
+ * @length: the COLOR engine data
+ * @error: a %GError, or %NULL
+ *
+ * Creates a profile and loads ICC data.
+ *
+ * Return value: a #GtkColorProfile object, otherwise %NULL and @error is set.
+ *
+ * Since: 2.20
+ **/
+GtkColorProfile *
+gtk_color_engine_create_profile (GtkColorEngine *color_engine,
+                                 const guint8   *data,
+                                 gsize           length,
+                                 GError        **error)
+{
+  GtkColorProfile *color_profile;
+  GtkColorEngineInterface *iface = GTK_COLOR_ENGINE_GET_IFACE (color_engine);
+
+  g_return_val_if_fail (GTK_IS_COLOR_ENGINE (color_engine), FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+  g_return_val_if_fail ((*iface->create_profile) != NULL, NULL);
+
+  color_profile = (*iface->create_profile) (color_engine, data, length, error);
+  return color_profile;
+}
+
+static gpointer
+gtk_color_engine_get_default_cb (gpointer data)
+{
+  GIOExtensionPoint *ep;
+  GList *extensions;
+
+  _gtk_io_modules_ensure_loaded ();
+  ep = g_io_extension_point_lookup (GTK_COLOR_ENGINE_EXTENSION_POINT_NAME);
+  extensions = g_io_extension_point_get_extensions (ep);
+  if (extensions != NULL)
+    return g_object_new (g_io_extension_get_type (extensions->data), NULL);
+  return g_object_new (GTK_TYPE_COLOR_ENGINE_FALLBACK, NULL);
+}
+
+/**
+ * gtk_color_engine_get_default:
+ *
+ * Gets the default color engine. If no engines are installed then a fallback
+ * engine is used which just copies the image data without modification.
+ *
+ * Return value: a #GtkColorEngine
+ *
+ * Since: 2.20
+ **/
+GtkColorEngine *
+gtk_color_engine_get_default (void)
+{
+  static GOnce once_init = G_ONCE_INIT;
+  return g_once (&once_init, gtk_color_engine_get_default_cb, NULL);
+}
+
+
+#define __GTK_COLOR_ENGINE_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkcolorengine.h b/gtk/gtkcolorengine.h
new file mode 100644
index 0000000..7779731
--- /dev/null
+++ b/gtk/gtkcolorengine.h
@@ -0,0 +1,84 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_COLOR_ENGINE_H
+#define __GTK_COLOR_ENGINE_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "gtkcolorprofile.h"
+#include "gtkcolortransform.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_ENGINE               (gtk_color_engine_get_type ())
+#define GTK_COLOR_ENGINE(o)                 (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_ENGINE, GtkColorEngine))
+#define GTK_IS_COLOR_ENGINE(o)              (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_ENGINE))
+#define GTK_COLOR_ENGINE_GET_IFACE(obj)     (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_COLOR_ENGINE, GtkColorEngineInterface))
+
+typedef struct _GtkColorEngine            GtkColorEngine;
+typedef struct _GtkColorEngineInterface   GtkColorEngineInterface;
+
+#define GTK_COLOR_ENGINE_EXTENSION_POINT_NAME "gtk-color-engine"
+
+/**
+ * GtkColorEngineInterface:
+ * @g_iface: The parent interface.
+ * @create_profile: Creates a #GtkColorProfile.
+ * @create_transform: Creates a #GtkColorTransform.
+ *
+ * An interface for creating color profiles and transforms.
+ **/
+struct _GtkColorEngineInterface
+{
+  GTypeInterface g_iface;
+  /* Virtual Table */
+  GtkColorProfile     *(*create_profile)    (GtkColorEngine *color_engine,
+                                             const guint8   *data,
+                                             gsize           length,
+                                             GError        **error);
+  GtkColorTransform   *(*create_transform)  (GtkColorEngine *color_engine);
+
+};
+
+GType                   gtk_color_engine_get_type           (void) G_GNUC_CONST;
+GtkColorEngine         *gtk_color_engine_get_default        (void);
+
+/* new profile */
+GtkColorProfile        *gtk_color_engine_create_profile (GtkColorEngine    *color_engine,
+                                                         const guint8      *data,
+                                                         gsize              length,
+                                                         GError           **error);
+
+/* new transform */
+GtkColorTransform      *gtk_color_engine_create_transform                (GtkColorEngine    *color_engine);
+GtkColorTransform      *gtk_color_engine_create_transform_from_profiles  (GtkColorEngine    *color_engine,
+                                                                          GtkColorProfile   *input_profile,
+                                                                          GtkColorProfile   *output_profile);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_ENGINE_H */
+
diff --git a/gtk/gtkcolorenginefallback.c b/gtk/gtkcolorenginefallback.c
new file mode 100644
index 0000000..649fa21
--- /dev/null
+++ b/gtk/gtkcolorenginefallback.c
@@ -0,0 +1,138 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "gtkcolorenginefallback.h"
+
+static void gtk_color_engine_fallback_iface_init (GtkColorEngineInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkColorEngineFallback, gtk_color_engine_fallback, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_ENGINE,
+                                                gtk_color_engine_fallback_iface_init))
+
+G_DEFINE_TYPE (GtkColorProfileFallback, gtk_color_profile_fallback, GTK_TYPE_COLOR_PROFILE)
+G_DEFINE_TYPE (GtkColorTransformFallback, gtk_color_transform_fallback, GTK_TYPE_COLOR_TRANSFORM)
+
+static void
+gtk_color_engine_fallback_init (GtkColorEngineFallback *color_engine_fallback)
+{
+}
+
+static void
+gtk_color_engine_fallback_class_init (GtkColorEngineFallbackClass *klass)
+{
+}
+
+static GtkColorTransform *
+gtk_color_transform_fallback_create_profile (GtkColorEngine *color_engine)
+{
+  GtkColorTransformFallback *color_transform;
+  color_transform = g_object_new (GTK_TYPE_COLOR_TRANSFORM_FALLBACK, NULL);
+  return GTK_COLOR_TRANSFORM (color_transform);
+}
+
+/**
+ * gtk_color_profile_fallback_create_profile:
+ **/
+GtkColorProfile *
+gtk_color_profile_fallback_create_profile (GtkColorEngine *color_engine,
+                                           const guint8   *data,
+                                           gsize           length,
+                                           GError        **error)
+{
+  GtkColorProfileFallback *color_profile;
+  color_profile = g_object_new (GTK_TYPE_COLOR_PROFILE_FALLBACK, NULL);
+  return GTK_COLOR_PROFILE (color_profile);
+}
+
+static void
+gtk_color_engine_fallback_iface_init (GtkColorEngineInterface *iface)
+{
+  iface->create_profile = gtk_color_profile_fallback_create_profile;
+  iface->create_transform = gtk_color_transform_fallback_create_profile;
+}
+
+static void
+gtk_color_profile_fallback_class_init (GtkColorProfileFallbackClass *klass)
+{
+}
+
+static void
+gtk_color_profile_fallback_init (GtkColorProfileFallback *color_profile_fallback)
+{
+}
+
+static GdkPixbuf *
+gtk_color_transform_fallback_apply_pixbuf (GtkColorTransform *color_transform,
+                                           GdkPixbuf         *pixbuf,
+                                           GError           **error)
+{
+  return gdk_pixbuf_copy (pixbuf);
+}
+
+static gboolean
+gtk_color_transform_fallback_apply_pixbuf_in_place (GtkColorTransform *color_transform,
+                                                    GdkPixbuf         *pixbuf,
+                                                    GError           **error)
+{
+  /* this is a NOP */
+  return TRUE;
+}
+
+static cairo_surface_t *
+gtk_color_transform_fallback_apply_surface (GtkColorTransform *color_transform,
+                                            cairo_surface_t   *surface,
+                                            GError           **error)
+{
+  return cairo_surface_create_similar (surface,
+                                       cairo_surface_get_content (surface),
+                                       cairo_image_surface_get_width (surface),
+                                       cairo_image_surface_get_height (surface));
+}
+
+static gboolean
+gtk_color_transform_fallback_apply_surface_in_place (GtkColorTransform *color_transform,
+                                                     cairo_surface_t   *surface,
+                                                     GError           **error)
+{
+  /* this is a NOP */
+  return TRUE;
+}
+
+static void
+gtk_color_transform_fallback_class_init (GtkColorTransformFallbackClass *klass)
+{
+  GtkColorTransformClass *parent_class = GTK_COLOR_TRANSFORM_CLASS (klass);
+  parent_class->apply_pixbuf_in_place = gtk_color_transform_fallback_apply_pixbuf_in_place;
+  parent_class->apply_pixbuf = gtk_color_transform_fallback_apply_pixbuf;
+  parent_class->apply_surface_in_place = gtk_color_transform_fallback_apply_surface_in_place;
+  parent_class->apply_surface = gtk_color_transform_fallback_apply_surface;
+}
+
+static void
+gtk_color_transform_fallback_init (GtkColorTransformFallback *color_transform_fallback)
+{
+}
+
diff --git a/gtk/gtkcolorenginefallback.h b/gtk/gtkcolorenginefallback.h
new file mode 100644
index 0000000..e570a7a
--- /dev/null
+++ b/gtk/gtkcolorenginefallback.h
@@ -0,0 +1,88 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COLOR_ENGINE_FALLBACK_H
+#define __GTK_COLOR_ENGINE_FALLBACK_H
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_ENGINE_FALLBACK          (gtk_color_engine_fallback_get_type ())
+#define GTK_COLOR_ENGINE_FALLBACK(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_ENGINE_FALLBACK, GtkColorEngineFallback))
+#define GTK_IS_COLOR_ENGINE_FALLBACK(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_ENGINE_FALLBACK))
+
+#define GTK_TYPE_COLOR_PROFILE_FALLBACK         (gtk_color_profile_fallback_get_type ())
+#define GTK_COLOR_PROFILE_FALLBACK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_PROFILE_FALLBACK, GtkColorProfileFallback))
+#define GTK_IS_COLOR_PROFILE_FALLBACK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_PROFILE_FALLBACK))
+
+#define GTK_TYPE_COLOR_TRANSFORM_FALLBACK       (gtk_color_transform_fallback_get_type ())
+#define GTK_COLOR_TRANSFORM_FALLBACK(o)         (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_TRANSFORM_FALLBACK, GtkColorTransformFallback))
+#define GTK_IS_COLOR_TRANSFORM_FALLBACK(o)      (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_TRANSFORM_FALLBACK))
+
+typedef struct _GtkColorEngineFallback          GtkColorEngineFallback;
+typedef struct _GtkColorEngineFallbackClass     GtkColorEngineFallbackClass;
+
+typedef struct _GtkColorTransformFallback       GtkColorTransformFallback;
+typedef struct _GtkColorTransformFallbackClass  GtkColorTransformFallbackClass;
+
+typedef struct _GtkColorProfileFallback         GtkColorProfileFallback;
+typedef struct _GtkColorProfileFallbackClass    GtkColorProfileFallbackClass;
+
+struct _GtkColorEngineFallback
+{
+   GObject parent;
+};
+
+struct _GtkColorEngineFallbackClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GtkColorTransformFallback
+{
+   GtkColorTransform parent;
+};
+
+struct _GtkColorTransformFallbackClass
+{
+  GtkColorTransformClass parent_class;
+};
+
+struct _GtkColorProfileFallback
+{
+   GtkColorProfile parent;
+};
+
+struct _GtkColorProfileFallbackClass
+{
+  GtkColorProfileClass parent_class;
+};
+
+GType      gtk_color_engine_fallback_get_type    (void) G_GNUC_CONST;
+GType      gtk_color_transform_fallback_get_type (void) G_GNUC_CONST;
+GType      gtk_color_profile_fallback_get_type   (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_ENGINE_FALLBACK_H */
+
diff --git a/gtk/gtkcolorprofile.c b/gtk/gtkcolorprofile.c
new file mode 100644
index 0000000..7a1bb4b
--- /dev/null
+++ b/gtk/gtkcolorprofile.c
@@ -0,0 +1,60 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gtk-color-profile
+ * @short_description: Base class for implementing ICC color profiles
+ * @include: gtk/gtk.h
+ * @title: GtkColorProfile
+ * @see_also: #GtkColorTransform, #GtkColorProfile
+ *
+ * #GtkColorProfile is a high level abstraction of a color profile. Typically
+ * this will be an ICC profile loaded from disk, or embedded in a source image.
+ * A color profile will allow you to change the colors of the image either to
+ * correctly render the colors on a given output device, or to deliberatly
+ * change the colors e.g. introducing a sepia effect on photographs.
+ *
+ * To construct a #GtkColorProfile, you have to get an instance of
+ * #GtkColorEngine, and then call gtk_color_engine_create_profile().
+ *
+ * You cannot create "empty" #GtkColorProfile objects, you always have to
+ * create them from ICC data.
+ */
+
+#include "config.h"
+
+#include "gtkcolorprofile.h"
+
+G_DEFINE_TYPE (GtkColorProfile, gtk_color_profile, G_TYPE_OBJECT)
+
+static void
+gtk_color_profile_class_init (GtkColorProfileClass *klass)
+{
+}
+
+static void
+gtk_color_profile_init (GtkColorProfile *color_profile)
+{
+}
+
+#define __GTK_COLOR_PROFILE_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkcolorprofile.h b/gtk/gtkcolorprofile.h
new file mode 100644
index 0000000..41267cc
--- /dev/null
+++ b/gtk/gtkcolorprofile.h
@@ -0,0 +1,66 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_COLOR_PROFILE_H
+#define __GTK_COLOR_PROFILE_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_PROFILE               (gtk_color_profile_get_type ())
+#define GTK_COLOR_PROFILE(o)                 (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_PROFILE, GtkColorProfile))
+#define GTK_COLOR_PROFILE_CLASS(k)           (G_TYPE_CHECK_CLASS_CAST((k), GTK_TYPE_COLOR_PROFILE, GtkColorProfileClass))
+#define GTK_IS_COLOR_PROFILE(o)              (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_PROFILE))
+#define GTK_IS_COLOR_PROFILE_CLASS(k)        (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLOR_PROFILE))
+#define GTK_COLOR_PROFILE_GET_CLASS(o)       (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLOR_PROFILE, GtkColorProfileClass))
+
+typedef struct _GtkColorProfilePrivate       GtkColorProfilePrivate;
+typedef struct _GtkColorProfile              GtkColorProfile;
+typedef struct _GtkColorProfileClass         GtkColorProfileClass;
+
+struct _GtkColorProfile
+{
+  GObject parent;
+  GtkColorProfilePrivate *priv;
+};
+
+struct _GtkColorProfileClass
+{
+  GObjectClass parent_class;
+  /* padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+};
+
+GType                    gtk_color_profile_get_type       (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_PROFILE_H */
+
diff --git a/gtk/gtkcolortransform.c b/gtk/gtkcolortransform.c
new file mode 100644
index 0000000..117ac04
--- /dev/null
+++ b/gtk/gtkcolortransform.c
@@ -0,0 +1,570 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gtk-color-transform
+ * @short_description: Base class for implementing ICC color transforms
+ * @include: gtk/gtk.h
+ * @title: GtkColorTransform
+ * @see_also: #GtkColorProfile, #GtkColorEngine
+ *
+ * #GtkColorTransform represents an object which can apply an ICC color
+ * transformation using one or two #GtkColorProfile objects.
+ *
+ * A #GtkColorTransform can tranform a #GdkPixbuf or #cairo_surface_t object
+ * from one colorspace to another, and can apply color corrections using ICC
+ * profiles.
+ *
+ * If a profile is not specified, e.g.
+ * |[
+ *  gtk_color_transform_set_output_profile(transform, NULL);
+ * ]|
+ * Then the output profile will use sRGB, the default built-in colorspace.
+ *
+ * The actual method used to map one gamut to another gamut is specified by the
+ * #GtkColorIntent. Usually this should be set to %GTK_COLOR_INTENT_PERCEPTUAL
+ * (which is also the default) unless full saturation colors are required.
+ */
+
+#include "config.h"
+#include <gdk/gdk.h>
+
+#include "gtkcolortransform.h"
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+static void gtk_color_transform_finalize (GObject * object);
+
+#define GTK_COLOR_TRANSFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_COLOR_TRANSFORM, GtkColorTransformPrivate))
+
+/**
+ * GtkColorTransformPrivate:
+ *
+ * Private #GtkColorTransform data
+ **/
+struct _GtkColorTransformPrivate
+{
+  GtkColorIntent     intent;
+  gboolean           black_point_compensation;
+  GtkColorProfile   *input_profile;
+  GtkColorProfile   *output_profile;
+};
+
+enum
+{
+  PROP_0,
+  PROP_INTENT,
+  PROP_BLACK_POINT_COMPENSATION,
+  PROP_INPUT_PROFILE,
+  PROP_OUTPUT_PROFILE,
+  PROP_LAST
+};
+
+G_DEFINE_TYPE (GtkColorTransform, gtk_color_transform, G_TYPE_OBJECT)
+
+/**
+ * gtk_color_transform_get_intent:
+ * @color_transform: a #GtkColorTransform
+ *
+ * Gets the rendering intent to use for this transform.
+ *
+ * Return value: a #GtkColorIntent
+ *
+ * Since: 2.20
+ **/
+GtkColorIntent
+gtk_color_transform_get_intent (GtkColorTransform *color_transform)
+{
+  g_return_val_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform), GTK_COLOR_INTENT_INVALID);
+  return color_transform->priv->intent;
+}
+
+/**
+ * gtk_color_transform_set_intent:
+ * @color_transform: a #GtkColorTransform
+ * @intent: a #GtkColorIntent
+ *
+ * Sets the rendering intent to use for this transform.
+ *
+ * Since: 2.20
+ **/
+void
+gtk_color_transform_set_intent (GtkColorTransform *color_transform,
+                                GtkColorIntent     intent)
+{
+  g_return_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform));
+  color_transform->priv->intent = intent;
+}
+
+/**
+ * gtk_color_transform_get_black_point_compensation:
+ * @color_transform: a #GtkColorTransform
+ *
+ * Gets the black point compensation setting for this transform.
+ *
+ * Return value: %TRUE if black point compensation is enabled
+ *
+ * Since: 2.20
+ **/
+gboolean
+gtk_color_transform_get_black_point_compensation (GtkColorTransform *color_transform)
+{
+  g_return_val_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform), FALSE);
+  return color_transform->priv->black_point_compensation;
+}
+
+/**
+ * gtk_color_transform_set_black_point_compensation:
+ * @color_transform: a #GtkColorTransform
+ * @black_point_compensation: if black point compensation should be used
+ *
+ * Sets the black point compensation setting for this transform.
+ *
+ * Black point compensation (BPC) is a way of changing the print density to be
+ * more rounded where the ink density is nearly at the maximum.
+ * This means tonal detail is still present where density is greater than the
+ * theoretical maximum. Some tones are lightened, but black level is preserved.
+ *
+ * Black point compensation is always on when using perceptual rendering intent.
+ *
+ * Since: 2.20
+ **/
+void
+gtk_color_transform_set_black_point_compensation (GtkColorTransform *color_transform,
+                                                  gboolean           black_point_compensation)
+{
+  g_return_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform));
+  color_transform->priv->black_point_compensation = black_point_compensation;
+}
+
+/**
+ * gtk_color_transform_set_input_profile:
+ * @color_transform: a #GtkColorTransform
+ * @profile: a #GtkColorProfile, or %NULL
+ *
+ * Sets an input profile to be used in this transform.
+ * If %NULL is used as the @profile then the internal sRGB space is used.
+ *
+ * Since: 2.20
+ **/
+void
+gtk_color_transform_set_input_profile (GtkColorTransform *color_transform,
+                                       GtkColorProfile   *profile)
+{
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  g_return_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform));
+  g_return_if_fail (GTK_IS_COLOR_PROFILE (profile) || profile == NULL);
+
+  /* close old profile */
+  if (priv->input_profile)
+    {
+      g_object_unref (priv->input_profile);
+      priv->input_profile = NULL;
+    }
+
+  /* set new profile */
+  if (profile != NULL)
+    priv->input_profile = g_object_ref (profile);
+
+  g_object_notify (G_OBJECT (color_transform), "input-profile");
+}
+
+/**
+ * gtk_color_transform_set_output_profile:
+ * @color_transform: a #GtkColorTransform
+ * @profile: a #GtkColorProfile, or %NULL
+ *
+ * Sets an output profile to be used in this transform.
+ * If %NULL is used as the @profile then the internal sRGB space is used.
+ *
+ * Since: 2.20
+ **/
+void
+gtk_color_transform_set_output_profile (GtkColorTransform *color_transform,
+                                        GtkColorProfile   *profile)
+{
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  g_return_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform));
+  g_return_if_fail (GTK_IS_COLOR_PROFILE (profile) || profile == NULL);
+
+  /* close old profile */
+  if (priv->output_profile)
+    {
+      g_object_unref (priv->output_profile);
+      priv->output_profile = NULL;
+    }
+
+  /* set new profile */
+  if (profile != NULL)
+    priv->output_profile = g_object_ref (profile);
+
+  g_object_notify (G_OBJECT (color_transform), "output-profile");
+}
+
+/**
+ * gtk_color_transform_set_input_profile:
+ * @color_transform: a #GtkColorTransform
+ *
+ * Returns the input profile to be used in this transform.
+ *
+ * Return value: the #GtkColorProfile, or %NULL if there is no profile set
+ *
+ * Since: 2.20
+ **/
+GtkColorProfile *
+gtk_color_transform_get_input_profile (GtkColorTransform *color_transform)
+{
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  g_return_val_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform), NULL);
+
+  if (priv->input_profile == NULL)
+    return NULL;
+  return priv->input_profile;
+}
+
+/**
+ * gtk_color_transform_set_output_profile:
+ * @color_transform: a #GtkColorTransform
+ *
+ * Returns the output profile to be used in this transform.
+ *
+ * Return value: the #GtkColorProfile, or %NULL if there is no profile set
+ *
+ * Since: 2.20
+ **/
+GtkColorProfile *
+gtk_color_transform_get_output_profile (GtkColorTransform *color_transform)
+{
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  g_return_val_if_fail (GTK_IS_COLOR_TRANSFORM (color_transform), NULL);
+
+  if (priv->output_profile == NULL)
+    return NULL;
+  return priv->output_profile;
+}
+
+/**
+ * gtk_color_transform_apply_pixbuf_in_place:
+ * @color_transform: a #GtkColorTransform
+ * @pixbuf: a #GdkPixbuf
+ * @error: a %GError, or %NULL
+ *
+ * Transform the pixmap in-place, destroying the old content.
+ *
+ * This function will be faster than gtk_color_transform_apply_pixbuf(), as a
+ * new pixmap does not have to be allocated, and the conversion can be done
+ * one row at a time.
+ *
+ * If the input profile or output profile have not been set then these are
+ * assumed to be sRGB.
+ *
+ * Return value: %TRUE if the pixbuf was transformed, otherwise %FALSE and
+ * @error is set.
+ *
+ * Since: 2.20
+ **/
+gboolean
+gtk_color_transform_apply_pixbuf_in_place (GtkColorTransform *color_transform,
+                                           GdkPixbuf         *pixbuf,
+                                           GError           **error)
+{
+  gboolean ret;
+  GtkColorTransformClass *klass = GTK_COLOR_TRANSFORM_GET_CLASS (color_transform);
+
+  g_return_val_if_fail (pixbuf != NULL, FALSE);
+  g_return_val_if_fail (klass->apply_pixbuf_in_place != NULL, FALSE);
+
+  ret = klass->apply_pixbuf_in_place (color_transform,
+                                      pixbuf,
+                                      error);
+  return ret;
+}
+
+/**
+ * gtk_color_transform_apply_pixbuf:
+ * @color_transform: a #GtkColorTransform
+ * @pixbuf_in: the source #GdkPixbuf
+ * @pixbuf_out: the destination #GdkPixbuf
+ * @error: a %GError, or %NULL
+ *
+ * Transform from one pixmap to another.
+ *
+ * This function will be slower than gtk_color_transform_apply_pixbuf_in_place(),
+ * as a new pixmap will have to be allocated by your application.
+ *
+ * If the input profile or output profile have not been set then these are
+ * assumed to be sRGB.
+ *
+ * Return value: a new #GdkPixbuf is the pixbuf was transformed, otherwise %NULL
+ * and @error is set.
+ *
+ * Since: 2.20
+ **/
+GdkPixbuf *
+gtk_color_transform_apply_pixbuf (GtkColorTransform *color_transform,
+                           GdkPixbuf         *pixbuf,
+                           GError           **error)
+{
+  GdkPixbuf *pixbuf_output;
+  GtkColorTransformClass *klass = GTK_COLOR_TRANSFORM_GET_CLASS (color_transform);
+
+  g_return_val_if_fail (pixbuf != NULL, NULL);
+  g_return_val_if_fail (klass->apply_pixbuf != NULL, NULL);
+
+  pixbuf_output = klass->apply_pixbuf (color_transform,
+                                      pixbuf,
+                                      error);
+  return pixbuf_output;
+}
+
+/**
+ * gtk_color_transform_apply_surface_in_place:
+ * @color_transform: a #GtkColorTransform
+ * @surface: a #cairo_surface_t
+ * @error: a %GError, or %NULL
+ *
+ * Transform the surface in-place, destroying the old content.
+ *
+ * This function will be faster than gtk_color_transform_apply_surface(), as a
+ * new surface does not have to be allocated, and the conversion can be done
+ * one row at a time.
+ *
+ * If the input profile or output profile have not been set then these are
+ * assumed to be sRGB.
+ *
+ * Return value: %TRUE if the surface was transformed, otherwise %FALSE and
+ * @error is set.
+ *
+ * Since: 2.20
+ **/
+gboolean
+gtk_color_transform_apply_surface_in_place (GtkColorTransform *color_transform,
+                                            cairo_surface_t   *surface,
+                                            GError           **error)
+{
+  gboolean ret;
+  GtkColorTransformClass *klass = GTK_COLOR_TRANSFORM_GET_CLASS (color_transform);
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+  g_return_val_if_fail (klass->apply_surface_in_place != NULL, FALSE);
+
+  ret = klass->apply_surface_in_place (color_transform,
+                                       surface,
+                                       error);
+  return ret;
+}
+
+/**
+ * gtk_color_transform_apply_surface:
+ * @color_transform: a #GtkColorTransform
+ * @surface_in: the source #cairo_surface_t
+ * @surface_out: the destination #cairo_surface_t
+ * @error: a %GError, or %NULL
+ *
+ * Transform from one surface to another.
+ *
+ * This function will be slower than gtk_color_transform_apply_surface_in_place(),
+ * as a new surface will have to be allocated by your application.
+ *
+ * If the input profile or output profile have not been set then these are
+ * assumed to be sRGB.
+ *
+ * Return value: a new #cairo_surface_t is the surface was transformed, otherwise %NULL
+ * and @error is set.
+ *
+ * Since: 2.20
+ **/
+cairo_surface_t *
+gtk_color_transform_apply_surface (GtkColorTransform *color_transform,
+                                   cairo_surface_t   *surface,
+                                   GError           **error)
+{
+  cairo_surface_t *surface_output;
+  GtkColorTransformClass *klass = GTK_COLOR_TRANSFORM_GET_CLASS (color_transform);
+
+  g_return_val_if_fail (surface != NULL, NULL);
+  g_return_val_if_fail (klass->apply_surface != NULL, NULL);
+
+  surface_output = klass->apply_surface (color_transform,
+                                         surface,
+                                         error);
+  return surface_output;
+}
+
+static void
+gtk_color_transform_get_property (GObject *object, guint prop_id,
+                                  GValue *value, GParamSpec *pspec)
+{
+  GtkColorTransform *color_transform = GTK_COLOR_TRANSFORM (object);
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  switch (prop_id)
+    {
+    case PROP_INTENT:
+      g_value_set_enum (value, priv->intent);
+      break;
+    case PROP_BLACK_POINT_COMPENSATION:
+      g_value_set_boolean (value, priv->black_point_compensation);
+      break;
+    case PROP_INPUT_PROFILE:
+      g_value_set_object (value, priv->input_profile);
+      break;
+    case PROP_OUTPUT_PROFILE:
+      g_value_set_object (value, priv->output_profile);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_color_transform_set_property (GObject *object, guint prop_id,
+                                  const GValue *value, GParamSpec *pspec)
+{
+  GtkColorTransform *color_transform = GTK_COLOR_TRANSFORM (object);
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  switch (prop_id)
+    {
+    case PROP_INTENT:
+      priv->intent = g_value_get_enum (value);
+      break;
+    case PROP_BLACK_POINT_COMPENSATION:
+      priv->black_point_compensation = g_value_get_boolean (value);
+      break;
+    case PROP_INPUT_PROFILE:
+      gtk_color_transform_set_input_profile (color_transform, g_value_get_object (value));
+      break;
+    case PROP_OUTPUT_PROFILE:
+      gtk_color_transform_set_output_profile (color_transform, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_color_transform_class_init (GtkColorTransformClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->finalize = gtk_color_transform_finalize;
+  object_class->get_property = gtk_color_transform_get_property;
+  object_class->set_property = gtk_color_transform_set_property;
+
+  /**
+    * GtkColorTransform:intent:
+    *
+    * The rendering intent used when applying a transform.
+    * If this is not set, it defaults to %GTK_COLOR_INTENT_PERCEPTUAL.
+    *
+    * Since: 2.20
+    */
+  g_object_class_install_property (object_class,
+                                   PROP_INTENT,
+                                   g_param_spec_enum ("intent",
+                                                       P_("Rendering intent"),
+                                                       P_("Which rendering intent that should be used"),
+                                                       GTK_TYPE_COLOR_INTENT,
+                                                       GTK_COLOR_INTENT_PERCEPTUAL,
+                                                       G_PARAM_READWRITE));
+
+  /**
+   * GtkColorTransform:black-point-compensation:
+    *
+    * Whether to use the black point compensation black smoothing funtionality.
+    * If this is not set, it defaults to %FALSE.
+    *
+    * Since: 2.20
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_BLACK_POINT_COMPENSATION,
+                                   g_param_spec_boolean ("black-point-compensation",
+                                                         P_("Black point compensation"),
+                                                         P_("If to use a compensating algorithm to preserve black"),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+
+  /**
+   * GtkColorTransform:input-profile:
+    *
+    * The #GtkColorProfile used as the input color profile.
+    *
+    * Since: 2.20
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_INPUT_PROFILE,
+                                   g_param_spec_object ("input-profile",
+                                                        P_("Input ICC profile"),
+                                                        P_("The input ICC profile to use in the transform"),
+                                                        GTK_TYPE_COLOR_PROFILE,
+                                                        G_PARAM_READWRITE));
+
+  /**
+   * GtkColorTransform:output-profile:
+    *
+    * The #GtkColorProfile used as the output color profile.
+    *
+    * Since: 2.20
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_OUTPUT_PROFILE,
+                                   g_param_spec_object ("output-profile",
+                                                        P_("Output ICC profile"),
+                                                        P_("The output ICC profile to use in the transform"),
+                                                        GTK_TYPE_COLOR_PROFILE,
+                                                        G_PARAM_READWRITE));
+
+  g_type_class_add_private (klass, sizeof (GtkColorTransformPrivate));
+}
+
+static void
+gtk_color_transform_init (GtkColorTransform *color_transform)
+{
+  color_transform->priv = GTK_COLOR_TRANSFORM_GET_PRIVATE (color_transform);
+  color_transform->priv->intent = GTK_COLOR_INTENT_PERCEPTUAL;
+  color_transform->priv->black_point_compensation = FALSE;
+  color_transform->priv->input_profile = NULL;
+  color_transform->priv->output_profile = NULL;
+}
+
+static void
+gtk_color_transform_finalize (GObject *object)
+{
+  GtkColorTransform *color_transform = GTK_COLOR_TRANSFORM (object);
+  GtkColorTransformPrivate *priv = color_transform->priv;
+
+  if (priv->input_profile != NULL)
+    g_object_unref (priv->input_profile);
+  if (priv->output_profile != NULL)
+    g_object_unref (priv->output_profile);
+
+  G_OBJECT_CLASS (gtk_color_transform_parent_class)->finalize (object);
+}
+
+#define __GTK_COLOR_TRANSFORM_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkcolortransform.h b/gtk/gtkcolortransform.h
new file mode 100644
index 0000000..5e30f8c
--- /dev/null
+++ b/gtk/gtkcolortransform.h
@@ -0,0 +1,117 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_COLOR_TRANSFORM_H
+#define __GTK_COLOR_TRANSFORM_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <cairo.h>
+
+#include "gtkcolorprofile.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_TRANSFORM             (gtk_color_transform_get_type ())
+#define GTK_COLOR_TRANSFORM(o)               (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_TRANSFORM, GtkColorTransform))
+#define GTK_COLOR_TRANSFORM_CLASS(k)         (G_TYPE_CHECK_CLASS_CAST((k), GTK_TYPE_COLOR_TRANSFORM, GtkColorTransformClass))
+#define GTK_IS_COLOR_TRANSFORM(o)            (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_TRANSFORM))
+#define GTK_IS_COLOR_TRANSFORM_CLASS(k)      (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLOR_TRANSFORM))
+#define GTK_COLOR_TRANSFORM_GET_CLASS(o)     (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLOR_TRANSFORM, GtkColorTransformClass))
+
+typedef struct _GtkColorTransformPrivate       GtkColorTransformPrivate;
+typedef struct _GtkColorTransform              GtkColorTransform;
+typedef struct _GtkColorTransformClass         GtkColorTransformClass;
+
+struct _GtkColorTransform
+{
+  GObject parent;
+  GtkColorTransformPrivate *priv;
+};
+
+typedef enum {
+  GTK_COLOR_INTENT_INVALID,
+  GTK_COLOR_INTENT_PERCEPTUAL,
+  GTK_COLOR_INTENT_RELATIVE_COLORMETRIC,
+  GTK_COLOR_INTENT_SATURATION,
+  GTK_COLOR_INTENT_ABSOLUTE_COLORMETRIC,
+  GTK_COLOR_INTENT_LAST
+} GtkColorIntent;
+
+struct _GtkColorTransformClass
+{
+  GObjectClass parent_class;
+  gboolean         (*apply_pixbuf_in_place)  (GtkColorTransform  *color_transform,
+                                              GdkPixbuf          *pixbuf,
+                                              GError            **error);
+  GdkPixbuf       *(*apply_pixbuf)           (GtkColorTransform  *color_transform,
+                                              GdkPixbuf          *pixbuf,
+                                              GError            **error);
+  gboolean         (*apply_surface_in_place) (GtkColorTransform  *color_transform,
+                                              cairo_surface_t    *surface,
+                                              GError            **error);
+  cairo_surface_t *(*apply_surface)          (GtkColorTransform  *color_transform,
+                                              cairo_surface_t    *surface,
+                                              GError            **error);
+  /* padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+};
+
+GType            gtk_color_transform_get_type             (void) G_GNUC_CONST;
+void             gtk_color_transform_set_input_profile    (GtkColorTransform    *color_transform,
+                                                           GtkColorProfile      *profile);
+void             gtk_color_transform_set_output_profile   (GtkColorTransform    *color_transform,
+                                                           GtkColorProfile      *profile);
+GtkColorProfile *gtk_color_transform_get_input_profile    (GtkColorTransform    *color_transform);
+GtkColorProfile *gtk_color_transform_get_output_profile   (GtkColorTransform    *color_transform);
+
+gboolean         gtk_color_transform_apply_pixbuf_in_place      (GtkColorTransform    *color_transform,
+                                                                 GdkPixbuf            *pixbuf,
+                                                                 GError              **error);
+GdkPixbuf       *gtk_color_transform_apply_pixbuf               (GtkColorTransform    *color_transform,
+                                                                 GdkPixbuf            *pixbuf,
+                                                                 GError              **error);
+
+gboolean         gtk_color_transform_apply_surface_in_place     (GtkColorTransform    *color_transform,
+                                                                 cairo_surface_t      *surface,
+                                                                 GError              **error);
+cairo_surface_t *gtk_color_transform_apply_surface              (GtkColorTransform    *color_transform,
+                                                                 cairo_surface_t      *surface,
+                                                                 GError              **error);
+
+GtkColorIntent   gtk_color_transform_get_intent                   (GtkColorTransform *color_transform);
+void             gtk_color_transform_set_intent                   (GtkColorTransform *color_transform,
+                                                                   GtkColorIntent    intent);
+gboolean         gtk_color_transform_get_black_point_compensation (GtkColorTransform *color_transform);
+void             gtk_color_transform_set_black_point_compensation (GtkColorTransform *color_transform,
+                                                                   gboolean           black_point_compensation);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_TRANSFORM_H */
+
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index b150bf3..d4d3a7a 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -27,6 +27,7 @@
 #include "config.h"
 
 #include <glib.h>
+#include <gio/gio.h>
 #include "gdkconfig.h"
 
 #include <locale.h>
@@ -50,6 +51,7 @@
 #include "gtkaccelmap.h"
 #include "gtkbox.h"
 #include "gtkclipboard.h"
+#include "gtkcolorengine.h"
 #include "gtkdnd.h"
 #include "gtkversion.h"
 #include "gtkmain.h"
@@ -822,6 +824,52 @@ gtk_get_option_group (gboolean open_default_display)
   return group;
 }
 
+static void
+_gtk_io_modules_ensure_extension_points_registered (void)
+{
+  static gboolean registered_extensions = FALSE;
+  GIOExtensionPoint *ep;
+
+  if (!registered_extensions)
+    {
+      registered_extensions = TRUE;
+      ep = g_io_extension_point_register (GTK_COLOR_ENGINE_EXTENSION_POINT_NAME);
+      g_io_extension_point_set_required_type (ep, GTK_TYPE_COLOR_ENGINE);
+    }
+}
+
+void
+_gtk_io_modules_ensure_loaded (void)
+{
+  static gboolean loaded_dirs = FALSE;
+  const gchar *module_path;
+  gchar *path;
+
+  _gtk_io_modules_ensure_extension_points_registered ();
+
+  if (!loaded_dirs)
+    {
+      loaded_dirs = TRUE;
+      path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_BINARY_VERSION, "giomodules", NULL);
+      g_io_modules_scan_all_in_directory (path);
+      g_free (path);
+
+      module_path = g_getenv ("GTK_EXTRA_GIOMODULES");
+      if (module_path)
+        {
+          gint i = 0;
+          gchar **paths;
+          paths = g_strsplit (module_path, ":", 0);
+          while (paths[i] != NULL)
+            {
+              g_io_modules_scan_all_in_directory (paths[i]);
+              i++;
+            }
+          g_strfreev (paths);
+        }
+    }
+}
+
 /**
  * gtk_init_with_args:
  * @argc: a pointer to the number of command line arguments.
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 7ba5a5d..479a0f1 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -112,6 +112,8 @@ gboolean _gtk_fnmatch (const char *pattern,
 #define GTK_DEFAULT_ACCEL_MOD_MASK GDK_META_MASK
 #endif
 
+void _gtk_io_modules_ensure_loaded (void);
+
 G_END_DECLS
 
 #endif /* __GTK_PRIVATE_H__ */
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 40d5fa5..9eb28a7 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -1,6 +1,6 @@
 include $(top_srcdir)/Makefile.decl
 
-SUBDIRS = input engines other
+SUBDIRS = input engines other giomodules
 
 if OS_UNIX
 SUBDIRS += printbackends
diff --git a/modules/giomodules/Makefile.am b/modules/giomodules/Makefile.am
new file mode 100644
index 0000000..29fc894
--- /dev/null
+++ b/modules/giomodules/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/Makefile.decl
+
+SUBDIRS =
+
+if HAVE_LCMS
+SUBDIRS += lcms
+endif
+
+DIST_SUBDIRS = lcms
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/giomodules/lcms/Makefile.am b/modules/giomodules/lcms/Makefile.am
new file mode 100644
index 0000000..d53fa80
--- /dev/null
+++ b/modules/giomodules/lcms/Makefile.am
@@ -0,0 +1,34 @@
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES = \
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/gdk				\
+	-I$(top_builddir)/gdk				\
+	-I$(top_srcdir)/gtk				\
+	-I$(top_builddir)/gtk				\
+	$(LCMS_CFLAGS)					\
+	$(GTK_DEP_CFLAGS)				\
+	$(GTK_DEBUG_FLAGS)
+
+LDADDS = \
+	$(top_builddir)/gtk/$(gtktargetlib)		\
+	$(GTK_DEP_LIBS)
+
+backenddir = $(libdir)/gtk-2.0/$(GTK_BINARY_VERSION)/giomodules
+
+backend_LTLIBRARIES = libcolorenginelcms.la
+
+libcolorenginelcms_la_SOURCES =				\
+	gtkcolorenginelcms.c				\
+	gtkcolorprofilelcms.c				\
+	gtkcolortransformlcms.c
+
+noinst_HEADERS =					\
+	gtkcolorenginelcms.h				\
+	gtkcolortransformlcms.h				\
+	gtkcolorprofilelcms.h
+
+libcolorenginelcms_la_LDFLAGS =  -avoid-version -module $(no_undefined) -export-symbols-regex '^g_io_module_(load|unload|query)'
+libcolorenginelcms_la_LIBADD = $(LDADDS) $(LCMS_LIBS)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/giomodules/lcms/gtkcolorenginelcms.c b/modules/giomodules/lcms/gtkcolorenginelcms.c
new file mode 100644
index 0000000..c91f6c5
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolorenginelcms.c
@@ -0,0 +1,146 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gtkcolorenginelcms.h"
+#include "gtkcolorprofilelcms.h"
+#include "gtkcolortransformlcms.h"
+
+static void gtk_color_engine_lcms_iface_init (GtkColorEngineInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GtkColorEngineLcms,
+                                gtk_color_engine_lcms,
+                                G_TYPE_OBJECT,
+                                0,
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (GTK_TYPE_COLOR_ENGINE,
+                                                               gtk_color_engine_lcms_iface_init))
+
+static GtkColorProfile *
+_gtk_color_engine_lcms_create_profile (GtkColorEngine *color_engine,
+                                       const guint8   *data,
+                                       gsize           length,
+                                       GError        **error)
+{
+  GtkColorProfile *color_profile;
+  gboolean ret;
+  color_profile = _gtk_color_profile_lcms_new ();
+  GTK_COLOR_PROFILE_LCMS(color_profile)->engine = g_object_ref (color_engine);
+  ret = _gtk_color_profile_lcms_set_from_data (color_profile, data, length, error);
+  if (!ret)
+    {
+      g_object_unref (color_profile);
+      color_profile = NULL;
+    }
+  return color_profile;
+}
+
+static GtkColorTransform *
+_gtk_color_engine_lcms_create_transform (GtkColorEngine *color_engine)
+{
+  GtkColorTransform *color_transform;
+  color_transform = _gtk_color_transform_lcms_new ();
+  GTK_COLOR_TRANSFORM_LCMS(color_transform)->engine = g_object_ref (color_engine);
+  return color_transform;
+}
+
+static void
+gtk_color_engine_lcms_iface_init (GtkColorEngineInterface *iface)
+{
+  iface->create_profile = _gtk_color_engine_lcms_create_profile;
+  iface->create_transform = _gtk_color_engine_lcms_create_transform;
+}
+
+static int
+gtk_color_engine_lcms_error_cb (gint         error_code,
+                                const gchar *error_text)
+{
+  g_warning ("LCMS error %i: %s", error_code, error_text);
+  return LCMS_ERRC_WARNING;
+}
+
+static void
+gtk_color_engine_lcms_library_init (void)
+{
+  static gboolean inited = FALSE;
+  if (inited)
+    return;
+
+  cmsSetErrorHandler (gtk_color_engine_lcms_error_cb);
+  cmsErrorAction (LCMS_ERROR_SHOW);
+
+  /* this is the default fallback language */
+  cmsSetLanguage ("en", "US");
+
+  inited = TRUE;
+}
+
+static void
+gtk_color_engine_lcms_init (GtkColorEngineLcms *color_engine_lcms)
+{
+  gtk_color_engine_lcms_library_init ();
+  color_engine_lcms->srgb_profile = cmsCreate_sRGBProfile ();
+}
+
+static void
+gtk_color_engine_lcms_class_init (GtkColorEngineLcmsClass *klass)
+{
+}
+
+static void
+gtk_color_engine_lcms_class_finalize (GtkColorEngineLcmsClass *klass)
+{
+}
+
+/**
+ * gtk_color_engine_lcms_register:
+ **/
+void
+gtk_color_engine_lcms_register (GIOModule *module)
+{
+  gtk_color_engine_lcms_register_type (G_TYPE_MODULE (module));
+  g_io_extension_point_implement (GTK_COLOR_ENGINE_EXTENSION_POINT_NAME,
+                                  GTK_TYPE_COLOR_ENGINE_LCMS,
+                                  "lcms",
+                                  10);
+}
+
+/**
+ * g_io_module_load:
+ **/
+void
+g_io_module_load (GIOModule *module)
+{
+  gtk_color_engine_lcms_register (module);
+}
+
+/**
+ * g_io_module_unload:
+ **/
+void
+g_io_module_unload (GIOModule *module)
+{
+  GtkColorEngineLcms *color_engine_lcms = GTK_COLOR_ENGINE_LCMS (module);
+  cmsCloseProfile (color_engine_lcms->srgb_profile);
+}
+
diff --git a/modules/giomodules/lcms/gtkcolorenginelcms.h b/modules/giomodules/lcms/gtkcolorenginelcms.h
new file mode 100644
index 0000000..0ad6065
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolorenginelcms.h
@@ -0,0 +1,55 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COLOR_ENGINE_LCMS_H
+#define __GTK_COLOR_ENGINE_LCMS_H
+
+#include <glib-object.h>
+#include <lcms.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_ENGINE_LCMS          (gtk_color_engine_lcms_get_type ())
+#define GTK_COLOR_ENGINE_LCMS(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_ENGINE_LCMS, GtkColorEngineLcms))
+#define GTK_IS_COLOR_ENGINE_LCMS(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_ENGINE_LCMS))
+
+typedef struct _GtkColorEngineLcms        GtkColorEngineLcms;
+typedef struct _GtkColorEngineLcmsClass   GtkColorEngineLcmsClass;
+
+struct _GtkColorEngineLcms
+{
+  GObject parent;
+  cmsHPROFILE srgb_profile;
+};
+
+struct _GtkColorEngineLcmsClass
+{
+  GObjectClass parent_class;
+};
+
+GType      gtk_color_engine_lcms_get_type    (void) G_GNUC_CONST;
+void       gtk_color_engine_lcms_register    (GIOModule *module);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_ENGINE_LCMS_H */
+
diff --git a/modules/giomodules/lcms/gtkcolorprofilelcms.c b/modules/giomodules/lcms/gtkcolorprofilelcms.c
new file mode 100644
index 0000000..018c8b5
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolorprofilelcms.c
@@ -0,0 +1,84 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gtkcolorprofilelcms.h"
+
+static void     gtk_color_profile_lcms_finalize  (GObject     *object);
+
+G_DEFINE_TYPE (GtkColorProfileLcms, gtk_color_profile_lcms, GTK_TYPE_COLOR_PROFILE)
+
+/**
+ * _gtk_color_profile_lcms_set_from_data:
+ **/
+gboolean
+_gtk_color_profile_lcms_set_from_data (GtkColorProfile *color_profile,
+                                       const guint8    *data,
+                                       gsize            length,
+                                       GError         **error)
+{
+  GtkColorProfileLcms *color_profile_lcms = GTK_COLOR_PROFILE_LCMS (color_profile);
+
+  if (color_profile_lcms->handle != NULL)
+    cmsCloseProfile (color_profile_lcms->handle);
+  color_profile_lcms->handle = cmsOpenProfileFromMem ((LPVOID)data, length);
+  return TRUE;
+}
+
+static void
+gtk_color_profile_lcms_class_init (GtkColorProfileLcmsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->finalize = gtk_color_profile_lcms_finalize;
+}
+
+static void
+gtk_color_profile_lcms_init (GtkColorProfileLcms *color_profile_lcms)
+{
+  color_profile_lcms->handle = NULL;
+}
+
+static void
+gtk_color_profile_lcms_finalize (GObject *object)
+{
+  GtkColorProfileLcms *color_profile_lcms = GTK_COLOR_PROFILE_LCMS (object);
+
+  if (color_profile_lcms->handle != NULL)
+    cmsCloseProfile (color_profile_lcms->handle);
+  g_object_unref (color_profile_lcms->engine);
+
+  G_OBJECT_CLASS (gtk_color_profile_lcms_parent_class)->finalize (object);
+}
+
+/**
+ * _gtk_color_profile_lcms_new:
+ **/
+GtkColorProfile *
+_gtk_color_profile_lcms_new (void)
+{
+  GtkColorProfileLcms *color_profile;
+  color_profile = g_object_new (GTK_TYPE_COLOR_PROFILE_LCMS, NULL);
+  return GTK_COLOR_PROFILE (color_profile);
+}
+
diff --git a/modules/giomodules/lcms/gtkcolorprofilelcms.h b/modules/giomodules/lcms/gtkcolorprofilelcms.h
new file mode 100644
index 0000000..cb8eca9
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolorprofilelcms.h
@@ -0,0 +1,60 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COLOR_PROFILE_LCMS_H
+#define __GTK_COLOR_PROFILE_LCMS_H
+
+#include <glib-object.h>
+#include <lcms.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_PROFILE_LCMS          (gtk_color_profile_lcms_get_type ())
+#define GTK_COLOR_PROFILE_LCMS(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_PROFILE_LCMS, GtkColorProfileLcms))
+#define GTK_IS_COLOR_PROFILE_LCMS(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_PROFILE_LCMS))
+
+typedef struct _GtkColorProfileLcms        GtkColorProfileLcms;
+typedef struct _GtkColorProfileLcmsClass   GtkColorProfileLcmsClass;
+
+struct _GtkColorProfileLcms
+{
+  GtkColorProfile parent;
+  GtkColorEngine *engine;
+  cmsHPROFILE handle;
+};
+
+struct _GtkColorProfileLcmsClass
+{
+  GtkColorProfileClass parent_class;
+};
+
+GType            gtk_color_profile_lcms_get_type      (void) G_GNUC_CONST;
+GtkColorProfile *_gtk_color_profile_lcms_new           (void);
+gboolean         _gtk_color_profile_lcms_set_from_data (GtkColorProfile *color_profile,
+                                                        const guint8    *data,
+                                                        gsize            length,
+                                                        GError         **error);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_PROFILE_LCMS_H */
+
diff --git a/modules/giomodules/lcms/gtkcolortransformlcms.c b/modules/giomodules/lcms/gtkcolortransformlcms.c
new file mode 100644
index 0000000..619be99
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolortransformlcms.c
@@ -0,0 +1,306 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <lcms.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+
+#include "gtkcolorenginelcms.h"
+#include "gtkcolorprofilelcms.h"
+#include "gtkcolortransformlcms.h"
+
+static void     gtk_color_transform_lcms_finalize  (GObject     *object);
+
+G_DEFINE_TYPE (GtkColorTransformLcms, gtk_color_transform_lcms, GTK_TYPE_COLOR_TRANSFORM)
+
+static DWORD
+gtk_color_transform_lcms_pixbuf_get_format (GdkPixbuf *pixbuf)
+{
+  if (gdk_pixbuf_get_has_alpha (pixbuf))
+    return TYPE_RGBA_8;
+  return TYPE_RGB_8;
+}
+
+static DWORD
+gtk_color_transform_lcms_get_flags (GtkColorTransform *color_transform)
+{
+  DWORD flags = 0;
+  if (gtk_color_transform_get_black_point_compensation (color_transform))
+    flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+  return flags;
+}
+
+static gint
+gtk_color_transform_lcms_get_intent (GtkColorTransform *color_transform)
+{
+  GtkColorIntent intent;
+  intent = gtk_color_transform_get_intent (color_transform);
+  if (intent == GTK_COLOR_INTENT_PERCEPTUAL)
+    return INTENT_PERCEPTUAL;
+  if (intent == GTK_COLOR_INTENT_RELATIVE_COLORMETRIC)
+    return INTENT_RELATIVE_COLORIMETRIC;
+  if (intent == GTK_COLOR_INTENT_SATURATION)
+    return INTENT_SATURATION;
+  if (intent == GTK_COLOR_INTENT_ABSOLUTE_COLORMETRIC)
+    return INTENT_ABSOLUTE_COLORIMETRIC;
+
+  /* choose a good default */
+  return INTENT_PERCEPTUAL;
+}
+
+static gboolean
+gtk_color_transform_lcms_apply_pixbuf_in_place (GtkColorTransform *color_transform,
+                                                GdkPixbuf         *pixbuf,
+                                                GError           **error)
+{
+  DWORD format;
+  DWORD flags;
+  gint intent;
+  gboolean ret = FALSE;
+  cmsHTRANSFORM transform;
+  gint width, height, rowstride;
+  guchar *p;
+  gint i;
+  GtkColorProfile *input_profile = NULL;
+  GtkColorProfile *output_profile = NULL;
+  gpointer input_profile_handle;
+  gpointer output_profile_handle;
+  GtkColorTransformLcms *color_transform_lcms = GTK_COLOR_TRANSFORM_LCMS(color_transform);
+
+  /* work out the LCMS format flags */
+  flags = gtk_color_transform_lcms_get_flags (color_transform);
+  intent = gtk_color_transform_lcms_get_intent (color_transform);
+  format = gtk_color_transform_lcms_pixbuf_get_format (pixbuf);
+
+  /* no profiles */
+  input_profile = gtk_color_transform_get_input_profile (color_transform);
+  output_profile = gtk_color_transform_get_output_profile (color_transform);
+  if (input_profile == NULL && output_profile == NULL)
+    {
+      /* no need to blit */
+      goto out;
+    }
+
+  /* fall back to sRGB */
+  if (input_profile == NULL)
+    input_profile_handle = GTK_COLOR_ENGINE_LCMS(color_transform_lcms->engine)->srgb_profile;
+  else
+    input_profile_handle = GTK_COLOR_PROFILE_LCMS(input_profile)->handle;
+
+  /* fall back to sRGB */
+  if (output_profile == NULL)
+    output_profile_handle = GTK_COLOR_ENGINE_LCMS(color_transform_lcms->engine)->srgb_profile;
+  else
+    output_profile_handle = GTK_COLOR_PROFILE_LCMS(output_profile)->handle;
+
+  /* create transform */
+  transform = cmsCreateTransform (input_profile_handle, format, output_profile_handle, format, intent, flags);
+
+  /* process each row */
+  height = gdk_pixbuf_get_height (pixbuf);
+  width = gdk_pixbuf_get_width (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  p = gdk_pixbuf_get_pixels (pixbuf);
+  for (i = 0; i < height; i++)
+    {
+      cmsDoTransform (transform, p, p, width);
+      p += rowstride;
+    }
+
+  ret = TRUE;
+  cmsDeleteTransform (transform);
+out:
+  return ret;
+}
+
+static GdkPixbuf *
+gtk_color_transform_lcms_apply_pixbuf (GtkColorTransform *color_transform,
+                                       GdkPixbuf         *pixbuf,
+                                       GError           **error)
+{
+  GdkPixbuf *pixbuf_output;
+  gboolean ret;
+
+  /* just copy the pixbuf and operate on the copy */
+  pixbuf_output = gdk_pixbuf_copy (pixbuf);
+  ret = gtk_color_transform_lcms_apply_pixbuf_in_place (color_transform, pixbuf_output, error);
+  if (!ret)
+    {
+      g_object_unref (pixbuf_output);
+      pixbuf_output = NULL;
+    }
+  return pixbuf_output;
+}
+
+
+/* LCMS doesn't ship all conversions by default, so define them here */
+#define TYPE_ARGB_32           (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1))
+#define TYPE_RGB_24            (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(3))
+
+static DWORD
+gtk_color_transform_lcms_surface_get_format (cairo_surface_t *surface)
+{
+  cairo_format_t format;
+  format = cairo_image_surface_get_format (surface);
+
+  if (format == CAIRO_FORMAT_ARGB32)
+    return TYPE_ARGB_32;
+  if (format == CAIRO_FORMAT_RGB24)
+    return TYPE_RGB_24;
+  return 0;
+}
+
+static gboolean
+gtk_color_transform_lcms_apply_surface_in_place (GtkColorTransform *color_transform,
+                                                 cairo_surface_t   *surface,
+                                                 GError           **error)
+{
+  DWORD format;
+  DWORD flags;
+  gint intent;
+  gboolean ret = FALSE;
+  cmsHTRANSFORM transform;
+  gint width, height, rowstride;
+  guchar *p;
+  gint i;
+  GtkColorProfile *input_profile = NULL;
+  GtkColorProfile *output_profile = NULL;
+  gpointer input_profile_handle;
+  gpointer output_profile_handle;
+  GtkColorTransformLcms *color_transform_lcms = GTK_COLOR_TRANSFORM_LCMS(color_transform);
+
+  /* work out the LCMS format flags */
+  flags = gtk_color_transform_lcms_get_flags (color_transform);
+  intent = gtk_color_transform_lcms_get_intent (color_transform);
+  format = gtk_color_transform_lcms_surface_get_format (surface);
+  if (format == 0)
+    {
+      if (error != NULL)
+        *error = g_error_new (1, 0, "format not supported");
+      goto out;
+    }
+
+  /* no profiles */
+  input_profile = gtk_color_transform_get_input_profile (color_transform);
+  output_profile = gtk_color_transform_get_output_profile (color_transform);
+  if (input_profile == NULL && output_profile == NULL)
+    {
+      /* no need to blit */
+      goto out;
+    }
+
+  /* fall back to sRGB */
+  if (input_profile == NULL)
+    input_profile_handle = GTK_COLOR_ENGINE_LCMS(color_transform_lcms->engine)->srgb_profile;
+  else
+    input_profile_handle = GTK_COLOR_PROFILE_LCMS(input_profile)->handle;
+
+  /* fall back to sRGB */
+  if (output_profile == NULL)
+    output_profile_handle = GTK_COLOR_ENGINE_LCMS(color_transform_lcms->engine)->srgb_profile;
+  else
+    output_profile_handle = GTK_COLOR_PROFILE_LCMS(output_profile)->handle;
+
+  /* create transform */
+  transform = cmsCreateTransform (input_profile_handle, format, output_profile_handle, format, intent, flags);
+
+  /* process each row */
+  height = cairo_image_surface_get_height (surface);
+  width = cairo_image_surface_get_width (surface);
+  rowstride = cairo_image_surface_get_stride (surface);
+  p = cairo_image_surface_get_data (surface);
+  cairo_surface_flush (surface);
+  for (i = 0; i < height; i++)
+    {
+      cmsDoTransform (transform, p, p, width);
+      p += rowstride;
+    }
+  cairo_surface_mark_dirty (surface);
+
+  ret = TRUE;
+  cmsDeleteTransform (transform);
+out:
+  return ret;
+}
+
+static cairo_surface_t *
+gtk_color_transform_lcms_apply_surface (GtkColorTransform *color_transform,
+                                        cairo_surface_t   *surface,
+                                        GError           **error)
+{
+  cairo_surface_t *surface_output;
+  gboolean ret;
+
+  /* just copy the surface and operate on the copy */
+  surface_output = cairo_surface_create_similar (surface,
+                                                 cairo_surface_get_content (surface),
+                                                 cairo_image_surface_get_width (surface),
+                                                 cairo_image_surface_get_height (surface));
+  ret = gtk_color_transform_lcms_apply_surface_in_place (color_transform, surface_output, error);
+  if (!ret)
+    {
+      g_object_unref (surface_output);
+      surface_output = NULL;
+    }
+  return surface_output;
+}
+
+static void
+gtk_color_transform_lcms_class_init (GtkColorTransformLcmsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkColorTransformClass *parent_class = GTK_COLOR_TRANSFORM_CLASS (klass);
+  object_class->finalize = gtk_color_transform_lcms_finalize;
+
+  parent_class->apply_pixbuf_in_place = gtk_color_transform_lcms_apply_pixbuf_in_place;
+  parent_class->apply_pixbuf = gtk_color_transform_lcms_apply_pixbuf;
+  parent_class->apply_surface_in_place = gtk_color_transform_lcms_apply_surface_in_place;
+  parent_class->apply_surface = gtk_color_transform_lcms_apply_surface;
+}
+
+static void
+gtk_color_transform_lcms_init (GtkColorTransformLcms *color_transform_lcms)
+{
+}
+
+static void
+gtk_color_transform_lcms_finalize (GObject *object)
+{
+  GtkColorTransformLcms *color_transform_lcms = GTK_COLOR_TRANSFORM_LCMS (object);
+
+  g_object_unref (color_transform_lcms->engine);
+
+  G_OBJECT_CLASS (gtk_color_transform_lcms_parent_class)->finalize (object);
+}
+
+/**
+ * _gtk_color_transform_lcms_new:
+ **/
+GtkColorTransform *
+_gtk_color_transform_lcms_new (void)
+{
+  GtkColorTransformLcms *color_transform;
+  color_transform = g_object_new (GTK_TYPE_COLOR_TRANSFORM_LCMS, NULL);
+  return GTK_COLOR_TRANSFORM (color_transform);
+}
+
diff --git a/modules/giomodules/lcms/gtkcolortransformlcms.h b/modules/giomodules/lcms/gtkcolortransformlcms.h
new file mode 100644
index 0000000..7d44d0e
--- /dev/null
+++ b/modules/giomodules/lcms/gtkcolortransformlcms.h
@@ -0,0 +1,54 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COLOR_TRANSFORM_LCMS_H
+#define __GTK_COLOR_TRANSFORM_LCMS_H
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLOR_TRANSFORM_LCMS          (gtk_color_transform_lcms_get_type ())
+#define GTK_COLOR_TRANSFORM_LCMS(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLOR_TRANSFORM_LCMS, GtkColorTransformLcms))
+#define GTK_IS_COLOR_TRANSFORM_LCMS(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLOR_TRANSFORM_LCMS))
+
+typedef struct _GtkColorTransformLcms        GtkColorTransformLcms;
+typedef struct _GtkColorTransformLcmsClass   GtkColorTransformLcmsClass;
+
+struct _GtkColorTransformLcms
+{
+  GtkColorTransform parent;
+  GtkColorEngine *engine;
+};
+
+struct _GtkColorTransformLcmsClass
+{
+  GtkColorTransformClass parent_class;
+};
+
+GType              gtk_color_transform_lcms_get_type    (void) G_GNUC_CONST;
+GtkColorTransform *_gtk_color_transform_lcms_new        (void);
+
+G_END_DECLS
+
+#endif /* __GTK_COLOR_TRANSFORM_LCMS_H */
+
