[gtk/matthiasc/color-profiles: 110/111] Split GdkColorProfile




commit 27361bf136e745d3fc40ad33ddfc84e82b0e2e99
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Oct 5 22:51:31 2021 -0400

    Split GdkColorProfile
    
    Introduce GdkICCProfile and GdkDerivedProfile subclasses.
    GdkICCProfile takes over the ICC profile functionality
    from GdkColorProfile. A GdkDerivedProfile is our way
    of encoding coordinate transformations on top of ICC
    profiles, such as HSV or Lch. Update the memory conversion
    code to only handle ICC profiles, and update the color
    conversion code to accept derived profiles as well as
    ICC profiles.

 gdk/gdk.h                    |   2 +
 gdk/gdkcolor.c               |  86 ++++++--
 gdk/gdkcolorprofile.c        | 403 ++-------------------------------
 gdk/gdkcolorprofile.h        |   1 +
 gdk/gdkcolorprofileprivate.h |  25 ++-
 gdk/gdkderivedprofile.c      | 513 +++++++++++++++++++++++++++++++++++++++++++
 gdk/gdkderivedprofile.h      |  71 ++++++
 gdk/gdkiccprofile.c          | 451 +++++++++++++++++++++++++++++++++++++
 gdk/gdkiccprofile.h          |  56 +++++
 gdk/gdkiccprofileprivate.h   |  24 ++
 gdk/gdkmemoryformat.c        |  10 +-
 gdk/gdkmemorytexture.c       |   1 -
 gdk/gdktexture.c             |   4 +-
 gdk/gdktypes.h               |   2 +
 gdk/loaders/gdkjpeg.c        |   6 +-
 gdk/loaders/gdkpng.c         |  30 +--
 gdk/loaders/gdktiff.c        |  22 +-
 gdk/meson.build              |   4 +
 gdk/x11/gdkdisplay-x11.c     |   3 +-
 19 files changed, 1261 insertions(+), 453 deletions(-)
---
diff --git a/gdk/gdk.h b/gdk/gdk.h
index 5cefc54955..74fb12dbc0 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -39,6 +39,7 @@
 #include <gdk/gdkcontentproviderimpl.h>
 #include <gdk/gdkcontentserializer.h>
 #include <gdk/gdkcursor.h>
+#include <gdk/gdkderivedprofile.h>
 #include <gdk/gdkdevice.h>
 #include <gdk/gdkdevicepad.h>
 #include <gdk/gdkdevicetool.h>
@@ -54,6 +55,7 @@
 #include <gdk/gdkframetimings.h>
 #include <gdk/gdkglcontext.h>
 #include <gdk/gdkgltexture.h>
+#include <gdk/gdkiccprofile.h>
 #include <gdk/gdkkeys.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkmemorytexture.h>
diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c
index ac5f3266c3..cbb1207a42 100644
--- a/gdk/gdkcolor.c
+++ b/gdk/gdkcolor.c
@@ -19,22 +19,22 @@
 #include "config.h"
 
 #include "gdkcolorprivate.h"
-
-#include "gdkcolorprofileprivate.h"
+#include "gdkiccprofileprivate.h"
+#include "gdkderivedprofile.h"
 
 static inline cmsHTRANSFORM *
-gdk_color_get_transform (GdkColorProfile *src,
-                         GdkColorProfile *dest)
+gdk_color_get_transform (GdkICCProfile *src,
+                         GdkICCProfile *dest)
 {
   cmsHPROFILE *src_profile, *dest_profile;
 
-  src_profile = gdk_color_profile_get_lcms_profile (src);
-  dest_profile = gdk_color_profile_get_lcms_profile (dest);
+  src_profile = gdk_icc_profile_get_lcms_profile (GDK_ICC_PROFILE (src));
+  dest_profile = gdk_icc_profile_get_lcms_profile (GDK_ICC_PROFILE (dest));
 
-  return gdk_color_profile_lookup_transform (src,
-                                             cmsFormatterForColorspaceOfProfile (src_profile, 4, 1),
-                                             dest,
-                                             cmsFormatterForColorspaceOfProfile (dest_profile, 4, 1));
+  return gdk_icc_profile_lookup_transform (src,
+                                           cmsFormatterForColorspaceOfProfile (src_profile, 4, 1),
+                                           dest,
+                                           cmsFormatterForColorspaceOfProfile (dest_profile, 4, 1));
 }
 
 void
@@ -42,16 +42,43 @@ gdk_color_convert (GdkColor        *self,
                    GdkColorProfile *profile,
                    const GdkColor  *other)
 {
-  gdk_color_init (self,
-                  profile,
-                  other->alpha,
-                  NULL,
-                  gdk_color_profile_get_n_components (profile));
-
-  cmsDoTransform (gdk_color_get_transform (other->profile, profile),
-                  gdk_color_get_components (other),
+  GdkColorProfile *src_profile, *dest_profile;
+  gsize n_components;
+  float *in;
+
+  n_components = gdk_color_profile_get_n_components (profile);
+
+  gdk_color_init (self, profile, other->alpha, NULL, n_components);
+
+  if (GDK_IS_DERIVED_PROFILE (other->profile))
+    {
+      in = g_alloca (sizeof (float) * n_components);
+      gdk_derived_profile_convert_to_base_profile (GDK_DERIVED_PROFILE (other->profile),
+                                                   gdk_color_get_components (other),
+                                                   in);
+      src_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (other->profile));
+    }
+  else
+    {
+      in = (float *)gdk_color_get_components (other);
+      src_profile = other->profile;
+    }
+
+  if (GDK_IS_DERIVED_PROFILE (profile))
+    dest_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (profile));
+  else
+    dest_profile = profile;
+
+  cmsDoTransform (gdk_color_get_transform (GDK_ICC_PROFILE (src_profile),
+                                           GDK_ICC_PROFILE (dest_profile)),
+                  in,
                   (float *) gdk_color_get_components (self),
                   1);
+
+  if (GDK_IS_DERIVED_PROFILE (profile))
+    gdk_derived_profile_convert_from_base_profile (GDK_DERIVED_PROFILE (profile),
+                                                   gdk_color_get_components (self),
+                                                   (float *)gdk_color_get_components (self));
 }
 
 void
@@ -59,16 +86,27 @@ gdk_color_convert_rgba (GdkColor        *self,
                         GdkColorProfile *profile,
                         const GdkRGBA   *rgba)
 {
-  gdk_color_init (self,
-                  profile,
-                  rgba->alpha,
-                  NULL,
-                  gdk_color_profile_get_n_components (profile));
+  GdkColorProfile *dest_profile;
+  gsize n_components;
 
-  cmsDoTransform (gdk_color_get_transform (gdk_color_profile_get_srgb (), profile),
+  n_components = gdk_color_profile_get_n_components (profile);
+  gdk_color_init (self, profile, rgba->alpha, NULL, n_components);
+
+  if (GDK_IS_DERIVED_PROFILE (profile))
+    dest_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (profile));
+  else
+    dest_profile = profile;
+
+  cmsDoTransform (gdk_color_get_transform (GDK_ICC_PROFILE (gdk_color_profile_get_srgb ()),
+                                           GDK_ICC_PROFILE (dest_profile)),
                   (float[3]) { rgba->red, rgba->green, rgba->blue },
                   (float *) gdk_color_get_components (self),
                   1);
+
+  if (GDK_IS_DERIVED_PROFILE (profile))
+    gdk_derived_profile_convert_from_base_profile (GDK_DERIVED_PROFILE (profile),
+                                                   gdk_color_get_components (self),
+                                                   (float *)gdk_color_get_components (self));
 }
 
 void
diff --git a/gdk/gdkcolorprofile.c b/gdk/gdkcolorprofile.c
index e8fbad1bb0..a3620da996 100644
--- a/gdk/gdkcolorprofile.c
+++ b/gdk/gdkcolorprofile.c
@@ -40,305 +40,39 @@
 
 #include "gdkintl.h"
 
-struct _GdkColorProfile
-{
-  GObject parent_instance;
-
-  GBytes *icc_profile;
-  cmsHPROFILE lcms_profile;
-};
-
-struct _GdkColorProfileClass
-{
-  GObjectClass parent_class;
-};
-
-enum {
-  PROP_0,
-  PROP_ICC_PROFILE,
-
-  N_PROPS
-};
-
-static GParamSpec *properties[N_PROPS];
-
-static gboolean
-gdk_color_profile_real_init (GInitable     *initable,
-                             GCancellable  *cancellable,
-                             GError       **error)
-{
-  GdkColorProfile *self = GDK_COLOR_PROFILE (initable);
-
-  if (self->lcms_profile == NULL)
-    {
-      const guchar *data;
-      gsize size;
-
-      if (self->icc_profile == NULL)
-        self->icc_profile = g_bytes_new (NULL, 0);
 
-      data = g_bytes_get_data (self->icc_profile, &size);
-
-      self->lcms_profile = cmsOpenProfileFromMem (data, size);
-      if (self->lcms_profile == NULL)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
-          return FALSE;
-        }
-    }
-
-  return TRUE;
-}
+G_DEFINE_TYPE (GdkColorProfile, gdk_color_profile, G_TYPE_OBJECT)
 
 static void
-gdk_color_profile_initable_init (GInitableIface *iface)
+gdk_color_profile_init (GdkColorProfile *profile)
 {
-  iface->init = gdk_color_profile_real_init;
 }
 
-
-G_DEFINE_TYPE_WITH_CODE (GdkColorProfile, gdk_color_profile, G_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gdk_color_profile_initable_init))
-
-static void
-gdk_color_profile_set_property (GObject      *gobject,
-                                guint         prop_id,
-                                const GValue *value,
-                                GParamSpec   *pspec)
+static gboolean
+gdk_color_profile_real_is_linear (GdkColorProfile *profile)
 {
-  GdkColorProfile *self = GDK_COLOR_PROFILE (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_ICC_PROFILE:
-      self->icc_profile = g_value_dup_boxed (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
+  return FALSE;
 }
 
-static void
-gdk_color_profile_get_property (GObject    *gobject,
-                                guint       prop_id,
-                                GValue     *value,
-                                GParamSpec *pspec)
+static gsize
+gdk_color_profile_real_get_n_components (GdkColorProfile *profile)
 {
-  GdkColorProfile *self = GDK_COLOR_PROFILE (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_ICC_PROFILE:
-      g_value_set_boxed (value, self->icc_profile);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
+  return 0;
 }
 
-static void
-gdk_color_profile_dispose (GObject *object)
+static gboolean
+gdk_color_profile_real_equal (gconstpointer profile1,
+                              gconstpointer profile2)
 {
-  GdkColorProfile *self = GDK_COLOR_PROFILE (object);
-
-  g_clear_pointer (&self->icc_profile, g_bytes_unref);
-  g_clear_pointer (&self->lcms_profile, cmsCloseProfile);
-
-  G_OBJECT_CLASS (gdk_color_profile_parent_class)->dispose (object);
+  return profile1 == profile2;
 }
 
 static void
 gdk_color_profile_class_init (GdkColorProfileClass *klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->set_property = gdk_color_profile_set_property;
-  gobject_class->get_property = gdk_color_profile_get_property;
-  gobject_class->dispose = gdk_color_profile_dispose;
-
-  /**
-   * GdkColorProfile:icc-profile: (attributes org.gtk.Property.get=gdk_color_profile_get_icc_profile)
-   *
-   * the ICC profile for this color profile
-   */
-  properties[PROP_ICC_PROFILE] =
-    g_param_spec_boxed ("icc-profile",
-                        P_("ICC profile"),
-                        P_("ICC profile for this color profile"),
-                        G_TYPE_BYTES,
-                        G_PARAM_READWRITE |
-                        G_PARAM_CONSTRUCT_ONLY |
-                        G_PARAM_STATIC_STRINGS |
-                        G_PARAM_EXPLICIT_NOTIFY);
-
-  g_object_class_install_properties (gobject_class, N_PROPS, properties);
-}
-
-static void
-gdk_color_profile_init (GdkColorProfile *self)
-{
-}
-
-/**
- * gdk_color_profile_get_srgb:
- *
- * Returns the color profile representing the sRGB color space.
- *
- * If you don't know anything about color profiles but need one for
- * use with some function, this one is most likely the right one.
- *
- * Returns: (transfer none): the color profile for the sRGB
- *   color space.
- *
- * Since: 4.6
- */
-GdkColorProfile *
-gdk_color_profile_get_srgb (void)
-{
-  static GdkColorProfile *srgb_profile;
-
-  if (g_once_init_enter (&srgb_profile))
-    {
-      GdkColorProfile *new_profile;
-
-      new_profile = gdk_color_profile_new_from_lcms_profile (cmsCreate_sRGBProfile (), NULL);
-      g_assert (new_profile);
-
-      g_once_init_leave (&srgb_profile, new_profile);
-    }
-
-  return srgb_profile;
-}
-
-/*<private>
- * gdk_color_profile_get_srgb_linear:
- *
- * Returns the linear color profile corresponding to the sRGB
- * color space.
- *
- * It can display the same colors, but it does not have a gamma curve.
- *
- * Returns: (transfer none): the color profile for the linear sRGB
- *   color space.
- */
-GdkColorProfile *
-gdk_color_profile_get_srgb_linear (void)
-{
-  static GdkColorProfile *srgb_linear_profile;
-
-  if (g_once_init_enter (&srgb_linear_profile))
-    {
-      cmsToneCurve *curve;
-      cmsHPROFILE lcms_profile;
-      GdkColorProfile *new_profile;
-
-      curve = cmsBuildGamma (NULL, 1.0);
-      lcms_profile = cmsCreateRGBProfile (&(cmsCIExyY) {
-                                            0.3127, 0.3290, 1.0
-                                          },
-                                          &(cmsCIExyYTRIPLE) {
-                                            { 0.6400, 0.3300, 1.0 },
-                                            { 0.3000, 0.6000, 1.0 },
-                                            { 0.1500, 0.0600, 1.0 }
-                                          },
-                                          (cmsToneCurve*[3]) { curve, curve, curve });
-      cmsFreeToneCurve (curve);
-
-      new_profile = gdk_color_profile_new_from_lcms_profile (lcms_profile, NULL);
-      g_assert (new_profile);
-
-      g_once_init_leave (&srgb_linear_profile, new_profile);
-    }
-
-  return srgb_linear_profile;
-}
-
-/**
- * gdk_color_profile_new_from_icc_bytes:
- * @bytes: The ICC profiles given as a `GBytes`
- * @error: Return location for an error
- *
- * Creates a new color profile for the given ICC profile data.
- *
- * if the profile is not valid, %NULL is returned and an error
- * is raised.
- *
- * Returns: a new `GdkColorProfile` or %NULL on error
- *
- * Since: 4.6
- */
-GdkColorProfile *
-gdk_color_profile_new_from_icc_bytes (GBytes  *bytes,
-                                      GError **error)
-{
-  g_return_val_if_fail (bytes != NULL, NULL);
-  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
-  return g_initable_new (GDK_TYPE_COLOR_PROFILE,
-                         NULL,
-                         error,
-                         "icc-profile", bytes,
-                         NULL);
-}
-
-GdkColorProfile *
-gdk_color_profile_new_from_lcms_profile (cmsHPROFILE   lcms_profile,
-                                         GError      **error)
-{
-  GdkColorProfile *result;
-  cmsUInt32Number size;
-  guchar *data;
-
-  size = 0;
-  if (!cmsSaveProfileToMem (lcms_profile, NULL, &size))
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
-      return NULL;
-    }
-
-  data = g_malloc (size);
-  if (!cmsSaveProfileToMem (lcms_profile, data, &size))
-    {
-      g_free (data);
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
-      return NULL;
-    }
-
-  result = g_object_new (GDK_TYPE_COLOR_PROFILE, NULL);
-  result->lcms_profile = lcms_profile;
-  result->icc_profile = g_bytes_new_take (data, size);
-
-  return result;
-}
-
-/**
- * gdk_color_profile_get_icc_profile: (attributes org.gtk.Method.get_property=icc-profile)
- * @self: a `GdkColorProfile`
- *
- * Returns the serialized ICC profile of @self as %GBytes.
- *
- * Returns: (transfer none): the ICC profile
- *
- * Since: 4.6
- */
-GBytes *
-gdk_color_profile_get_icc_profile (GdkColorProfile *self)
-{
-  g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), NULL);
-
-  return self->icc_profile;
-}
-
-cmsHPROFILE *
-gdk_color_profile_get_lcms_profile (GdkColorProfile *self)
-{
-  g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), NULL);
-
-  return self->lcms_profile;
+  klass->is_linear = gdk_color_profile_real_is_linear;
+  klass->get_n_components = gdk_color_profile_real_get_n_components;
+  klass->equal = gdk_color_profile_real_equal;
 }
 
 /**
@@ -361,11 +95,7 @@ gdk_color_profile_is_linear (GdkColorProfile *self)
 {
   g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), FALSE);
 
-  /* FIXME: Make this useful */
-  if (self == gdk_color_profile_get_srgb_linear ())
-    return TRUE;
-
-  return FALSE;
+  return GDK_COLOR_PROFILE_GET_CLASS (self)->is_linear (self);
 }
 
 /**
@@ -384,7 +114,7 @@ gdk_color_profile_get_n_components (GdkColorProfile *self)
 {
   g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), 3);
 
-  return cmsChannelsOf (cmsGetColorSpace (self->lcms_profile));
+  return GDK_COLOR_PROFILE_GET_CLASS (self)->get_n_components (self);
 }
 
 /**
@@ -406,100 +136,11 @@ gboolean
 gdk_color_profile_equal (gconstpointer profile1,
                          gconstpointer profile2)
 {
-  return profile1 == profile2 ||
-         g_bytes_equal (GDK_COLOR_PROFILE (profile1)->icc_profile,
-                        GDK_COLOR_PROFILE (profile2)->icc_profile);
-}
-
-typedef struct _GdkColorTransformCache GdkColorTransformCache;
-
-struct _GdkColorTransformCache
-{
-  GdkColorProfile *source;
-  guint            source_type;
-  GdkColorProfile *dest;
-  guint            dest_type;
-};
-
-static void
-gdk_color_transform_cache_free (gpointer data)
-{
-  g_free (data);
-}
-
-static guint
-gdk_color_transform_cache_hash (gconstpointer data)
-{
-  const GdkColorTransformCache *cache = data;
-
-  return g_direct_hash (cache->source) ^
-         (g_direct_hash (cache->dest) >> 2) ^
-         ((cache->source_type << 16) | (cache->source_type >> 16)) ^
-         cache->dest_type;
-}
-
-static gboolean
-gdk_color_transform_cache_equal (gconstpointer data1,
-                                 gconstpointer data2)
-{
-  const GdkColorTransformCache *cache1 = data1;
-  const GdkColorTransformCache *cache2 = data2;
-
-  return cache1->source == cache2->source && 
-         cache1->source_type == cache2->source_type && 
-         cache1->dest == cache2->dest && 
-         cache1->dest_type == cache2->dest_type;
-}
-
-cmsHTRANSFORM *
-gdk_color_profile_lookup_transform (GdkColorProfile *source,
-                                    guint            source_type,
-                                    GdkColorProfile *dest,
-                                    guint            dest_type)
-{
-  GdkColorTransformCache *entry;
-  static GHashTable *cache = NULL;
-  cmsHTRANSFORM *transform;
-
-  if (cache == NULL)
-    cache = g_hash_table_new_full (gdk_color_transform_cache_hash,
-                                   gdk_color_transform_cache_equal,
-                                   gdk_color_transform_cache_free,
-                                   cmsDeleteTransform);
+  if (profile1 == profile2)
+    return TRUE;
 
-  transform = g_hash_table_lookup (cache,
-                                   &(GdkColorTransformCache) {
-                                     source, source_type,
-                                     dest, dest_type
-                                   });
-  if (G_UNLIKELY (transform == NULL))
-    {
-      transform = cmsCreateTransform (gdk_color_profile_get_lcms_profile (source),
-                                      source_type,
-                                      gdk_color_profile_get_lcms_profile (dest),
-                                      dest_type,
-                                      INTENT_PERCEPTUAL,
-                                      cmsFLAGS_COPY_ALPHA);
-      entry = g_new (GdkColorTransformCache, 1);
-      *entry = (GdkColorTransformCache) {
-                 source, source_type,
-                 dest, dest_type
-               };
-      g_hash_table_insert (cache, entry, transform);
-    }
-  
-  return transform;
-}
+  if (G_OBJECT_TYPE (profile1) != G_OBJECT_TYPE (profile2))
+    return FALSE;
 
-/* Check if the color profile and the memory format have the
- * same color components.
- */
-gboolean
-gdk_color_profile_supports_memory_format (GdkColorProfile *profile,
-                                          GdkMemoryFormat  format)
-{
-  /* Currently, all our memory formats are RGB (with or without alpha).
-   * Update this when that changes.
-   */
-  return cmsGetColorSpace (profile->lcms_profile) == cmsSigRgbData;
+  return GDK_COLOR_PROFILE_GET_CLASS (profile1)->equal (profile1, profile2);
 }
diff --git a/gdk/gdkcolorprofile.h b/gdk/gdkcolorprofile.h
index 6cd5329694..d5da6296de 100644
--- a/gdk/gdkcolorprofile.h
+++ b/gdk/gdkcolorprofile.h
@@ -63,6 +63,7 @@ GDK_AVAILABLE_IN_4_6
 gboolean                     gdk_color_profile_equal                      (gconstpointer         profile1,
                                                                            gconstpointer         profile2);
 
+
 G_END_DECLS
 
 #endif /* __GDK_COLOR_PROFILE_H__ */
diff --git a/gdk/gdkcolorprofileprivate.h b/gdk/gdkcolorprofileprivate.h
index 419ecdc1af..f92f91191e 100644
--- a/gdk/gdkcolorprofileprivate.h
+++ b/gdk/gdkcolorprofileprivate.h
@@ -8,19 +8,24 @@
 
 G_BEGIN_DECLS
 
-GdkColorProfile *            gdk_color_profile_get_srgb_linear            (void) G_GNUC_CONST;
+struct _GdkColorProfile
+{
+  GObject parent_instance;
+};
 
-GdkColorProfile *            gdk_color_profile_new_from_lcms_profile      (cmsHPROFILE           
lcms_profile,
-                                                                           GError              **error);
+struct _GdkColorProfileClass
+{
+  GObjectClass parent_class;
 
-cmsHPROFILE *                gdk_color_profile_get_lcms_profile           (GdkColorProfile      *self);
+  gboolean (* is_linear)        (GdkColorProfile *profile);
+  gsize    (* get_n_components) (GdkColorProfile *profile);
+  gboolean (* equal)            (gconstpointer    profile1,
+                                 gconstpointer    profile2);
+};
 
-cmsHTRANSFORM *              gdk_color_profile_lookup_transform           (GdkColorProfile      *source,
-                                                                           guint                 source_type,
-                                                                           GdkColorProfile      *dest,
-                                                                           guint                 dest_type);
-gboolean                     gdk_color_profile_supports_memory_format     (GdkColorProfile      *profile,
-                                                                           GdkMemoryFormat       format);
+GdkColorProfile *            gdk_color_profile_get_srgb_linear            (void) G_GNUC_CONST;
+GdkColorProfile *            gdk_color_profile_get_hsl                    (void) G_GNUC_CONST;
+GdkColorProfile *            gdk_color_profile_get_hwb                    (void) G_GNUC_CONST;
 
 G_END_DECLS
 
diff --git a/gdk/gdkderivedprofile.c b/gdk/gdkderivedprofile.c
new file mode 100644
index 0000000000..a734dc5a96
--- /dev/null
+++ b/gdk/gdkderivedprofile.c
@@ -0,0 +1,513 @@
+/* gdkderivedprofile.c
+ *
+ * Copyright 2021 (c) Red Hat, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * GdkDerivedProfile:
+ *
+ * Since: 4.6
+ */
+
+#include "config.h"
+
+#include "gdkderivedprofile.h"
+#include "gdkcolorprofileprivate.h"
+#include "gdkenumtypes.h"
+
+#include "gdkintl.h"
+
+struct _GdkDerivedProfile
+{
+  GdkColorProfile parent_instance;
+
+  GdkColorSpace color_space;
+  GdkColorProfile *base_profile;
+};
+
+struct _GdkDerivedProfileClass
+{
+  GdkColorProfileClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_BASE_PROFILE,
+  PROP_COLOR_SPACE,
+
+  N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+G_DEFINE_TYPE (GdkDerivedProfile, gdk_derived_profile, GDK_TYPE_COLOR_PROFILE)
+
+static void
+gdk_derived_profile_init (GdkDerivedProfile *profile)
+{
+}
+
+static void
+gdk_derived_profile_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PROFILE:
+      self->base_profile = g_value_dup_object (value);
+      break;
+
+    case PROP_COLOR_SPACE:
+      self->color_space = g_value_get_enum (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdk_derived_profile_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PROFILE:
+      g_value_set_object (value, self->base_profile);
+      break;
+
+    case PROP_COLOR_SPACE:
+      g_value_set_enum (value, self->color_space);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdk_derived_profile_dispose (GObject *object)
+{
+  GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
+
+  g_clear_object (&self->base_profile);
+
+  G_OBJECT_CLASS (gdk_derived_profile_parent_class)->dispose (object);
+}
+
+static gboolean
+gdk_derived_profile_is_linear (GdkColorProfile *profile)
+{
+  GdkDerivedProfile *self = GDK_DERIVED_PROFILE (profile);
+
+  return self->base_profile == gdk_color_profile_get_srgb_linear ();
+}
+
+static gsize
+gdk_derived_profile_get_n_components (GdkColorProfile *profile)
+{
+  GdkDerivedProfile *self = GDK_DERIVED_PROFILE (profile);
+
+  return gdk_color_profile_get_n_components (self->base_profile);
+}
+
+static gboolean
+gdk_derived_profile_equal (gconstpointer profile1,
+                           gconstpointer profile2)
+{
+  GdkDerivedProfile *p1 = GDK_DERIVED_PROFILE (profile1);
+  GdkDerivedProfile *p2 = GDK_DERIVED_PROFILE (profile2);
+
+  return p1->color_space == p2->color_space &&
+         gdk_color_profile_equal (p1->base_profile, p2->base_profile);
+}
+
+static void
+gdk_derived_profile_class_init (GdkDerivedProfileClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GdkColorProfileClass *profile_class = GDK_COLOR_PROFILE_CLASS (klass);
+
+  gobject_class->set_property = gdk_derived_profile_set_property;
+  gobject_class->get_property = gdk_derived_profile_get_property;
+  gobject_class->dispose = gdk_derived_profile_dispose;
+
+  profile_class->is_linear = gdk_derived_profile_is_linear;
+  profile_class->get_n_components = gdk_derived_profile_get_n_components;
+  profile_class->equal = gdk_derived_profile_equal;
+
+  /**
+   * GdkDerivedProfile:base-profile: (attributes org.gtk.Property.get=gdk_derived_profile_get_base_profile)
+   *
+   * The base profile for this color profile.
+   */
+  properties[PROP_BASE_PROFILE] =
+    g_param_spec_object ("base-profile",
+                         P_("Base profile"),
+                         P_("Base profile for this color profile"),
+                         GDK_TYPE_ICC_PROFILE,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS |
+                         G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GdkDerivedProfile:color-space: (attributes org.gtk.Property.get=gdk_derived_profile_get_color_space)
+   *
+   * The color space for this color profile.
+   */
+  properties[PROP_COLOR_SPACE] =
+    g_param_spec_enum ("color-space",
+                       P_("Color space"),
+                       P_("Color space for this color profile"),
+                       GDK_TYPE_COLOR_SPACE,
+                       GDK_COLOR_SPACE_HSL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS |
+                       G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+/**
+ * gdk_derived_profile_get_base_profile:
+ * @profile: a `GdkDerivedProfile`
+ *
+ * Returns the base profile for this profile.
+ *
+ * Returns: (transfer none): the base profile
+ *
+ * Since: 4.6
+ */
+GdkColorProfile *
+gdk_derived_profile_get_base_profile (GdkDerivedProfile *self)
+{
+  return self->base_profile;
+}
+
+/**
+ * gdk_derived_profile_get_color_space:
+ * @profile: a `GdkDerivedProfile`
+ *
+ * Returns the color space for this profile.
+ *
+ * Returns: the color space
+ *
+ * Since: 4.6
+ */
+GdkColorSpace
+gdk_derived_profile_get_color_space (GdkDerivedProfile *self)
+{
+  return self->color_space;
+}
+
+/*<private>
+ * gdk_color_profile_get_hsl:
+ *
+ * Returns the color profile corresponding to the HSL
+ * color space.
+ *
+ * It can display the same colors as sRGB, but it encodes
+ * the coordinates differently.
+ *
+ * Returns: (transfer none): the color profile for the HSL
+ *   color space.
+ */
+GdkColorProfile *
+gdk_color_profile_get_hsl (void)
+{
+  static GdkColorProfile *hsl_profile;
+
+  if (g_once_init_enter (&hsl_profile))
+    {
+      GdkColorProfile *new_profile;
+
+      new_profile = g_object_new (GDK_TYPE_DERIVED_PROFILE,
+                                  "base-profile", gdk_color_profile_get_srgb (),
+                                  "color-space", GDK_COLOR_SPACE_HSL,
+                                  NULL);
+
+      g_assert (new_profile);
+
+      g_once_init_leave (&hsl_profile, new_profile);
+    }
+
+  return hsl_profile;
+}
+
+GdkColorProfile *
+gdk_color_profile_get_hwb (void)
+{
+  static GdkColorProfile *hwb_profile;
+
+  if (g_once_init_enter (&hwb_profile))
+    {
+      GdkColorProfile *new_profile;
+
+      new_profile = g_object_new (GDK_TYPE_DERIVED_PROFILE,
+                                  "base-profile", gdk_color_profile_get_srgb (),
+                                  "color-space", GDK_COLOR_SPACE_HWB,
+                                  NULL);
+
+      g_assert (new_profile);
+
+      g_once_init_leave (&hwb_profile, new_profile);
+    }
+
+  return hwb_profile;
+}
+
+static void
+hsl_to_rgb (const float *in,
+            float       *out)
+{
+  float lightness;
+  float saturation;
+  float m1, m2;
+  float orig_hue, hue;
+
+  lightness = in[2];
+  saturation = in[1];
+  orig_hue = in[0];
+
+  if (lightness <= 0.5)
+    m2 = lightness * (1 + saturation);
+  else
+    m2 = lightness + saturation - lightness * saturation;
+  m1 = 2 * lightness - m2;
+
+  if (saturation == 0)
+    {
+      out[0] = out[1] = out[2] = lightness;
+    }
+  else
+    {
+      hue = orig_hue + 120;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        out[0] = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        out[0] = m2;
+      else if (hue < 240)
+        out[0] = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        out[0] = m1;
+
+      hue = orig_hue;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        out[1] = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        out[1] = m2;
+      else if (hue < 240)
+        out[1] = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        out[1] = m1;
+
+      hue = orig_hue - 120;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        out[2] = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        out[2] = m2;
+      else if (hue < 240)
+        out[2] = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        out[2] = m1;
+    }
+}
+
+static void
+rgb_to_hsl (const float *in,
+            float       *out)
+{
+  float min;
+  float max;
+  float red;
+  float green;
+  float blue;
+  float delta;
+  float hue;
+  float saturation;
+  float lightness;
+
+  red = in[0];
+  green = in[1];
+  blue = in[2];
+
+  if (red > green)
+    {
+      if (red > blue)
+        max = red;
+      else
+        max = blue;
+
+      if (green < blue)
+        min = green;
+      else
+        min = blue;
+    }
+  else
+    {
+      if (green > blue)
+        max = green;
+      else
+        max = blue;
+
+      if (red < blue)
+        min = red;
+      else
+        min = blue;
+    }
+
+  lightness = (max + min) / 2;
+  saturation = 0;
+  hue = 0;
+
+  if (max != min)
+    {
+      if (lightness <= 0.5)
+        saturation = (max - min) / (max + min);
+      else
+        saturation = (max - min) / (2 - max - min);
+
+      delta = max -min;
+      if (red == max)
+        hue = (green - blue) / delta;
+      else if (green == max)
+        hue = 2 + (blue - red) / delta;
+      else if (blue == max)
+        hue = 4 + (red - green) / delta;
+
+      hue *= 60;
+      if (hue < 0.0)
+        hue += 360;
+    }
+
+  out[0] = hue;
+  out[1] = saturation;
+  out[2] = lightness;
+}
+
+static void
+hwb_to_rgb (const float *in,
+            float       *out)
+{
+  float hue;
+  float white;
+  float black;
+  float m[3];
+
+  hue = in[0];
+  white = in[1];
+  black = in[2];
+
+  white /= 100;
+  black /= 100;
+
+  if (white + black >= 1)
+    {
+      out[0] = out[1] = out[2] = white / (white + black);
+      return;
+    }
+
+  m[0] = hue;
+  m[1] = 1;
+  m[2] = 0.5;
+
+  hsl_to_rgb (m, out);
+
+  out[0] = out[0] * (1 - white - black) + white;
+  out[1] = out[1] * (1 - white - black) + white;
+  out[2] = out[2] * (1 - white - black) + white;
+}
+
+static void
+rgb_to_hwb (const float *in,
+            float       *out)
+{
+  float white;
+  float black;
+
+  rgb_to_hsl (in, out);
+
+  white = MIN (MIN (out[0], out[1]), out[2]);
+  black = 1 - MAX (MAX (out[0], out[1]), out[2]);
+
+  out[1] = white * 100;
+  out[2] = black * 100;
+}
+
+void
+gdk_derived_profile_convert_to_base_profile (GdkDerivedProfile *profile,
+                                             const float       *in,
+                                             float             *out)
+{
+  switch (gdk_derived_profile_get_color_space (profile))
+    {
+    case GDK_COLOR_SPACE_HSL:
+      hsl_to_rgb (in, out);
+      break;
+    case GDK_COLOR_SPACE_HWB:
+      hwb_to_rgb (in, out);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+}
+
+void
+gdk_derived_profile_convert_from_base_profile (GdkDerivedProfile *profile,
+                                               const float       *in,
+                                               float            *out)
+{
+  switch (gdk_derived_profile_get_color_space (profile))
+    {
+    case GDK_COLOR_SPACE_HSL:
+      rgb_to_hsl (in, out);
+      break;
+    case GDK_COLOR_SPACE_HWB:
+      rgb_to_hwb (in, out);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+}
+
diff --git a/gdk/gdkderivedprofile.h b/gdk/gdkderivedprofile.h
new file mode 100644
index 0000000000..015822027d
--- /dev/null
+++ b/gdk/gdkderivedprofile.h
@@ -0,0 +1,71 @@
+/* gdkderivedprofile.h
+ *
+ * Copyright 2021 (c) Red Hat, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_DERIVED_PROFILE_H__
+#define __GDK_DERIVED_PROFILE_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdkcolorprofile.h>
+#include <gdk/gdkiccprofile.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DERIVED_PROFILE (gdk_derived_profile_get_type ())
+
+#define GDK_DERIVED_PROFILE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DERIVED_PROFILE, 
GdkDerivedProfile))
+#define GDK_IS_DERIVED_PROFILE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DERIVED_PROFILE))
+#define GDK_DERIVED_PROFILE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DERIVED_PROFILE, 
GdkDerivedProfileClass))
+#define GDK_IS_DERIVED_PROFILE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DERIVED_PROFILE))
+#define GDK_DERIVED_PROFILE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DERIVED_PROFILE, 
GdkDerivedProfileClass))
+
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDerivedProfile, g_object_unref)
+
+typedef struct _GdkDerivedProfileClass        GdkDerivedProfileClass;
+
+GDK_AVAILABLE_IN_4_6
+GType                        gdk_derived_profile_get_type  (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_4_6
+GdkColorProfile *            gdk_derived_profile_get_base_profile (GdkDerivedProfile *profile);
+
+typedef enum {
+  GDK_COLOR_SPACE_HSL,
+  GDK_COLOR_SPACE_HWB,
+} GdkColorSpace;
+
+GDK_AVAILABLE_IN_4_6
+GdkColorSpace                gdk_derived_profile_get_color_space (GdkDerivedProfile *profile);
+
+GDK_AVAILABLE_IN_4_6
+void                         gdk_derived_profile_convert_to_base_profile   (GdkDerivedProfile *profile,
+                                                                            const float       *in,
+                                                                            float             *out);
+
+GDK_AVAILABLE_IN_4_6
+void                         gdk_derived_profile_convert_from_base_profile (GdkDerivedProfile *profile,
+                                                                            const float       *in,
+                                                                            float             *out);
+
+G_END_DECLS
+
+#endif /* __GDK_DERIVED_PROFILE_H__ */
diff --git a/gdk/gdkiccprofile.c b/gdk/gdkiccprofile.c
new file mode 100644
index 0000000000..16089d37c2
--- /dev/null
+++ b/gdk/gdkiccprofile.c
@@ -0,0 +1,451 @@
+/* gdkiccprofile.c
+ *
+ * Copyright 2021 (c) Benjamin Otte
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * GdkICCProfile:
+ *
+ * `GdkICCProfile` is used to describe ICC color profiles.
+ *
+ * It is used to associate color profiles defined by the [International
+ * Color Consortium (ICC)](https://color.org/) with texture and color data.
+ *
+ * Each `GdkColorProfile` encapsulates an
+ * [ICC profile](https://en.wikipedia.org/wiki/ICC_profile). That profile
+ * can be queried via the using [property@Gdk.ColorProfile:icc-profile]
+ * property.
+ *
+ * `GdkICCProfile` objects are immutable and therefore threadsafe.
+ *
+ * Since: 4.6
+ */
+
+#include "config.h"
+
+#include "gdkiccprofileprivate.h"
+#include "gdkcolorprofileprivate.h"
+
+#include "gdkintl.h"
+
+struct _GdkICCProfile
+{
+  GdkColorProfile parent_instance;
+
+  GBytes *icc_profile;
+  cmsHPROFILE lcms_profile;
+};
+
+struct _GdkICCProfileClass
+{
+  GdkColorProfileClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_ICC_PROFILE,
+
+  N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+static gboolean
+gdk_icc_profile_real_init (GInitable     *initable,
+                           GCancellable  *cancellable,
+                           GError       **error)
+{
+  GdkICCProfile *self = GDK_ICC_PROFILE (initable);
+
+  if (self->lcms_profile == NULL)
+    {
+      const guchar *data;
+      gsize size;
+
+      if (self->icc_profile == NULL)
+        self->icc_profile = g_bytes_new (NULL, 0);
+
+      data = g_bytes_get_data (self->icc_profile, &size);
+
+      self->lcms_profile = cmsOpenProfileFromMem (data, size);
+      if (self->lcms_profile == NULL)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
+          return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+static void
+gdk_icc_profile_initable_init (GInitableIface *iface)
+{
+  iface->init = gdk_icc_profile_real_init;
+}
+
+
+G_DEFINE_TYPE_WITH_CODE (GdkICCProfile, gdk_icc_profile, GDK_TYPE_COLOR_PROFILE,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gdk_icc_profile_initable_init))
+
+static void
+gdk_icc_profile_set_property (GObject      *gobject,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GdkICCProfile *self = GDK_ICC_PROFILE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ICC_PROFILE:
+      self->icc_profile = g_value_dup_boxed (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdk_icc_profile_get_property (GObject    *gobject,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GdkICCProfile *self = GDK_ICC_PROFILE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ICC_PROFILE:
+      g_value_set_boxed (value, self->icc_profile);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdk_icc_profile_dispose (GObject *object)
+{
+  GdkICCProfile *self = GDK_ICC_PROFILE (object);
+
+  g_clear_pointer (&self->icc_profile, g_bytes_unref);
+  g_clear_pointer (&self->lcms_profile, cmsCloseProfile);
+
+  G_OBJECT_CLASS (gdk_icc_profile_parent_class)->dispose (object);
+}
+
+static gboolean
+gdk_icc_profile_is_linear (GdkColorProfile *profile)
+{
+  return profile == gdk_color_profile_get_srgb_linear ();
+}
+
+static gsize
+gdk_icc_profile_get_n_components (GdkColorProfile *profile)
+{
+  GdkICCProfile *self = GDK_ICC_PROFILE (profile);
+
+  return cmsChannelsOf (cmsGetColorSpace (self->lcms_profile));
+}
+
+static gboolean
+gdk_icc_profile_equal (gconstpointer profile1,
+                         gconstpointer profile2)
+{
+  return g_bytes_equal (GDK_ICC_PROFILE (profile1)->icc_profile,
+                        GDK_ICC_PROFILE (profile2)->icc_profile);
+}
+
+static void
+gdk_icc_profile_class_init (GdkICCProfileClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GdkColorProfileClass *profile_class = GDK_COLOR_PROFILE_CLASS (klass);
+
+  gobject_class->set_property = gdk_icc_profile_set_property;
+  gobject_class->get_property = gdk_icc_profile_get_property;
+  gobject_class->dispose = gdk_icc_profile_dispose;
+
+  profile_class->is_linear = gdk_icc_profile_is_linear;
+  profile_class->get_n_components = gdk_icc_profile_get_n_components;
+  profile_class->equal = gdk_icc_profile_equal;
+
+  /**
+   * GdkICCProfile:icc-profile: (attributes org.gtk.Property.get=gdk_icc_profile_get_icc_profile)
+   *
+   * the ICC profile for this color profile
+   */
+  properties[PROP_ICC_PROFILE] =
+    g_param_spec_boxed ("icc-profile",
+                        P_("ICC profile"),
+                        P_("ICC profile for this color profile"),
+                        G_TYPE_BYTES,
+                        G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS |
+                        G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gdk_icc_profile_init (GdkICCProfile *self)
+{
+}
+
+/**
+ * gdk_color_profile_get_srgb:
+ *
+ * Returns the color profile representing the sRGB color space.
+ *
+ * If you don't know anything about color profiles but need one for
+ * use with some function, this one is most likely the right one.
+ *
+ * Returns: (transfer none): the color profile for the sRGB
+ *   color space.
+ *
+ * Since: 4.6
+ */
+GdkColorProfile *
+gdk_color_profile_get_srgb (void)
+{
+  static GdkColorProfile *srgb_profile;
+
+  if (g_once_init_enter (&srgb_profile))
+    {
+      GdkColorProfile *new_profile;
+
+      new_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (cmsCreate_sRGBProfile (), 
NULL));
+      g_assert (new_profile);
+
+      g_once_init_leave (&srgb_profile, new_profile);
+    }
+
+  return srgb_profile;
+}
+
+/*<private>
+ * gdk_color_profile_get_srgb_linear:
+ *
+ * Returns the linear color profile corresponding to the sRGB
+ * color space.
+ *
+ * It can display the same colors, but it does not have a gamma curve.
+ *
+ * Returns: (transfer none): the color profile for the linear sRGB
+ *   color space.
+ */
+GdkColorProfile *
+gdk_color_profile_get_srgb_linear (void)
+{
+  static GdkColorProfile *srgb_linear_profile;
+
+  if (g_once_init_enter (&srgb_linear_profile))
+    {
+      cmsToneCurve *curve;
+      cmsHPROFILE lcms_profile;
+      GdkColorProfile *new_profile;
+
+      curve = cmsBuildGamma (NULL, 1.0);
+      lcms_profile = cmsCreateRGBProfile (&(cmsCIExyY) {
+                                            0.3127, 0.3290, 1.0
+                                          },
+                                          &(cmsCIExyYTRIPLE) {
+                                            { 0.6400, 0.3300, 1.0 },
+                                            { 0.3000, 0.6000, 1.0 },
+                                            { 0.1500, 0.0600, 1.0 }
+                                          },
+                                          (cmsToneCurve*[3]) { curve, curve, curve });
+      cmsFreeToneCurve (curve);
+
+      new_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (lcms_profile, NULL));
+      g_assert (new_profile);
+
+      g_once_init_leave (&srgb_linear_profile, new_profile);
+    }
+
+  return srgb_linear_profile;
+}
+
+/**
+ * gdk_icc_profile_new_from_icc_bytes:
+ * @bytes: The ICC profiles given as a `GBytes`
+ * @error: Return location for an error
+ *
+ * Creates a new color profile for the given ICC profile data.
+ *
+ * if the profile is not valid, %NULL is returned and an error
+ * is raised.
+ *
+ * Returns: a new `GdkColorProfile` or %NULL on error
+ *
+ * Since: 4.6
+ */
+GdkICCProfile *
+gdk_icc_profile_new_from_icc_bytes (GBytes  *bytes,
+                                    GError **error)
+{
+  g_return_val_if_fail (bytes != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  return g_initable_new (GDK_TYPE_ICC_PROFILE,
+                         NULL,
+                         error,
+                         "icc-profile", bytes,
+                         NULL);
+}
+
+GdkICCProfile *
+gdk_icc_profile_new_from_lcms_profile (cmsHPROFILE   lcms_profile,
+                                       GError      **error)
+{
+  GdkICCProfile *result;
+  cmsUInt32Number size;
+  guchar *data;
+
+  size = 0;
+  if (!cmsSaveProfileToMem (lcms_profile, NULL, &size))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
+      return NULL;
+    }
+
+  data = g_malloc (size);
+  if (!cmsSaveProfileToMem (lcms_profile, data, &size))
+    {
+      g_free (data);
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
+      return NULL;
+    }
+
+  result = g_object_new (GDK_TYPE_ICC_PROFILE, NULL);
+  result->lcms_profile = lcms_profile;
+  result->icc_profile = g_bytes_new_take (data, size);
+
+  return result;
+}
+
+/**
+ * gdk_icc_profile_get_icc_profile: (attributes org.gtk.Method.get_property=icc-profile)
+ * @self: a `GdkICCProfile`
+ *
+ * Returns the serialized ICC profile of @self as %GBytes.
+ *
+ * Returns: (transfer none): the ICC profile
+ *
+ * Since: 4.6
+ */
+GBytes *
+gdk_icc_profile_get_icc_profile (GdkICCProfile *self)
+{
+  g_return_val_if_fail (GDK_IS_ICC_PROFILE (self), NULL);
+
+  return self->icc_profile;
+}
+
+cmsHPROFILE *
+gdk_icc_profile_get_lcms_profile (GdkICCProfile *self)
+{
+  g_return_val_if_fail (GDK_IS_ICC_PROFILE (self), NULL);
+
+  return self->lcms_profile;
+}
+
+
+typedef struct _GdkICCTransformCache GdkICCTransformCache;
+
+struct _GdkICCTransformCache
+{
+  GdkICCProfile *source;
+  guint          source_type;
+  GdkICCProfile *dest;
+  guint          dest_type;
+};
+
+static void
+gdk_icc_transform_cache_free (gpointer data)
+{
+  g_free (data);
+}
+
+static guint
+gdk_icc_transform_cache_hash (gconstpointer data)
+{
+  const GdkICCTransformCache *cache = data;
+
+  return g_direct_hash (cache->source) ^
+         (g_direct_hash (cache->dest) >> 2) ^
+         ((cache->source_type << 16) | (cache->source_type >> 16)) ^
+         cache->dest_type;
+}
+
+static gboolean
+gdk_icc_transform_cache_equal (gconstpointer data1,
+                               gconstpointer data2)
+{
+  const GdkICCTransformCache *cache1 = data1;
+  const GdkICCTransformCache *cache2 = data2;
+
+  return cache1->source == cache2->source &&
+         cache1->source_type == cache2->source_type &&
+         cache1->dest == cache2->dest &&
+         cache1->dest_type == cache2->dest_type;
+}
+
+cmsHTRANSFORM *
+gdk_icc_profile_lookup_transform (GdkICCProfile *source,
+                                  guint          source_type,
+                                  GdkICCProfile *dest,
+                                  guint          dest_type)
+{
+  GdkICCTransformCache *entry;
+  static GHashTable *cache = NULL;
+  cmsHTRANSFORM *transform;
+
+  if (cache == NULL)
+    cache = g_hash_table_new_full (gdk_icc_transform_cache_hash,
+                                   gdk_icc_transform_cache_equal,
+                                   gdk_icc_transform_cache_free,
+                                   cmsDeleteTransform);
+
+  transform = g_hash_table_lookup (cache,
+                                   &(GdkICCTransformCache) {
+                                     source, source_type,
+                                     dest, dest_type
+                                   });
+  if (G_UNLIKELY (transform == NULL))
+    {
+      transform = cmsCreateTransform (gdk_icc_profile_get_lcms_profile (source),
+                                      source_type,
+                                      gdk_icc_profile_get_lcms_profile (dest),
+                                      dest_type,
+                                      INTENT_PERCEPTUAL,
+                                      cmsFLAGS_COPY_ALPHA);
+      entry = g_new (GdkICCTransformCache, 1);
+      *entry = (GdkICCTransformCache) {
+                 source, source_type,
+                 dest, dest_type
+               };
+      g_hash_table_insert (cache, entry, transform);
+    }
+
+  return transform;
+}
diff --git a/gdk/gdkiccprofile.h b/gdk/gdkiccprofile.h
new file mode 100644
index 0000000000..a3801e3cbd
--- /dev/null
+++ b/gdk/gdkiccprofile.h
@@ -0,0 +1,56 @@
+/* gdkiccprofile.h
+ *
+ * Copyright 2021 (c) Benjamin Otte
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_ICC_PROFILE_H__
+#define __GDK_ICC_PROFILE_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdkcolorprofile.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_ICC_PROFILE (gdk_icc_profile_get_type ())
+
+#define GDK_ICC_PROFILE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_ICC_PROFILE, 
GdkICCProfile))
+#define GDK_IS_ICC_PROFILE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_ICC_PROFILE))
+#define GDK_ICC_PROFILE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_ICC_PROFILE, 
GdkICCProfileClass))
+#define GDK_IS_ICC_PROFILE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_ICC_PROFILE))
+#define GDK_ICC_PROFILE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_ICC_PROFILE, 
GdkICCProfileClass))
+
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkICCProfile, g_object_unref)
+
+typedef struct _GdkICCProfileClass        GdkICCProfileClass;
+
+GDK_AVAILABLE_IN_4_6
+GType                        gdk_icc_profile_get_type                   (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_4_6
+GdkICCProfile *              gdk_icc_profile_new_from_icc_bytes         (GBytes               *bytes,
+                                                                         GError              **error);
+
+GDK_AVAILABLE_IN_4_6
+GBytes *                     gdk_icc_profile_get_icc_profile            (GdkICCProfile      *self);
+
+G_END_DECLS
+
+#endif /* __GDK_ICC_PROFILE_H__ */
diff --git a/gdk/gdkiccprofileprivate.h b/gdk/gdkiccprofileprivate.h
new file mode 100644
index 0000000000..ba35535915
--- /dev/null
+++ b/gdk/gdkiccprofileprivate.h
@@ -0,0 +1,24 @@
+#ifndef __GDK_ICC_PROFILE_PRIVATE_H__
+#define __GDK_ICC_PROFILE_PRIVATE_H__
+
+#include "gdkiccprofile.h"
+#include "gdkmemorytexture.h"
+
+#include <lcms2.h>
+
+G_BEGIN_DECLS
+
+
+GdkICCProfile *              gdk_icc_profile_new_from_lcms_profile      (cmsHPROFILE         lcms_profile,
+                                                                         GError            **error);
+
+cmsHPROFILE *                gdk_icc_profile_get_lcms_profile           (GdkICCProfile      *self);
+
+cmsHTRANSFORM *              gdk_icc_profile_lookup_transform           (GdkICCProfile      *source,
+                                                                         guint               source_type,
+                                                                         GdkICCProfile      *dest,
+                                                                         guint               dest_type);
+
+G_END_DECLS
+
+#endif /* __GDK_COLOR_PROFILE_PRIVATE_H__ */
diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c
index 182b3f37db..cdd2c9a009 100644
--- a/gdk/gdkmemoryformat.c
+++ b/gdk/gdkmemoryformat.c
@@ -21,7 +21,7 @@
 
 #include "gdkmemoryformatprivate.h"
 
-#include "gdkcolorprofileprivate.h"
+#include "gdkiccprofileprivate.h"
 #include "gdkprofilerprivate.h"
 #include "gsk/ngl/fp16private.h"
 
@@ -822,10 +822,10 @@ gdk_memory_convert_transform (guchar              *dest_data,
   guchar *src_tmp, *dest_tmp;
   gsize y;
 
-  transform = gdk_color_profile_lookup_transform (src_profile,
-                                                  src_desc->lcms.type,
-                                                  dest_profile,
-                                                  dest_desc->lcms.type);
+  transform = gdk_icc_profile_lookup_transform (GDK_ICC_PROFILE (src_profile),
+                                                src_desc->lcms.type,
+                                                GDK_ICC_PROFILE (dest_profile),
+                                                dest_desc->lcms.type);
 
   if (src_desc->to_lcms)
     src_tmp = g_malloc_n (src_desc->lcms.bpp, width);
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index 68c0d29aa2..d8a7caa5b8 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -231,7 +231,6 @@ gdk_memory_texture_new_with_color_profile (int              width,
   g_return_val_if_fail (GDK_IS_COLOR_PROFILE (color_profile), NULL);
   g_return_val_if_fail (bytes != NULL, NULL);
   g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
-  g_return_val_if_fail (gdk_color_profile_supports_memory_format (color_profile, format), NULL);
 
   bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride);
 
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 199ab1196f..94c168b78a 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -41,7 +41,7 @@
 #include "gdktextureprivate.h"
 
 #include "gdkcairo.h"
-#include "gdkcolorprofile.h"
+#include "gdkiccprofile.h"
 #include "gdkintl.h"
 #include "gdkmemoryformatprivate.h"
 #include "gdkmemorytextureprivate.h"
@@ -457,7 +457,7 @@ gdk_color_profile_from_pixbuf (GdkPixbuf *pixbuf)
 
       icc_data = g_base64_decode (icc_profile_base64, &icc_len);
       bytes = g_bytes_new_take (icc_data, icc_len);
-      profile = gdk_color_profile_new_from_icc_bytes (bytes, NULL);
+      profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
       g_bytes_unref (bytes);
     }
   if (!profile)
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index 0abf410591..7b5639b1e2 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -74,6 +74,8 @@ typedef cairo_rectangle_int_t         GdkRectangle;
 /* Forward declarations of commonly used types */
 typedef struct _GdkRGBA               GdkRGBA;
 typedef struct _GdkColorProfile       GdkColorProfile;
+typedef struct _GdkICCProfile         GdkICCProfile;
+typedef struct _GdkDerivedProfile     GdkDerivedProfile;
 typedef struct _GdkContentFormats     GdkContentFormats;
 typedef struct _GdkContentProvider    GdkContentProvider;
 typedef struct _GdkCursor             GdkCursor;
diff --git a/gdk/loaders/gdkjpeg.c b/gdk/loaders/gdkjpeg.c
index 164459869d..ab24eaa965 100644
--- a/gdk/loaders/gdkjpeg.c
+++ b/gdk/loaders/gdkjpeg.c
@@ -19,7 +19,7 @@
 
 #include "gdkjpegprivate.h"
 
-#include "gdkcolorprofile.h"
+#include "gdkiccprofile.h"
 #include "gdkintl.h"
 #include "gdkmemorytextureprivate.h"
 #include "gdktexture.h"
@@ -262,7 +262,7 @@ gdk_load_jpeg (GBytes  *input_bytes,
   if (jpeg_read_icc_profile (&info, &icc_data, &icc_len))
     {
       GBytes *icc_bytes = g_bytes_new_with_free_func (icc_data, icc_len, free, icc_data);
-      color_profile = gdk_color_profile_new_from_icc_bytes (icc_bytes, error);
+      color_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (icc_bytes, error));
       g_bytes_unref (icc_bytes);
     }
   else
@@ -340,7 +340,7 @@ gdk_save_jpeg (GdkTexture *texture)
 
   jpeg_start_compress (&info, TRUE);
 
-  bytes = gdk_color_profile_get_icc_profile (color_profile);
+  bytes = gdk_icc_profile_get_icc_profile (GDK_ICC_PROFILE (color_profile));
   jpeg_write_icc_profile (&info,
                           g_bytes_get_data (bytes, NULL),
                           g_bytes_get_size (bytes));
diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c
index 23a535bfc4..df9ce28ab0 100644
--- a/gdk/loaders/gdkpng.c
+++ b/gdk/loaders/gdkpng.c
@@ -19,7 +19,7 @@
 
 #include "gdkpngprivate.h"
 
-#include "gdkcolorprofileprivate.h"
+#include "gdkiccprofileprivate.h"
 #include "gdkintl.h"
 #include "gdkmemoryformatprivate.h"
 #include "gdkmemorytextureprivate.h"
@@ -148,7 +148,7 @@ gdk_png_get_color_profile (png_struct *png,
     {
       GBytes *bytes = g_bytes_new (icc_data, icc_len);
 
-      profile = gdk_color_profile_new_from_icc_bytes (bytes, NULL);
+      profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
       g_bytes_unref (bytes);
       if (profile)
         return profile;
@@ -192,7 +192,7 @@ gdk_png_get_color_profile (png_struct *png,
   lcms_profile = cmsCreateRGBProfile (&whitepoint,
                                       &primaries,
                                       (cmsToneCurve*[3]) { curve, curve, curve });
-  profile = gdk_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+  profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (lcms_profile, NULL));
   /* FIXME: errors? */
   if (profile == NULL)
     profile = g_object_ref (gdk_color_profile_get_srgb ());
@@ -202,25 +202,28 @@ gdk_png_get_color_profile (png_struct *png,
 }
 
 static void
-gdk_png_set_color_profile (png_struct      *png,
-                           png_info        *info,
-                           GdkColorProfile *profile)
+gdk_png_set_icc_profile (png_struct    *png,
+                         png_info      *info,
+                         GdkICCProfile *profile)
 {
   /* FIXME: allow deconstructing RGB profiles into gAMA and cHRM instead of
-   * falling back to iCCP */
+   * falling back to iCCP
+   */
   if (profile == gdk_color_profile_get_srgb ())
     {
       png_set_sRGB_gAMA_and_cHRM (png, info, /* FIXME */ PNG_sRGB_INTENT_PERCEPTUAL);
     }
-  else
+  else if (GDK_IS_ICC_PROFILE (profile))
     {
-      GBytes *bytes = gdk_color_profile_get_icc_profile (profile);
+      GBytes *bytes = gdk_icc_profile_get_icc_profile (profile);
       png_set_iCCP (png, info,
                     "ICC profile",
                     0,
                     g_bytes_get_data (bytes, NULL),
                     g_bytes_get_size (bytes));
     }
+  else
+    g_assert_not_reached ();
 }
 
 /* }}} */
@@ -419,7 +422,7 @@ gdk_save_png (GdkTexture *texture)
 
   width = gdk_texture_get_width (texture);
   height = gdk_texture_get_height (texture);
-  color_profile = gdk_texture_get_color_profile (texture);
+  color_profile = GDK_ICC_PROFILE (gdk_texture_get_color_profile (texture));
 
   memtex = GDK_MEMORY_TEXTURE (gdk_texture_download_texture (texture));
   format = gdk_memory_texture_get_format (memtex);
@@ -501,10 +504,7 @@ gdk_save_png (GdkTexture *texture)
       return NULL;
     }
 
-  memtex = gdk_memory_texture_convert (memtex,
-                                       format,
-                                       color_profile,
-                                       NULL);
+  memtex = gdk_memory_texture_convert (memtex, format, color_profile, NULL);
 
   png_set_write_fn (png, &io, png_write_func, png_flush_func);
 
@@ -514,7 +514,7 @@ gdk_save_png (GdkTexture *texture)
                 PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);
 
-  gdk_png_set_color_profile (png, info, color_profile);
+  gdk_png_set_icc_profile (png, info, GDK_ICC_PROFILE (color_profile));
 
   png_write_info (png, info);
 
diff --git a/gdk/loaders/gdktiff.c b/gdk/loaders/gdktiff.c
index ef4b5820b7..1ec7e1f596 100644
--- a/gdk/loaders/gdktiff.c
+++ b/gdk/loaders/gdktiff.c
@@ -19,7 +19,7 @@
 
 #include "gdktiffprivate.h"
 
-#include "gdkcolorprofileprivate.h"
+#include "gdkiccprofileprivate.h"
 #include "gdkintl.h"
 #include "gdkmemoryformatprivate.h"
 #include "gdkmemorytextureprivate.h"
@@ -249,7 +249,7 @@ flip_02 (guchar *data,
 /* {{{ Color profile handling */
 
 static GdkColorProfile *
-gdk_tiff_get_color_profile (TIFF *tiff)
+gdk_tiff_get_icc_profile (TIFF *tiff)
 {
   const char *icc_data;
   guint icc_len;
@@ -260,7 +260,7 @@ gdk_tiff_get_color_profile (TIFF *tiff)
       GdkColorProfile *profile;
 
       icc_bytes = g_bytes_new (icc_data, icc_len);
-      profile = gdk_color_profile_new_from_icc_bytes (icc_bytes, NULL);
+      profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (icc_bytes, NULL));
       g_bytes_unref (icc_bytes);
 
       if (profile)
@@ -271,10 +271,10 @@ gdk_tiff_get_color_profile (TIFF *tiff)
 }
 
 static void
-gdk_tiff_set_color_profile (TIFF            *tiff,
-                            GdkColorProfile *profile)
+gdk_tiff_set_icc_profile (TIFF          *tiff,
+                          GdkICCProfile *profile)
 {
-  GBytes *bytes = gdk_color_profile_get_icc_profile (profile);
+  GBytes *bytes = gdk_icc_profile_get_icc_profile (profile);
 
   TIFFSetField (tiff, TIFFTAG_ICCPROFILE,
                 g_bytes_get_size (bytes),
@@ -316,13 +316,13 @@ gdk_save_tiff (GdkTexture *texture)
   GBytes *result = NULL;
   GdkTexture *memory_texture;
   GdkMemoryFormat format;
-  GdkColorProfile *color_profile;
+  GdkICCProfile *icc_profile;
 
   tif = tiff_open_write (&result);
 
   width = gdk_texture_get_width (texture);
   height = gdk_texture_get_height (texture);
-  color_profile = gdk_texture_get_color_profile (texture);
+  icc_profile = GDK_ICC_PROFILE (gdk_texture_get_color_profile (texture));
 
   memory_texture = gdk_texture_download_texture (texture);
   format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture));
@@ -366,7 +366,7 @@ gdk_save_tiff (GdkTexture *texture)
   TIFFSetField (tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
   TIFFSetField (tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
 
-  gdk_tiff_set_color_profile (tif, color_profile);
+  gdk_tiff_set_icc_profile (tif, icc_profile);
 
   if (samples_per_pixel > 3)
     {
@@ -426,7 +426,7 @@ load_fallback (TIFF             *tif,
       return NULL;
     }
 
-  profile = gdk_tiff_get_color_profile (tif);
+  profile = gdk_tiff_get_icc_profile (tif);
 
   bytes = g_bytes_new_take (data, width * height * 4);
 
@@ -546,7 +546,7 @@ gdk_load_tiff (GBytes  *input_bytes,
       line += stride;
     }
 
-  profile = gdk_tiff_get_color_profile (tif);
+  profile = gdk_tiff_get_icc_profile (tif);
 
   bpp = gdk_memory_format_bytes_per_pixel (format);
   bytes = g_bytes_new_take (data, width * height * bpp);
diff --git a/gdk/meson.build b/gdk/meson.build
index 3cabde2d08..d99dcde292 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -12,6 +12,7 @@ gdk_public_sources = files([
   'gdkcontentproviderimpl.c',
   'gdkcontentserializer.c',
   'gdkcursor.c',
+  'gdkderivedprofile.c',
   'gdkdevice.c',
   'gdkdevicepad.c',
   'gdkdevicetool.c',
@@ -30,6 +31,7 @@ gdk_public_sources = files([
   'gdkglobals.c',
   'gdkgltexture.c',
   'gdkhsla.c',
+  'gdkiccprofile.c',
   'gdkkeys.c',
   'gdkkeyuni.c',
   'gdkmemoryformat.c',
@@ -73,6 +75,7 @@ gdk_public_headers = files([
   'gdkcontentproviderimpl.h',
   'gdkcontentserializer.h',
   'gdkcursor.h',
+  'gdkderivedprofile.h',
   'gdkdevice.h',
   'gdkdevicepad.h',
   'gdkdevicetool.h',
@@ -86,6 +89,7 @@ gdk_public_headers = files([
   'gdkframetimings.h',
   'gdkglcontext.h',
   'gdkgltexture.h',
+  'gdkiccprofile.h',
   'gdkkeys.h',
   'gdkkeysyms.h',
   'gdkmemorytexture.h',
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 0d8e126a8a..e12f77edff 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -38,6 +38,7 @@
 #include "gdkkeysprivate.h"
 #include "gdkmarshalers.h"
 #include "xsettings-client.h"
+#include "gdkiccprofileprivate.h"
 
 #include "gdkcairocontext-x11.h"
 #include "gdkclipboard-x11.h"
@@ -1463,7 +1464,7 @@ gdk_x11_display_check_color_profile (GdkX11Display *self)
     }
 
   g_clear_object (&self->color_profile);
-  self->color_profile = gdk_color_profile_new_from_icc_bytes (bytes, NULL);
+  self->color_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
   if (!self->color_profile)
     self->color_profile = g_object_ref (gdk_color_profile_get_srgb ());
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]