[gimp] Initial space invasion commit in GIMP



commit e09e563a70fef5d7dd55e5e8d0e280348f1ef9d4
Author: Michael Natterer <mitch gimp org>
Date:   Sat Jul 21 14:23:01 2018 +0200

    Initial space invasion commit in GIMP
    
    All babl formats now have a space equivalent to a color profile,
    determining the format's primaries and TRCs. This commit makes GIMP
    aware of this.
    
    libgimp:
    
    - enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
      as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
      NON_LINEAR and PERCPTUAL for each encoding, matching the babl
      encoding variants RGB, R'G'B' and R~G~B~.
    
    - gimp_color_transform_can_gegl_copy() now returns TRUE if both
      profiles can return a babl space, increasing the amount of fast babl
      color conversions significantly.
    
    - TODO: no solution yet for getting libgimp drawable proxy buffers in
      the right format with space.
    
    plug-ins:
    
    - follow the GimpPrecision change.
    
    - TODO: everything else unchanged and partly broken or sub-optimal,
      like setting a new image's color profile too late.
    
    app:
    
    - add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
      replacement for all "linear" booleans.
    
    - change gimp-babl functions to take babl spaces and GimpTRCType
      parameters and support all sorts of new perceptual ~ formats.
    
    - a lot of places changed in the early days of goat invasion didn't
      take advantage of gimp-babl utility functions and constructed
      formats manually. They all needed revisiting and many now use much
      simpler code calling gimp-babl API.
    
    - change gimp_babl_format_get_color_profile() to really extract a
      newly allocated color profile from the format, and add
      gimp_babl_get_builtin_color_profile() which does the same as
      gimp_babl_format_get_color_profile() did before. Visited all callers
      to decide whether they are looking for the format's actual profile,
      or for one of the builtin profiles, simplifying code that only needs
      builtin profiles.
    
    - drawables have a new get_space_api(), get_linear() is now get_trc().
    
    - images now have a "layer space" and an API to get it,
      gimp_image_get_layer_format() returns formats in that space.
    
    - an image's layer space is created from the image's color profile,
      change gimpimage-color-profile to deal with that correctly
    
    - change many babl_format() calls to babl_format_with_space() and take
      the space from passed formats or drawables
    
    - add function gimp_layer_fix_format_space() which replaces the
      layer's buffer with one that has the image's layer format, but
      doesn't change pixel values
    
    - use gimp_layer_fix_format_space() to make sure layers loaded from
      XCF and created by plug-ins have the right space when added to the
      image, because it's impossible to always assign the right space upon
      layer creation
    
    - "assign color profile" and "discard color profile" now require use
      of gimp_layer_fix_format_space() too because the profile is now
      embedded in all formats via the space.  Add
      gimp_image_assign_color_profile() which does all that and call it
      instead of a simple gimp_image_set_color_profile(), also from the
      PDB set-color-profile functions, which are essentially "assign" and
      "discard" calls.
    
    - generally, make sure a new image's color profile is set before
      adding layers to it, gimp_image_set_color_profile() is more than
      before considered know-what-you-are-doing API.
    
    - take special precaution in all places that call
      gimp_drawable_convert_type(), we now must pass a new_profile from
      all callers that convert layers within the same image (such as
      image_convert_type, image_convert_precision), because the layer's
      new space can't be determined from the image's layer format during
      the call.
    
    - change all "linear" properties to "trc", in all config objects like
      for levels and curves, in the histogram, in the widgets. This results
      in some GUI that now has three choices instead of two.
      TODO: we might want to reduce that back to two later.
    
    - keep "linear" boolean properties around as compat if needed for file
      pasring, but always convert the parsed parsed boolean to
      GimpTRCType.
    
    - TODO: the image's "enable color management" switch is currently
      broken, will fix that in another commit.

 app/actions/image-actions.c                   |   19 +-
 app/actions/image-commands.c                  |   45 +-
 app/actions/image-commands.h                  |    2 +-
 app/core/core-enums.c                         |   31 +
 app/core/core-enums.h                         |   12 +
 app/core/gimpbuffer.c                         |   32 +-
 app/core/gimpbuffer.h                         |    1 +
 app/core/gimpchannel.c                        |   21 +-
 app/core/gimpdrawable-fill.c                  |    2 +
 app/core/gimpdrawable-preview.c               |   25 +-
 app/core/gimpdrawable-private.h               |   32 +-
 app/core/gimpdrawable.c                       |   45 +-
 app/core/gimpdrawable.h                       |    3 +-
 app/core/gimpdrawablefilter.c                 |   30 +-
 app/core/gimpgrouplayer.c                     |    6 +-
 app/core/gimphistogram.c                      |   96 +--
 app/core/gimphistogram.h                      |    2 +-
 app/core/gimpimage-color-profile.c            |  138 +++-
 app/core/gimpimage-color-profile.h            |    7 +-
 app/core/gimpimage-convert-indexed.c          |   16 +-
 app/core/gimpimage-convert-precision.c        |   93 +--
 app/core/gimpimage-convert-type.c             |   15 +-
 app/core/gimpimage-duplicate.c                |    6 +-
 app/core/gimpimage-new.c                      |    2 +-
 app/core/gimpimage-preview.c                  |   10 +-
 app/core/gimpimage-private.h                  |    1 +
 app/core/gimpimage.c                          |   50 +-
 app/core/gimpimage.h                          |    5 +-
 app/core/gimplayer-new.c                      |    6 +
 app/core/gimplayer.c                          |   74 +-
 app/core/gimplayer.h                          |    4 +
 app/core/gimppickable-contiguous-region.c     |    5 +-
 app/core/gimpprojection.c                     |    2 +-
 app/core/gimpselection.c                      |    3 +-
 app/core/gimptemplate.c                       |   36 +-
 app/dialogs/convert-precision-dialog.c        |   31 +-
 app/display/gimpdisplayshell-profile.c        |    2 +-
 app/display/gimpdisplayshell.c                |    4 +
 app/display/gimpdisplayshell.h                |    1 +
 app/file/file-import.c                        |    2 +-
 app/file/file-open.c                          |   16 +-
 app/gegl/gimp-babl-compat.c                   |   31 +-
 app/gegl/gimp-babl.c                          | 1031 +++++++++++++++----------
 app/gegl/gimp-babl.h                          |   29 +-
 app/gegl/gimp-gegl-loops.cc                   |   12 +-
 app/gegl/gimp-gegl-mask-combine.c             |   20 +-
 app/operations/gimpcurvesconfig.c             |   39 +-
 app/operations/gimpcurvesconfig.h             |    2 +-
 app/operations/gimplevelsconfig.c             |   39 +-
 app/operations/gimplevelsconfig.h             |    2 +-
 app/operations/gimpoperationcomposecrop.c     |    2 +-
 app/operations/gimpoperationcurves.c          |   13 +-
 app/operations/gimpoperationlevels.c          |   13 +-
 app/operations/gimpoperationmaskcomponents.c  |    6 +-
 app/operations/gimpoperationpointfilter.c     |   27 +-
 app/operations/gimpoperationpointfilter.h     |    4 +-
 app/operations/layer-modes/gimp-layer-modes.c |    3 +-
 app/paint/gimpbrushcore.c                     |    8 +-
 app/paint/gimppaintcore-loops.cc              |   13 +-
 app/paint/gimppaintcore-loops.h               |    3 +-
 app/paint/gimppaintcore.c                     |   16 +-
 app/pdb/drawable-cmds.c                       |    5 +-
 app/pdb/drawable-color-cmds.c                 |    8 +-
 app/pdb/floating-sel-cmds.c                   |    9 +-
 app/pdb/image-cmds.c                          |    8 +-
 app/pdb/image-color-profile-cmds.c            |   16 +-
 app/pdb/image-convert-cmds.c                  |    6 +-
 app/pdb/layer-cmds.c                          |   21 +-
 app/pdb/plug-in-compat-cmds.c                 |    5 +-
 app/tests/gimp-app-test-utils.c               |    2 +-
 app/tests/test-xcf.c                          |    2 +-
 app/tools/gimpcurvestool.c                    |   33 +-
 app/tools/gimplevelstool.c                    |   29 +-
 app/widgets/gimpcolorframe.c                  |   40 +-
 app/widgets/gimphistogrameditor.c             |   36 +-
 app/widgets/gimphistogrameditor.h             |    2 +-
 app/widgets/gimptemplateeditor.c              |   11 +-
 app/widgets/gimpwidgets-utils.c               |    5 +-
 app/xcf/xcf-load.c                            |   70 +-
 libgimp/gimpdrawable.c                        |    4 +
 libgimp/gimpimage_pdb.c                       |    4 +-
 libgimp/gimpimagecolorprofile_pdb.c           |    9 +-
 libgimpbase/gimpbaseenums.c                   |   46 +-
 libgimpbase/gimpbaseenums.h                   |   82 +-
 libgimpcolor/gimpcolorprofile.c               |    2 +-
 libgimpcolor/gimpcolortransform.c             |   28 +-
 pdb/enums.pl                                  |   47 +-
 pdb/groups/drawable.pdb                       |    5 +-
 pdb/groups/drawable_color.pdb                 |    8 +-
 pdb/groups/floating_sel.pdb                   |    9 +-
 pdb/groups/image.pdb                          |   13 +-
 pdb/groups/image_color_profile.pdb            |   20 +-
 pdb/groups/image_convert.pdb                  |    6 +-
 pdb/groups/layer.pdb                          |   21 +-
 pdb/groups/plug_in_compat.pdb                 |    5 +-
 plug-ins/common/file-gegl.c                   |   12 +-
 plug-ins/common/file-jp2-load.c               |    6 +-
 plug-ins/common/file-png.c                    |   13 +-
 plug-ins/common/file-pnm.c                    |    9 +-
 plug-ins/common/file-ps.c                     |    2 +-
 plug-ins/common/file-raw-data.c               |    2 +-
 plug-ins/common/wavelet-decompose.c           |   18 +-
 plug-ins/file-fits/fits.c                     |    4 +-
 plug-ins/file-jpeg/jpeg-load.c                |    2 +-
 plug-ins/file-psd/psd-load.c                  |    6 +-
 plug-ins/file-tiff/file-tiff-load.c           |   14 +-
 plug-ins/file-tiff/file-tiff-save.c           |   24 +-
 107 files changed, 1854 insertions(+), 1121 deletions(-)
---
diff --git a/app/actions/image-actions.c b/app/actions/image-actions.c
index 2689f2cc04..3b13a62912 100644
--- a/app/actions/image-actions.c
+++ b/app/actions/image-actions.c
@@ -244,19 +244,19 @@ static const GimpRadioActionEntry image_convert_precision_actions[] =
     GIMP_COMPONENT_TYPE_DOUBLE, GIMP_HELP_IMAGE_CONVERT_DOUBLE }
 };
 
-static const GimpRadioActionEntry image_convert_gamma_actions[] =
+static const GimpRadioActionEntry image_convert_trc_actions[] =
 {
   { "image-convert-gamma", NULL,
     NC_("image-convert-action", "Perceptual gamma (sRGB)"), NULL,
     NC_("image-convert-action",
         "Convert the image to perceptual (sRGB) gamma"),
-    FALSE, GIMP_HELP_IMAGE_CONVERT_GAMMA },
+    GIMP_TRC_NON_LINEAR, GIMP_HELP_IMAGE_CONVERT_GAMMA },
 
   { "image-convert-linear", NULL,
     NC_("image-convert-action", "Linear light"), NULL,
     NC_("image-convert-action",
         "Convert the image to linear light"),
-    TRUE, GIMP_HELP_IMAGE_CONVERT_GAMMA }
+    GIMP_TRC_LINEAR, GIMP_HELP_IMAGE_CONVERT_GAMMA }
 };
 
 static const GimpEnumActionEntry image_flip_actions[] =
@@ -320,10 +320,10 @@ image_actions_setup (GimpActionGroup *group)
                                        G_CALLBACK (image_convert_precision_cmd_callback));
 
   gimp_action_group_add_radio_actions (group, "image-convert-action",
-                                       image_convert_gamma_actions,
-                                       G_N_ELEMENTS (image_convert_gamma_actions),
+                                       image_convert_trc_actions,
+                                       G_N_ELEMENTS (image_convert_trc_actions),
                                        NULL, 0,
-                                       G_CALLBACK (image_convert_gamma_cmd_callback));
+                                       G_CALLBACK (image_convert_trc_cmd_callback));
 
   gimp_action_group_add_enum_actions (group, "image-action",
                                       image_flip_actions,
@@ -393,8 +393,9 @@ image_actions_update (GimpActionGroup *group,
 
       gimp_action_group_set_action_active (group, action, TRUE);
 
-      if (gimp_babl_format_get_linear (gimp_image_get_layer_format (image,
-                                                                    FALSE)))
+      if (gimp_babl_format_get_trc (gimp_image_get_layer_format (image,
+                                                                 FALSE)) ==
+          GIMP_TRC_LINEAR)
         {
           gimp_action_group_set_action_active (group, "image-convert-linear",
                                                TRUE);
@@ -406,7 +407,7 @@ image_actions_update (GimpActionGroup *group,
         }
 
       is_indexed  = (base_type == GIMP_INDEXED);
-      is_u8_gamma = (precision == GIMP_PRECISION_U8_GAMMA);
+      is_u8_gamma = (precision == GIMP_PRECISION_U8_NON_LINEAR);
       is_double   = (component_type == GIMP_COMPONENT_TYPE_DOUBLE);
       aux         = (gimp_image_get_active_channel (image) != NULL);
       lp          = ! gimp_image_is_empty (image);
diff --git a/app/actions/image-commands.c b/app/actions/image-commands.c
index 59a73ec404..4c79330670 100644
--- a/app/actions/image-commands.c
+++ b/app/actions/image-commands.c
@@ -268,30 +268,28 @@ image_convert_base_type_cmd_callback (GtkAction *action,
           GimpColorProfileCallback  callback;
           GimpColorProfile         *current_profile;
           GimpColorProfile         *default_profile;
-          const Babl               *format;
+          GimpTRCType               trc;
 
           current_profile =
             gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
 
+          trc = gimp_babl_trc (gimp_image_get_precision (image));
+
           if (value == GIMP_RGB)
             {
               dialog_type = COLOR_PROFILE_DIALOG_CONVERT_TO_RGB;
               callback    = image_convert_rgb_callback;
 
-              format = gimp_babl_format (GIMP_RGB,
-                                         gimp_image_get_precision (image),
-                                         TRUE);
-              default_profile = gimp_babl_format_get_color_profile (format);
+              default_profile = gimp_babl_get_builtin_color_profile (GIMP_RGB,
+                                                                     trc);
             }
           else
             {
               dialog_type = COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY;
               callback    = image_convert_gray_callback;
 
-              format = gimp_babl_format (GIMP_GRAY,
-                                         gimp_image_get_precision (image),
-                                         TRUE);
-              default_profile = gimp_babl_format_get_color_profile (format);
+              default_profile = gimp_babl_get_builtin_color_profile (GIMP_GRAY,
+                                                                     trc);
             }
 
           dialog = color_profile_dialog_new (dialog_type,
@@ -394,21 +392,21 @@ image_convert_precision_cmd_callback (GtkAction *action,
 }
 
 void
-image_convert_gamma_cmd_callback (GtkAction *action,
-                                  GtkAction *current,
-                                  gpointer   data)
+image_convert_trc_cmd_callback (GtkAction *action,
+                                GtkAction *current,
+                                gpointer   data)
 {
   GimpImage     *image;
   GimpDisplay   *display;
-  gboolean       value;
+  GimpTRCType    value;
   GimpPrecision  precision;
   return_if_no_image (image, data);
   return_if_no_display (display, data);
 
   value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
 
-  if (value == gimp_babl_format_get_linear (gimp_image_get_layer_format (image,
-                                                                         FALSE)))
+  if (value == gimp_babl_format_get_trc (gimp_image_get_layer_format (image,
+                                                                      FALSE)))
     return;
 
   precision = gimp_babl_precision (gimp_image_get_component_type (image),
@@ -530,7 +528,7 @@ image_color_profile_discard_cmd_callback (GtkAction *action,
   GimpImage *image;
   return_if_no_image (image, data);
 
-  gimp_image_set_color_profile (image, NULL, NULL);
+  gimp_image_assign_color_profile (image, NULL, NULL, NULL);
   gimp_image_flush (image);
 }
 
@@ -1191,7 +1189,7 @@ image_convert_precision_callback (GtkWidget        *dialog,
 
   /* random formats with the right precision */
   old_format = gimp_image_get_layer_format (image, FALSE);
-  new_format = gimp_babl_format (GIMP_RGB, precision, FALSE);
+  new_format = gimp_babl_format (GIMP_RGB, precision, FALSE, NULL);
 
   old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
               babl_format_get_n_components (old_format));
@@ -1242,11 +1240,7 @@ image_profile_assign_callback (GtkWidget                *dialog,
 {
   GError *error = NULL;
 
-  gimp_image_undo_group_start (image,
-                               GIMP_UNDO_GROUP_PARASITE_ATTACH,
-                               _("Assign color profile"));
-
-  if (! gimp_image_set_color_profile (image, new_profile, &error))
+  if (! gimp_image_assign_color_profile (image, new_profile, NULL, &error))
     {
       gimp_message (image->gimp, G_OBJECT (dialog),
                     GIMP_MESSAGE_ERROR,
@@ -1259,13 +1253,6 @@ image_profile_assign_callback (GtkWidget                *dialog,
       return;
     }
 
-  gimp_image_set_is_color_managed (image, TRUE, TRUE);
-
-  /*  omg...  */
-  gimp_image_parasite_detach (image, "icc-profile-name");
-
-  gimp_image_undo_group_end (image);
-
   gimp_image_flush (image);
 
   gtk_widget_destroy (dialog);
diff --git a/app/actions/image-commands.h b/app/actions/image-commands.h
index bed674d0d0..fc5ee4d4c0 100644
--- a/app/actions/image-commands.h
+++ b/app/actions/image-commands.h
@@ -30,7 +30,7 @@ void   image_convert_base_type_cmd_callback        (GtkAction *action,
 void   image_convert_precision_cmd_callback        (GtkAction *action,
                                                     GtkAction *current,
                                                     gpointer   data);
-void   image_convert_gamma_cmd_callback            (GtkAction *action,
+void   image_convert_trc_cmd_callback              (GtkAction *action,
                                                     GtkAction *current,
                                                     gpointer   data);
 
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index 2bc635773f..993670f3a2 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -923,6 +923,37 @@ gimp_thumbnail_size_get_type (void)
   return type;
 }
 
+GType
+gimp_trc_type_get_type (void)
+{
+  static const GEnumValue values[] =
+  {
+    { GIMP_TRC_LINEAR, "GIMP_TRC_LINEAR", "linear" },
+    { GIMP_TRC_NON_LINEAR, "GIMP_TRC_NON_LINEAR", "non-linear" },
+    { GIMP_TRC_PERCEPTUAL, "GIMP_TRC_PERCEPTUAL", "perceptual" },
+    { 0, NULL, NULL }
+  };
+
+  static const GimpEnumDesc descs[] =
+  {
+    { GIMP_TRC_LINEAR, NC_("trc-type", "Linear"), NULL },
+    { GIMP_TRC_NON_LINEAR, NC_("trc-type", "Non-Linear"), NULL },
+    { GIMP_TRC_PERCEPTUAL, NC_("trc-type", "Perceptual"), NULL },
+    { 0, NULL, NULL }
+  };
+
+  static GType type = 0;
+
+  if (G_UNLIKELY (! type))
+    {
+      type = g_enum_register_static ("GimpTRCType", values);
+      gimp_type_set_translation_context (type, "trc-type");
+      gimp_enum_set_value_descriptions (type, descs);
+    }
+
+  return type;
+}
+
 GType
 gimp_undo_event_get_type (void)
 {
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 4916ae117f..90a690643a 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -407,6 +407,18 @@ typedef enum  /*< pdb-skip >*/
 } GimpThumbnailSize;
 
 
+#define GIMP_TYPE_TRC_TYPE (gimp_trc_type_get_type ())
+
+GType gimp_trc_type_get_type (void) G_GNUC_CONST;
+
+typedef enum  /*< pdb-skip >*/
+{
+  GIMP_TRC_LINEAR,     /*< desc="Linear"     >*/
+  GIMP_TRC_NON_LINEAR, /*< desc="Non-Linear" >*/
+  GIMP_TRC_PERCEPTUAL  /*< desc="Perceptual" >*/
+} GimpTRCType;
+
+
 #define GIMP_TYPE_UNDO_EVENT (gimp_undo_event_get_type ())
 
 GType gimp_undo_event_get_type (void) G_GNUC_CONST;
diff --git a/app/core/gimpbuffer.c b/app/core/gimpbuffer.c
index e58e9312cf..297293c98a 100644
--- a/app/core/gimpbuffer.c
+++ b/app/core/gimpbuffer.c
@@ -139,6 +139,7 @@ gimp_buffer_get_memsize (GimpObject *object,
 
   memsize += gimp_gegl_buffer_get_memsize (buffer->buffer);
   memsize += gimp_g_object_get_memsize (G_OBJECT (buffer->color_profile));
+  memsize += gimp_g_object_get_memsize (G_OBJECT (buffer->format_profile));
 
   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
                                                                   gui_size);
@@ -229,13 +230,16 @@ gimp_buffer_get_new_preview (GimpViewable *viewable,
   GimpTempBuf *preview;
 
   if (babl_format_is_palette (format))
-    format = gimp_babl_format (GIMP_RGB, GIMP_PRECISION_U8_GAMMA,
-                               babl_format_has_alpha (format));
+    format = gimp_babl_format (GIMP_RGB,
+                               GIMP_PRECISION_U8_NON_LINEAR,
+                               babl_format_has_alpha (format),
+                               babl_format_get_space (format));
   else
     format = gimp_babl_format (gimp_babl_format_get_base_type (format),
                                gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
-                                                    gimp_babl_format_get_linear (format)),
-                               babl_format_has_alpha (format));
+                                                    gimp_babl_format_get_trc (format)),
+                               babl_format_has_alpha (format),
+                               babl_format_get_space (format));
 
   preview = gimp_temp_buf_new (width, height, format);
 
@@ -332,14 +336,17 @@ gimp_buffer_get_description (GimpViewable  *viewable,
 
 static const guint8 *
 gimp_buffer_color_managed_get_icc_profile (GimpColorManaged *managed,
-                             gsize            *len)
+                                           gsize            *len)
 {
   GimpBuffer *buffer = GIMP_BUFFER (managed);
 
   if (buffer->color_profile)
     return gimp_color_profile_get_icc_profile (buffer->color_profile, len);
 
-  return NULL;
+  /* creates buffer->format_profile */
+  gimp_color_managed_get_color_profile (managed);
+
+  return gimp_color_profile_get_icc_profile (buffer->format_profile, len);
 }
 
 static GimpColorProfile *
@@ -350,7 +357,11 @@ gimp_buffer_color_managed_get_color_profile (GimpColorManaged *managed)
   if (buffer->color_profile)
     return buffer->color_profile;
 
-  return gimp_babl_format_get_color_profile (gimp_buffer_get_format (buffer));
+  if (! buffer->format_profile)
+    buffer->format_profile =
+      gimp_babl_format_get_color_profile (gimp_buffer_get_format (buffer));
+
+  return buffer->format_profile;
 }
 
 static void
@@ -524,11 +535,10 @@ gimp_buffer_set_color_profile (GimpBuffer       *buffer,
 
   if (profile != buffer->color_profile)
     {
-      g_clear_object (&buffer->color_profile);
-
-      if (profile)
-        buffer->color_profile = g_object_ref (profile);
+      g_set_object (&buffer->color_profile, profile);
     }
+
+  g_clear_object (&buffer->format_profile);
 }
 
 GimpColorProfile *
diff --git a/app/core/gimpbuffer.h b/app/core/gimpbuffer.h
index 2949baeeb1..1e1c738e19 100644
--- a/app/core/gimpbuffer.h
+++ b/app/core/gimpbuffer.h
@@ -45,6 +45,7 @@ struct _GimpBuffer
   GimpUnit          unit;
 
   GimpColorProfile *color_profile;
+  GimpColorProfile *format_profile;
 };
 
 struct _GimpBufferClass
diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c
index 8fe0e277ac..0c5e67c975 100644
--- a/app/core/gimpchannel.c
+++ b/app/core/gimpchannel.c
@@ -32,6 +32,7 @@
 #include "paint/gimppaintcore-stroke.h"
 #include "paint/gimppaintoptions.h"
 
+#include "gegl/gimp-babl.h"
 #include "gegl/gimp-gegl-apply-operation.h"
 #include "gegl/gimp-gegl-loops.h"
 #include "gegl/gimp-gegl-mask.h"
@@ -406,10 +407,11 @@ gimp_channel_get_node (GimpFilter *filter)
 
   g_warn_if_fail (channel->color_node == NULL);
 
-  if (gimp_drawable_get_linear (drawable))
-    color_format = babl_format ("RGBA float");
-  else
-    color_format = babl_format ("R'G'B'A float");
+  color_format =
+    gimp_babl_format (GIMP_RGB,
+                      gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                           gimp_drawable_get_trc (drawable)),
+                      TRUE, NULL);
 
   channel->color_node = gegl_node_new_child (node,
                                              "operation", "gegl:color",
@@ -1040,12 +1042,11 @@ gimp_channel_set_buffer (GimpDrawable *drawable,
 
   if (gimp_filter_peek_node (GIMP_FILTER (channel)))
     {
-      const Babl *color_format;
-
-      if (gimp_drawable_get_linear (drawable))
-        color_format = babl_format ("RGBA float");
-      else
-        color_format = babl_format ("R'G'B'A float");
+      const Babl *color_format =
+        gimp_babl_format (GIMP_RGB,
+                          gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                               gimp_drawable_get_trc (drawable)),
+                          TRUE, NULL);
 
       gegl_node_set (channel->color_node,
                      "format", color_format,
diff --git a/app/core/gimpdrawable-fill.c b/app/core/gimpdrawable-fill.c
index 6ffa21bcc2..89d89c1145 100644
--- a/app/core/gimpdrawable-fill.c
+++ b/app/core/gimpdrawable-fill.c
@@ -113,6 +113,8 @@ gimp_drawable_fill_buffer (GimpDrawable  *drawable,
                                        TRUE,
                                        NULL);
 
+      g_object_unref (src_profile);
+
       gegl_buffer_set_pattern (buffer, NULL, dest_buffer,
                                pattern_offset_x, pattern_offset_y);
 
diff --git a/app/core/gimpdrawable-preview.c b/app/core/gimpdrawable-preview.c
index 605d763f9a..b18a6ee168 100644
--- a/app/core/gimpdrawable-preview.c
+++ b/app/core/gimpdrawable-preview.c
@@ -139,33 +139,30 @@ gimp_drawable_get_new_pixbuf (GimpViewable *viewable,
 const Babl *
 gimp_drawable_get_preview_format (GimpDrawable *drawable)
 {
-  gboolean alpha;
-  gboolean linear;
+  const Babl  *space;
+  gboolean     alpha;
+  GimpTRCType  trc;
 
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
 
-  alpha  = gimp_drawable_has_alpha (drawable);
-  linear = gimp_drawable_get_linear (drawable);
+  space = gimp_drawable_get_space (drawable);
+  alpha = gimp_drawable_has_alpha (drawable);
+  trc   = gimp_drawable_get_trc (drawable);
 
   switch (gimp_drawable_get_base_type (drawable))
     {
     case GIMP_GRAY:
       return gimp_babl_format (GIMP_GRAY,
                                gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
-                                                    linear),
-                               alpha);
+                                                    trc),
+                               alpha, space);
 
     case GIMP_RGB:
+    case GIMP_INDEXED:
       return gimp_babl_format (GIMP_RGB,
                                gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
-                                                    linear),
-                               alpha);
-
-    case GIMP_INDEXED:
-      if (alpha)
-        return babl_format ("R'G'B'A u8");
-      else
-        return babl_format ("R'G'B' u8");
+                                                    trc),
+                               alpha, space);
     }
 
   g_return_val_if_reached (NULL);
diff --git a/app/core/gimpdrawable-private.h b/app/core/gimpdrawable-private.h
index 67f142f6c7..cdf14ca11b 100644
--- a/app/core/gimpdrawable-private.h
+++ b/app/core/gimpdrawable-private.h
@@ -20,25 +20,27 @@
 
 struct _GimpDrawablePrivate
 {
-  GeglBuffer     *buffer; /* buffer for drawable data */
-  GeglBuffer     *shadow; /* shadow buffer            */
+  GeglBuffer       *buffer; /* buffer for drawable data */
+  GeglBuffer       *shadow; /* shadow buffer            */
 
-  GeglNode       *source_node;
-  GeglNode       *buffer_source_node;
-  GimpContainer  *filter_stack;
-  GeglNode       *convert_format;
+  GimpColorProfile *format_profile;
 
-  GimpLayer      *floating_selection;
-  GimpFilter     *fs_filter;
-  GeglNode       *fs_crop_node;
-  GimpApplicator *fs_applicator;
+  GeglNode         *source_node;
+  GeglNode         *buffer_source_node;
+  GimpContainer    *filter_stack;
+  GeglNode         *convert_format;
 
-  GeglNode       *mode_node;
+  GimpLayer        *floating_selection;
+  GimpFilter       *fs_filter;
+  GeglNode         *fs_crop_node;
+  GimpApplicator   *fs_applicator;
 
-  gint            paint_count;
-  GeglBuffer     *paint_buffer;
-  cairo_region_t *paint_copy_region;
-  cairo_region_t *paint_update_region;
+  GeglNode         *mode_node;
+
+  gint              paint_count;
+  GeglBuffer       *paint_buffer;
+  cairo_region_t   *paint_copy_region;
+  cairo_region_t   *paint_update_region;
 };
 
 #endif /* __GIMP_DRAWABLE_PRIVATE_H__ */
diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c
index 42da1180e6..ce8302e24e 100644
--- a/app/core/gimpdrawable.c
+++ b/app/core/gimpdrawable.c
@@ -331,6 +331,7 @@ gimp_drawable_finalize (GObject *object)
     gimp_drawable_end_paint (drawable);
 
   g_clear_object (&drawable->private->buffer);
+  g_clear_object (&drawable->private->format_profile);
 
   gimp_drawable_free_shadow_buffer (drawable);
 
@@ -686,9 +687,14 @@ gimp_drawable_get_icc_profile (GimpColorManaged *managed,
 static GimpColorProfile *
 gimp_drawable_get_color_profile (GimpColorManaged *managed)
 {
-  const Babl *format = gimp_drawable_get_format (GIMP_DRAWABLE (managed));
+  GimpDrawable *drawable = GIMP_DRAWABLE (managed);
+  const Babl   *format   = gimp_drawable_get_format (drawable);
 
-  return gimp_babl_format_get_color_profile (format);
+  if (! drawable->private->format_profile)
+    drawable->private->format_profile =
+      gimp_babl_format_get_color_profile (format);
+
+  return drawable->private->format_profile;
 }
 
 static void
@@ -746,14 +752,15 @@ gimp_drawable_real_estimate_memsize (GimpDrawable      *drawable,
                                      gint               width,
                                      gint               height)
 {
-  GimpImage  *image  = gimp_item_get_image (GIMP_ITEM (drawable));
-  gboolean    linear = gimp_drawable_get_linear (drawable);
-  const Babl *format;
+  GimpImage   *image = gimp_item_get_image (GIMP_ITEM (drawable));
+  GimpTRCType  trc   = gimp_drawable_get_trc (drawable);
+  const Babl  *format;
 
   format = gimp_image_get_format (image,
                                   gimp_drawable_get_base_type (drawable),
-                                  gimp_babl_precision (component_type, linear),
-                                  gimp_drawable_has_alpha (drawable));
+                                  gimp_babl_precision (component_type, trc),
+                                  gimp_drawable_has_alpha (drawable),
+                                  NULL);
 
   return (gint64) babl_format_get_bytes_per_pixel (format) * width * height;
 }
@@ -817,6 +824,7 @@ gimp_drawable_real_set_buffer (GimpDrawable *drawable,
     old_has_alpha = gimp_drawable_has_alpha (drawable);
 
   g_set_object (&drawable->private->buffer, buffer);
+  g_clear_object (&drawable->private->format_profile);
 
   if (drawable->private->buffer_source_node)
     gegl_node_set (drawable->private->buffer_source_node,
@@ -1124,7 +1132,8 @@ gimp_drawable_convert_type (GimpDrawable      *drawable,
   new_format = gimp_image_get_format (dest_image,
                                       new_base_type,
                                       new_precision,
-                                      new_has_alpha);
+                                      new_has_alpha,
+                                      NULL /* handled by layer */);
 
   old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
               babl_format_get_n_components (old_format));
@@ -1428,6 +1437,14 @@ gimp_drawable_push_undo (GimpDrawable *drawable,
                                                  x, y, width, height);
 }
 
+const Babl *
+gimp_drawable_get_space (GimpDrawable *drawable)
+{
+  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
+
+  return babl_format_get_space (gimp_drawable_get_format (drawable));
+}
+
 const Babl *
 gimp_drawable_get_format (GimpDrawable *drawable)
 {
@@ -1444,7 +1461,8 @@ gimp_drawable_get_format_with_alpha (GimpDrawable *drawable)
   return gimp_image_get_format (gimp_item_get_image (GIMP_ITEM (drawable)),
                                 gimp_drawable_get_base_type (drawable),
                                 gimp_drawable_get_precision (drawable),
-                                TRUE);
+                                TRUE,
+                                gimp_drawable_get_space (drawable));
 }
 
 const Babl *
@@ -1455,11 +1473,12 @@ gimp_drawable_get_format_without_alpha (GimpDrawable *drawable)
   return gimp_image_get_format (gimp_item_get_image (GIMP_ITEM (drawable)),
                                 gimp_drawable_get_base_type (drawable),
                                 gimp_drawable_get_precision (drawable),
-                                FALSE);
+                                FALSE,
+                                gimp_drawable_get_space (drawable));
 }
 
-gboolean
-gimp_drawable_get_linear (GimpDrawable *drawable)
+GimpTRCType
+gimp_drawable_get_trc (GimpDrawable *drawable)
 {
   const Babl *format;
 
@@ -1467,7 +1486,7 @@ gimp_drawable_get_linear (GimpDrawable *drawable)
 
   format = gegl_buffer_get_format (drawable->private->buffer);
 
-  return gimp_babl_format_get_linear (format);
+  return gimp_babl_format_get_trc (format);
 }
 
 gboolean
diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h
index 54e3752117..659139ff1b 100644
--- a/app/core/gimpdrawable.h
+++ b/app/core/gimpdrawable.h
@@ -208,11 +208,12 @@ void            gimp_drawable_push_undo          (GimpDrawable       *drawable,
                                                   gint                width,
                                                   gint                height);
 
+const Babl      * gimp_drawable_get_space            (GimpDrawable    *drawable);
 const Babl      * gimp_drawable_get_format           (GimpDrawable    *drawable);
 const Babl      * gimp_drawable_get_format_with_alpha(GimpDrawable    *drawable);
 const Babl      * gimp_drawable_get_format_without_alpha
                                                      (GimpDrawable    *drawable);
-gboolean          gimp_drawable_get_linear           (GimpDrawable    *drawable);
+GimpTRCType       gimp_drawable_get_trc              (GimpDrawable    *drawable);
 gboolean          gimp_drawable_has_alpha            (GimpDrawable    *drawable);
 GimpImageBaseType gimp_drawable_get_base_type        (GimpDrawable    *drawable);
 GimpComponentType gimp_drawable_get_component_type   (GimpDrawable    *drawable);
diff --git a/app/core/gimpdrawablefilter.c b/app/core/gimpdrawablefilter.c
index bd0f7e7435..faefd27282 100644
--- a/app/core/gimpdrawablefilter.c
+++ b/app/core/gimpdrawablefilter.c
@@ -713,8 +713,9 @@ gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter)
       drawable_format =
         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
                           gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
-                                               gimp_babl_format_get_linear (drawable_format)),
-                          babl_format_has_alpha (drawable_format));
+                                               gimp_babl_format_get_trc (drawable_format)),
+                          babl_format_has_alpha (drawable_format),
+                          babl_format_get_space (drawable_format));
 
       /*  convert the filter input/output formats to something we have
        *  built-in color profiles for (see the get_color_profile()
@@ -764,8 +765,16 @@ gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter)
                          "dest-format",  drawable_format,
                          NULL);
 
+          if (filter->has_input)
+            g_object_unref (input_profile);
+          g_object_unref (output_profile);
+
           return;
         }
+
+      if (filter->has_input)
+        g_object_unref (input_profile);
+      g_object_unref (output_profile);
     }
 
   g_printerr ("using gegl copy\n");
@@ -787,8 +796,16 @@ gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter)
 {
   if (filter->gamma_hack)
     {
-      const Babl *drawable_format;
-      const Babl *cast_format;
+      const Babl  *drawable_format;
+      const Babl  *cast_format;
+      GimpTRCType  trc = GIMP_TRC_LINEAR;
+
+      switch (gimp_drawable_get_trc (filter->drawable))
+        {
+        case GIMP_TRC_LINEAR:     trc = GIMP_TRC_NON_LINEAR; break;
+        case GIMP_TRC_NON_LINEAR: trc = GIMP_TRC_LINEAR;     break;
+        case GIMP_TRC_PERCEPTUAL: trc = GIMP_TRC_LINEAR;     break;
+        }
 
       drawable_format =
         gimp_drawable_get_format_with_alpha (filter->drawable);
@@ -796,8 +813,9 @@ gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter)
       cast_format =
         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
                           gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
-                                               ! gimp_babl_format_get_linear (drawable_format)),
-                          TRUE);
+                                               trc),
+                          TRUE,
+                          babl_format_get_space (drawable_format));
 
       if (filter->has_input)
         {
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index f6de335be3..ca19a8270e 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -947,10 +947,12 @@ get_projection_format (GimpProjectable   *projectable,
     {
     case GIMP_RGB:
     case GIMP_INDEXED:
-      return gimp_image_get_format (image, GIMP_RGB, precision, TRUE);
+      return gimp_image_get_format (image, GIMP_RGB, precision, TRUE,
+                                    gimp_image_get_layer_space (image));
 
     case GIMP_GRAY:
-      return gimp_image_get_format (image, GIMP_GRAY, precision, TRUE);
+      return gimp_image_get_format (image, GIMP_GRAY, precision, TRUE,
+                                    gimp_image_get_layer_space (image));
     }
 
   g_return_val_if_reached (NULL);
diff --git a/app/core/gimphistogram.c b/app/core/gimphistogram.c
index c08ca371af..109dffa201 100644
--- a/app/core/gimphistogram.c
+++ b/app/core/gimphistogram.c
@@ -53,11 +53,11 @@ enum
 
 struct _GimpHistogramPrivate
 {
-  gboolean   linear;
-  gint       n_channels;
-  gint       n_bins;
-  gdouble   *values;
-  GimpAsync *calculate_async;
+  GimpTRCType  trc;
+  gint         n_channels;
+  gint         n_bins;
+  gdouble     *values;
+  GimpAsync   *calculate_async;
 };
 
 typedef struct
@@ -230,11 +230,11 @@ gimp_histogram_get_memsize (GimpObject *object,
 /*  public functions  */
 
 GimpHistogram *
-gimp_histogram_new (gboolean linear)
+gimp_histogram_new (GimpTRCType trc)
 {
   GimpHistogram *histogram = g_object_new (GIMP_TYPE_HISTOGRAM, NULL);
 
-  histogram->priv->linear = linear;
+  histogram->priv->trc = trc;
 
   return histogram;
 }
@@ -258,7 +258,7 @@ gimp_histogram_duplicate (GimpHistogram *histogram)
   if (histogram->priv->calculate_async)
     gimp_waitable_wait (GIMP_WAITABLE (histogram->priv->calculate_async));
 
-  dup = gimp_histogram_new (histogram->priv->linear);
+  dup = gimp_histogram_new (histogram->priv->trc);
 
   dup->priv->n_channels = histogram->priv->n_channels;
   dup->priv->n_bins     = histogram->priv->n_bins;
@@ -869,76 +869,42 @@ gimp_histogram_calculate_internal (GimpAsync        *async,
   CalculateData         data;
   GimpHistogramPrivate *priv;
   const Babl           *format;
+  const Babl           *space;
 
   priv = context->histogram->priv;
 
   format = gegl_buffer_get_format (context->buffer);
+  space  = babl_format_get_space (format);
 
   if (babl_format_get_type (format, 0) == babl_type ("u8"))
     context->n_bins = 256;
   else
     context->n_bins = 1024;
 
-  if (babl_format_is_palette (format))
+  switch (gimp_babl_format_get_base_type (format))
     {
-      if (babl_format_has_alpha (format))
-        {
-          if (priv->linear)
-            format = babl_format ("RGB float");
-          else
-            format = babl_format ("R'G'B' float");
-        }
-      else
-        {
-          if (priv->linear)
-            format = babl_format ("RGBA float");
-          else
-            format = babl_format ("R'G'B'A float");
-        }
-    }
-  else
-    {
-      const Babl *model = babl_format_get_model (format);
+    case GIMP_RGB:
+    case GIMP_INDEXED:
+      format = gimp_babl_format (GIMP_RGB,
+                                 gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                                      priv->trc),
+                                 babl_format_has_alpha (format),
+                                 space);
+      break;
 
-      if (model == babl_model ("Y") ||
-          model == babl_model ("Y'"))
-        {
-          if (priv->linear)
-            format = babl_format ("Y float");
-          else
-            format = babl_format ("Y' float");
-        }
-      else if (model == babl_model ("YA") ||
-               model == babl_model ("Y'A"))
-        {
-          if (priv->linear)
-            format = babl_format ("YA float");
-          else
-            format = babl_format ("Y'A float");
-        }
-      else if (model == babl_model ("RGB") ||
-               model == babl_model ("R'G'B'"))
-        {
-          if (priv->linear)
-            format = babl_format ("RGB float");
-          else
-            format = babl_format ("R'G'B' float");
-        }
-      else if (model == babl_model ("RGBA") ||
-               model == babl_model ("R'G'B'A"))
-        {
-          if (priv->linear)
-            format = babl_format ("RGBA float");
-          else
-            format = babl_format ("R'G'B'A float");
-        }
-      else
-        {
-          if (async)
-            gimp_async_abort (async);
+    case GIMP_GRAY:
+      format = gimp_babl_format (GIMP_GRAY,
+                                 gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                                      priv->trc),
+                                 babl_format_has_alpha (format),
+                                 space);
+      break;
 
-          g_return_if_reached ();
-        }
+    default:
+      if (async)
+        gimp_async_abort (async);
+
+      g_return_if_reached ();
     }
 
   context->n_components = babl_format_get_n_components (format);
diff --git a/app/core/gimphistogram.h b/app/core/gimphistogram.h
index 0871ece5b7..52264d1676 100644
--- a/app/core/gimphistogram.h
+++ b/app/core/gimphistogram.h
@@ -50,7 +50,7 @@ struct _GimpHistogramClass
 
 GType           gimp_histogram_get_type        (void) G_GNUC_CONST;
 
-GimpHistogram * gimp_histogram_new             (gboolean              linear);
+GimpHistogram * gimp_histogram_new             (GimpTRCType           trc);
 
 GimpHistogram * gimp_histogram_duplicate       (GimpHistogram        *histogram);
 
diff --git a/app/core/gimpimage-color-profile.c b/app/core/gimpimage-color-profile.c
index b004cadbaf..5337b5bc1b 100644
--- a/app/core/gimpimage-color-profile.c
+++ b/app/core/gimpimage-color-profile.c
@@ -2,7 +2,7 @@
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
  * gimpimage-color-profile.c
- * Copyright (C) 2015 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2015-2018 Michael Natterer <mitch gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,8 +39,8 @@
 
 #include "gimp.h"
 #include "gimpcontext.h"
-#include "gimpdrawable.h"
 #include "gimperror.h"
+#include "gimplayer.h"
 #include "gimpimage.h"
 #include "gimpimage-color-profile.h"
 #include "gimpimage-colormap.h"
@@ -68,6 +68,9 @@ static void   gimp_image_convert_profile_colormap (GimpImage                *ima
                                                    gboolean                  bpc,
                                                    GimpProgress             *progress);
 
+static void   gimp_image_fix_layer_format_spaces  (GimpImage                *image,
+                                                   GimpProgress             *progress);
+
 static void   gimp_image_create_color_transforms  (GimpImage                *image);
 
 
@@ -346,9 +349,9 @@ gimp_image_validate_color_profile_by_format (const Babl         *format,
 
   if (is_builtin)
     {
-      GimpColorProfile *builtin;
-
-      builtin = gimp_babl_format_get_color_profile (format);
+      GimpColorProfile *builtin =
+        gimp_babl_get_builtin_color_profile (gimp_babl_format_get_base_type (format),
+                                             gimp_babl_format_get_trc (format));
 
       *is_builtin = gimp_color_profile_is_equal (profile, builtin);
     }
@@ -365,7 +368,58 @@ gimp_image_get_builtin_color_profile (GimpImage *image)
 
   format = gimp_image_get_layer_format (image, FALSE);
 
-  return gimp_babl_format_get_color_profile (format);
+  return gimp_babl_get_builtin_color_profile (gimp_babl_format_get_base_type (format),
+                                              gimp_babl_format_get_trc (format));
+}
+
+gboolean
+gimp_image_assign_color_profile (GimpImage         *image,
+                                 GimpColorProfile  *dest_profile,
+                                 GimpProgress      *progress,
+                                 GError           **error)
+{
+  GimpColorProfile *src_profile;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+  g_return_val_if_fail (dest_profile == NULL ||
+                        GIMP_IS_COLOR_PROFILE (dest_profile), FALSE);
+  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (dest_profile &&
+      ! gimp_image_validate_color_profile (image, dest_profile, NULL, error))
+    return FALSE;
+
+  src_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
+
+  if (src_profile == dest_profile ||
+      (src_profile && dest_profile &&
+       gimp_color_profile_is_equal (src_profile, dest_profile)))
+    return TRUE;
+
+  if (progress)
+    gimp_progress_start (progress, FALSE,
+                         dest_profile ?
+                         _("Assigning color profile") :
+                         _("Discarding color profile"));
+
+  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT,
+                               dest_profile ?
+                               _("Assign color profile") :
+                               _("Discard color profile"));
+
+  if (dest_profile)
+    gimp_image_set_is_color_managed (image, TRUE, TRUE);
+
+  gimp_image_set_color_profile (image, dest_profile, NULL);
+  /*  omg...  */
+  gimp_image_parasite_detach (image, "icc-profile-name");
+
+  gimp_image_fix_layer_format_spaces (image, progress);
+
+  gimp_image_undo_group_end (image);
+
+  return TRUE;
 }
 
 gboolean
@@ -400,6 +454,11 @@ gimp_image_convert_color_profile (GimpImage                *image,
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT,
                                _("Color profile conversion"));
 
+  gimp_image_set_is_color_managed (image, TRUE, TRUE);
+  gimp_image_set_color_profile (image, dest_profile, NULL);
+  /*  omg...  */
+  gimp_image_parasite_detach (image, "icc-profile-name");
+
   switch (gimp_image_get_base_type (image))
     {
     case GIMP_RGB:
@@ -415,14 +474,10 @@ gimp_image_convert_color_profile (GimpImage                *image,
                                            src_profile, dest_profile,
                                            intent, bpc,
                                            progress);
+      gimp_image_fix_layer_format_spaces (image, progress);
       break;
     }
 
-  gimp_image_set_is_color_managed (image, TRUE, TRUE);
-  gimp_image_set_color_profile (image, dest_profile, NULL);
-  /*  omg...  */
-  gimp_image_parasite_detach (image, "icc-profile-name");
-
   gimp_image_undo_group_end (image);
 
   if (progress)
@@ -625,6 +680,7 @@ _gimp_image_free_color_profile (GimpImage *image)
   GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
 
   g_clear_object (&private->color_profile);
+  private->layer_space = NULL;
 
   _gimp_image_free_color_transforms (image);
 }
@@ -652,10 +708,20 @@ _gimp_image_update_color_profile (GimpImage          *image,
 
   if (icc_parasite)
     {
+      GError *error = NULL;
+
       private->color_profile =
         gimp_color_profile_new_from_icc_profile (gimp_parasite_data (icc_parasite),
                                                  gimp_parasite_data_size (icc_parasite),
                                                  NULL);
+
+      private->layer_space =
+        gimp_color_profile_get_space (private->color_profile,
+                                      GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+                                      &error);
+      if (! private->layer_space)
+        g_printerr ("%s: failed to create Babl space from profile: %s\n",
+                    G_STRFUNC, error->message);
     }
 
   gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image));
@@ -692,21 +758,28 @@ gimp_image_convert_profile_layers (GimpImage                *image,
 
   while ((drawable = gimp_object_queue_pop (queue)))
     {
-      gimp_drawable_push_undo (drawable, NULL, NULL,
-                               0, 0,
-                               gimp_item_get_width  (GIMP_ITEM (drawable)),
-                               gimp_item_get_height (GIMP_ITEM (drawable)));
+      GimpItem   *item = GIMP_ITEM (drawable);
+      GeglBuffer *buffer;
+      gboolean    alpha;
+
+      alpha = gimp_drawable_has_alpha (drawable);
+
+      buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                                gimp_item_get_width  (item),
+                                                gimp_item_get_height (item)),
+                                gimp_image_get_layer_format (image, alpha));
 
       gimp_gegl_convert_color_profile (gimp_drawable_get_buffer (drawable),
                                        NULL,
                                        src_profile,
-                                       gimp_drawable_get_buffer (drawable),
+                                       buffer,
                                        NULL,
                                        dest_profile,
                                        intent, bpc,
                                        progress);
 
-      gimp_drawable_update (drawable, 0, 0, -1, -1);
+      gimp_drawable_set_buffer (drawable, TRUE, NULL, buffer);
+      g_object_unref (buffer);
     }
 
   g_object_unref (queue);
@@ -732,8 +805,10 @@ gimp_image_convert_profile_colormap (GimpImage                *image,
     flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION;
 
   transform = gimp_color_transform_new (src_profile,
+                                        /* EEK SPACE */
                                         babl_format ("R'G'B' u8"),
                                         dest_profile,
+                                        /* EEK SPACE */
                                         babl_format ("R'G'B' u8"),
                                         intent, flags);
 
@@ -755,6 +830,35 @@ gimp_image_convert_profile_colormap (GimpImage                *image,
   g_free (cmap);
 }
 
+static void
+gimp_image_fix_layer_format_spaces (GimpImage    *image,
+                                    GimpProgress *progress)
+{
+  GimpObjectQueue *queue;
+  GList           *layers;
+  GList           *list;
+  GimpLayer       *layer;
+
+  queue = gimp_object_queue_new (progress);
+
+  layers = gimp_image_get_layer_list (image);
+
+  for (list = layers; list; list = g_list_next (list))
+    {
+      if (! gimp_viewable_get_children (list->data))
+        gimp_object_queue_push (queue, list->data);
+    }
+
+  g_list_free (layers);
+
+  while ((layer = gimp_object_queue_pop (queue)))
+    {
+      gimp_layer_fix_format_space (layer, TRUE, TRUE);
+    }
+
+  g_object_unref (queue);
+}
+
 static void
 gimp_image_create_color_transforms (GimpImage *image)
 {
diff --git a/app/core/gimpimage-color-profile.h b/app/core/gimpimage-color-profile.h
index ae89038494..d6c9c599a9 100644
--- a/app/core/gimpimage-color-profile.h
+++ b/app/core/gimpimage-color-profile.h
@@ -2,7 +2,7 @@
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
  * gimpimage-color-profile.h
- * Copyright (C) 2015 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2015-2018 Michael Natterer <mitch gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -68,6 +68,11 @@ gboolean             gimp_image_validate_color_profile_by_format
 GimpColorProfile   * gimp_image_get_builtin_color_profile
                                                        (GimpImage           *image);
 
+gboolean             gimp_image_assign_color_profile   (GimpImage           *image,
+                                                        GimpColorProfile    *dest_profile,
+                                                        GimpProgress        *progress,
+                                                        GError             **error);
+
 gboolean             gimp_image_convert_color_profile  (GimpImage           *image,
                                                         GimpColorProfile    *dest_profile,
                                                         GimpColorRenderingIntent  intent,
diff --git a/app/core/gimpimage-convert-indexed.c b/app/core/gimpimage-convert-indexed.c
index 1bca247cd4..e56e7ebc5c 100644
--- a/app/core/gimpimage-convert-indexed.c
+++ b/app/core/gimpimage-convert-indexed.c
@@ -809,14 +809,11 @@ gimp_image_convert_indexed (GimpImage               *image,
 
   g_object_set (image, "base-type", GIMP_INDEXED, NULL);
 
-  /* when converting from GRAY, convert to the new type's builtin
-   * profile.
+  /* when converting from GRAY, always convert to the new type's
+   * builtin profile
    */
   if (old_type == GIMP_GRAY)
-    {
-      if (gimp_image_get_color_profile (image))
-        dest_profile = gimp_image_get_builtin_color_profile (image);
-    }
+    dest_profile = gimp_image_get_builtin_color_profile (image);
 
   /*  Build histogram if necessary.  */
   rgb_to_lab_fish = babl_fish (babl_format ("R'G'B' float"),
@@ -1062,12 +1059,7 @@ gimp_image_convert_indexed (GimpImage               *image,
   /*  When converting from GRAY, set the new profile.
    */
   if (old_type == GIMP_GRAY)
-    {
-      if (gimp_image_get_color_profile (image))
-        gimp_image_set_color_profile (image, dest_profile, NULL);
-      else
-        gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image));
-    }
+    gimp_image_set_color_profile (image, dest_profile, NULL);
 
   /*  Delete the quantizer object, if there is one */
   if (quantobj)
diff --git a/app/core/gimpimage-convert-precision.c b/app/core/gimpimage-convert-precision.c
index ae80fbefaf..7221661bd8 100644
--- a/app/core/gimpimage-convert-precision.c
+++ b/app/core/gimpimage-convert-precision.c
@@ -24,6 +24,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
 
+#include "libgimpbase/gimpbase.h"
 #include "libgimpcolor/gimpcolor.h"
 
 #include "core-types.h"
@@ -63,7 +64,8 @@ gimp_image_convert_precision (GimpImage        *image,
   GimpProgress     *sub_progress;
   GList            *layers;
   GimpDrawable     *drawable;
-  const gchar      *undo_desc    = NULL;
+  const gchar      *enum_desc;
+  gchar            *undo_desc = NULL;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (precision != gimp_image_get_precision (image));
@@ -71,45 +73,11 @@ gimp_image_convert_precision (GimpImage        *image,
                                         precision));
   g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
 
-  switch (precision)
-    {
-    case GIMP_PRECISION_U8_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 8 bit linear integer");
-      break;
-    case GIMP_PRECISION_U8_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 8 bit gamma integer");
-      break;
-    case GIMP_PRECISION_U16_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 16 bit linear integer");
-      break;
-    case GIMP_PRECISION_U16_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 16 bit gamma integer");
-      break;
-    case GIMP_PRECISION_U32_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 32 bit linear integer");
-      break;
-    case GIMP_PRECISION_U32_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 32 bit gamma integer");
-      break;
-    case GIMP_PRECISION_HALF_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 16 bit linear floating point");
-      break;
-    case GIMP_PRECISION_HALF_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 16 bit gamma floating point");
-      break;
-    case GIMP_PRECISION_FLOAT_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 32 bit linear floating point");
-      break;
-    case GIMP_PRECISION_FLOAT_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 32 bit gamma floating point");
-      break;
-    case GIMP_PRECISION_DOUBLE_LINEAR:
-      undo_desc = C_("undo-type", "Convert Image to 64 bit linear floating point");
-      break;
-    case GIMP_PRECISION_DOUBLE_GAMMA:
-      undo_desc = C_("undo-type", "Convert Image to 64 bit gamma floating point");
-      break;
-    }
+  gimp_enum_get_value (GIMP_TYPE_PRECISION, precision,
+                       NULL, NULL, &enum_desc, NULL);
+
+  undo_desc = g_strdup_printf (C_("undo-type", "Convert Image to %s"),
+                               enum_desc);
 
   if (progress)
     gimp_progress_start (progress, FALSE, "%s", undo_desc);
@@ -128,6 +96,7 @@ gimp_image_convert_precision (GimpImage        *image,
 
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT,
                                undo_desc);
+  g_free (undo_desc);
 
   /*  Push the image precision to the stack  */
   gimp_image_undo_push_image_precision (image, NULL);
@@ -142,15 +111,19 @@ gimp_image_convert_precision (GimpImage        *image,
 
   if (old_profile)
     {
-      if (gimp_babl_format_get_linear (old_format) !=
-          gimp_babl_format_get_linear (new_format))
+      /* we use old_format and new_format just for looking at their
+       * TRCs, new_format's space might be incorrect, don't use it
+       * for anything else.
+       */
+      if (gimp_babl_format_get_trc (old_format) !=
+          gimp_babl_format_get_trc (new_format))
         {
           /* when converting between linear and gamma, we create a new
            * profile using the original profile's chromacities and
            * whitepoint, but a linear/sRGB-gamma TRC.
            */
 
-          if (gimp_babl_format_get_linear (new_format))
+          if (gimp_babl_format_get_trc (new_format) == GIMP_TRC_LINEAR)
             {
               new_profile =
                 gimp_color_profile_new_linear_from_color_profile (old_profile);
@@ -161,21 +134,26 @@ gimp_image_convert_precision (GimpImage        *image,
                 gimp_color_profile_new_srgb_trc_from_color_profile (old_profile);
             }
 
-          /* if a new profile cannot be be generated, convert to the
-           * builtin profile, which is better than leaving the user with
-           * broken colors
-           */
-          if (! new_profile)
-            {
-              new_profile = gimp_image_get_builtin_color_profile (image);
-              g_object_ref (new_profile);
-            }
         }
 
       if (! new_profile)
         new_profile = g_object_ref (old_profile);
     }
 
+  /* we always need a profile for convert_type on the same image, use
+   * the new precision's builtin profile as a fallback if the image
+   * didn't have a profile before, or it couldn't be converted
+   */
+  if (! new_profile)
+    {
+      GimpImageBaseType base_type = gimp_image_get_base_type (image);
+      GimpTRCType       trc       = gimp_babl_trc (precision);
+
+      new_profile = gimp_babl_get_builtin_color_profile (base_type,
+                                                         trc);
+      g_object_ref (new_profile);
+    }
+
   while ((drawable = gimp_object_queue_pop (queue)))
     {
       if (drawable == GIMP_DRAWABLE (gimp_image_get_mask (image)))
@@ -219,13 +197,12 @@ gimp_image_convert_precision (GimpImage        *image,
         }
     }
 
-  if (new_profile)
-    {
-      if (new_profile != old_profile)
-        gimp_image_set_color_profile (image, new_profile, NULL);
+  if (new_profile != old_profile)
+    gimp_image_set_color_profile (image, new_profile, NULL);
+  else
+    gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image));
 
-      g_object_unref (new_profile);
-    }
+  g_object_unref (new_profile);
 
   gimp_image_undo_group_end (image);
 
diff --git a/app/core/gimpimage-convert-type.c b/app/core/gimpimage-convert-type.c
index 4298a495ec..12c3f6fc8f 100644
--- a/app/core/gimpimage-convert-type.c
+++ b/app/core/gimpimage-convert-type.c
@@ -68,7 +68,8 @@ gimp_image_convert_type (GimpImage          *image,
 
   new_layer_format = gimp_babl_format (new_type,
                                        gimp_image_get_precision (image),
-                                       TRUE);
+                                       TRUE,
+                                       gimp_image_get_layer_space (image));
 
   if (dest_profile &&
       ! gimp_image_validate_color_profile_by_format (new_layer_format,
@@ -114,13 +115,14 @@ gimp_image_convert_type (GimpImage          *image,
 
   g_object_set (image, "base-type", new_type, NULL);
 
-  /*  When converting to/from GRAY, convert to the new type's builtin
-   *  profile if none was passed.
+  /*  When converting to/from GRAY, always convert to the new type's
+   *  builtin profile as a fallback, we need one for convert_type on
+   *  the same image
    */
   if (old_type == GIMP_GRAY ||
       new_type == GIMP_GRAY)
     {
-      if (! dest_profile && gimp_image_get_color_profile (image))
+      if (! dest_profile)
         dest_profile = gimp_image_get_builtin_color_profile (image);
     }
 
@@ -143,10 +145,7 @@ gimp_image_convert_type (GimpImage          *image,
   if (old_type == GIMP_GRAY ||
       new_type == GIMP_GRAY)
     {
-      if (gimp_image_get_color_profile (image))
-        gimp_image_set_color_profile (image, dest_profile, NULL);
-      else
-        gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image));
+      gimp_image_set_color_profile (image, dest_profile, NULL);
     }
 
   gimp_image_undo_group_end (image);
diff --git a/app/core/gimpimage-duplicate.c b/app/core/gimpimage-duplicate.c
index 9e327aee98..05537638ad 100644
--- a/app/core/gimpimage-duplicate.c
+++ b/app/core/gimpimage-duplicate.c
@@ -109,9 +109,6 @@ gimp_image_duplicate (GimpImage *image)
   /*  Store the source uri to be used by the save dialog  */
   gimp_image_duplicate_save_source_file (image, new_image);
 
-  /*  Copy the colormap if necessary  */
-  gimp_image_duplicate_colormap (image, new_image);
-
   /*  Copy resolution information  */
   gimp_image_duplicate_resolution (image, new_image);
 
@@ -119,6 +116,9 @@ gimp_image_duplicate (GimpImage *image)
   gimp_image_duplicate_parasites (image, new_image);
   gimp_image_duplicate_color_profile (image, new_image);
 
+  /*  Copy the colormap if necessary  */
+  gimp_image_duplicate_colormap (image, new_image);
+
   /*  Copy the layers  */
   active_layer = gimp_image_duplicate_layers (image, new_image);
 
diff --git a/app/core/gimpimage-new.c b/app/core/gimpimage-new.c
index 02c0fa22cc..32635c30c3 100644
--- a/app/core/gimpimage-new.c
+++ b/app/core/gimpimage-new.c
@@ -366,7 +366,7 @@ gimp_image_new_from_pixbuf (Gimp        *gimp,
                                  gdk_pixbuf_get_width  (pixbuf),
                                  gdk_pixbuf_get_height (pixbuf),
                                  base_type,
-                                 GIMP_PRECISION_U8_GAMMA,
+                                 GIMP_PRECISION_U8_NON_LINEAR,
                                  FALSE);
 
   gimp_image_undo_disable (new_image);
diff --git a/app/core/gimpimage-preview.c b/app/core/gimpimage-preview.c
index 2840635595..34fbb768fb 100644
--- a/app/core/gimpimage-preview.c
+++ b/app/core/gimpimage-preview.c
@@ -107,7 +107,7 @@ gimp_image_get_new_preview (GimpViewable *viewable,
 {
   GimpImage   *image = GIMP_IMAGE (viewable);
   const Babl  *format;
-  gboolean     linear;
+  GimpTRCType  trc;
   GimpTempBuf *buf;
   gdouble      scale_x;
   gdouble      scale_y;
@@ -116,12 +116,12 @@ gimp_image_get_new_preview (GimpViewable *viewable,
   scale_y = (gdouble) height / (gdouble) gimp_image_get_height (image);
 
   format = gimp_projectable_get_format (GIMP_PROJECTABLE (image));
-  linear = gimp_babl_format_get_linear (format);
+  trc    = gimp_babl_format_get_trc (format);
 
   format = gimp_babl_format (gimp_babl_format_get_base_type (format),
-                             gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
-                                                  linear),
-                             babl_format_has_alpha (format));
+                             gimp_babl_precision (GIMP_COMPONENT_TYPE_U8, trc),
+                             babl_format_has_alpha (format),
+                             babl_format_get_space (format));
 
   buf = gimp_temp_buf_new (width, height, format);
 
diff --git a/app/core/gimpimage-private.h b/app/core/gimpimage-private.h
index d00d1634ad..3a1604974b 100644
--- a/app/core/gimpimage-private.h
+++ b/app/core/gimpimage-private.h
@@ -59,6 +59,7 @@ struct _GimpImagePrivate
 
   gboolean           is_color_managed;      /*  is this image color managed  */
   GimpColorProfile  *color_profile;         /*  image's color profile        */
+  const Babl        *layer_space;           /*  image's Babl layer space     */
 
   /*  Cached color transforms: from layer to sRGB u8 and double, and back    */
   gboolean            color_transforms_created;
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index ad209ec9a7..9040bd0fdd 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -633,7 +633,7 @@ gimp_image_class_init (GimpImageClass *klass)
   g_object_class_install_property (object_class, PROP_PRECISION,
                                    g_param_spec_enum ("precision", NULL, NULL,
                                                       GIMP_TYPE_PRECISION,
-                                                      GIMP_PRECISION_U8_GAMMA,
+                                                      GIMP_PRECISION_U8_NON_LINEAR,
                                                       GIMP_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT));
 
@@ -705,7 +705,7 @@ gimp_image_init (GimpImage *image)
   private->yresolution         = 1.0;
   private->resolution_unit     = GIMP_UNIT_INCH;
   private->base_type           = GIMP_RGB;
-  private->precision           = GIMP_PRECISION_U8_GAMMA;
+  private->precision           = GIMP_PRECISION_U8_NON_LINEAR;
   private->new_layer_mode      = -1;
 
   private->colormap            = NULL;
@@ -1342,14 +1342,18 @@ gimp_image_real_colormap_changed (GimpImage *image,
 
   if (private->colormap && private->n_colors > 0)
     {
+      const Babl *space = gimp_image_get_layer_space (image);
+
       babl_palette_set_palette (private->babl_palette_rgb,
                                 gimp_babl_format (GIMP_RGB,
-                                                  private->precision, FALSE),
+                                                  private->precision, FALSE,
+                                                  space),
                                 private->colormap,
                                 private->n_colors);
       babl_palette_set_palette (private->babl_palette_rgba,
                                 gimp_babl_format (GIMP_RGB,
-                                                  private->precision, FALSE),
+                                                  private->precision, FALSE,
+                                                  space),
                                 private->colormap,
                                 private->n_colors);
     }
@@ -1449,11 +1453,13 @@ gimp_image_get_proj_format (GimpProjectable *projectable)
     case GIMP_RGB:
     case GIMP_INDEXED:
       return gimp_image_get_format (image, GIMP_RGB,
-                                    gimp_image_get_precision (image), TRUE);
+                                    gimp_image_get_precision (image), TRUE,
+                                    gimp_image_get_layer_space (image));
 
     case GIMP_GRAY:
       return gimp_image_get_format (image, GIMP_GRAY,
-                                    gimp_image_get_precision (image), TRUE);
+                                    gimp_image_get_precision (image), TRUE,
+                                    gimp_image_get_layer_space (image));
     }
 
   g_return_val_if_reached (NULL);
@@ -1817,7 +1823,8 @@ const Babl *
 gimp_image_get_format (GimpImage         *image,
                        GimpImageBaseType  base_type,
                        GimpPrecision      precision,
-                       gboolean           with_alpha)
+                       gboolean           with_alpha,
+                       const Babl        *space)
 {
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
 
@@ -1825,10 +1832,10 @@ gimp_image_get_format (GimpImage         *image,
     {
     case GIMP_RGB:
     case GIMP_GRAY:
-      return gimp_babl_format (base_type, precision, with_alpha);
+      return gimp_babl_format (base_type, precision, with_alpha, space);
 
     case GIMP_INDEXED:
-      if (precision == GIMP_PRECISION_U8_GAMMA)
+      if (precision == GIMP_PRECISION_U8_NON_LINEAR)
         {
           if (with_alpha)
             return gimp_image_colormap_get_rgba_format (image);
@@ -1840,6 +1847,14 @@ gimp_image_get_format (GimpImage         *image,
   g_return_val_if_reached (NULL);
 }
 
+const Babl *
+gimp_image_get_layer_space (GimpImage *image)
+{
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  return GIMP_IMAGE_GET_PRIVATE (image)->layer_space;
+}
+
 const Babl *
 gimp_image_get_layer_format (GimpImage *image,
                              gboolean   with_alpha)
@@ -1849,7 +1864,8 @@ gimp_image_get_layer_format (GimpImage *image,
   return gimp_image_get_format (image,
                                 gimp_image_get_base_type (image),
                                 gimp_image_get_precision (image),
-                                with_alpha);
+                                with_alpha,
+                                gimp_image_get_layer_space (image));
 }
 
 const Babl *
@@ -1861,10 +1877,10 @@ gimp_image_get_channel_format (GimpImage *image)
 
   precision = gimp_image_get_precision (image);
 
-  if (precision == GIMP_PRECISION_U8_GAMMA)
+  if (precision == GIMP_PRECISION_U8_NON_LINEAR)
     return gimp_image_get_format (image, GIMP_GRAY,
                                   gimp_image_get_precision (image),
-                                  FALSE);
+                                  FALSE, NULL);
 
   return gimp_babl_mask_format (precision);
 }
@@ -2494,7 +2510,7 @@ gimp_image_get_xcf_version (GimpImage    *image,
    */
 
   /* need version 7 for != 8-bit gamma images */
-  if (gimp_image_get_precision (image) != GIMP_PRECISION_U8_GAMMA)
+  if (gimp_image_get_precision (image) != GIMP_PRECISION_U8_NON_LINEAR)
     {
       ADD_REASON (g_strdup_printf (_("High bit-depth images were added "
                                      "in %s"), "GIMP 2.10"));
@@ -2502,8 +2518,12 @@ gimp_image_get_xcf_version (GimpImage    *image,
     }
 
   /* need version 12 for > 8-bit images for proper endian swapping */
-  if (gimp_image_get_precision (image) > GIMP_PRECISION_U8_GAMMA)
-    version = MAX (12, version);
+  if (gimp_image_get_component_type (image) > GIMP_COMPONENT_TYPE_U8)
+    {
+      ADD_REASON (g_strdup_printf (_("Encoding of high bit-depth images was "
+                                     "fixed in %s"), "GIMP 2.10"));
+      version = MAX (12, version);
+    }
 
   /* need version 8 for zlib compression */
   if (zlib_compression)
diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h
index 4e04a9a5e0..ac6523f3a7 100644
--- a/app/core/gimpimage.h
+++ b/app/core/gimpimage.h
@@ -122,7 +122,10 @@ GimpPrecision      gimp_image_get_precision      (GimpImage          *image);
 const Babl    * gimp_image_get_format            (GimpImage          *image,
                                                   GimpImageBaseType   base_type,
                                                   GimpPrecision       precision,
-                                                  gboolean            with_alpha);
+                                                  gboolean            with_alpha,
+                                                  const Babl         *space);
+
+const Babl    * gimp_image_get_layer_space       (GimpImage          *image);
 const Babl    * gimp_image_get_layer_format      (GimpImage          *image,
                                                   gboolean            with_alpha);
 const Babl    * gimp_image_get_channel_format    (GimpImage          *image);
diff --git a/app/core/gimplayer-new.c b/app/core/gimplayer-new.c
index ee031b37e2..e83414fde8 100644
--- a/app/core/gimplayer-new.c
+++ b/app/core/gimplayer-new.c
@@ -237,6 +237,10 @@ gimp_layer_new_convert_buffer (GimpLayer         *layer,
 
       src_profile = gimp_babl_format_get_color_profile (src_format);
     }
+  else
+    {
+      g_object_ref (src_profile);
+    }
 
   dest_profile =
     gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer));
@@ -245,4 +249,6 @@ gimp_layer_new_convert_buffer (GimpLayer         *layer,
                                    dest_buffer, NULL, dest_profile,
                                    GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
                                    TRUE, NULL);
+
+  g_object_unref (src_profile);
 }
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index 9827b19094..b1fdd4d361 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -1366,6 +1366,8 @@ gimp_layer_convert_type (GimpDrawable     *drawable,
 {
   GimpLayer       *layer = GIMP_LAYER (drawable);
   GimpObjectQueue *queue = NULL;
+  const Babl      *dest_space;
+  const Babl      *space_format;
   gboolean         convert_mask;
 
   convert_mask = layer->mask &&
@@ -1394,7 +1396,26 @@ gimp_layer_convert_type (GimpDrawable     *drawable,
   if (queue)
     gimp_object_queue_pop (queue);
 
-  GIMP_LAYER_GET_CLASS (layer)->convert_type (layer, dest_image, new_format,
+  /*  when called with a dest_profile, always use the space from that
+   *  profile, we can't use gimp_image_get_layer_space() during an
+   *  image type or precision conversion
+   */
+  if (dest_profile)
+    {
+      dest_space =
+        gimp_color_profile_get_space (dest_profile,
+                                      GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+                                      NULL);
+    }
+  else
+    {
+      dest_space = gimp_image_get_layer_space (dest_image);
+    }
+
+  space_format = babl_format_with_space (babl_format_get_encoding (new_format),
+                                         dest_space);
+
+  GIMP_LAYER_GET_CLASS (layer)->convert_type (layer, dest_image, space_format,
                                               dest_profile, layer_dither_type,
                                               mask_dither_type, push_undo,
                                               progress);
@@ -1480,10 +1501,10 @@ gimp_layer_set_buffer (GimpDrawable *drawable,
                        gint          offset_y)
 {
   GeglBuffer *old_buffer = gimp_drawable_get_buffer (drawable);
-  gint        old_linear = -1;
+  gint        old_trc    = -1;
 
   if (old_buffer)
-    old_linear = gimp_drawable_get_linear (drawable);
+    old_trc = gimp_drawable_get_trc (drawable);
 
   GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
                                                   push_undo, undo_desc,
@@ -1492,7 +1513,7 @@ gimp_layer_set_buffer (GimpDrawable *drawable,
 
   if (gimp_filter_peek_node (GIMP_FILTER (drawable)))
     {
-      if (gimp_drawable_get_linear (drawable) != old_linear)
+      if (gimp_drawable_get_trc (drawable) != old_trc)
         gimp_layer_update_mode_node (GIMP_LAYER (drawable));
     }
 }
@@ -1768,6 +1789,48 @@ gimp_layer_layer_mask_update (GimpDrawable *drawable,
 
 /*  public functions  */
 
+void
+gimp_layer_fix_format_space (GimpLayer *layer,
+                             gboolean   copy_buffer,
+                             gboolean   push_undo)
+{
+  GimpDrawable *drawable;
+  const Babl   *format;
+
+  g_return_if_fail (GIMP_IS_LAYER (layer));
+  g_return_if_fail (push_undo == FALSE || copy_buffer == TRUE);
+
+  drawable = GIMP_DRAWABLE (layer);
+
+  format = gimp_image_get_layer_format (gimp_item_get_image (GIMP_ITEM (layer)),
+                                        gimp_drawable_has_alpha (drawable));
+
+  if (format != gimp_drawable_get_format (drawable))
+    {
+      GeglBuffer *buffer;
+
+      buffer = gegl_buffer_new
+        (GEGL_RECTANGLE (0, 0,
+                         gimp_item_get_width  (GIMP_ITEM (layer)),
+                         gimp_item_get_height (GIMP_ITEM (layer))),
+         format);
+
+      if (copy_buffer)
+        {
+          gegl_buffer_set_format (buffer, gimp_drawable_get_format (drawable));
+
+          gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
+                                 NULL, GEGL_ABYSS_NONE,
+                                 buffer, NULL);
+
+          gegl_buffer_set_format (buffer, NULL);
+        }
+
+      gimp_drawable_set_buffer (drawable, push_undo, NULL, buffer);
+      g_object_unref (buffer);
+    }
+}
+
 GimpLayer *
 gimp_layer_get_parent (GimpLayer *layer)
 {
@@ -2022,7 +2085,8 @@ gimp_layer_create_mask (GimpLayer       *layer,
             const Babl *copy_format =
               gimp_image_get_format (image, GIMP_GRAY,
                                      gimp_drawable_get_precision (drawable),
-                                     gimp_drawable_has_alpha (drawable));
+                                     gimp_drawable_has_alpha (drawable),
+                                     NULL);
 
             src_buffer =
               gegl_buffer_new (GEGL_RECTANGLE (0, 0,
diff --git a/app/core/gimplayer.h b/app/core/gimplayer.h
index ae1d5c524f..ec1c35a3c7 100644
--- a/app/core/gimplayer.h
+++ b/app/core/gimplayer.h
@@ -143,6 +143,10 @@ struct _GimpLayerClass
 
 GType           gimp_layer_get_type            (void) G_GNUC_CONST;
 
+void            gimp_layer_fix_format_space    (GimpLayer            *layer,
+                                                gboolean              copy_buffer,
+                                                gboolean              push_undo);
+
 GimpLayer     * gimp_layer_get_parent          (GimpLayer            *layer);
 
 GimpLayerMask * gimp_layer_get_mask            (GimpLayer            *layer);
diff --git a/app/core/gimppickable-contiguous-region.c b/app/core/gimppickable-contiguous-region.c
index 52754ce67c..3d625b53db 100644
--- a/app/core/gimppickable-contiguous-region.c
+++ b/app/core/gimppickable-contiguous-region.c
@@ -269,8 +269,9 @@ choose_format (GeglBuffer          *buffer,
         format = babl_format ("R'G'B'A float");
       else
         format = gimp_babl_format (gimp_babl_format_get_base_type (format),
-                                   GIMP_PRECISION_FLOAT_GAMMA,
-                                   *has_alpha);
+                                   GIMP_PRECISION_FLOAT_NON_LINEAR,
+                                   *has_alpha,
+                                   NULL);
       break;
 
     case GIMP_SELECT_CRITERION_R:
diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c
index 1cbae9bead..32db96ce47 100644
--- a/app/core/gimpprojection.c
+++ b/app/core/gimpprojection.c
@@ -349,7 +349,7 @@ gimp_projection_estimate_memsize (GimpImageBaseType type,
 
   format = gimp_babl_format (type,
                              gimp_babl_precision (component_type, FALSE),
-                             TRUE);
+                             TRUE, NULL);
   bytes  = babl_format_get_bytes_per_pixel (format);
 
   /* The pyramid levels constitute a geometric sum with a ratio of 1/4. */
diff --git a/app/core/gimpselection.c b/app/core/gimpselection.c
index b5cb3a6303..327dae5fad 100644
--- a/app/core/gimpselection.c
+++ b/app/core/gimpselection.c
@@ -713,7 +713,8 @@ gimp_selection_extract (GimpSelection *selection,
       dest_format = gimp_image_get_format (image, GIMP_RGB,
                                            gimp_image_get_precision (image),
                                            add_alpha ||
-                                           babl_format_has_alpha (src_format));
+                                           babl_format_has_alpha (src_format),
+                                           babl_format_get_space (src_format));
     }
   else
     {
diff --git a/app/core/gimptemplate.c b/app/core/gimptemplate.c
index 0023525f42..5240917f2d 100644
--- a/app/core/gimptemplate.c
+++ b/app/core/gimptemplate.c
@@ -57,6 +57,7 @@ enum
   PROP_PRECISION,
   PROP_COMPONENT_TYPE,
   PROP_LINEAR,
+  PROP_TRC,
   PROP_COLOR_MANAGED,
   PROP_COLOR_PROFILE,
   PROP_FILL_TYPE,
@@ -188,7 +189,7 @@ gimp_template_class_init (GimpTemplateClass *klass)
                          "precision",
                          _("Precision"),
                          NULL,
-                         GIMP_TYPE_PRECISION, GIMP_PRECISION_U8_GAMMA,
+                         GIMP_TYPE_PRECISION, GIMP_PRECISION_U8_NON_LINEAR,
                          GIMP_PARAM_STATIC_STRINGS);
 
   g_object_class_install_property (object_class, PROP_COMPONENT_TYPE,
@@ -200,13 +201,14 @@ gimp_template_class_init (GimpTemplateClass *klass)
                                                       G_PARAM_READWRITE |
                                                       GIMP_PARAM_STATIC_STRINGS));
 
-  g_object_class_install_property (object_class, PROP_LINEAR,
-                                   g_param_spec_boolean ("linear",
-                                                         _("Gamma"),
-                                                         NULL,
-                                                         FALSE,
-                                                         G_PARAM_READWRITE |
-                                                         GIMP_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_TRC,
+                                   g_param_spec_enum ("trc",
+                                                      _("Linear/Perceptual"),
+                                                      NULL,
+                                                      GIMP_TYPE_TRC_TYPE,
+                                                      GIMP_TRC_NON_LINEAR,
+                                                      G_PARAM_READWRITE |
+                                                      GIMP_PARAM_STATIC_STRINGS));
 
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_COLOR_MANAGED,
                             "color-managed",
@@ -300,18 +302,18 @@ gimp_template_set_property (GObject      *object,
     case PROP_PRECISION:
       private->precision = g_value_get_enum (value);
       g_object_notify (object, "component-type");
-      g_object_notify (object, "linear");
+      g_object_notify (object, "trc");
       break;
     case PROP_COMPONENT_TYPE:
       private->precision =
         gimp_babl_precision (g_value_get_enum (value),
-                             gimp_babl_linear (private->precision));
+                             gimp_babl_trc (private->precision));
       g_object_notify (object, "precision");
       break;
-    case PROP_LINEAR:
+    case PROP_TRC:
       private->precision =
         gimp_babl_precision (gimp_babl_component_type (private->precision),
-                             g_value_get_boolean (value));
+                             g_value_get_enum (value));
       g_object_notify (object, "precision");
       break;
     case PROP_COLOR_MANAGED:
@@ -378,8 +380,8 @@ gimp_template_get_property (GObject    *object,
     case PROP_COMPONENT_TYPE:
       g_value_set_enum (value, gimp_babl_component_type (private->precision));
       break;
-    case PROP_LINEAR:
-      g_value_set_boolean (value, gimp_babl_linear (private->precision));
+    case PROP_TRC:
+      g_value_set_enum (value, gimp_babl_trc (private->precision));
       break;
     case PROP_COLOR_MANAGED:
       g_value_set_boolean (value, private->color_managed);
@@ -416,7 +418,8 @@ gimp_template_notify (GObject    *object,
   /* the initial layer */
   format = gimp_babl_format (private->base_type,
                              private->precision,
-                             private->fill_type == GIMP_FILL_TRANSPARENT);
+                             private->fill_type == GIMP_FILL_TRANSPARENT,
+                             NULL);
   bytes = babl_format_get_bytes_per_pixel (format);
 
   /* the selection */
@@ -545,7 +548,8 @@ gimp_template_get_base_type (GimpTemplate *template)
 GimpPrecision
 gimp_template_get_precision (GimpTemplate *template)
 {
-  g_return_val_if_fail (GIMP_IS_TEMPLATE (template), GIMP_PRECISION_U8_GAMMA);
+  g_return_val_if_fail (GIMP_IS_TEMPLATE (template),
+                        GIMP_PRECISION_U8_NON_LINEAR);
 
   return GET_PRIVATE (template)->precision;
 }
diff --git a/app/dialogs/convert-precision-dialog.c b/app/dialogs/convert-precision-dialog.c
index 7743f4316f..f65408849b 100644
--- a/app/dialogs/convert-precision-dialog.c
+++ b/app/dialogs/convert-precision-dialog.c
@@ -45,7 +45,7 @@ struct _ConvertDialog
 {
   GimpImage                    *image;
   GimpComponentType             component_type;
-  gboolean                      linear;
+  GimpTRCType                   trc;
   GeglDitherMethod              layer_dither_method;
   GeglDitherMethod              text_layer_dither_method;
   GeglDitherMethod              channel_dither_method;
@@ -88,7 +88,7 @@ convert_precision_dialog_new (GimpImage                    *image,
   gint           old_bits;
   gint           new_bits;
   gboolean       dither;
-  gboolean       linear;
+  GimpTRCType    trc;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
@@ -99,7 +99,8 @@ convert_precision_dialog_new (GimpImage                    *image,
   old_format = gimp_image_get_layer_format (image, FALSE);
   new_format = gimp_babl_format (GIMP_RGB,
                                  gimp_babl_precision (component_type, FALSE),
-                                 FALSE);
+                                 FALSE,
+                                 babl_format_get_space (old_format));
 
   old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
               babl_format_get_n_components (old_format));
@@ -119,21 +120,21 @@ convert_precision_dialog_new (GimpImage                    *image,
     {
     case GIMP_COMPONENT_TYPE_U8:
       /* default to gamma when converting 8 bit */
-      linear = FALSE;
+      trc = GIMP_TRC_NON_LINEAR;
       break;
 
     case GIMP_COMPONENT_TYPE_U16:
     case GIMP_COMPONENT_TYPE_U32:
     default:
       /* leave gamma alone by default when converting to 16/32 bit int */
-      linear = gimp_babl_format_get_linear (old_format);
+      trc = gimp_babl_format_get_trc (old_format);
       break;
 
     case GIMP_COMPONENT_TYPE_HALF:
     case GIMP_COMPONENT_TYPE_FLOAT:
     case GIMP_COMPONENT_TYPE_DOUBLE:
       /* default to linear when converting to floating point */
-      linear = TRUE;
+      trc = GIMP_TRC_LINEAR;
       break;
     }
 
@@ -141,7 +142,7 @@ convert_precision_dialog_new (GimpImage                    *image,
 
   private->image                    = image;
   private->component_type           = component_type;
-  private->linear                   = linear;
+  private->trc                      = trc;
   private->layer_dither_method      = layer_dither_method;
   private->text_layer_dither_method = text_layer_dither_method;
   private->channel_dither_method    = channel_dither_method;
@@ -198,11 +199,17 @@ convert_precision_dialog_new (GimpImage                    *image,
 
   vbox = gimp_int_radio_group_new (FALSE, NULL,
                                    G_CALLBACK (gimp_radio_button_update),
-                                   &private->linear,
-                                   linear,
+                                   &private->trc,
+                                   trc,
 
-                                   _("Perceptual gamma (sRGB)"), FALSE, NULL,
-                                   _("Linear light"),            TRUE,  NULL,
+                                   _("Linear light"),
+                                   GIMP_TRC_LINEAR, NULL,
+
+                                   _("Non-Linear"),
+                                   GIMP_TRC_NON_LINEAR, NULL,
+
+                                   _("Perceptual (sRGB)"),
+                                   GIMP_TRC_PERCEPTUAL, NULL,
 
                                    NULL);
   gtk_container_add (GTK_CONTAINER (frame), vbox);
@@ -322,7 +329,7 @@ convert_precision_dialog_response (GtkWidget     *dialog,
   if (response_id == GTK_RESPONSE_OK)
     {
       GimpPrecision precision = gimp_babl_precision (private->component_type,
-                                                     private->linear);
+                                                     private->trc);
 
       private->callback (dialog,
                          private->image,
diff --git a/app/display/gimpdisplayshell-profile.c b/app/display/gimpdisplayshell-profile.c
index 71a6c94572..57f290a04a 100644
--- a/app/display/gimpdisplayshell-profile.c
+++ b/app/display/gimpdisplayshell-profile.c
@@ -108,7 +108,7 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
   if (gimp_display_shell_has_filter (shell))
     {
       filter_format  = shell->filter_format;
-      filter_profile = gimp_babl_format_get_color_profile (filter_format);
+      filter_profile = shell->filter_profile;
     }
   else
     {
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 8469de8993..1d68a8c1e1 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -35,6 +35,8 @@
 #include "config/gimpdisplayconfig.h"
 #include "config/gimpdisplayoptions.h"
 
+#include "gegl/gimp-babl.h"
+
 #include "core/gimp.h"
 #include "core/gimp-utils.h"
 #include "core/gimpchannel.h"
@@ -320,6 +322,8 @@ gimp_display_shell_init (GimpDisplayShell *shell)
   shell->override_cursor   = (GimpCursorType) -1;
 
   shell->filter_format     = babl_format ("R'G'B'A float");
+  shell->filter_profile    = gimp_babl_get_builtin_color_profile (GIMP_RGB,
+                                                                  GIMP_TRC_NON_LINEAR);
 
   shell->motion_buffer   = gimp_motion_buffer_new ();
 
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index 3dae3d05a5..2435c8e9f3 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -161,6 +161,7 @@ struct _GimpDisplayShell
 
   GimpColorTransform *filter_transform;
   const Babl         *filter_format;   /*  filter_buffer's format             */
+  GimpColorProfile   *filter_profile;  /*  filter_format's profile            */
   GeglBuffer         *filter_buffer;   /*  buffer for display filters         */
   guchar             *filter_data;     /*  filter_buffer's pixels             */
   gint                filter_stride;   /*  filter_buffer's stride             */
diff --git a/app/file/file-import.c b/app/file/file-import.c
index f5e9baf97b..137b9520ba 100644
--- a/app/file/file-import.c
+++ b/app/file/file-import.c
@@ -73,7 +73,7 @@ file_import_image (GimpImage    *image,
                                             progress);
 
               if (config->import_promote_dither &&
-                  old_precision == GIMP_PRECISION_U8_GAMMA)
+                  old_precision == GIMP_PRECISION_U8_NON_LINEAR)
                 {
                   gimp_image_convert_dither_u8 (image, progress);
                 }
diff --git a/app/file/file-open.c b/app/file/file-open.c
index 97f3b32e96..4550725c46 100644
--- a/app/file/file-open.c
+++ b/app/file/file-open.c
@@ -399,26 +399,26 @@ file_open_thumbnail (Gimp           *gimp,
                     {
                     case GIMP_RGB_IMAGE:
                       *format = gimp_babl_format (GIMP_RGB,
-                                                  GIMP_PRECISION_U8_GAMMA,
-                                                  FALSE);
+                                                  GIMP_PRECISION_U8_NON_LINEAR,
+                                                  FALSE, NULL);
                       break;
 
                     case GIMP_RGBA_IMAGE:
                       *format = gimp_babl_format (GIMP_RGB,
-                                                  GIMP_PRECISION_U8_GAMMA,
-                                                  TRUE);
+                                                  GIMP_PRECISION_U8_NON_LINEAR,
+                                                  TRUE, NULL);
                       break;
 
                     case GIMP_GRAY_IMAGE:
                       *format = gimp_babl_format (GIMP_GRAY,
-                                                  GIMP_PRECISION_U8_GAMMA,
-                                                  FALSE);
+                                                  GIMP_PRECISION_U8_NON_LINEAR,
+                                                  FALSE, NULL);
                       break;
 
                     case GIMP_GRAYA_IMAGE:
                       *format = gimp_babl_format (GIMP_GRAY,
-                                                  GIMP_PRECISION_U8_GAMMA,
-                                                  TRUE);
+                                                  GIMP_PRECISION_U8_NON_LINEAR,
+                                                  TRUE, NULL);
                       break;
 
                     case GIMP_INDEXED_IMAGE:
diff --git a/app/gegl/gimp-babl-compat.c b/app/gegl/gimp-babl-compat.c
index f94b708638..4f987c6a64 100644
--- a/app/gegl/gimp-babl-compat.c
+++ b/app/gegl/gimp-babl-compat.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <string.h>
+
 #include <gegl.h>
 
 #include "gimp-gegl-types.h"
@@ -31,29 +33,33 @@
 GimpImageType
 gimp_babl_format_get_image_type (const Babl *format)
 {
-  const Babl *model;
+  const gchar *name;
 
   g_return_val_if_fail (format != NULL, -1);
 
-  model = babl_format_get_model (format);
+  name = babl_get_name (babl_format_get_model (format));
 
-  if (model == babl_model ("Y") ||
-      model == babl_model ("Y'"))
+  if (! strcmp (name, "Y")  ||
+      ! strcmp (name, "Y'") ||
+      ! strcmp (name, "Y~"))
     {
       return GIMP_GRAY_IMAGE;
     }
-  else if (model == babl_model ("YA") ||
-           model == babl_model ("Y'A"))
+  else if (! strcmp (name, "YA")   ||
+           ! strcmp (name, "Y'A") ||
+           ! strcmp (name, "Y~A"))
     {
       return GIMP_GRAYA_IMAGE;
     }
-  else if (model == babl_model ("RGB") ||
-           model == babl_model ("R'G'B'"))
+  else if (! strcmp (name, "RGB")    ||
+           ! strcmp (name, "R'G'B'") ||
+           ! strcmp (name, "R~G~B~"))
     {
       return GIMP_RGB_IMAGE;
     }
-  else if (model == babl_model ("RGBA") ||
-           model == babl_model ("R'G'B'A"))
+  else if (! strcmp (name, "RGBA")    ||
+           ! strcmp (name, "R'G'B'A") ||
+           ! strcmp (name, "R~G~B~A"))
     {
       return GIMP_RGBA_IMAGE;
     }
@@ -78,6 +84,7 @@ gimp_babl_compat_u8_format (const Babl *format)
     return format;
 
   return gimp_babl_format (gimp_babl_format_get_base_type (format),
-                           GIMP_PRECISION_U8_GAMMA,
-                           babl_format_has_alpha (format));
+                           GIMP_PRECISION_U8_NON_LINEAR,
+                           babl_format_has_alpha (format),
+                           babl_format_get_space (format));
 }
diff --git a/app/gegl/gimp-babl.c b/app/gegl/gimp-babl.c
index 83af4073df..4383fe9540 100644
--- a/app/gegl/gimp-babl.c
+++ b/app/gegl/gimp-babl.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <string.h>
+
 #include <cairo.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
@@ -36,221 +38,86 @@
 void
 gimp_babl_init (void)
 {
-  babl_format_new ("name", "R u8",
-                   babl_model ("RGBA"),
-                   babl_type ("u8"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' u8",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u8"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G u8",
-                   babl_model ("RGBA"),
-                   babl_type ("u8"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' u8",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u8"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B u8",
-                   babl_model ("RGBA"),
-                   babl_type ("u8"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' u8",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u8"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A u8",
-                   babl_model ("RGBA"),
-                   babl_type ("u8"),
-                   babl_component ("A"),
-                   NULL);
-
-  babl_format_new ("name", "R u16",
-                   babl_model ("RGBA"),
-                   babl_type ("u16"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' u16",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u16"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G u16",
-                   babl_model ("RGBA"),
-                   babl_type ("u16"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' u16",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u16"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B u16",
-                   babl_model ("RGBA"),
-                   babl_type ("u16"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' u16",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u16"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A u16",
-                   babl_model ("RGBA"),
-                   babl_type ("u16"),
-                   babl_component ("A"),
-                   NULL);
-
-  babl_format_new ("name", "R u32",
-                   babl_model ("RGBA"),
-                   babl_type ("u32"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' u32",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u32"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G u32",
-                   babl_model ("RGBA"),
-                   babl_type ("u32"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' u32",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u32"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B u32",
-                   babl_model ("RGBA"),
-                   babl_type ("u32"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' u32",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("u32"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A u32",
-                   babl_model ("RGBA"),
-                   babl_type ("u32"),
-                   babl_component ("A"),
-                   NULL);
-
-  babl_format_new ("name", "R half",
-                   babl_model ("RGBA"),
-                   babl_type ("half"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' half",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("half"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G half",
-                   babl_model ("RGBA"),
-                   babl_type ("half"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' half",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("half"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B half",
-                   babl_model ("RGBA"),
-                   babl_type ("half"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' half",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("half"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A half",
-                   babl_model ("RGBA"),
-                   babl_type ("half"),
-                   babl_component ("A"),
-                   NULL);
-
-  babl_format_new ("name", "R float",
-                   babl_model ("RGBA"),
-                   babl_type ("float"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' float",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("float"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G float",
-                   babl_model ("RGBA"),
-                   babl_type ("float"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' float",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("float"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B float",
-                   babl_model ("RGBA"),
-                   babl_type ("float"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' float",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("float"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A float",
-                   babl_model ("RGBA"),
-                   babl_type ("float"),
-                   babl_component ("A"),
-                   NULL);
-
-  babl_format_new ("name", "R double",
-                   babl_model ("RGBA"),
-                   babl_type ("double"),
-                   babl_component ("R"),
-                   NULL);
-  babl_format_new ("name", "R' double",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("double"),
-                   babl_component ("R'"),
-                   NULL);
-  babl_format_new ("name", "G double",
-                   babl_model ("RGBA"),
-                   babl_type ("double"),
-                   babl_component ("G"),
-                   NULL);
-  babl_format_new ("name", "G' double",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("double"),
-                   babl_component ("G'"),
-                   NULL);
-  babl_format_new ("name", "B double",
-                   babl_model ("RGBA"),
-                   babl_type ("double"),
-                   babl_component ("B"),
-                   NULL);
-  babl_format_new ("name", "B' double",
-                   babl_model ("R'G'B'A"),
-                   babl_type ("double"),
-                   babl_component ("B'"),
-                   NULL);
-  babl_format_new ("name", "A double",
-                   babl_model ("RGBA"),
-                   babl_type ("double"),
-                   babl_component ("A"),
-                   NULL);
+  static const gchar *babl_types[] =
+  {
+    "u8",
+    "u16",
+    "u32",
+    "half",
+    "float",
+    "double"
+  };
+
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (babl_types); i++)
+    {
+      gchar name[16];
+
+      g_snprintf (name, sizeof (name), "R %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("RGBA"),
+                       babl_type (babl_types[i]),
+                       babl_component ("R"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "R' %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R'G'B'A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("R'"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "R~ %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R~G~B~A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("R~"),
+                       NULL);
+
+      g_snprintf (name, sizeof (name), "G %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("RGBA"),
+                       babl_type (babl_types[i]),
+                       babl_component ("G"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "G' %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R'G'B'A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("G'"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "G~ %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R~G~B~A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("G~"),
+                       NULL);
+
+      g_snprintf (name, sizeof (name), "B %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("RGBA"),
+                       babl_type (babl_types[i]),
+                       babl_component ("B"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "B' %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R'G'B'A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("B'"),
+                       NULL);
+      g_snprintf (name, sizeof (name), "B~ %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("R~G~B~A"),
+                       babl_type (babl_types[i]),
+                       babl_component ("B~"),
+                       NULL);
+
+      g_snprintf (name, sizeof (name), "A %s", babl_types[i]);
+      babl_format_new ("name", name,
+                       babl_model ("RGBA"),
+                       babl_type (babl_types[i]),
+                       babl_component ("A"),
+                       NULL);
+    }
 }
 
 void
@@ -315,101 +182,143 @@ babl_descriptions[] =
 {
   { "RGB u8",         N_("RGB") },
   { "R'G'B' u8",      N_("RGB") },
+  { "R~G~B~ u8",      N_("RGB") },
   { "RGB u16",        N_("RGB") },
   { "R'G'B' u16",     N_("RGB") },
+  { "R~G~B~ u16",     N_("RGB") },
   { "RGB u32",        N_("RGB") },
   { "R'G'B' u32",     N_("RGB") },
+  { "R~G~B~ u32",     N_("RGB") },
   { "RGB half",       N_("RGB") },
   { "R'G'B' half",    N_("RGB") },
+  { "R~G~B~ half",    N_("RGB") },
   { "RGB float",      N_("RGB") },
   { "R'G'B' float",   N_("RGB") },
+  { "R~G~B~ float",   N_("RGB") },
   { "RGB double",     N_("RGB") },
   { "R'G'B' double",  N_("RGB") },
+  { "R~G~B~ double",  N_("RGB") },
 
   { "RGBA u8",        N_("RGB-alpha") },
   { "R'G'B'A u8",     N_("RGB-alpha") },
+  { "R~G~B~A u8",     N_("RGB-alpha") },
   { "RGBA u16",       N_("RGB-alpha") },
   { "R'G'B'A u16",    N_("RGB-alpha") },
+  { "R~G~B~A u16",    N_("RGB-alpha") },
   { "RGBA u32",       N_("RGB-alpha") },
   { "R'G'B'A u32",    N_("RGB-alpha") },
+  { "R~G~B~A u32",    N_("RGB-alpha") },
   { "RGBA half",      N_("RGB-alpha") },
   { "R'G'B'A half",   N_("RGB-alpha") },
+  { "R~G~B~A half",   N_("RGB-alpha") },
   { "RGBA float",     N_("RGB-alpha") },
   { "R'G'B'A float",  N_("RGB-alpha") },
+  { "R~G~B~A float",  N_("RGB-alpha") },
   { "RGBA double",    N_("RGB-alpha") },
   { "R'G'B'A double", N_("RGB-alpha") },
+  { "R~G~B~A double", N_("RGB-alpha") },
 
   { "Y u8",           N_("Grayscale") },
   { "Y' u8",          N_("Grayscale") },
+  { "Y~ u8",          N_("Grayscale") },
   { "Y u16",          N_("Grayscale") },
   { "Y' u16",         N_("Grayscale") },
+  { "Y~ u16",         N_("Grayscale") },
   { "Y u32",          N_("Grayscale") },
   { "Y' u32",         N_("Grayscale") },
+  { "Y~ u32",         N_("Grayscale") },
   { "Y half",         N_("Grayscale") },
   { "Y' half",        N_("Grayscale") },
+  { "Y~ half",        N_("Grayscale") },
   { "Y float",        N_("Grayscale") },
   { "Y' float",       N_("Grayscale") },
+  { "Y~ float",       N_("Grayscale") },
   { "Y double",       N_("Grayscale") },
   { "Y' double",      N_("Grayscale") },
+  { "Y~ double",      N_("Grayscale") },
 
   { "YA u8",          N_("Grayscale-alpha") },
   { "Y'A u8",         N_("Grayscale-alpha") },
+  { "Y~A u8",         N_("Grayscale-alpha") },
   { "YA u16",         N_("Grayscale-alpha") },
   { "Y'A u16",        N_("Grayscale-alpha") },
+  { "Y~A u16",        N_("Grayscale-alpha") },
   { "YA u32",         N_("Grayscale-alpha") },
   { "Y'A u32",        N_("Grayscale-alpha") },
+  { "Y~A u32",        N_("Grayscale-alpha") },
   { "YA half",        N_("Grayscale-alpha") },
   { "Y'A half",       N_("Grayscale-alpha") },
+  { "Y~A half",       N_("Grayscale-alpha") },
   { "YA float",       N_("Grayscale-alpha") },
   { "Y'A float",      N_("Grayscale-alpha") },
+  { "Y~A float",      N_("Grayscale-alpha") },
   { "YA double",      N_("Grayscale-alpha") },
   { "Y'A double",     N_("Grayscale-alpha") },
+  { "Y~A double",     N_("Grayscale-alpha") },
 
   { "R u8",           N_("Red component") },
   { "R' u8",          N_("Red component") },
+  { "R~ u8",          N_("Red component") },
   { "R u16",          N_("Red component") },
   { "R' u16",         N_("Red component") },
+  { "R~ u16",         N_("Red component") },
   { "R u32",          N_("Red component") },
   { "R' u32",         N_("Red component") },
+  { "R~ u32",         N_("Red component") },
   { "R half",         N_("Red component") },
   { "R' half",        N_("Red component") },
+  { "R~ half",        N_("Red component") },
   { "R float",        N_("Red component") },
   { "R' float",       N_("Red component") },
+  { "R~ float",       N_("Red component") },
   { "R double",       N_("Red component") },
   { "R' double",      N_("Red component") },
+  { "R~ double",      N_("Red component") },
 
   { "G u8",           N_("Green component") },
   { "G' u8",          N_("Green component") },
+  { "G~ u8",          N_("Green component") },
   { "G u16",          N_("Green component") },
   { "G' u16",         N_("Green component") },
+  { "G~ u16",         N_("Green component") },
   { "G u32",          N_("Green component") },
   { "G' u32",         N_("Green component") },
+  { "G~ u32",         N_("Green component") },
   { "G half",         N_("Green component") },
   { "G' half",        N_("Green component") },
+  { "G~ half",        N_("Green component") },
   { "G float",        N_("Green component") },
   { "G' float",       N_("Green component") },
+  { "G~ float",       N_("Green component") },
   { "G double",       N_("Green component") },
   { "G' double",      N_("Green component") },
+  { "G~ double",      N_("Green component") },
 
   { "B u8",           N_("Blue component") },
   { "B' u8",          N_("Blue component") },
+  { "B~ u8",          N_("Blue component") },
   { "B u16",          N_("Blue component") },
   { "B' u16",         N_("Blue component") },
+  { "B~ u16",         N_("Blue component") },
   { "B u32",          N_("Blue component") },
   { "B' u32",         N_("Blue component") },
+  { "B~ u32",         N_("Blue component") },
   { "B half",         N_("Blue component") },
   { "B' half",        N_("Blue component") },
+  { "B~ half",        N_("Blue component") },
   { "B float",        N_("Blue component") },
   { "B' float",       N_("Blue component") },
+  { "B~ float",       N_("Blue component") },
   { "B double",       N_("Blue component") },
   { "B' double",      N_("Blue component") },
-
-  { "A u8",          N_("Alpha component") },
-  { "A u16",         N_("Alpha component") },
-  { "A u32",         N_("Alpha component") },
-  { "A half",        N_("Alpha component") },
-  { "A float",       N_("Alpha component") },
-  { "A double",      N_("Alpha component") }
+  { "B~ double",      N_("Blue component") },
+
+  { "A u8",           N_("Alpha component") },
+  { "A u16",          N_("Alpha component") },
+  { "A u32",          N_("Alpha component") },
+  { "A half",         N_("Alpha component") },
+  { "A float",        N_("Alpha component") },
+  { "A double",       N_("Alpha component") }
 };
 
 static GHashTable *babl_description_hash = NULL;
@@ -443,28 +352,27 @@ gimp_babl_format_get_description (const Babl *babl)
     }
 
   description = g_hash_table_lookup (babl_description_hash,
-                                     babl_get_name (babl));
+                                     babl_format_get_encoding (babl));
 
   if (description)
     return description;
 
   return g_strconcat ("ERROR: unknown Babl format ",
-                      babl_get_name (babl), NULL);
+                      babl_format_get_encoding (babl), NULL);
 }
 
 GimpColorProfile *
-gimp_babl_format_get_color_profile (const Babl *format)
+gimp_babl_get_builtin_color_profile (GimpImageBaseType base_type,
+                                     GimpTRCType       trc)
 {
   static GimpColorProfile *srgb_profile        = NULL;
   static GimpColorProfile *linear_rgb_profile  = NULL;
   static GimpColorProfile *gray_profile        = NULL;
   static GimpColorProfile *linear_gray_profile = NULL;
 
-  g_return_val_if_fail (format != NULL, NULL);
-
-  if (gimp_babl_format_get_base_type (format) == GIMP_GRAY)
+  if (base_type == GIMP_GRAY)
     {
-      if (gimp_babl_format_get_linear (format))
+      if (trc == GIMP_TRC_LINEAR)
         {
           if (! linear_gray_profile)
             {
@@ -489,7 +397,7 @@ gimp_babl_format_get_color_profile (const Babl *format)
     }
   else
     {
-      if (gimp_babl_format_get_linear (format))
+      if (trc == GIMP_TRC_LINEAR)
         {
           if (! linear_rgb_profile)
             {
@@ -514,28 +422,101 @@ gimp_babl_format_get_color_profile (const Babl *format)
     }
 }
 
+GimpColorProfile *
+gimp_babl_format_get_color_profile (const Babl *format)
+{
+  const Babl       *non_linear_format;
+  const gchar      *icc;
+  gint              icc_len;
+  GimpColorProfile *profile;
+  GimpColorProfile *retval = NULL;
+
+  g_return_val_if_fail (format != NULL, NULL);
+
+  if (gimp_babl_format_get_trc (format) == GIMP_TRC_NON_LINEAR)
+    {
+      non_linear_format = format;
+    }
+  else
+    {
+      GimpImageBaseType base_type = GIMP_RGB;
+      GimpComponentType component_type;
+
+      switch (gimp_babl_format_get_base_type (format))
+        {
+        case GIMP_RGB:
+        case GIMP_INDEXED:
+          base_type = GIMP_RGB;
+          break;
+
+        case GIMP_GRAY:
+          base_type = GIMP_GRAY;
+          break;
+        }
+
+      component_type = gimp_babl_format_get_component_type (format);
+
+      non_linear_format =
+        gimp_babl_format (base_type,
+                          gimp_babl_precision (component_type,
+                                               GIMP_TRC_NON_LINEAR),
+                          babl_format_has_alpha (format),
+                          babl_format_get_space (format));
+    }
+
+  icc = babl_space_get_icc (babl_format_get_space (non_linear_format),
+                            &icc_len);
+
+  profile = gimp_color_profile_new_from_icc_profile ((const guint8 *) icc,
+                                                     icc_len, NULL);
+
+  switch (gimp_babl_format_get_trc (format))
+    {
+    case GIMP_TRC_LINEAR:
+      retval = gimp_color_profile_new_linear_from_color_profile (profile);
+      break;
+
+    case GIMP_TRC_NON_LINEAR:
+      retval = g_object_ref (profile);
+      break;
+
+    case GIMP_TRC_PERCEPTUAL:
+      retval = gimp_color_profile_new_srgb_trc_from_color_profile (profile);
+      break;
+    }
+
+  g_object_unref (profile);
+
+  return retval;
+}
+
 GimpImageBaseType
 gimp_babl_format_get_base_type (const Babl *format)
 {
-  const Babl *model;
+  const gchar *name;
 
   g_return_val_if_fail (format != NULL, -1);
 
-  model = babl_format_get_model (format);
+  name = babl_get_name (babl_format_get_model (format));
 
-  if (model == babl_model ("Y")  ||
-      model == babl_model ("Y'") ||
-      model == babl_model ("YA") ||
-      model == babl_model ("Y'A"))
+  if (! strcmp (name, "Y")   ||
+      ! strcmp (name, "Y'")  ||
+      ! strcmp (name, "Y~")  ||
+      ! strcmp (name, "YA")  ||
+      ! strcmp (name, "Y'A") ||
+      ! strcmp (name, "Y~A"))
     {
       return GIMP_GRAY;
     }
-  else if (model == babl_model ("RGB")     ||
-           model == babl_model ("R'G'B'")  ||
-           model == babl_model ("RGBA")    ||
-           model == babl_model ("R'G'B'A") ||
-           model == babl_model ("RaGaBaA") ||
-           model == babl_model ("R'aG'aB'aA"))
+  else if (! strcmp (name, "RGB")        ||
+           ! strcmp (name, "R'G'B'")     ||
+           ! strcmp (name, "R~G~B~")     ||
+           ! strcmp (name, "RGBA")       ||
+           ! strcmp (name, "R'G'B'A")    ||
+           ! strcmp (name, "R~G~B~A")    ||
+           ! strcmp (name, "RaGaBaA")    ||
+           ! strcmp (name, "R'aG'aB'aA") ||
+           ! strcmp (name, "R~aG~aB~aA"))
     {
       return GIMP_RGB;
     }
@@ -581,8 +562,9 @@ gimp_babl_format_get_precision (const Babl *format)
 
   type = babl_format_get_type (format, 0);
 
-  if (gimp_babl_format_get_linear (format))
+  switch (gimp_babl_format_get_trc (format))
     {
+    case GIMP_TRC_LINEAR:
       if (type == babl_type ("u8"))
         return GIMP_PRECISION_U8_LINEAR;
       else if (type == babl_type ("u16"))
@@ -595,57 +577,81 @@ gimp_babl_format_get_precision (const Babl *format)
         return GIMP_PRECISION_FLOAT_LINEAR;
       else if (type == babl_type ("double"))
         return GIMP_PRECISION_DOUBLE_LINEAR;
-    }
-  else
-    {
+      break;
+
+    case GIMP_TRC_NON_LINEAR:
       if (type == babl_type ("u8"))
-        return GIMP_PRECISION_U8_GAMMA;
+        return GIMP_PRECISION_U8_NON_LINEAR;
       else if (type == babl_type ("u16"))
-        return GIMP_PRECISION_U16_GAMMA;
+        return GIMP_PRECISION_U16_NON_LINEAR;
       else if (type == babl_type ("u32"))
-        return GIMP_PRECISION_U32_GAMMA;
+        return GIMP_PRECISION_U32_NON_LINEAR;
       else if (type == babl_type ("half"))
-        return GIMP_PRECISION_HALF_GAMMA;
+        return GIMP_PRECISION_HALF_NON_LINEAR;
       else if (type == babl_type ("float"))
-        return GIMP_PRECISION_FLOAT_GAMMA;
+        return GIMP_PRECISION_FLOAT_NON_LINEAR;
       else if (type == babl_type ("double"))
-        return GIMP_PRECISION_DOUBLE_GAMMA;
+        return GIMP_PRECISION_DOUBLE_NON_LINEAR;
+      break;
+
+    case GIMP_TRC_PERCEPTUAL:
+      if (type == babl_type ("u8"))
+        return GIMP_PRECISION_U8_PERCEPTUAL;
+      else if (type == babl_type ("u16"))
+        return GIMP_PRECISION_U16_PERCEPTUAL;
+      else if (type == babl_type ("u32"))
+        return GIMP_PRECISION_U32_PERCEPTUAL;
+      else if (type == babl_type ("half"))
+        return GIMP_PRECISION_HALF_PERCEPTUAL;
+      else if (type == babl_type ("float"))
+        return GIMP_PRECISION_FLOAT_PERCEPTUAL;
+      else if (type == babl_type ("double"))
+        return GIMP_PRECISION_DOUBLE_PERCEPTUAL;
+      break;
     }
 
   g_return_val_if_reached (-1);
 }
 
-gboolean
-gimp_babl_format_get_linear (const Babl *format)
+GimpTRCType
+gimp_babl_format_get_trc (const Babl *format)
 {
-  const Babl *model;
+  const gchar *name;
 
   g_return_val_if_fail (format != NULL, FALSE);
 
-  model = babl_format_get_model (format);
+  name = babl_get_name (babl_format_get_model (format));
 
-  if (model == babl_model ("Y")    ||
-      model == babl_model ("YA")   ||
-      model == babl_model ("RGB")  ||
-      model == babl_model ("RGBA") ||
-      model == babl_model ("RaGaBaA"))
+  if (! strcmp (name, "Y")    ||
+      ! strcmp (name, "YA")   ||
+      ! strcmp (name, "RGB")  ||
+      ! strcmp (name, "RGBA") ||
+      ! strcmp (name, "RaGaBaA"))
     {
-      return TRUE;
+      return GIMP_TRC_LINEAR;
+    }
+  else if (! strcmp (name, "Y'")      ||
+           ! strcmp (name, "Y'A")     ||
+           ! strcmp (name, "R'G'B'")  ||
+           ! strcmp (name, "R'G'B'A") ||
+           ! strcmp (name, "R'aG'aB'aA"))
+    {
+      return GIMP_TRC_NON_LINEAR;
     }
-  else if (model == babl_model ("Y'")      ||
-           model == babl_model ("Y'A")     ||
-           model == babl_model ("R'G'B'")  ||
-           model == babl_model ("R'G'B'A") ||
-           model == babl_model ("R'aG'aB'aA"))
+  else if (! strcmp (name, "Y~")      ||
+           ! strcmp (name, "Y~A")     ||
+           ! strcmp (name, "R~G~B~")  ||
+           ! strcmp (name, "R~G~B~A") ||
+           ! strcmp (name, "R~aG~aB~aA"))
     {
-      return FALSE;
+      return GIMP_TRC_PERCEPTUAL;
     }
   else if (babl_format_is_palette (format))
     {
-      return FALSE;
+      return GIMP_TRC_NON_LINEAR;
     }
 
-  g_return_val_if_reached (FALSE);
+  g_return_val_if_reached (GIMP_TRC_LINEAR);
 }
 
 GimpComponentType
@@ -654,35 +660,41 @@ gimp_babl_component_type (GimpPrecision precision)
   switch (precision)
     {
     case GIMP_PRECISION_U8_LINEAR:
-    case GIMP_PRECISION_U8_GAMMA:
+    case GIMP_PRECISION_U8_NON_LINEAR:
+    case GIMP_PRECISION_U8_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_U8;
 
     case GIMP_PRECISION_U16_LINEAR:
-    case GIMP_PRECISION_U16_GAMMA:
+    case GIMP_PRECISION_U16_NON_LINEAR:
+    case GIMP_PRECISION_U16_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_U16;
 
     case GIMP_PRECISION_U32_LINEAR:
-    case GIMP_PRECISION_U32_GAMMA:
+    case GIMP_PRECISION_U32_NON_LINEAR:
+    case GIMP_PRECISION_U32_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_U32;
 
     case GIMP_PRECISION_HALF_LINEAR:
-    case GIMP_PRECISION_HALF_GAMMA:
+    case GIMP_PRECISION_HALF_NON_LINEAR:
+    case GIMP_PRECISION_HALF_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_HALF;
 
     case GIMP_PRECISION_FLOAT_LINEAR:
-    case GIMP_PRECISION_FLOAT_GAMMA:
+    case GIMP_PRECISION_FLOAT_NON_LINEAR:
+    case GIMP_PRECISION_FLOAT_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_FLOAT;
 
     case GIMP_PRECISION_DOUBLE_LINEAR:
-    case GIMP_PRECISION_DOUBLE_GAMMA:
+    case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+    case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
       return GIMP_COMPONENT_TYPE_DOUBLE;
     }
 
   g_return_val_if_reached (-1);
 }
 
-gboolean
-gimp_babl_linear (GimpPrecision precision)
+GimpTRCType
+gimp_babl_trc (GimpPrecision precision)
 {
   switch (precision)
     {
@@ -692,61 +704,93 @@ gimp_babl_linear (GimpPrecision precision)
     case GIMP_PRECISION_HALF_LINEAR:
     case GIMP_PRECISION_FLOAT_LINEAR:
     case GIMP_PRECISION_DOUBLE_LINEAR:
-      return TRUE;
-
-    case GIMP_PRECISION_U8_GAMMA:
-    case GIMP_PRECISION_U16_GAMMA:
-    case GIMP_PRECISION_U32_GAMMA:
-    case GIMP_PRECISION_HALF_GAMMA:
-    case GIMP_PRECISION_FLOAT_GAMMA:
-    case GIMP_PRECISION_DOUBLE_GAMMA:
-      return FALSE;
+      return GIMP_TRC_LINEAR;
+
+    case GIMP_PRECISION_U8_NON_LINEAR:
+    case GIMP_PRECISION_U16_NON_LINEAR:
+    case GIMP_PRECISION_U32_NON_LINEAR:
+    case GIMP_PRECISION_HALF_NON_LINEAR:
+    case GIMP_PRECISION_FLOAT_NON_LINEAR:
+    case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+      return GIMP_TRC_NON_LINEAR;
+
+    case GIMP_PRECISION_U8_PERCEPTUAL:
+    case GIMP_PRECISION_U16_PERCEPTUAL:
+    case GIMP_PRECISION_U32_PERCEPTUAL:
+    case GIMP_PRECISION_HALF_PERCEPTUAL:
+    case GIMP_PRECISION_FLOAT_PERCEPTUAL:
+    case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
+      return GIMP_TRC_PERCEPTUAL;
     }
 
-  g_return_val_if_reached (FALSE);
+  g_return_val_if_reached (GIMP_TRC_LINEAR);
 }
 
 GimpPrecision
 gimp_babl_precision (GimpComponentType component,
-                     gboolean          linear)
+                     GimpTRCType       trc)
 {
   switch (component)
     {
     case GIMP_COMPONENT_TYPE_U8:
-      if (linear)
-        return GIMP_PRECISION_U8_LINEAR;
-      else
-        return GIMP_PRECISION_U8_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_U8_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_U8_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_U8_PERCEPTUAL;
+        default:
+          break;
+        }
 
     case GIMP_COMPONENT_TYPE_U16:
-      if (linear)
-        return GIMP_PRECISION_U16_LINEAR;
-      else
-        return GIMP_PRECISION_U16_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_U16_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_U16_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_U16_PERCEPTUAL;
+        default:
+          break;
+        }
 
     case GIMP_COMPONENT_TYPE_U32:
-      if (linear)
-        return GIMP_PRECISION_U32_LINEAR;
-      else
-        return GIMP_PRECISION_U32_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_U32_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_U32_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_U32_PERCEPTUAL;
+        default:
+          break;
+        }
 
     case GIMP_COMPONENT_TYPE_HALF:
-      if (linear)
-        return GIMP_PRECISION_HALF_LINEAR;
-      else
-        return GIMP_PRECISION_HALF_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_HALF_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_HALF_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_HALF_PERCEPTUAL;
+        default:
+          break;
+        }
 
     case GIMP_COMPONENT_TYPE_FLOAT:
-      if (linear)
-        return GIMP_PRECISION_FLOAT_LINEAR;
-      else
-        return GIMP_PRECISION_FLOAT_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_FLOAT_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_FLOAT_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_FLOAT_PERCEPTUAL;
+        default:
+          break;
+        }
 
     case GIMP_COMPONENT_TYPE_DOUBLE:
-      if (linear)
-        return GIMP_PRECISION_DOUBLE_LINEAR;
-      else
-        return GIMP_PRECISION_DOUBLE_GAMMA;
+      switch (trc)
+        {
+        case GIMP_TRC_LINEAR:     return GIMP_PRECISION_DOUBLE_LINEAR;
+        case GIMP_TRC_NON_LINEAR: return GIMP_PRECISION_DOUBLE_NON_LINEAR;
+        case GIMP_TRC_PERCEPTUAL: return GIMP_PRECISION_DOUBLE_PERCEPTUAL;
+        default:
+          break;
+        }
 
     default:
       break;
@@ -768,7 +812,7 @@ gimp_babl_is_valid (GimpImageBaseType base_type,
     case GIMP_INDEXED:
       switch (precision)
         {
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_NON_LINEAR:
           return TRUE;
 
         default:
@@ -782,7 +826,8 @@ gimp_babl_is_valid (GimpImageBaseType base_type,
 const Babl *
 gimp_babl_format (GimpImageBaseType  base_type,
                   GimpPrecision      precision,
-                  gboolean           with_alpha)
+                  gboolean           with_alpha,
+                  const Babl        *space)
 {
   switch (base_type)
     {
@@ -791,75 +836,111 @@ gimp_babl_format (GimpImageBaseType  base_type,
         {
         case GIMP_PRECISION_U8_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA u8");
+            return babl_format_with_space ("RGBA u8", space);
+          else
+            return babl_format_with_space ("RGB u8", space);
+
+        case GIMP_PRECISION_U8_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("R'G'B'A u8", space);
           else
-            return babl_format ("RGB u8");
+            return babl_format_with_space ("R'G'B' u8", space);
 
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("R'G'B'A u8");
+            return babl_format_with_space ("R~G~B~A u8", space);
           else
-            return babl_format ("R'G'B' u8");
+            return babl_format_with_space ("R~G~B~ u8", space);
 
         case GIMP_PRECISION_U16_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA u16");
+            return babl_format_with_space ("RGBA u16", space);
+          else
+            return babl_format_with_space ("RGB u16", space);
+
+        case GIMP_PRECISION_U16_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("R'G'B'A u16", space);
           else
-            return babl_format ("RGB u16");
+            return babl_format_with_space ("R'G'B' u16", space);
 
-        case GIMP_PRECISION_U16_GAMMA:
+        case GIMP_PRECISION_U16_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("R'G'B'A u16");
+            return babl_format_with_space ("R~G~B~A u16", space);
           else
-            return babl_format ("R'G'B' u16");
+            return babl_format_with_space ("R~G~B~ u16", space);
 
         case GIMP_PRECISION_U32_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA u32");
+            return babl_format_with_space ("RGBA u32", space);
           else
-            return babl_format ("RGB u32");
+            return babl_format_with_space ("RGB u32", space);
 
-        case GIMP_PRECISION_U32_GAMMA:
+        case GIMP_PRECISION_U32_NON_LINEAR:
           if (with_alpha)
-            return babl_format ("R'G'B'A u32");
+            return babl_format_with_space ("R'G'B'A u32", space);
           else
-            return babl_format ("R'G'B' u32");
+            return babl_format_with_space ("R'G'B' u32", space);
+
+        case GIMP_PRECISION_U32_PERCEPTUAL:
+          if (with_alpha)
+            return babl_format_with_space ("R~G~B~A u32", space);
+          else
+            return babl_format_with_space ("R~G~B~ u32", space);
 
         case GIMP_PRECISION_HALF_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA half");
+            return babl_format_with_space ("RGBA half", space);
           else
-            return babl_format ("RGB half");
+            return babl_format_with_space ("RGB half", space);
 
-        case GIMP_PRECISION_HALF_GAMMA:
+        case GIMP_PRECISION_HALF_NON_LINEAR:
           if (with_alpha)
-            return babl_format ("R'G'B'A half");
+            return babl_format_with_space ("R'G'B'A half", space);
           else
-            return babl_format ("R'G'B' half");
+            return babl_format_with_space ("R'G'B' half", space);
+
+        case GIMP_PRECISION_HALF_PERCEPTUAL:
+          if (with_alpha)
+            return babl_format_with_space ("R~G~B~A half", space);
+          else
+            return babl_format_with_space ("R~G~B~ half", space);
 
         case GIMP_PRECISION_FLOAT_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA float");
+            return babl_format_with_space ("RGBA float", space);
+          else
+            return babl_format_with_space ("RGB float", space);
+
+        case GIMP_PRECISION_FLOAT_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("R'G'B'A float", space);
           else
-            return babl_format ("RGB float");
+            return babl_format_with_space ("R'G'B' float", space);
 
-        case GIMP_PRECISION_FLOAT_GAMMA:
+        case GIMP_PRECISION_FLOAT_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("R'G'B'A float");
+            return babl_format_with_space ("R~G~B~A float", space);
           else
-            return babl_format ("R'G'B' float");
+            return babl_format_with_space ("R~G~B~ float", space);
 
         case GIMP_PRECISION_DOUBLE_LINEAR:
           if (with_alpha)
-            return babl_format ("RGBA double");
+            return babl_format_with_space ("RGBA double", space);
+          else
+            return babl_format_with_space ("RGB double", space);
+
+        case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("R'G'B'A double", space);
           else
-            return babl_format ("RGB double");
+            return babl_format_with_space ("R'G'B' double", space);
 
-        case GIMP_PRECISION_DOUBLE_GAMMA:
+        case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("R'G'B'A double");
+            return babl_format_with_space ("R~G~B~A double", space);
           else
-            return babl_format ("R'G'B' double");
+            return babl_format_with_space ("R~G~B~ double", space);
 
         default:
           break;
@@ -871,75 +952,111 @@ gimp_babl_format (GimpImageBaseType  base_type,
         {
         case GIMP_PRECISION_U8_LINEAR:
           if (with_alpha)
-            return babl_format ("YA u8");
+            return babl_format_with_space ("YA u8", space);
+          else
+            return babl_format_with_space ("Y u8", space);
+
+        case GIMP_PRECISION_U8_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("Y'A u8", space);
           else
-            return babl_format ("Y u8");
+            return babl_format_with_space ("Y' u8", space);
 
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("Y'A u8");
+            return babl_format_with_space ("Y~A u8", space);
           else
-            return babl_format ("Y' u8");
+            return babl_format_with_space ("Y~ u8", space);
 
         case GIMP_PRECISION_U16_LINEAR:
           if (with_alpha)
-            return babl_format ("YA u16");
+            return babl_format_with_space ("YA u16", space);
           else
-            return babl_format ("Y u16");
+            return babl_format_with_space ("Y u16", space);
 
-        case GIMP_PRECISION_U16_GAMMA:
+        case GIMP_PRECISION_U16_NON_LINEAR:
           if (with_alpha)
-            return babl_format ("Y'A u16");
+            return babl_format_with_space ("Y'A u16", space);
           else
-            return babl_format ("Y' u16");
+            return babl_format_with_space ("Y' u16", space);
+
+        case GIMP_PRECISION_U16_PERCEPTUAL:
+          if (with_alpha)
+            return babl_format_with_space ("Y~A u16", space);
+          else
+            return babl_format_with_space ("Y~ u16", space);
 
         case GIMP_PRECISION_U32_LINEAR:
           if (with_alpha)
-            return babl_format ("YA u32");
+            return babl_format_with_space ("YA u32", space);
           else
-            return babl_format ("Y u32");
+            return babl_format_with_space ("Y u32", space);
 
-        case GIMP_PRECISION_U32_GAMMA:
+        case GIMP_PRECISION_U32_NON_LINEAR:
           if (with_alpha)
-            return babl_format ("Y'A u32");
+            return babl_format_with_space ("Y'A u32", space);
           else
-            return babl_format ("Y' u32");
+            return babl_format_with_space ("Y' u32", space);
+
+        case GIMP_PRECISION_U32_PERCEPTUAL:
+          if (with_alpha)
+            return babl_format_with_space ("Y~A u32", space);
+          else
+            return babl_format_with_space ("Y~ u32", space);
 
         case GIMP_PRECISION_HALF_LINEAR:
           if (with_alpha)
-            return babl_format ("YA half");
+            return babl_format_with_space ("YA half", space);
+          else
+            return babl_format_with_space ("Y half", space);
+
+        case GIMP_PRECISION_HALF_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("Y'A half", space);
           else
-            return babl_format ("Y half");
+            return babl_format_with_space ("Y' half", space);
 
-        case GIMP_PRECISION_HALF_GAMMA:
+        case GIMP_PRECISION_HALF_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("Y'A half");
+            return babl_format_with_space ("Y~A half", space);
           else
-            return babl_format ("Y' half");
+            return babl_format_with_space ("Y~ half", space);
 
         case GIMP_PRECISION_FLOAT_LINEAR:
           if (with_alpha)
-            return babl_format ("YA float");
+            return babl_format_with_space ("YA float", space);
+          else
+            return babl_format_with_space ("Y float", space);
+
+        case GIMP_PRECISION_FLOAT_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("Y'A float", space);
           else
-            return babl_format ("Y float");
+            return babl_format_with_space ("Y' float", space);
 
-        case GIMP_PRECISION_FLOAT_GAMMA:
+        case GIMP_PRECISION_FLOAT_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("Y'A float");
+            return babl_format_with_space ("Y~A float", space);
           else
-            return babl_format ("Y' float");
+            return babl_format_with_space ("Y~ float", space);
 
         case GIMP_PRECISION_DOUBLE_LINEAR:
           if (with_alpha)
-            return babl_format ("YA double");
+            return babl_format_with_space ("YA double", space);
+          else
+            return babl_format_with_space ("Y double", space);
+
+        case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+          if (with_alpha)
+            return babl_format_with_space ("Y'A double", space);
           else
-            return babl_format ("Y double");
+            return babl_format_with_space ("Y' double", space);
 
-        case GIMP_PRECISION_DOUBLE_GAMMA:
+        case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
           if (with_alpha)
-            return babl_format ("Y'A double");
+            return babl_format_with_space ("Y~A double", space);
           else
-            return babl_format ("Y' double");
+            return babl_format_with_space ("Y~ double", space);
 
         default:
           break;
@@ -992,7 +1109,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' u8");
@@ -1004,6 +1121,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U8_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ u8");
+            case 1: return babl_format ("G~ u8");
+            case 2: return babl_format ("B~ u8");
+            case 3: return babl_format ("A u8");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_U16_LINEAR:
           switch (index)
             {
@@ -1016,7 +1145,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U16_GAMMA:
+        case GIMP_PRECISION_U16_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' u16");
@@ -1028,6 +1157,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U16_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ u16");
+            case 1: return babl_format ("G~ u16");
+            case 2: return babl_format ("B~ u16");
+            case 3: return babl_format ("A u16");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_U32_LINEAR:
           switch (index)
             {
@@ -1040,7 +1181,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U32_GAMMA:
+        case GIMP_PRECISION_U32_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' u32");
@@ -1052,6 +1193,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U32_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ u32");
+            case 1: return babl_format ("G~ u32");
+            case 2: return babl_format ("B~ u32");
+            case 3: return babl_format ("A u32");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_HALF_LINEAR:
           switch (index)
             {
@@ -1064,7 +1217,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_HALF_GAMMA:
+        case GIMP_PRECISION_HALF_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' half");
@@ -1076,6 +1229,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_HALF_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ half");
+            case 1: return babl_format ("G~ half");
+            case 2: return babl_format ("B~ half");
+            case 3: return babl_format ("A half");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_FLOAT_LINEAR:
           switch (index)
             {
@@ -1088,7 +1253,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_FLOAT_GAMMA:
+        case GIMP_PRECISION_FLOAT_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' float");
@@ -1100,6 +1265,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_FLOAT_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ float");
+            case 1: return babl_format ("G~ float");
+            case 2: return babl_format ("B~ float");
+            case 3: return babl_format ("A float");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_DOUBLE_LINEAR:
           switch (index)
             {
@@ -1112,7 +1289,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_DOUBLE_GAMMA:
+        case GIMP_PRECISION_DOUBLE_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("R' double");
@@ -1124,6 +1301,18 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("R~ double");
+            case 1: return babl_format ("G~ double");
+            case 2: return babl_format ("B~ double");
+            case 3: return babl_format ("A double");
+            default:
+              break;
+            }
+          break;
+
         default:
           break;
         }
@@ -1142,7 +1331,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' u8");
@@ -1152,6 +1341,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U8_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ u8");
+            case 1: return babl_format ("A u8");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_U16_LINEAR:
           switch (index)
             {
@@ -1162,7 +1361,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U16_GAMMA:
+        case GIMP_PRECISION_U16_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' u16");
@@ -1172,6 +1371,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U16_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ u16");
+            case 1: return babl_format ("A u16");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_U32_LINEAR:
           switch (index)
             {
@@ -1182,7 +1391,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_U32_GAMMA:
+        case GIMP_PRECISION_U32_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' u32");
@@ -1192,6 +1401,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_U32_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ u32");
+            case 1: return babl_format ("A u32");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_HALF_LINEAR:
           switch (index)
             {
@@ -1202,7 +1421,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_HALF_GAMMA:
+        case GIMP_PRECISION_HALF_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' half");
@@ -1212,6 +1431,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_HALF_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ half");
+            case 1: return babl_format ("A half");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_FLOAT_LINEAR:
           switch (index)
             {
@@ -1222,7 +1451,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_FLOAT_GAMMA:
+        case GIMP_PRECISION_FLOAT_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' float");
@@ -1232,6 +1461,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_FLOAT_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ float");
+            case 1: return babl_format ("A float");
+            default:
+              break;
+            }
+          break;
+
         case GIMP_PRECISION_DOUBLE_LINEAR:
           switch (index)
             {
@@ -1242,7 +1481,7 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
-        case GIMP_PRECISION_DOUBLE_GAMMA:
+        case GIMP_PRECISION_DOUBLE_NON_LINEAR:
           switch (index)
             {
             case 0: return babl_format ("Y' double");
@@ -1252,6 +1491,16 @@ gimp_babl_component_format (GimpImageBaseType base_type,
             }
           break;
 
+        case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
+          switch (index)
+            {
+            case 0: return babl_format ("Y~ double");
+            case 1: return babl_format ("A double");
+            default:
+              break;
+            }
+          break;
+
         default:
           break;
         }
@@ -1282,7 +1531,8 @@ gimp_babl_print_pixel (const Babl *format,
   if (babl_format_is_palette (format))
     {
       const Babl *f = gimp_babl_format (GIMP_RGB, precision,
-                                        babl_format_has_alpha (format));
+                                        babl_format_has_alpha (format),
+                                        babl_format_get_space (format));
 
       babl_process (babl_fish (format, f), pixel, tmp_pixel, 1);
 
@@ -1332,11 +1582,12 @@ gimp_babl_print_pixel (const Babl *format,
         const Babl   *f;
 
         p = gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
-                                 gimp_babl_format_get_linear (format));
+                                 gimp_babl_format_get_trc (format));
 
         f = gimp_babl_format (gimp_babl_format_get_base_type (format),
                               p,
-                              babl_format_has_alpha (format));
+                              babl_format_has_alpha (format),
+                              babl_format_get_space (format));
 
         babl_process (babl_fish (format, f), pixel, tmp_pixel, 1);
 
diff --git a/app/gegl/gimp-babl.h b/app/gegl/gimp-babl.h
index 12db267eaa..8dfd10445a 100644
--- a/app/gegl/gimp-babl.h
+++ b/app/gegl/gimp-babl.h
@@ -23,27 +23,36 @@
 
 
 void                gimp_babl_init             (void);
-void                gimp_babl_init_fishes      (GimpInitStatusFunc status_callback);
+void                gimp_babl_init_fishes      (GimpInitStatusFunc  status_callback);
 
-const gchar       * gimp_babl_format_get_description    (const Babl *format);
-GimpColorProfile  * gimp_babl_format_get_color_profile  (const Babl *format);
+const gchar       * gimp_babl_format_get_description
+                                               (const Babl        *format);
+GimpColorProfile  * gimp_babl_format_get_color_profile
+                                               (const Babl        *format);
+GimpColorProfile  * gimp_babl_get_builtin_color_profile
+                                               (GimpImageBaseType  base_type,
+                                                GimpTRCType        trc);
 
-GimpImageBaseType   gimp_babl_format_get_base_type      (const Babl *format);
-GimpComponentType   gimp_babl_format_get_component_type (const Babl *format);
-GimpPrecision       gimp_babl_format_get_precision      (const Babl *format);
-gboolean            gimp_babl_format_get_linear         (const Babl *format);
+GimpImageBaseType   gimp_babl_format_get_base_type
+                                               (const Babl        *format);
+GimpComponentType   gimp_babl_format_get_component_type
+                                               (const Babl        *format);
+GimpPrecision       gimp_babl_format_get_precision
+                                               (const Babl        *format);
+GimpTRCType         gimp_babl_format_get_trc   (const Babl        *format);
 
 GimpComponentType   gimp_babl_component_type   (GimpPrecision      precision);
-gboolean            gimp_babl_linear           (GimpPrecision      precision);
+GimpTRCType         gimp_babl_trc              (GimpPrecision      precision);
 GimpPrecision       gimp_babl_precision        (GimpComponentType  component,
-                                                gboolean           linear);
+                                                GimpTRCType        trc);
 
 gboolean            gimp_babl_is_valid         (GimpImageBaseType  base_type,
                                                 GimpPrecision      precision);
 
 const Babl        * gimp_babl_format           (GimpImageBaseType  base_type,
                                                 GimpPrecision      precision,
-                                                gboolean           with_alpha);
+                                                gboolean           with_alpha,
+                                                const Babl        *space);
 const Babl        * gimp_babl_mask_format      (GimpPrecision      precision);
 const Babl        * gimp_babl_component_format (GimpImageBaseType  base_type,
                                                 GimpPrecision      precision,
diff --git a/app/gegl/gimp-gegl-loops.cc b/app/gegl/gimp-gegl-loops.cc
index d4bb732175..1c5febf6f9 100644
--- a/app/gegl/gimp-gegl-loops.cc
+++ b/app/gegl/gimp-gegl-loops.cc
@@ -123,22 +123,26 @@ gimp_gegl_convolve (GeglBuffer          *src_buffer,
   if (babl_format_is_palette (src_format))
     src_format = gimp_babl_format (GIMP_RGB,
                                    GIMP_PRECISION_FLOAT_LINEAR,
-                                   babl_format_has_alpha (src_format));
+                                   babl_format_has_alpha (src_format),
+                                   babl_format_get_space (src_format));
   else
     src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format),
                                    GIMP_PRECISION_FLOAT_LINEAR,
-                                   babl_format_has_alpha (src_format));
+                                   babl_format_has_alpha (src_format),
+                                   babl_format_get_space (src_format));
 
   dest_format = gegl_buffer_get_format (dest_buffer);
 
   if (babl_format_is_palette (dest_format))
     dest_format = gimp_babl_format (GIMP_RGB,
                                     GIMP_PRECISION_FLOAT_LINEAR,
-                                    babl_format_has_alpha (dest_format));
+                                    babl_format_has_alpha (dest_format),
+                                    babl_format_get_space (dest_format));
   else
     dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format),
                                     GIMP_PRECISION_FLOAT_LINEAR,
-                                    babl_format_has_alpha (dest_format));
+                                    babl_format_has_alpha (dest_format),
+                                    babl_format_get_space (dest_format));
 
   src_components  = babl_format_get_n_components (src_format);
   dest_components = babl_format_get_n_components (dest_format);
diff --git a/app/gegl/gimp-gegl-mask-combine.c b/app/gegl/gimp-gegl-mask-combine.c
index a949cdb11a..abedf61de9 100644
--- a/app/gegl/gimp-gegl-mask-combine.c
+++ b/app/gegl/gimp-gegl-mask-combine.c
@@ -402,10 +402,12 @@ gimp_gegl_mask_combine_buffer (GeglBuffer     *mask,
    *  gimp-channel-combine-masks procedure, it's the only place that
    *  allows to combine arbitrary channels with each other.
    */
-  if (gimp_babl_format_get_linear (gegl_buffer_get_format (mask)))
-    mask_format = babl_format ("Y float");
-  else
-    mask_format = babl_format ("Y' float");
+  mask_format = gegl_buffer_get_format (mask);
+  mask_format = gimp_babl_format
+    (GIMP_GRAY,
+     gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                          gimp_babl_format_get_trc (mask_format)),
+     FALSE, NULL);
 
   iter = gegl_buffer_iterator_new (mask, &rect, 0,
                                    mask_format,
@@ -424,10 +426,12 @@ gimp_gegl_mask_combine_buffer (GeglBuffer     *mask,
    *
    *  See https://bugzilla.gnome.org/show_bug.cgi?id=791519
    */
-  if (gimp_babl_format_get_linear (gegl_buffer_get_format (add_on)))
-    add_on_format = babl_format ("Y float");
-  else
-    add_on_format = babl_format ("Y' float");
+  add_on_format = gegl_buffer_get_format (add_on);
+  add_on_format = gimp_babl_format
+    (GIMP_GRAY,
+     gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                          gimp_babl_format_get_trc (mask_format)),
+     FALSE, NULL);
 
   gegl_buffer_iterator_add (iter, add_on, &rect, 0,
                             add_on_format,
diff --git a/app/operations/gimpcurvesconfig.c b/app/operations/gimpcurvesconfig.c
index 4855ac8135..d772917230 100644
--- a/app/operations/gimpcurvesconfig.c
+++ b/app/operations/gimpcurvesconfig.c
@@ -43,6 +43,7 @@
 enum
 {
   PROP_0,
+  PROP_TRC,
   PROP_LINEAR,
   PROP_CHANNEL,
   PROP_CURVE
@@ -99,6 +100,14 @@ gimp_curves_config_class_init (GimpCurvesConfigClass *klass)
 
   viewable_class->default_icon_name = "gimp-tool-curves";
 
+  GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
+                         "trc",
+                         _("Linear/Perceptual"),
+                         _("Work on linear or perceptual RGB"),
+                         GIMP_TYPE_TRC_TYPE,
+                         GIMP_TRC_NON_LINEAR, 0);
+
+  /* compat */
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR,
                             "linear",
                             _("Linear"),
@@ -176,8 +185,12 @@ gimp_curves_config_get_property (GObject    *object,
 
   switch (property_id)
     {
+    case PROP_TRC:
+      g_value_set_enum (value, self->trc);
+      break;
+
     case PROP_LINEAR:
-      g_value_set_boolean (value, self->linear);
+      g_value_set_boolean (value, self->trc == GIMP_TRC_LINEAR ? TRUE : FALSE);
       break;
 
     case PROP_CHANNEL:
@@ -204,8 +217,14 @@ gimp_curves_config_set_property (GObject      *object,
 
   switch (property_id)
     {
+    case PROP_TRC:
+      self->trc = g_value_get_enum (value);
+      break;
+
     case PROP_LINEAR:
-      self->linear = g_value_get_boolean (value);
+      self->trc = g_value_get_boolean (value) ?
+                  GIMP_TRC_LINEAR : GIMP_TRC_NON_LINEAR;
+      g_object_notify (object, "trc");
       break;
 
     case PROP_CHANNEL:
@@ -242,8 +261,8 @@ gimp_curves_config_serialize (GimpConfig       *config,
   GimpHistogramChannel  old_channel;
   gboolean              success = TRUE;
 
-  if (! gimp_config_serialize_property_by_name (config, "time",   writer) ||
-      ! gimp_config_serialize_property_by_name (config, "linear", writer))
+  if (! gimp_config_serialize_property_by_name (config, "time", writer) ||
+      ! gimp_config_serialize_property_by_name (config, "trc",  writer))
     return FALSE;
 
   old_channel = c_config->channel;
@@ -299,7 +318,7 @@ gimp_curves_config_equal (GimpConfig *a,
   GimpCurvesConfig     *config_b = GIMP_CURVES_CONFIG (b);
   GimpHistogramChannel  channel;
 
-  if (config_a->linear != config_b->linear)
+  if (config_a->trc != config_b->trc)
     return FALSE;
 
   for (channel = GIMP_HISTOGRAM_VALUE;
@@ -340,7 +359,7 @@ gimp_curves_config_reset (GimpConfig *config)
       gimp_curves_config_reset_channel (c_config);
     }
 
-  gimp_config_reset_property (G_OBJECT (config), "linear");
+  gimp_config_reset_property (G_OBJECT (config), "trc");
   gimp_config_reset_property (G_OBJECT (config), "channel");
 }
 
@@ -362,10 +381,10 @@ gimp_curves_config_copy (GimpConfig  *src,
                         flags);
     }
 
-  dest_config->linear  = src_config->linear;
+  dest_config->trc     = src_config->trc;
   dest_config->channel = src_config->channel;
 
-  g_object_notify (G_OBJECT (dest), "linear");
+  g_object_notify (G_OBJECT (dest), "trc");
   g_object_notify (G_OBJECT (dest), "channel");
 
   return TRUE;
@@ -615,9 +634,9 @@ gimp_curves_config_load_cruft (GimpCurvesConfig  *config,
       gimp_data_thaw (GIMP_DATA (curve));
     }
 
-  config->linear = FALSE;
+  config->trc = GIMP_TRC_NON_LINEAR;
 
-  g_object_notify (G_OBJECT (config), "linear");
+  g_object_notify (G_OBJECT (config), "trc");
 
   g_object_thaw_notify (G_OBJECT (config));
 
diff --git a/app/operations/gimpcurvesconfig.h b/app/operations/gimpcurvesconfig.h
index 3c8b7ae5fd..2461f63c93 100644
--- a/app/operations/gimpcurvesconfig.h
+++ b/app/operations/gimpcurvesconfig.h
@@ -39,7 +39,7 @@ struct _GimpCurvesConfig
 {
   GimpSettings          parent_instance;
 
-  gboolean              linear;
+  GimpTRCType           trc;
 
   GimpHistogramChannel  channel;
 
diff --git a/app/operations/gimplevelsconfig.c b/app/operations/gimplevelsconfig.c
index 27325a3083..9fc290a3cd 100644
--- a/app/operations/gimplevelsconfig.c
+++ b/app/operations/gimplevelsconfig.c
@@ -47,6 +47,7 @@
 enum
 {
   PROP_0,
+  PROP_TRC,
   PROP_LINEAR,
   PROP_CHANNEL,
   PROP_LOW_INPUT,
@@ -104,6 +105,14 @@ gimp_levels_config_class_init (GimpLevelsConfigClass *klass)
 
   viewable_class->default_icon_name = "gimp-tool-levels";
 
+  GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
+                         "trc",
+                         _("Linear/Perceptual"),
+                         _("Work on linear or perceptual RGB"),
+                         GIMP_TYPE_TRC_TYPE,
+                         GIMP_TRC_NON_LINEAR, 0);
+
+  /* compat */
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR,
                             "linear",
                             _("Linear"),
@@ -186,8 +195,12 @@ gimp_levels_config_get_property (GObject    *object,
 
   switch (property_id)
     {
+    case PROP_TRC:
+      g_value_set_enum (value, self->trc);
+      break;
+
     case PROP_LINEAR:
-      g_value_set_boolean (value, self->linear);
+      g_value_set_boolean (value, self->trc == GIMP_TRC_LINEAR ? TRUE : FALSE);
       break;
 
     case PROP_CHANNEL:
@@ -238,8 +251,14 @@ gimp_levels_config_set_property (GObject      *object,
 
   switch (property_id)
     {
+    case PROP_TRC:
+      self->trc = g_value_get_enum (value);
+      break;
+
     case PROP_LINEAR:
-      self->linear = g_value_get_boolean (value);
+      self->trc = g_value_get_boolean (value) ?
+                  GIMP_TRC_LINEAR : GIMP_TRC_NON_LINEAR;
+      g_object_notify (object, "trc");
       break;
 
     case PROP_CHANNEL:
@@ -296,7 +315,7 @@ gimp_levels_config_serialize (GimpConfig       *config,
   gboolean              success = TRUE;
 
   if (! gimp_config_serialize_property_by_name (config, "time",         writer) ||
-      ! gimp_config_serialize_property_by_name (config, "linear",       writer) ||
+      ! gimp_config_serialize_property_by_name (config, "trc",          writer) ||
       ! gimp_config_serialize_property_by_name (config, "clamp-input",  writer) ||
       ! gimp_config_serialize_property_by_name (config, "clamp-output", writer))
     return FALSE;
@@ -358,7 +377,7 @@ gimp_levels_config_equal (GimpConfig *a,
   GimpLevelsConfig     *config_b = GIMP_LEVELS_CONFIG (b);
   GimpHistogramChannel  channel;
 
-  if (config_a->linear       != config_b->linear      ||
+  if (config_a->trc          != config_b->trc         ||
       config_a->clamp_input  != config_b->clamp_input ||
       config_a->clamp_output != config_b->clamp_output)
     return FALSE;
@@ -394,7 +413,7 @@ gimp_levels_config_reset (GimpConfig *config)
       gimp_levels_config_reset_channel (l_config);
     }
 
-  gimp_config_reset_property (G_OBJECT (config), "linear");
+  gimp_config_reset_property (G_OBJECT (config), "trc");
   gimp_config_reset_property (G_OBJECT (config), "channel");
   gimp_config_reset_property (G_OBJECT (config), "clamp-input");
   gimp_config_reset_property (G_OBJECT (config), "clamp_output");
@@ -426,12 +445,12 @@ gimp_levels_config_copy (GimpConfig  *src,
   g_object_notify (G_OBJECT (dest), "low-output");
   g_object_notify (G_OBJECT (dest), "high-output");
 
-  dest_config->linear       = src_config->linear;
+  dest_config->trc          = src_config->trc;
   dest_config->channel      = src_config->channel;
   dest_config->clamp_input  = src_config->clamp_input;
   dest_config->clamp_output = src_config->clamp_output;
 
-  g_object_notify (G_OBJECT (dest), "linear");
+  g_object_notify (G_OBJECT (dest), "trc");
   g_object_notify (G_OBJECT (dest), "channel");
   g_object_notify (G_OBJECT (dest), "clamp-input");
   g_object_notify (G_OBJECT (dest), "clamp-output");
@@ -689,7 +708,7 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
 
   curves = g_object_new (GIMP_TYPE_CURVES_CONFIG, NULL);
 
-  curves->linear = config->linear;
+  curves->trc = config->trc;
 
   for (channel = GIMP_HISTOGRAM_VALUE;
        channel <= GIMP_HISTOGRAM_ALPHA;
@@ -894,11 +913,11 @@ gimp_levels_config_load_cruft (GimpLevelsConfig  *config,
       config->high_output[i] = high_output[i] / 255.0;
     }
 
-  config->linear       = FALSE;
+  config->trc          = GIMP_TRC_NON_LINEAR;
   config->clamp_input  = TRUE;
   config->clamp_output = TRUE;
 
-  g_object_notify (G_OBJECT (config), "linear");
+  g_object_notify (G_OBJECT (config), "trc");
   g_object_notify (G_OBJECT (config), "low-input");
   g_object_notify (G_OBJECT (config), "high-input");
   g_object_notify (G_OBJECT (config), "clamp-input");
diff --git a/app/operations/gimplevelsconfig.h b/app/operations/gimplevelsconfig.h
index fb73e81e27..6aa05252b2 100644
--- a/app/operations/gimplevelsconfig.h
+++ b/app/operations/gimplevelsconfig.h
@@ -39,7 +39,7 @@ struct _GimpLevelsConfig
 {
   GimpSettings          parent_instance;
 
-  gboolean              linear;
+  GimpTRCType           trc;
 
   GimpHistogramChannel  channel;
 
diff --git a/app/operations/gimpoperationcomposecrop.c b/app/operations/gimpoperationcomposecrop.c
index 43f2821292..1af6b198b9 100644
--- a/app/operations/gimpoperationcomposecrop.c
+++ b/app/operations/gimpoperationcomposecrop.c
@@ -205,7 +205,7 @@ gimp_operation_compose_crop_prepare (GeglOperation *operation)
         {
           const Babl *model = babl_format_get_model (input_format);
 
-          if (model == babl_model ("R'G'B'A"))
+          if (! strcmp (babl_get_name (model), "R'G'B'A"))
             format = babl_format_with_space ("R'G'B'A float", input_format);
           else
             format = babl_format_with_space ("RGBA float", input_format);
diff --git a/app/operations/gimpoperationcurves.c b/app/operations/gimpoperationcurves.c
index e83b1427a1..34f315625a 100644
--- a/app/operations/gimpoperationcurves.c
+++ b/app/operations/gimpoperationcurves.c
@@ -70,12 +70,13 @@ gimp_operation_curves_class_init (GimpOperationCurvesClass *klass)
   point_class->process = gimp_operation_curves_process;
 
   g_object_class_install_property (object_class,
-                                   GIMP_OPERATION_POINT_FILTER_PROP_LINEAR,
-                                   g_param_spec_boolean ("linear",
-                                                         "Linear",
-                                                         "Whether to operate on linear RGB",
-                                                         FALSE,
-                                                         G_PARAM_READWRITE));
+                                   GIMP_OPERATION_POINT_FILTER_PROP_TRC,
+                                   g_param_spec_enum ("trc",
+                                                      "Linear/Percptual",
+                                                      "What TRC to operate on",
+                                                      GIMP_TYPE_TRC_TYPE,
+                                                      GIMP_TRC_NON_LINEAR,
+                                                      G_PARAM_READWRITE));
 
   g_object_class_install_property (object_class,
                                    GIMP_OPERATION_POINT_FILTER_PROP_CONFIG,
diff --git a/app/operations/gimpoperationlevels.c b/app/operations/gimpoperationlevels.c
index ea91a48631..63d6d21cd4 100644
--- a/app/operations/gimpoperationlevels.c
+++ b/app/operations/gimpoperationlevels.c
@@ -67,12 +67,13 @@ gimp_operation_levels_class_init (GimpOperationLevelsClass *klass)
   point_class->process = gimp_operation_levels_process;
 
   g_object_class_install_property (object_class,
-                                   GIMP_OPERATION_POINT_FILTER_PROP_LINEAR,
-                                   g_param_spec_boolean ("linear",
-                                                         "Linear",
-                                                         "Whether to operate on linear RGB",
-                                                         FALSE,
-                                                         G_PARAM_READWRITE));
+                                   GIMP_OPERATION_POINT_FILTER_PROP_TRC,
+                                   g_param_spec_enum ("trc",
+                                                      "Linear/Percptual",
+                                                      "What TRC to operate on",
+                                                      GIMP_TYPE_TRC_TYPE,
+                                                      GIMP_TRC_NON_LINEAR,
+                                                      G_PARAM_READWRITE));
 
   g_object_class_install_property (object_class,
                                    GIMP_OPERATION_POINT_FILTER_PROP_CONFIG,
diff --git a/app/operations/gimpoperationmaskcomponents.c b/app/operations/gimpoperationmaskcomponents.c
index 0cac310862..1c9425c410 100644
--- a/app/operations/gimpoperationmaskcomponents.c
+++ b/app/operations/gimpoperationmaskcomponents.c
@@ -149,10 +149,10 @@ gimp_operation_mask_components_prepare (GeglOperation *operation)
     {
       const Babl *model = babl_format_get_model (format);
 
-      if (model == babl_model ("R'G'B'A"))
-        format = babl_format ("R'G'B'A float");
+      if (! strcmp (babl_get_name (model), "R'G'B'A"))
+        format = babl_format_with_space ("R'G'B'A float", format);
       else
-        format = babl_format ("RGBA float");
+        format = babl_format_with_space ("RGBA float", format);
     }
   else
     {
diff --git a/app/operations/gimpoperationpointfilter.c b/app/operations/gimpoperationpointfilter.c
index b9bfa1d3af..13f7613bf8 100644
--- a/app/operations/gimpoperationpointfilter.c
+++ b/app/operations/gimpoperationpointfilter.c
@@ -73,8 +73,8 @@ gimp_operation_point_filter_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case GIMP_OPERATION_POINT_FILTER_PROP_LINEAR:
-      g_value_set_boolean (value, self->linear);
+    case GIMP_OPERATION_POINT_FILTER_PROP_TRC:
+      g_value_set_enum (value, self->trc);
       break;
 
     case GIMP_OPERATION_POINT_FILTER_PROP_CONFIG:
@@ -97,8 +97,8 @@ gimp_operation_point_filter_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case GIMP_OPERATION_POINT_FILTER_PROP_LINEAR:
-      self->linear = g_value_get_boolean (value);
+    case GIMP_OPERATION_POINT_FILTER_PROP_TRC:
+      self->trc = g_value_get_enum (value);
       break;
 
     case GIMP_OPERATION_POINT_FILTER_PROP_CONFIG:
@@ -121,10 +121,21 @@ gimp_operation_point_filter_prepare (GeglOperation *operation)
                                                                      "input");
   const Babl               *format;
 
-  if (self->linear)
-    format = babl_format_with_space ("RGBA float", space);
-  else
-    format = babl_format_with_space ("R'G'B'A float", space);
+  switch (self->trc)
+    {
+    default:
+    case GIMP_TRC_LINEAR:
+      format = babl_format_with_space ("RGBA float", space);
+      break;
+
+    case GIMP_TRC_NON_LINEAR:
+      format = babl_format_with_space ("R'G'B'A float", space);
+      break;
+
+    case GIMP_TRC_PERCEPTUAL:
+      format = babl_format_with_space ("R~G~B~A float", space);
+      break;
+    }
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "output", format);
diff --git a/app/operations/gimpoperationpointfilter.h b/app/operations/gimpoperationpointfilter.h
index f039af78c6..10b7ffa3b7 100644
--- a/app/operations/gimpoperationpointfilter.h
+++ b/app/operations/gimpoperationpointfilter.h
@@ -29,7 +29,7 @@
 enum
 {
   GIMP_OPERATION_POINT_FILTER_PROP_0,
-  GIMP_OPERATION_POINT_FILTER_PROP_LINEAR,
+  GIMP_OPERATION_POINT_FILTER_PROP_TRC,
   GIMP_OPERATION_POINT_FILTER_PROP_CONFIG
 };
 
@@ -48,7 +48,7 @@ struct _GimpOperationPointFilter
 {
   GeglOperationPointFilter  parent_instance;
 
-  gboolean                  linear;
+  GimpTRCType               trc;
   GObject                  *config;
 };
 
diff --git a/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
index a8788753a6..50abd060aa 100644
--- a/app/operations/layer-modes/gimp-layer-modes.c
+++ b/app/operations/layer-modes/gimp-layer-modes.c
@@ -1427,7 +1427,8 @@ gimp_layer_mode_get_format (GimpLayerMode        mode,
       /* compositing is color-space agnostic.  return a format that has a fast
        * conversion path to/from the preferred format.
        */
-      if (! preferred_format || gimp_babl_format_get_linear (preferred_format))
+      if (! preferred_format ||
+          gimp_babl_format_get_trc (preferred_format) == GIMP_TRC_LINEAR)
         return babl_format ("RGBA float");
       else
         return babl_format ("R'G'B'A float");
diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c
index a2289cf419..e5076f723a 100644
--- a/app/paint/gimpbrushcore.c
+++ b/app/paint/gimpbrushcore.c
@@ -1287,14 +1287,16 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore            *core,
 
   if (mode == GIMP_BRUSH_SOFT && brush_mask)
     {
-      GimpImageBaseType pixmap_base_type;
-      GimpPrecision     pixmap_precision;
+      GimpImageBaseType  pixmap_base_type;
+      GimpPrecision      pixmap_precision;
+      const Babl        *pixmap_space;
 
       pixmap_base_type = gimp_babl_format_get_base_type (pixmap_format);
       pixmap_precision = gimp_babl_format_get_precision (pixmap_format);
+      pixmap_space     = babl_format_get_space (pixmap_format);
 
       fish = babl_fish (gimp_babl_format (pixmap_base_type, pixmap_precision,
-                                          TRUE),
+                                          TRUE, pixmap_space),
                         area_format);
     }
   else
diff --git a/app/paint/gimppaintcore-loops.cc b/app/paint/gimppaintcore-loops.cc
index 1491bc422e..f7fdee0a4f 100644
--- a/app/paint/gimppaintcore-loops.cc
+++ b/app/paint/gimppaintcore-loops.cc
@@ -25,6 +25,8 @@ extern "C"
 
 #include "paint-types.h"
 
+#include "gegl/gimp-babl.h"
+
 #include "operations/layer-modes/gimp-layer-modes.h"
 
 #include "core/gimp-parallel.h"
@@ -1324,17 +1326,18 @@ mask_components_onto (GeglBuffer          *src_buffer,
                       GeglBuffer          *dst_buffer,
                       const GeglRectangle *roi,
                       GimpComponentMask    mask,
-                      gboolean             linear_mode)
+                      GimpTRCType          trc,
+                      const Babl          *space)
 {
   const Babl *iterator_format;
 
   if (! roi)
     roi = gegl_buffer_get_extent (dst_buffer);
 
-  if (linear_mode)
-    iterator_format = babl_format ("RGBA float");
-  else
-    iterator_format = babl_format ("R'G'B'A float");
+  iterator_format =
+    gimp_babl_format (GIMP_RGB,
+                      gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT, trc),
+                      TRUE, space);
 
   gimp_parallel_distribute_area (roi, MIN_PARALLEL_SUB_AREA,
                                  [=] (const GeglRectangle *area)
diff --git a/app/paint/gimppaintcore-loops.h b/app/paint/gimppaintcore-loops.h
index 605dd369f8..6d8fb9a459 100644
--- a/app/paint/gimppaintcore-loops.h
+++ b/app/paint/gimppaintcore-loops.h
@@ -97,7 +97,8 @@ void mask_components_onto               (GeglBuffer                     *src_buf
                                          GeglBuffer                     *dst_buffer,
                                          const GeglRectangle            *roi,
                                          GimpComponentMask               mask,
-                                         gboolean                        linear_mode);
+                                         GimpTRCType                     trc,
+                                         const Babl                     *space);
 
 
 #endif /* __GIMP_PAINT_CORE_LOOPS_H__ */
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index ceedd16844..5e4ce3cc30 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -30,6 +30,7 @@
 
 #include "operations/layer-modes/gimp-layer-modes.h"
 
+#include "gegl/gimp-babl.h"
 #include "gegl/gimp-gegl-loops.h"
 #include "gegl/gimp-gegl-nodes.h"
 #include "gegl/gimp-gegl-utils.h"
@@ -467,12 +468,12 @@ gimp_paint_core_start (GimpPaintCore     *core,
       /* Allocate the scratch buffer if there's a component mask */
       if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_MASK_ALL)
         {
-          const Babl *format;
-
-          if (gimp_drawable_get_linear (drawable))
-            format = babl_format ("RGBA float");
-          else
-            format = babl_format ("R'G'B'A float");
+          const Babl *format =
+            gimp_babl_format (GIMP_RGB,
+                              gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                                   gimp_drawable_get_trc (drawable)),
+                              TRUE,
+                              gimp_drawable_get_space (drawable));
 
           core->comp_buffer =
             gegl_buffer_new (GEGL_RECTANGLE (0, 0,
@@ -950,7 +951,8 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                                                 width,
                                                 height),
                                 gimp_drawable_get_active_mask (drawable),
-                                gimp_drawable_get_linear (drawable));
+                                gimp_drawable_get_trc (drawable),
+                                gimp_drawable_get_space (drawable));
         }
     }
 
diff --git a/app/pdb/drawable-cmds.c b/app/pdb/drawable-cmds.c
index 88cf445c6b..fe3de6d11f 100644
--- a/app/pdb/drawable-cmds.c
+++ b/app/pdb/drawable-cmds.c
@@ -74,7 +74,10 @@ drawable_get_format_invoker (GimpProcedure         *procedure,
       if (gimp->plug_in_manager->current_plug_in)
         gimp_plug_in_enable_precision (gimp->plug_in_manager->current_plug_in);
 
-      format = g_strdup (babl_get_name (gimp_drawable_get_format (drawable)));
+      /* EEK SPACE: this needs more code on the libgimp side, we currently
+       * lose the space
+       */
+      format = g_strdup (babl_format_get_encoding (gimp_drawable_get_format (drawable)));
     }
 
   return_vals = gimp_procedure_get_return_values (procedure, success,
diff --git a/app/pdb/drawable-color-cmds.c b/app/pdb/drawable-color-cmds.c
index 7c359c6c0f..5fa6cfa9df 100644
--- a/app/pdb/drawable-color-cmds.c
+++ b/app/pdb/drawable-color-cmds.c
@@ -405,7 +405,7 @@ drawable_histogram_invoker (GimpProcedure         *procedure,
           gint           n_bins;
           gint           start;
           gboolean       precision_enabled;
-          gboolean       linear;
+          GimpTRCType    trc;
           gint           end;
 
           precision_enabled =
@@ -413,11 +413,11 @@ drawable_histogram_invoker (GimpProcedure         *procedure,
             gimp_plug_in_precision_enabled (gimp->plug_in_manager->current_plug_in);
 
           if (precision_enabled)
-            linear = gimp_drawable_get_linear (drawable);
+            trc = gimp_drawable_get_trc (drawable);
           else
-            linear = FALSE;
+            trc = GIMP_TRC_NON_LINEAR;
 
-          histogram = gimp_histogram_new (linear);
+          histogram = gimp_histogram_new (trc);
           gimp_drawable_calculate_histogram (drawable, histogram, FALSE);
 
           n_bins = gimp_histogram_n_bins (histogram);
diff --git a/app/pdb/floating-sel-cmds.c b/app/pdb/floating-sel-cmds.c
index 002d291381..54bc434d26 100644
--- a/app/pdb/floating-sel-cmds.c
+++ b/app/pdb/floating-sel-cmds.c
@@ -162,7 +162,14 @@ floating_sel_attach_invoker (GimpProcedure         *procedure,
       if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                      GIMP_PDB_ITEM_CONTENT, error) &&
           gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
-        floating_sel_attach (layer, drawable);
+        {
+          /* see layer-new */
+          if (gimp_drawable_is_gray (GIMP_DRAWABLE (layer)) &&
+              GIMP_IS_LAYER (drawable))
+            gimp_layer_fix_format_space (layer, TRUE, FALSE);
+
+          floating_sel_attach (layer, drawable);
+        }
       else
         success = FALSE;
     }
diff --git a/app/pdb/image-cmds.c b/app/pdb/image-cmds.c
index 327ceaee81..110288674a 100644
--- a/app/pdb/image-cmds.c
+++ b/app/pdb/image-cmds.c
@@ -156,7 +156,7 @@ image_new_invoker (GimpProcedure         *procedure,
   if (success)
     {
       image = gimp_create_image (gimp, width, height, type,
-                                 GIMP_PRECISION_U8_GAMMA, FALSE);
+                                 GIMP_PRECISION_U8_NON_LINEAR, FALSE);
 
       if (! image)
         success = FALSE;
@@ -803,6 +803,10 @@ image_insert_layer_invoker (GimpProcedure         *procedure,
           if (position == -1 && parent == NULL)
             parent = GIMP_IMAGE_ACTIVE_PARENT;
 
+          /* see layer-new */
+          if (gimp_drawable_is_gray (GIMP_DRAWABLE (layer)))
+            gimp_layer_fix_format_space (layer, TRUE, FALSE);
+
           success = gimp_image_add_layer (image, layer,
                                           parent, MAX (position, -1), TRUE);
         }
@@ -2873,7 +2877,7 @@ register_image_procs (GimpPDB *pdb)
   gimp_procedure_set_static_strings (procedure,
                                      "gimp-image-new-with-precision",
                                      "Creates a new image with the specified width, height, type and 
precision.",
-                                     "Creates a new image, undisplayed with the specified extents, type and 
precision. Indexed images can only be created at GIMP_PRECISION_U8_GAMMA precision. See 'gimp-image-new' for 
further details.",
+                                     "Creates a new image, undisplayed with the specified extents, type and 
precision. Indexed images can only be created at GIMP_PRECISION_U8_NON_LINEAR precision. See 'gimp-image-new' 
for further details.",
                                      "Michael Natterer <mitch gimp org>",
                                      "Michael Natterer",
                                      "2012",
diff --git a/app/pdb/image-color-profile-cmds.c b/app/pdb/image-color-profile-cmds.c
index 30e515c6d9..db2a1f48a4 100644
--- a/app/pdb/image-color-profile-cmds.c
+++ b/app/pdb/image-color-profile-cmds.c
@@ -163,7 +163,8 @@ image_set_color_profile_invoker (GimpProcedure         *procedure,
 
           if (profile)
             {
-              success = gimp_image_set_color_profile (image, profile, error);
+              success = gimp_image_assign_color_profile (image, profile,
+                                                         progress, error);
               g_object_unref (profile);
             }
           else
@@ -171,7 +172,8 @@ image_set_color_profile_invoker (GimpProcedure         *procedure,
         }
       else
         {
-          success = gimp_image_set_color_profile (image, NULL, error);
+          success = gimp_image_assign_color_profile (image, NULL,
+                                                     progress, error);
         }
     }
 
@@ -205,7 +207,8 @@ image_set_color_profile_from_file_invoker (GimpProcedure         *procedure,
 
           if (profile)
             {
-              success = gimp_image_set_color_profile (image, profile, error);
+              success = gimp_image_assign_color_profile (image, profile,
+                                                         progress, error);
               g_object_unref (profile);
             }
           else
@@ -215,7 +218,8 @@ image_set_color_profile_from_file_invoker (GimpProcedure         *procedure,
         }
       else
         {
-          success = gimp_image_set_color_profile (image, NULL, error);
+          success = gimp_image_assign_color_profile (image, NULL,
+                                                     progress, error);
         }
     }
 
@@ -402,7 +406,7 @@ register_image_color_profile_procs (GimpPDB *pdb)
   gimp_procedure_set_static_strings (procedure,
                                      "gimp-image-set-color-profile",
                                      "Sets the image's color profile",
-                                     "This procedure sets the image's color profile, or unsets it if NULL is 
passed as 'color_profile'. This procedure does no color conversion.",
+                                     "This procedure sets the image's color profile, or unsets it if NULL is 
passed as 'color_profile'. This procedure does no color conversion. However, it will change the pixel format 
of all layers to contain the babl space matching the profile. You must call this procedure before adding 
layers to the image.",
                                      "Michael Natterer <mitch gimp org>",
                                      "Michael Natterer",
                                      "2015",
@@ -436,7 +440,7 @@ register_image_color_profile_procs (GimpPDB *pdb)
   gimp_procedure_set_static_strings (procedure,
                                      "gimp-image-set-color-profile-from-file",
                                      "Sets the image's color profile from an ICC file",
-                                     "This procedure sets the image's color profile from a file containing 
an ICC profile, or unsets it if NULL is passed as 'uri'. This procedure does no color conversion.",
+                                     "This procedure sets the image's color profile from a file containing 
an ICC profile, or unsets it if NULL is passed as 'uri'. This procedure does no color conversion. However, it 
will change the pixel format of all layers to contain the babl space matching the profile. You must call this 
procedure before adding layers to the image.",
                                      "Michael Natterer <mitch gimp org>",
                                      "Michael Natterer",
                                      "2015",
diff --git a/app/pdb/image-convert-cmds.c b/app/pdb/image-convert-cmds.c
index a17cb36ce4..d379032f1e 100644
--- a/app/pdb/image-convert-cmds.c
+++ b/app/pdb/image-convert-cmds.c
@@ -137,9 +137,9 @@ image_convert_indexed_invoker (GimpProcedure         *procedure,
     {
       GimpPalette *pal = NULL;
 
-      if (gimp_pdb_image_is_not_base_type (image, GIMP_INDEXED, error)        &&
-          gimp_pdb_image_is_precision (image, GIMP_PRECISION_U8_GAMMA, error) &&
-          gimp_babl_is_valid (GIMP_INDEXED, gimp_image_get_precision (image)) &&
+      if (gimp_pdb_image_is_not_base_type (image, GIMP_INDEXED, error)             &&
+          gimp_pdb_image_is_precision (image, GIMP_PRECISION_U8_NON_LINEAR, error) &&
+          gimp_babl_is_valid (GIMP_INDEXED, gimp_image_get_precision (image))      &&
           gimp_item_stack_is_flat (GIMP_ITEM_STACK (gimp_image_get_layers (image))))
         {
           switch (palette_type)
diff --git a/app/pdb/layer-cmds.c b/app/pdb/layer-cmds.c
index 46cea9e331..479e3cf141 100644
--- a/app/pdb/layer-cmds.c
+++ b/app/pdb/layer-cmds.c
@@ -125,12 +125,21 @@ layer_new_invoker (GimpProcedure         *procedure,
           break;
         }
 
-      /* do not use gimp_image_get_layer_format() because it might
-       * be the floating selection of a channel or mask
-       */
-      format = gimp_image_get_format (image, base_type,
-                                      gimp_image_get_precision (image),
-                                      has_alpha);
+      if (base_type == GIMP_GRAY)
+        {
+          /* do not use gimp_image_get_layer_format() because it might
+           * be the floating selection of a channel or mask, we will
+           * fix the format in image-add-layer and floating-sel-attach
+           */
+          format = gimp_image_get_format (image, base_type,
+                                          gimp_image_get_precision (image),
+                                          has_alpha,
+                                          NULL /* will fix later */);
+        }
+      else
+        {
+          format = gimp_image_get_layer_format (image, has_alpha);
+        }
 
       layer = gimp_layer_new (image, width, height,
                               format, name, opacity / 100.0, mode);
diff --git a/app/pdb/plug-in-compat-cmds.c b/app/pdb/plug-in-compat-cmds.c
index 94458db36e..fc0d172181 100644
--- a/app/pdb/plug-in-compat-cmds.c
+++ b/app/pdb/plug-in-compat-cmds.c
@@ -121,7 +121,7 @@ static GeglNode *
 wrap_in_gamma_cast (GeglNode     *node,
                     GimpDrawable *drawable)
 {
-  if (! gimp_drawable_get_linear (drawable))
+  if (gimp_drawable_get_trc (drawable) != GIMP_TRC_LINEAR)
     {
       const Babl *drawable_format;
       const Babl *cast_format;
@@ -137,7 +137,8 @@ wrap_in_gamma_cast (GeglNode     *node,
         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
                           gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
                                                TRUE),
-                          babl_format_has_alpha (drawable_format));
+                          babl_format_has_alpha (drawable_format),
+                          babl_format_get_space (drawable_format));
 
       new_node = gegl_node_new ();
 
diff --git a/app/tests/gimp-app-test-utils.c b/app/tests/gimp-app-test-utils.c
index e2ce63fe4e..8182728804 100644
--- a/app/tests/gimp-app-test-utils.c
+++ b/app/tests/gimp-app-test-utils.c
@@ -180,7 +180,7 @@ gimp_test_utils_create_image (Gimp *gimp,
   GimpLayer *layer;
 
   image = gimp_image_new (gimp, width, height,
-                          GIMP_RGB, GIMP_PRECISION_U8_GAMMA);
+                          GIMP_RGB, GIMP_PRECISION_U8_NON_LINEAR);
 
   layer = gimp_layer_new (image,
                           width,
diff --git a/app/tests/test-xcf.c b/app/tests/test-xcf.c
index 536c897d74..843c641430 100644
--- a/app/tests/test-xcf.c
+++ b/app/tests/test-xcf.c
@@ -66,7 +66,7 @@
 #define GIMP_MAINIMAGE_WIDTH            100
 #define GIMP_MAINIMAGE_HEIGHT           90
 #define GIMP_MAINIMAGE_TYPE             GIMP_RGB
-#define GIMP_MAINIMAGE_PRECISION        GIMP_PRECISION_U8_GAMMA
+#define GIMP_MAINIMAGE_PRECISION        GIMP_PRECISION_U8_NON_LINEAR
 
 #define GIMP_MAINIMAGE_LAYER1_NAME      "layer1"
 #define GIMP_MAINIMAGE_LAYER1_WIDTH     50
diff --git a/app/tools/gimpcurvestool.c b/app/tools/gimpcurvestool.c
index 4eecb0641f..5597ca048b 100644
--- a/app/tools/gimpcurvestool.c
+++ b/app/tools/gimpcurvestool.c
@@ -199,12 +199,12 @@ gimp_curves_tool_initialize (GimpTool     *tool,
   config = GIMP_CURVES_CONFIG (filter_tool->config);
 
   gegl_node_set (filter_tool->operation,
-                 "linear", config->linear,
+                 "trc", config->trc,
                  NULL);
 
-  histogram = gimp_histogram_new (config->linear);
-  g_object_unref (gimp_drawable_calculate_histogram_async (
-    drawable, histogram, FALSE));
+  histogram = gimp_histogram_new (config->trc);
+  g_object_unref (gimp_drawable_calculate_histogram_async (drawable, histogram,
+                                                           FALSE));
   gimp_histogram_view_set_background (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                       histogram);
   g_object_unref (histogram);
@@ -446,12 +446,9 @@ gimp_curves_tool_dialog (GimpFilterTool *filter_tool)
   gtk_widget_show (hbox2);
 
   /*  The linear/perceptual radio buttons  */
-  hbox2 = gimp_prop_boolean_icon_box_new (G_OBJECT (config),
-                                          "linear",
-                                          GIMP_ICON_COLOR_SPACE_LINEAR,
-                                          GIMP_ICON_COLOR_SPACE_PERCEPTUAL,
-                                          _("Adjust curves in linear light"),
-                                          _("Adjust curves perceptually"));
+  hbox2 = gimp_prop_enum_icon_box_new (G_OBJECT (config), "trc",
+                                       "gimp-color-space",
+                                       -1, -1);
   gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
   gtk_widget_show (hbox2);
 
@@ -570,9 +567,9 @@ gimp_curves_tool_reset (GimpFilterTool *filter_tool)
   g_object_freeze_notify (G_OBJECT (config));
 
   if (default_config)
-    g_object_set (config, "linear", default_config->linear, NULL);
+    g_object_set (config, "trc", default_config->trc, NULL);
   else
-    gimp_config_reset_property (G_OBJECT (config), "linear");
+    gimp_config_reset_property (G_OBJECT (config), "trc");
 
   for (channel = GIMP_HISTOGRAM_VALUE;
        channel <= GIMP_HISTOGRAM_ALPHA;
@@ -619,17 +616,17 @@ gimp_curves_tool_config_notify (GimpFilterTool   *filter_tool,
       ! curves_tool->graph)
     return;
 
-  if (! strcmp (pspec->name, "linear"))
+  if (! strcmp (pspec->name, "trc"))
     {
       GimpHistogram *histogram;
 
       gegl_node_set (filter_tool->operation,
-                     "linear", curves_config->linear,
+                     "trc", curves_config->trc,
                      NULL);
 
-      histogram = gimp_histogram_new (curves_config->linear);
-      g_object_unref (gimp_drawable_calculate_histogram_async (
-        GIMP_TOOL (filter_tool)->drawable, histogram, FALSE));
+      histogram = gimp_histogram_new (curves_config->trc);
+      g_object_unref (gimp_drawable_calculate_histogram_async
+                      (GIMP_TOOL (filter_tool)->drawable, histogram, FALSE));
       gimp_histogram_view_set_background (GIMP_HISTOGRAM_VIEW (curves_tool->graph),
                                           histogram);
       g_object_unref (histogram);
@@ -701,7 +698,7 @@ gimp_curves_tool_color_picked (GimpFilterTool *filter_tool,
   GimpDrawable     *drawable = GIMP_TOOL (tool)->drawable;
   GimpRGB           rgb      = *color;
 
-  if (config->linear)
+  if (config->trc == GIMP_TRC_LINEAR)
     babl_process (babl_fish (babl_format ("R'G'B'A double"),
                              babl_format ("RGBA double")),
                   &rgb, &rgb, 1);
diff --git a/app/tools/gimplevelstool.c b/app/tools/gimplevelstool.c
index 11df77bf60..71c5283296 100644
--- a/app/tools/gimplevelstool.c
+++ b/app/tools/gimplevelstool.c
@@ -202,15 +202,15 @@ gimp_levels_tool_initialize (GimpTool     *tool,
   config = GIMP_LEVELS_CONFIG (filter_tool->config);
 
   gegl_node_set (filter_tool->operation,
-                 "linear", config->linear,
+                 "trc", config->trc,
                  NULL);
 
   g_clear_object (&l_tool->histogram);
   g_clear_object (&l_tool->histogram_async);
-  l_tool->histogram = gimp_histogram_new (config->linear);
+  l_tool->histogram = gimp_histogram_new (config->trc);
 
-  l_tool->histogram_async = gimp_drawable_calculate_histogram_async (
-    drawable, l_tool->histogram, FALSE);
+  l_tool->histogram_async = gimp_drawable_calculate_histogram_async
+    (drawable, l_tool->histogram, FALSE);
   gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (l_tool->histogram_view),
                                      l_tool->histogram);
 
@@ -397,12 +397,9 @@ gimp_levels_tool_dialog (GimpFilterTool *filter_tool)
   gtk_widget_show (hbox2);
 
   /*  The linear/perceptual radio buttons  */
-  hbox2 = gimp_prop_boolean_icon_box_new (G_OBJECT (config),
-                                          "linear",
-                                          GIMP_ICON_COLOR_SPACE_LINEAR,
-                                          GIMP_ICON_COLOR_SPACE_PERCEPTUAL,
-                                          _("Adjust levels in linear light"),
-                                          _("Adjust levels perceptually"));
+  hbox2 = gimp_prop_enum_icon_box_new (G_OBJECT (config), "trc",
+                                       "gimp-color-space",
+                                       -1, -1);
   gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
   gtk_widget_show (hbox2);
 
@@ -688,18 +685,18 @@ gimp_levels_tool_config_notify (GimpFilterTool   *filter_tool,
       ! levels_tool->histogram_view)
     return;
 
-  if (! strcmp (pspec->name, "linear"))
+  if (! strcmp (pspec->name, "trc"))
     {
       gegl_node_set (filter_tool->operation,
-                     "linear", levels_config->linear,
+                     "trc", levels_config->trc,
                      NULL);
 
       g_clear_object (&levels_tool->histogram);
       g_clear_object (&levels_tool->histogram_async);
-      levels_tool->histogram = gimp_histogram_new (levels_config->linear);
+      levels_tool->histogram = gimp_histogram_new (levels_config->trc);
 
-      levels_tool->histogram_async = gimp_drawable_calculate_histogram_async (
-        GIMP_TOOL (filter_tool)->drawable, levels_tool->histogram, FALSE);
+      levels_tool->histogram_async = gimp_drawable_calculate_histogram_async
+        (GIMP_TOOL (filter_tool)->drawable, levels_tool->histogram, FALSE);
       gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (levels_tool->histogram_view),
                                          levels_tool->histogram);
     }
@@ -815,7 +812,7 @@ gimp_levels_tool_color_picked (GimpFilterTool *color_tool,
   GimpRGB           rgb         = *color;
   guint             value       = GPOINTER_TO_UINT (identifier);
 
-  if (config->linear)
+  if (config->trc == GIMP_TRC_LINEAR)
     babl_process (babl_fish (babl_format ("R'G'B'A double"),
                              babl_format ("RGBA double")),
                   &rgb, &rgb, 1);
diff --git a/app/widgets/gimpcolorframe.c b/app/widgets/gimpcolorframe.c
index e94d044a6c..cb76bf186e 100644
--- a/app/widgets/gimpcolorframe.c
+++ b/app/widgets/gimpcolorframe.c
@@ -681,9 +681,13 @@ gimp_color_frame_update (GimpColorFrame *frame)
     {
     case GIMP_COLOR_PICK_MODE_PIXEL:
       {
-        GimpImageBaseType base_type;
+        GimpImageBaseType  base_type;
+        GimpTRCType        trc;
+        const Babl        *space;
 
         base_type = gimp_babl_format_get_base_type (frame->sample_format);
+        trc       = gimp_babl_format_get_trc (frame->sample_format);
+        space     = babl_format_get_space (frame->sample_format);
 
         if (frame->sample_valid)
           {
@@ -692,38 +696,30 @@ gimp_color_frame_update (GimpColorFrame *frame)
 
             switch (gimp_babl_format_get_precision (frame->sample_format))
               {
-              case GIMP_PRECISION_U8_GAMMA:
+              case GIMP_PRECISION_U8_NON_LINEAR:
                 if (babl_format_is_palette (frame->sample_format))
                   {
                     print_format = gimp_babl_format (GIMP_RGB,
-                                                     GIMP_PRECISION_U8_GAMMA,
-                                                     has_alpha);
+                                                     GIMP_PRECISION_U8_NON_LINEAR,
+                                                     has_alpha,
+                                                     space);
                     break;
                   }
                 /* else fall thru */
 
-              case GIMP_PRECISION_U8_LINEAR:
-              case GIMP_PRECISION_U16_LINEAR:
-              case GIMP_PRECISION_U16_GAMMA:
-              case GIMP_PRECISION_U32_LINEAR:
-              case GIMP_PRECISION_U32_GAMMA:
-              case GIMP_PRECISION_FLOAT_LINEAR:
-              case GIMP_PRECISION_FLOAT_GAMMA:
-              case GIMP_PRECISION_DOUBLE_LINEAR:
-              case GIMP_PRECISION_DOUBLE_GAMMA:
+              default:
                 print_format = frame->sample_format;
                 break;
 
-              case GIMP_PRECISION_HALF_GAMMA:
-                print_format = gimp_babl_format (base_type,
-                                                 GIMP_PRECISION_FLOAT_GAMMA,
-                                                 has_alpha);
-                break;
-
               case GIMP_PRECISION_HALF_LINEAR:
-                print_format = gimp_babl_format (base_type,
-                                                 GIMP_PRECISION_FLOAT_LINEAR,
-                                                 has_alpha);
+              case GIMP_PRECISION_HALF_NON_LINEAR:
+              case GIMP_PRECISION_HALF_PERCEPTUAL:
+                print_format =
+                  gimp_babl_format (base_type,
+                                    gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+                                                         trc),
+                                    has_alpha,
+                                    space);
                 break;
               }
 
diff --git a/app/widgets/gimphistogrameditor.c b/app/widgets/gimphistogrameditor.c
index 5d23897a58..6d72c3228e 100644
--- a/app/widgets/gimphistogrameditor.c
+++ b/app/widgets/gimphistogrameditor.c
@@ -46,7 +46,7 @@
 enum
 {
   PROP_0,
-  PROP_LINEAR
+  PROP_TRC
 };
 
 
@@ -107,12 +107,14 @@ gimp_histogram_editor_class_init (GimpHistogramEditorClass *klass)
 
   image_editor_class->set_image = gimp_histogram_editor_set_image;
 
-  g_object_class_install_property (object_class, PROP_LINEAR,
-                                   g_param_spec_boolean ("linear",
-                                                         _("Linear"), NULL,
-                                                         TRUE,
-                                                         GIMP_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class, PROP_TRC,
+                                   g_param_spec_enum ("trc",
+                                                      _("Linear/Preceptual"),
+                                                      NULL,
+                                                      GIMP_TYPE_TRC_TYPE,
+                                                      GIMP_TRC_LINEAR,
+                                                      GIMP_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT));
 }
 
 static void
@@ -167,11 +169,9 @@ gimp_histogram_editor_init (GimpHistogramEditor *editor)
   gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
   gtk_widget_show (menu);
 
-  menu = gimp_prop_boolean_icon_box_new (G_OBJECT (editor), "linear",
-                                         GIMP_ICON_COLOR_SPACE_LINEAR,
-                                         GIMP_ICON_COLOR_SPACE_PERCEPTUAL,
-                                         _("Show values in linear space"),
-                                         _("Show values in perceptual space"));
+  menu = gimp_prop_enum_icon_box_new (G_OBJECT (editor), "trc",
+                                      "gimp-color-space",
+                                      -1, -1);
   gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
   gtk_widget_show (menu);
 
@@ -246,8 +246,8 @@ gimp_histogram_editor_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_LINEAR:
-      editor->linear = g_value_get_boolean (value);
+    case PROP_TRC:
+      editor->trc = g_value_get_enum (value);
 
       if (editor->histogram)
         {
@@ -280,8 +280,8 @@ gimp_histogram_editor_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case PROP_LINEAR:
-      g_value_set_boolean (value, editor->linear);
+    case PROP_TRC:
+      g_value_set_enum (value, editor->trc);
       break;
 
    default:
@@ -487,7 +487,7 @@ gimp_histogram_editor_validate (GimpHistogramEditor *editor)
             {
               GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
 
-              editor->histogram = gimp_histogram_new (editor->linear);
+              editor->histogram = gimp_histogram_new (editor->trc);
 
               gimp_histogram_view_set_histogram (view, editor->histogram);
             }
@@ -557,7 +557,7 @@ gimp_histogram_editor_buffer_update (GimpHistogramEditor *editor,
                                      const GParamSpec    *pspec)
 {
   g_object_set (editor,
-                "linear", gimp_drawable_get_linear (editor->drawable),
+                "trc", gimp_drawable_get_trc (editor->drawable),
                 NULL);
 }
 
diff --git a/app/widgets/gimphistogrameditor.h b/app/widgets/gimphistogrameditor.h
index 51f8f12a46..1bd3a4b109 100644
--- a/app/widgets/gimphistogrameditor.h
+++ b/app/widgets/gimphistogrameditor.h
@@ -36,7 +36,7 @@ struct _GimpHistogramEditor
 {
   GimpImageEditor       parent_instance;
 
-  gboolean              linear;
+  GimpTRCType           trc;
 
   GimpDrawable         *drawable;
   GimpHistogram        *histogram;
diff --git a/app/widgets/gimptemplateeditor.c b/app/widgets/gimptemplateeditor.c
index 63bec8ff47..0a5b1805f3 100644
--- a/app/widgets/gimptemplateeditor.c
+++ b/app/widgets/gimptemplateeditor.c
@@ -403,10 +403,9 @@ gimp_template_editor_constructed (GObject *object)
                     G_CALLBACK (gimp_template_editor_precision_changed),
                     editor);
 
-  combo = gimp_prop_boolean_combo_box_new (G_OBJECT (template),
-                                           "linear",
-                                           _("Linear light"),
-                                           _("Perceptual gamma (sRGB)"));
+  combo = gimp_prop_enum_combo_box_new (G_OBJECT (template), "trc",
+                                        GIMP_TRC_LINEAR,
+                                        GIMP_TRC_NON_LINEAR);
   gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++,
                             _("_Gamma:"), 0.0, 0.5,
                             combo, 1);
@@ -637,7 +636,7 @@ gimp_template_editor_precision_changed (GtkWidget          *widget,
     case GIMP_COMPONENT_TYPE_U8:
       /* default to gamma for 8 bit */
       g_object_set (private->template,
-                    "linear", FALSE,
+                    "trc", GIMP_TRC_NON_LINEAR,
                     NULL);
       break;
 
@@ -652,7 +651,7 @@ gimp_template_editor_precision_changed (GtkWidget          *widget,
     case GIMP_COMPONENT_TYPE_DOUBLE:
       /* default to linear for floating point */
       g_object_set (private->template,
-                    "linear", TRUE,
+                    "trc", GIMP_TRC_LINEAR,
                     NULL);
       break;
     }
diff --git a/app/widgets/gimpwidgets-utils.c b/app/widgets/gimpwidgets-utils.c
index fe2b542377..c18ff50861 100644
--- a/app/widgets/gimpwidgets-utils.c
+++ b/app/widgets/gimpwidgets-utils.c
@@ -1692,7 +1692,6 @@ gimp_color_profile_store_add_defaults (GimpColorProfileStore  *store,
                                        GError                **error)
 {
   GimpColorProfile *profile;
-  const Babl       *format;
   gchar            *label;
   GError           *my_error = NULL;
 
@@ -1700,8 +1699,8 @@ gimp_color_profile_store_add_defaults (GimpColorProfileStore  *store,
   g_return_val_if_fail (GIMP_IS_COLOR_CONFIG (config), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  format  = gimp_babl_format (base_type, precision, TRUE);
-  profile = gimp_babl_format_get_color_profile (format);
+  profile = gimp_babl_get_builtin_color_profile (base_type,
+                                                 gimp_babl_trc (precision));
 
   if (base_type == GIMP_GRAY)
     {
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 4f622e74e2..aca8f9fd17 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -161,7 +161,7 @@ xcf_load_image (Gimp     *gimp,
   gint                width;
   gint                height;
   gint                image_type;
-  GimpPrecision       precision = GIMP_PRECISION_U8_GAMMA;
+  GimpPrecision       precision = GIMP_PRECISION_U8_NON_LINEAR;
   gint                num_successful_elements = 0;
   GList              *syms;
   GList              *iter;
@@ -184,11 +184,11 @@ xcf_load_image (Gimp     *gimp,
         {
           switch (p)
             {
-            case 0: precision = GIMP_PRECISION_U8_GAMMA;     break;
-            case 1: precision = GIMP_PRECISION_U16_GAMMA;    break;
-            case 2: precision = GIMP_PRECISION_U32_LINEAR;   break;
-            case 3: precision = GIMP_PRECISION_HALF_LINEAR;  break;
-            case 4: precision = GIMP_PRECISION_FLOAT_LINEAR; break;
+            case 0: precision = GIMP_PRECISION_U8_NON_LINEAR;  break;
+            case 1: precision = GIMP_PRECISION_U16_NON_LINEAR; break;
+            case 2: precision = GIMP_PRECISION_U32_LINEAR;     break;
+            case 3: precision = GIMP_PRECISION_HALF_LINEAR;    break;
+            case 4: precision = GIMP_PRECISION_FLOAT_LINEAR;   break;
             default:
               goto hard_error;
             }
@@ -198,16 +198,16 @@ xcf_load_image (Gimp     *gimp,
         {
           switch (p)
             {
-            case 100: precision = GIMP_PRECISION_U8_LINEAR; break;
-            case 150: precision = GIMP_PRECISION_U8_GAMMA; break;
-            case 200: precision = GIMP_PRECISION_U16_LINEAR; break;
-            case 250: precision = GIMP_PRECISION_U16_GAMMA; break;
-            case 300: precision = GIMP_PRECISION_U32_LINEAR; break;
-            case 350: precision = GIMP_PRECISION_U32_GAMMA; break;
-            case 400: precision = GIMP_PRECISION_HALF_LINEAR; break;
-            case 450: precision = GIMP_PRECISION_HALF_GAMMA; break;
-            case 500: precision = GIMP_PRECISION_FLOAT_LINEAR; break;
-            case 550: precision = GIMP_PRECISION_FLOAT_GAMMA; break;
+            case 100: precision = GIMP_PRECISION_U8_LINEAR;        break;
+            case 150: precision = GIMP_PRECISION_U8_NON_LINEAR;    break;
+            case 200: precision = GIMP_PRECISION_U16_LINEAR;       break;
+            case 250: precision = GIMP_PRECISION_U16_NON_LINEAR;   break;
+            case 300: precision = GIMP_PRECISION_U32_LINEAR;       break;
+            case 350: precision = GIMP_PRECISION_U32_NON_LINEAR;   break;
+            case 400: precision = GIMP_PRECISION_HALF_LINEAR;      break;
+            case 450: precision = GIMP_PRECISION_HALF_NON_LINEAR;  break;
+            case 500: precision = GIMP_PRECISION_FLOAT_LINEAR;     break;
+            case 550: precision = GIMP_PRECISION_FLOAT_NON_LINEAR; break;
             default:
               goto hard_error;
             }
@@ -571,7 +571,16 @@ xcf_load_image (Gimp     *gimp,
   xcf_load_add_masks (image);
 
   if (info->floating_sel && info->floating_sel_drawable)
-    floating_sel_attach (info->floating_sel, info->floating_sel_drawable);
+    {
+      /* we didn't fix the loaded floating selection's format before
+       * because we didn't know if it needed the layer space
+       */
+      if (GIMP_IS_LAYER (info->floating_sel_drawable) &&
+          gimp_drawable_is_gray (GIMP_DRAWABLE (info->floating_sel)))
+        gimp_layer_fix_format_space (info->floating_sel, TRUE, FALSE);
+
+      floating_sel_attach (info->floating_sel, info->floating_sel_drawable);
+    }
 
   if (info->active_layer)
     gimp_image_set_active_layer (image, info->active_layer);
@@ -1703,12 +1712,20 @@ xcf_load_layer (XcfInfo    *info,
   if (width <= 0 || height <= 0)
     return NULL;
 
-  /* do not use gimp_image_get_layer_format() because it might
-   * be the floating selection of a channel or mask
-   */
-  format = gimp_image_get_format (image, base_type,
-                                  gimp_image_get_precision (image),
-                                  has_alpha);
+  if (base_type == GIMP_GRAY)
+    {
+      /* do not use gimp_image_get_layer_format() because it might
+       * be the floating selection of a channel or mask
+       */
+      format = gimp_image_get_format (image, base_type,
+                                      gimp_image_get_precision (image),
+                                      has_alpha,
+                                      NULL /* we will fix the space later */);
+    }
+  else
+    {
+      format = gimp_image_get_layer_format (image, has_alpha);
+    }
 
   /* create a new layer */
   layer = gimp_layer_new (image, width, height,
@@ -1743,6 +1760,13 @@ xcf_load_layer (XcfInfo    *info,
         info->floating_sel = layer;
     }
 
+  /* if this is not the floating selection, we can fix the layer's
+   * space already now, the function will do nothing if we already
+   * created the layer with the right format
+   */
+  if (! floating && base_type == GIMP_GRAY)
+    gimp_layer_fix_format_space (layer, FALSE, FALSE);
+
   /* read the hierarchy and layer mask offsets */
   xcf_read_offset (info, &hierarchy_offset,  1);
   xcf_read_offset (info, &layer_mask_offset, 1);
diff --git a/libgimp/gimpdrawable.c b/libgimp/gimpdrawable.c
index e96b7016e3..88fffd47b9 100644
--- a/libgimp/gimpdrawable.c
+++ b/libgimp/gimpdrawable.c
@@ -422,6 +422,10 @@ gimp_drawable_get_format (gint32 drawable_ID)
   const Babl *format     = NULL;
   gchar      *format_str = _gimp_drawable_get_format (drawable_ID);
 
+  /* EEK SPACE _gimp_drawable_get_format() only returns the encoding,
+   * needs to create the actual space from the image's profile
+   */
+
   if (format_str)
     {
       if (gimp_drawable_is_indexed (drawable_ID))
diff --git a/libgimp/gimpimage_pdb.c b/libgimp/gimpimage_pdb.c
index ff1616e50b..add4b1b1e4 100644
--- a/libgimp/gimpimage_pdb.c
+++ b/libgimp/gimpimage_pdb.c
@@ -165,8 +165,8 @@ gimp_image_new (gint              width,
  *
  * Creates a new image, undisplayed with the specified extents, type
  * and precision. Indexed images can only be created at
- * GIMP_PRECISION_U8_GAMMA precision. See gimp_image_new() for further
- * details.
+ * GIMP_PRECISION_U8_NON_LINEAR precision. See gimp_image_new() for
+ * further details.
  *
  * Returns: The ID of the newly created image.
  *
diff --git a/libgimp/gimpimagecolorprofile_pdb.c b/libgimp/gimpimagecolorprofile_pdb.c
index ba55760520..4afa2575b4 100644
--- a/libgimp/gimpimagecolorprofile_pdb.c
+++ b/libgimp/gimpimagecolorprofile_pdb.c
@@ -137,7 +137,9 @@ _gimp_image_get_effective_color_profile (gint32  image_ID,
  *
  * This procedure sets the image's color profile, or unsets it if NULL
  * is passed as 'color_profile'. This procedure does no color
- * conversion.
+ * conversion. However, it will change the pixel format of all layers
+ * to contain the babl space matching the profile. You must call this
+ * procedure before adding layers to the image.
  *
  * Returns: TRUE on success.
  *
@@ -175,7 +177,10 @@ _gimp_image_set_color_profile (gint32        image_ID,
  *
  * This procedure sets the image's color profile from a file containing
  * an ICC profile, or unsets it if NULL is passed as 'uri'. This
- * procedure does no color conversion.
+ * procedure does no color conversion. However, it will change the
+ * pixel format of all layers to contain the babl space matching the
+ * profile. You must call this procedure before adding layers to the
+ * image.
  *
  * Returns: TRUE on success.
  *
diff --git a/libgimpbase/gimpbaseenums.c b/libgimpbase/gimpbaseenums.c
index dfd7b4c4f1..003eda0273 100644
--- a/libgimpbase/gimpbaseenums.c
+++ b/libgimpbase/gimpbaseenums.c
@@ -1444,16 +1444,28 @@ gimp_precision_get_type (void)
   static const GEnumValue values[] =
   {
     { GIMP_PRECISION_U8_LINEAR, "GIMP_PRECISION_U8_LINEAR", "u8-linear" },
-    { GIMP_PRECISION_U8_GAMMA, "GIMP_PRECISION_U8_GAMMA", "u8-gamma" },
+    { GIMP_PRECISION_U8_NON_LINEAR, "GIMP_PRECISION_U8_NON_LINEAR", "u8-non-linear" },
+    { GIMP_PRECISION_U8_PERCEPTUAL, "GIMP_PRECISION_U8_PERCEPTUAL", "u8-perceptual" },
     { GIMP_PRECISION_U16_LINEAR, "GIMP_PRECISION_U16_LINEAR", "u16-linear" },
-    { GIMP_PRECISION_U16_GAMMA, "GIMP_PRECISION_U16_GAMMA", "u16-gamma" },
+    { GIMP_PRECISION_U16_NON_LINEAR, "GIMP_PRECISION_U16_NON_LINEAR", "u16-non-linear" },
+    { GIMP_PRECISION_U16_PERCEPTUAL, "GIMP_PRECISION_U16_PERCEPTUAL", "u16-perceptual" },
     { GIMP_PRECISION_U32_LINEAR, "GIMP_PRECISION_U32_LINEAR", "u32-linear" },
-    { GIMP_PRECISION_U32_GAMMA, "GIMP_PRECISION_U32_GAMMA", "u32-gamma" },
+    { GIMP_PRECISION_U32_NON_LINEAR, "GIMP_PRECISION_U32_NON_LINEAR", "u32-non-linear" },
+    { GIMP_PRECISION_U32_PERCEPTUAL, "GIMP_PRECISION_U32_PERCEPTUAL", "u32-perceptual" },
     { GIMP_PRECISION_HALF_LINEAR, "GIMP_PRECISION_HALF_LINEAR", "half-linear" },
-    { GIMP_PRECISION_HALF_GAMMA, "GIMP_PRECISION_HALF_GAMMA", "half-gamma" },
+    { GIMP_PRECISION_HALF_NON_LINEAR, "GIMP_PRECISION_HALF_NON_LINEAR", "half-non-linear" },
+    { GIMP_PRECISION_HALF_PERCEPTUAL, "GIMP_PRECISION_HALF_PERCEPTUAL", "half-perceptual" },
     { GIMP_PRECISION_FLOAT_LINEAR, "GIMP_PRECISION_FLOAT_LINEAR", "float-linear" },
-    { GIMP_PRECISION_FLOAT_GAMMA, "GIMP_PRECISION_FLOAT_GAMMA", "float-gamma" },
+    { GIMP_PRECISION_FLOAT_NON_LINEAR, "GIMP_PRECISION_FLOAT_NON_LINEAR", "float-non-linear" },
+    { GIMP_PRECISION_FLOAT_PERCEPTUAL, "GIMP_PRECISION_FLOAT_PERCEPTUAL", "float-perceptual" },
     { GIMP_PRECISION_DOUBLE_LINEAR, "GIMP_PRECISION_DOUBLE_LINEAR", "double-linear" },
+    { GIMP_PRECISION_DOUBLE_NON_LINEAR, "GIMP_PRECISION_DOUBLE_NON_LINEAR", "double-non-linear" },
+    { GIMP_PRECISION_DOUBLE_PERCEPTUAL, "GIMP_PRECISION_DOUBLE_PERCEPTUAL", "double-perceptual" },
+    { GIMP_PRECISION_U8_GAMMA, "GIMP_PRECISION_U8_GAMMA", "u8-gamma" },
+    { GIMP_PRECISION_U16_GAMMA, "GIMP_PRECISION_U16_GAMMA", "u16-gamma" },
+    { GIMP_PRECISION_U32_GAMMA, "GIMP_PRECISION_U32_GAMMA", "u32-gamma" },
+    { GIMP_PRECISION_HALF_GAMMA, "GIMP_PRECISION_HALF_GAMMA", "half-gamma" },
+    { GIMP_PRECISION_FLOAT_GAMMA, "GIMP_PRECISION_FLOAT_GAMMA", "float-gamma" },
     { GIMP_PRECISION_DOUBLE_GAMMA, "GIMP_PRECISION_DOUBLE_GAMMA", "double-gamma" },
     { 0, NULL, NULL }
   };
@@ -1461,17 +1473,29 @@ gimp_precision_get_type (void)
   static const GimpEnumDesc descs[] =
   {
     { GIMP_PRECISION_U8_LINEAR, NC_("precision", "8-bit linear integer"), NULL },
-    { GIMP_PRECISION_U8_GAMMA, NC_("precision", "8-bit gamma integer"), NULL },
+    { GIMP_PRECISION_U8_NON_LINEAR, NC_("precision", "8-bit non-linear integer"), NULL },
+    { GIMP_PRECISION_U8_PERCEPTUAL, NC_("precision", "8-bit perceptual integer"), NULL },
     { GIMP_PRECISION_U16_LINEAR, NC_("precision", "16-bit linear integer"), NULL },
-    { GIMP_PRECISION_U16_GAMMA, NC_("precision", "16-bit gamma integer"), NULL },
+    { GIMP_PRECISION_U16_NON_LINEAR, NC_("precision", "16-bit non-linear integer"), NULL },
+    { GIMP_PRECISION_U16_PERCEPTUAL, NC_("precision", "16-bit perceptual integer"), NULL },
     { GIMP_PRECISION_U32_LINEAR, NC_("precision", "32-bit linear integer"), NULL },
-    { GIMP_PRECISION_U32_GAMMA, NC_("precision", "32-bit gamma integer"), NULL },
+    { GIMP_PRECISION_U32_NON_LINEAR, NC_("precision", "32-bit non-linear integer"), NULL },
+    { GIMP_PRECISION_U32_PERCEPTUAL, NC_("precision", "32-bit perceptual integer"), NULL },
     { GIMP_PRECISION_HALF_LINEAR, NC_("precision", "16-bit linear floating point"), NULL },
-    { GIMP_PRECISION_HALF_GAMMA, NC_("precision", "16-bit gamma floating point"), NULL },
+    { GIMP_PRECISION_HALF_NON_LINEAR, NC_("precision", "16-bit non-linear floating point"), NULL },
+    { GIMP_PRECISION_HALF_PERCEPTUAL, NC_("precision", "16-bit perceptual floating point"), NULL },
     { GIMP_PRECISION_FLOAT_LINEAR, NC_("precision", "32-bit linear floating point"), NULL },
-    { GIMP_PRECISION_FLOAT_GAMMA, NC_("precision", "32-bit gamma floating point"), NULL },
+    { GIMP_PRECISION_FLOAT_NON_LINEAR, NC_("precision", "32-bit non-linear floating point"), NULL },
+    { GIMP_PRECISION_FLOAT_PERCEPTUAL, NC_("precision", "32-bit perceptual floating point"), NULL },
     { GIMP_PRECISION_DOUBLE_LINEAR, NC_("precision", "64-bit linear floating point"), NULL },
-    { GIMP_PRECISION_DOUBLE_GAMMA, NC_("precision", "64-bit gamma floating point"), NULL },
+    { GIMP_PRECISION_DOUBLE_NON_LINEAR, NC_("precision", "64-bit non-linear floating point"), NULL },
+    { GIMP_PRECISION_DOUBLE_PERCEPTUAL, NC_("precision", "64-bit perceptual floating point"), NULL },
+    { GIMP_PRECISION_U8_GAMMA, "GIMP_PRECISION_U8_GAMMA", NULL },
+    { GIMP_PRECISION_U16_GAMMA, "GIMP_PRECISION_U16_GAMMA", NULL },
+    { GIMP_PRECISION_U32_GAMMA, "GIMP_PRECISION_U32_GAMMA", NULL },
+    { GIMP_PRECISION_HALF_GAMMA, "GIMP_PRECISION_HALF_GAMMA", NULL },
+    { GIMP_PRECISION_FLOAT_GAMMA, "GIMP_PRECISION_FLOAT_GAMMA", NULL },
+    { GIMP_PRECISION_DOUBLE_GAMMA, "GIMP_PRECISION_DOUBLE_GAMMA", NULL },
     { 0, NULL, NULL }
   };
 
diff --git a/libgimpbase/gimpbaseenums.h b/libgimpbase/gimpbaseenums.h
index 37d503d638..edc507a8d9 100644
--- a/libgimpbase/gimpbaseenums.h
+++ b/libgimpbase/gimpbaseenums.h
@@ -970,18 +970,37 @@ typedef enum
 
 /**
  * GimpPrecision:
- * @GIMP_PRECISION_U8_LINEAR:     8-bit linear integer
- * @GIMP_PRECISION_U8_GAMMA:      8-bit gamma integer
- * @GIMP_PRECISION_U16_LINEAR:    16-bit linear integer
- * @GIMP_PRECISION_U16_GAMMA:     16-bit gamma integer
- * @GIMP_PRECISION_U32_LINEAR:    32-bit linear integer
- * @GIMP_PRECISION_U32_GAMMA:     32-bit gamma integer
- * @GIMP_PRECISION_HALF_LINEAR:   16-bit linear floating point
- * @GIMP_PRECISION_HALF_GAMMA:    16-bit gamma floating point
- * @GIMP_PRECISION_FLOAT_LINEAR:  32-bit linear floating point
- * @GIMP_PRECISION_FLOAT_GAMMA:   32-bit gamma floating point
- * @GIMP_PRECISION_DOUBLE_LINEAR: 64-bit linear floating point
- * @GIMP_PRECISION_DOUBLE_GAMMA:  64-bit gamma floating point
+ * @GIMP_PRECISION_U8_LINEAR:         8-bit linear integer
+ * @GIMP_PRECISION_U8_NON_LINEAR:     8-bit non-linear integer
+ * @GIMP_PRECISION_U8_PERCEPTUAL:     8-bit perceptual integer
+ * @GIMP_PRECISION_U16_LINEAR:        16-bit linear integer
+ * @GIMP_PRECISION_U16_NON_LINEAR:    16-bit non-linear integer
+ * @GIMP_PRECISION_U16_PERCEPTUAL:    16-bit perceptual integer
+ * @GIMP_PRECISION_U32_LINEAR:        32-bit linear integer
+ * @GIMP_PRECISION_U32_NON_LINEAR:    32-bit non-linear integer
+ * @GIMP_PRECISION_U32_PERCEPTUAL:    32-bit perceptual integer
+ * @GIMP_PRECISION_HALF_LINEAR:       16-bit linear floating point
+ * @GIMP_PRECISION_HALF_NON_LINEAR:   16-bit non-linear floating point
+ * @GIMP_PRECISION_HALF_PERCEPTUAL:   16-bit perceptual floating point
+ * @GIMP_PRECISION_FLOAT_LINEAR:      32-bit linear floating point
+ * @GIMP_PRECISION_FLOAT_NON_LINEAR:  32-bit non-linear floating point
+ * @GIMP_PRECISION_FLOAT_PERCEPTUAL:  32-bit perceptual floating point
+ * @GIMP_PRECISION_DOUBLE_LINEAR:     64-bit linear floating point
+ * @GIMP_PRECISION_DOUBLE_NON_LINEAR: 64-bit non-linear floating point
+ * @GIMP_PRECISION_DOUBLE_PERCEPTUAL: 64-bit perceptual floating point
+ *
+ * @GIMP_PRECISION_U8_GAMMA:      deprecated alias for
+ *                                @GIMP_PRECISION_U8_NON_LINEAR
+ * @GIMP_PRECISION_U16_GAMMA:     deprecated alias for
+ *                                @GIMP_PRECISION_U16_NON_LINEAR
+ * @GIMP_PRECISION_U32_GAMMA:     deprecated alias for
+ *                                @GIMP_PRECISION_U32_NON_LINEAR
+ * @GIMP_PRECISION_HALF_GAMMA:    deprecated alias for
+ *                                @GIMP_PRECISION_HALF_NON_LINEAR
+ * @GIMP_PRECISION_FLOAT_GAMMA:   deprecated alias for
+ *                                @GIMP_PRECISION_FLOAT_NON_LINEAR
+ * @GIMP_PRECISION_DOUBLE_GAMMA:  deprecated alias for
+ *                                @GIMP_PRECISION_DOUBLE_NON_LINEAR
  *
  * Precisions for pixel encoding.
  *
@@ -993,18 +1012,33 @@ GType gimp_precision_get_type (void) G_GNUC_CONST;
 
 typedef enum
 {
-  GIMP_PRECISION_U8_LINEAR     = 100, /*< desc="8-bit linear integer"         >*/
-  GIMP_PRECISION_U8_GAMMA      = 150, /*< desc="8-bit gamma integer"          >*/
-  GIMP_PRECISION_U16_LINEAR    = 200, /*< desc="16-bit linear integer"        >*/
-  GIMP_PRECISION_U16_GAMMA     = 250, /*< desc="16-bit gamma integer"         >*/
-  GIMP_PRECISION_U32_LINEAR    = 300, /*< desc="32-bit linear integer"        >*/
-  GIMP_PRECISION_U32_GAMMA     = 350, /*< desc="32-bit gamma integer"         >*/
-  GIMP_PRECISION_HALF_LINEAR   = 500, /*< desc="16-bit linear floating point" >*/
-  GIMP_PRECISION_HALF_GAMMA    = 550, /*< desc="16-bit gamma floating point"  >*/
-  GIMP_PRECISION_FLOAT_LINEAR  = 600, /*< desc="32-bit linear floating point" >*/
-  GIMP_PRECISION_FLOAT_GAMMA   = 650, /*< desc="32-bit gamma floating point"  >*/
-  GIMP_PRECISION_DOUBLE_LINEAR = 700, /*< desc="64-bit linear floating point" >*/
-  GIMP_PRECISION_DOUBLE_GAMMA  = 750  /*< desc="64-bit gamma floating point"  >*/
+  GIMP_PRECISION_U8_LINEAR         = 100, /*< desc="8-bit linear integer"         >*/
+  GIMP_PRECISION_U8_NON_LINEAR     = 150, /*< desc="8-bit non-linear integer"          >*/
+  GIMP_PRECISION_U8_PERCEPTUAL     = 175, /*< desc="8-bit perceptual integer"          >*/
+  GIMP_PRECISION_U16_LINEAR        = 200, /*< desc="16-bit linear integer"        >*/
+  GIMP_PRECISION_U16_NON_LINEAR    = 250, /*< desc="16-bit non-linear integer"         >*/
+  GIMP_PRECISION_U16_PERCEPTUAL    = 275, /*< desc="16-bit perceptual integer"         >*/
+  GIMP_PRECISION_U32_LINEAR        = 300, /*< desc="32-bit linear integer"        >*/
+  GIMP_PRECISION_U32_NON_LINEAR    = 350, /*< desc="32-bit non-linear integer"         >*/
+  GIMP_PRECISION_U32_PERCEPTUAL    = 375, /*< desc="32-bit perceptual integer"         >*/
+  GIMP_PRECISION_HALF_LINEAR       = 500, /*< desc="16-bit linear floating point" >*/
+  GIMP_PRECISION_HALF_NON_LINEAR   = 550, /*< desc="16-bit non-linear floating point"  >*/
+  GIMP_PRECISION_HALF_PERCEPTUAL   = 575, /*< desc="16-bit perceptual floating point"  >*/
+  GIMP_PRECISION_FLOAT_LINEAR      = 600, /*< desc="32-bit linear floating point" >*/
+  GIMP_PRECISION_FLOAT_NON_LINEAR  = 650, /*< desc="32-bit non-linear floating point"  >*/
+  GIMP_PRECISION_FLOAT_PERCEPTUAL  = 675, /*< desc="32-bit perceptual floating point"  >*/
+  GIMP_PRECISION_DOUBLE_LINEAR     = 700, /*< desc="64-bit linear floating point" >*/
+  GIMP_PRECISION_DOUBLE_NON_LINEAR = 750, /*< desc="64-bit non-linear floating point"  >*/
+  GIMP_PRECISION_DOUBLE_PERCEPTUAL = 775, /*< desc="64-bit perceptual floating point"  >*/
+
+#ifndef GIMP_DISABLE_DEPRECATED
+  GIMP_PRECISION_U8_GAMMA      = GIMP_PRECISION_U8_NON_LINEAR,
+  GIMP_PRECISION_U16_GAMMA     = GIMP_PRECISION_U16_NON_LINEAR,
+  GIMP_PRECISION_U32_GAMMA     = GIMP_PRECISION_U32_NON_LINEAR,
+  GIMP_PRECISION_HALF_GAMMA    = GIMP_PRECISION_HALF_NON_LINEAR,
+  GIMP_PRECISION_FLOAT_GAMMA   = GIMP_PRECISION_FLOAT_NON_LINEAR,
+  GIMP_PRECISION_DOUBLE_GAMMA  = GIMP_PRECISION_DOUBLE_NON_LINEAR
+  #endif
 } GimpPrecision;
 
 
diff --git a/libgimpcolor/gimpcolorprofile.c b/libgimpcolor/gimpcolorprofile.c
index dfc90975ae..9d64e8f1dd 100644
--- a/libgimpcolor/gimpcolorprofile.c
+++ b/libgimpcolor/gimpcolorprofile.c
@@ -1521,7 +1521,7 @@ gimp_color_profile_get_format (GimpColorProfile          *profile,
   if (! space)
     return NULL;
 
-  return babl_format_with_space (babl_get_name (format), space);
+  return babl_format_with_space (babl_format_get_encoding (format), space);
 }
 
 /**
diff --git a/libgimpcolor/gimpcolortransform.c b/libgimpcolor/gimpcolortransform.c
index 27264ef1ee..b6e7fc286c 100644
--- a/libgimpcolor/gimpcolortransform.c
+++ b/libgimpcolor/gimpcolortransform.c
@@ -564,34 +564,18 @@ gboolean
 gimp_color_transform_can_gegl_copy (GimpColorProfile *src_profile,
                                     GimpColorProfile *dest_profile)
 {
-  static GimpColorProfile *srgb_profile        = NULL;
-  static GimpColorProfile *srgb_linear_profile = NULL;
-  static GimpColorProfile *gray_profile        = NULL;
-  static GimpColorProfile *gray_linear_profile = NULL;
-
   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (src_profile), FALSE);
   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (dest_profile), FALSE);
 
   if (gimp_color_profile_is_equal (src_profile, dest_profile))
     return TRUE;
 
-  if (! srgb_profile)
-    {
-      srgb_profile        = gimp_color_profile_new_rgb_srgb ();
-      srgb_linear_profile = gimp_color_profile_new_rgb_srgb_linear ();
-      gray_profile        = gimp_color_profile_new_d65_gray_srgb_trc ();
-      gray_linear_profile = gimp_color_profile_new_d65_gray_linear ();
-    }
-
-  if ((gimp_color_profile_is_equal (src_profile, srgb_profile)        ||
-       gimp_color_profile_is_equal (src_profile, srgb_linear_profile) ||
-       gimp_color_profile_is_equal (src_profile, gray_profile)        ||
-       gimp_color_profile_is_equal (src_profile, gray_linear_profile))
-      &&
-      (gimp_color_profile_is_equal (dest_profile, srgb_profile)        ||
-       gimp_color_profile_is_equal (dest_profile, srgb_linear_profile) ||
-       gimp_color_profile_is_equal (dest_profile, gray_profile)        ||
-       gimp_color_profile_is_equal (dest_profile, gray_linear_profile)))
+  if (gimp_color_profile_get_space (src_profile,
+                                    GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+                                    NULL) &&
+      gimp_color_profile_get_space (dest_profile,
+                                    GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+                                    NULL))
     {
       return TRUE;
     }
diff --git a/pdb/enums.pl b/pdb/enums.pl
index a265ae9c96..33601e4eeb 100644
--- a/pdb/enums.pl
+++ b/pdb/enums.pl
@@ -466,27 +466,52 @@ package Gimp::CodeGen::enums;
     GimpPrecision =>
        { contig => 0,
          header => 'libgimpbase/gimpbaseenums.h',
-         symbols => [ qw(GIMP_PRECISION_U8_LINEAR GIMP_PRECISION_U8_GAMMA
-                         GIMP_PRECISION_U16_LINEAR GIMP_PRECISION_U16_GAMMA
-                         GIMP_PRECISION_U32_LINEAR GIMP_PRECISION_U32_GAMMA
+         symbols => [ qw(GIMP_PRECISION_U8_LINEAR
+                         GIMP_PRECISION_U8_NON_LINEAR
+                         GIMP_PRECISION_U8_PERCEPTUAL
+                         GIMP_PRECISION_U16_LINEAR
+                         GIMP_PRECISION_U16_NON_LINEAR
+                         GIMP_PRECISION_U16_PERCEPTUAL
+                         GIMP_PRECISION_U32_LINEAR
+                         GIMP_PRECISION_U32_NON_LINEAR
+                         GIMP_PRECISION_U32_PERCEPTUAL
                          GIMP_PRECISION_HALF_LINEAR
-                         GIMP_PRECISION_HALF_GAMMA
+                         GIMP_PRECISION_HALF_NON_LINEAR
+                         GIMP_PRECISION_HALF_PERCEPTUAL
                          GIMP_PRECISION_FLOAT_LINEAR
-                         GIMP_PRECISION_FLOAT_GAMMA
+                         GIMP_PRECISION_FLOAT_NON_LINEAR
+                         GIMP_PRECISION_FLOAT_PERCEPTUAL
                          GIMP_PRECISION_DOUBLE_LINEAR
+                         GIMP_PRECISION_DOUBLE_NON_LINEAR
+                         GIMP_PRECISION_DOUBLE_PERCEPTUAL
+                         GIMP_PRECISION_U8_GAMMA GIMP_PRECISION_U16_GAMMA
+                         GIMP_PRECISION_U32_GAMMA GIMP_PRECISION_HALF_GAMMA
+                         GIMP_PRECISION_FLOAT_GAMMA
                          GIMP_PRECISION_DOUBLE_GAMMA) ],
          mapping => { GIMP_PRECISION_U8_LINEAR => '100',
-                      GIMP_PRECISION_U8_GAMMA => '150',
+                      GIMP_PRECISION_U8_NON_LINEAR => '150',
+                      GIMP_PRECISION_U8_PERCEPTUAL => '175',
                       GIMP_PRECISION_U16_LINEAR => '200',
-                      GIMP_PRECISION_U16_GAMMA => '250',
+                      GIMP_PRECISION_U16_NON_LINEAR => '250',
+                      GIMP_PRECISION_U16_PERCEPTUAL => '275',
                       GIMP_PRECISION_U32_LINEAR => '300',
-                      GIMP_PRECISION_U32_GAMMA => '350',
+                      GIMP_PRECISION_U32_NON_LINEAR => '350',
+                      GIMP_PRECISION_U32_PERCEPTUAL => '375',
                       GIMP_PRECISION_HALF_LINEAR => '500',
-                      GIMP_PRECISION_HALF_GAMMA => '550',
+                      GIMP_PRECISION_HALF_NON_LINEAR => '550',
+                      GIMP_PRECISION_HALF_PERCEPTUAL => '575',
                       GIMP_PRECISION_FLOAT_LINEAR => '600',
-                      GIMP_PRECISION_FLOAT_GAMMA => '650',
+                      GIMP_PRECISION_FLOAT_NON_LINEAR => '650',
+                      GIMP_PRECISION_FLOAT_PERCEPTUAL => '675',
                       GIMP_PRECISION_DOUBLE_LINEAR => '700',
-                      GIMP_PRECISION_DOUBLE_GAMMA => '750' }
+                      GIMP_PRECISION_DOUBLE_NON_LINEAR => '750',
+                      GIMP_PRECISION_DOUBLE_PERCEPTUAL => '775',
+                      GIMP_PRECISION_U8_GAMMA => 'GIMP_PRECISION_U8_NON_LINEAR',
+                      GIMP_PRECISION_U16_GAMMA => 'GIMP_PRECISION_U16_NON_LINEAR',
+                      GIMP_PRECISION_U32_GAMMA => 'GIMP_PRECISION_U32_NON_LINEAR',
+                      GIMP_PRECISION_HALF_GAMMA => 'GIMP_PRECISION_HALF_NON_LINEAR',
+                      GIMP_PRECISION_FLOAT_GAMMA => 'GIMP_PRECISION_FLOAT_NON_LINEAR',
+                      GIMP_PRECISION_DOUBLE_GAMMA => 'GIMP_PRECISION_DOUBLE_NON_LINEAR' }
        },
     GimpProgressCommand =>
        { contig => 1,
diff --git a/pdb/groups/drawable.pdb b/pdb/groups/drawable.pdb
index 2ceb2ce8ac..860d4b7f86 100644
--- a/pdb/groups/drawable.pdb
+++ b/pdb/groups/drawable.pdb
@@ -290,7 +290,10 @@ sub drawable_get_format {
   if (gimp->plug_in_manager->current_plug_in)
     gimp_plug_in_enable_precision (gimp->plug_in_manager->current_plug_in);
 
-  format = g_strdup (babl_get_name (gimp_drawable_get_format (drawable)));
+  /* EEK SPACE: this needs more code on the libgimp side, we currently
+   * lose the space
+   */
+  format = g_strdup (babl_format_get_encoding (gimp_drawable_get_format (drawable)));
 }
 CODE
     );
diff --git a/pdb/groups/drawable_color.pdb b/pdb/groups/drawable_color.pdb
index be70c1ba80..ff68c96198 100644
--- a/pdb/groups/drawable_color.pdb
+++ b/pdb/groups/drawable_color.pdb
@@ -451,7 +451,7 @@ HELP
       gint           n_bins;
       gint           start;
       gboolean       precision_enabled;
-      gboolean       linear;
+      GimpTRCType    trc;
       gint           end;
 
       precision_enabled =
@@ -459,11 +459,11 @@ HELP
         gimp_plug_in_precision_enabled (gimp->plug_in_manager->current_plug_in);
 
       if (precision_enabled)
-        linear = gimp_drawable_get_linear (drawable);
+        trc = gimp_drawable_get_trc (drawable);
       else
-        linear = FALSE;
+        trc = GIMP_TRC_NON_LINEAR;
 
-      histogram = gimp_histogram_new (linear);
+      histogram = gimp_histogram_new (trc);
       gimp_drawable_calculate_histogram (drawable, histogram, FALSE);
 
       n_bins = gimp_histogram_n_bins (histogram);
diff --git a/pdb/groups/floating_sel.pdb b/pdb/groups/floating_sel.pdb
index 3bf8f7a790..36d465a0a6 100644
--- a/pdb/groups/floating_sel.pdb
+++ b/pdb/groups/floating_sel.pdb
@@ -156,7 +156,14 @@ HELP
   if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                  GIMP_PDB_ITEM_CONTENT, error) &&
       gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
-    floating_sel_attach (layer, drawable);
+    {
+      /* see layer-new */
+      if (gimp_drawable_is_gray (GIMP_DRAWABLE (layer)) &&
+          GIMP_IS_LAYER (drawable))
+        gimp_layer_fix_format_space (layer, TRUE, FALSE);
+
+      floating_sel_attach (layer, drawable);
+    }
   else
     success = FALSE;
 }
diff --git a/pdb/groups/image.pdb b/pdb/groups/image.pdb
index 3b047dc6e5..18429003c1 100644
--- a/pdb/groups/image.pdb
+++ b/pdb/groups/image.pdb
@@ -119,7 +119,7 @@ HELP
         code => <<'CODE'
 {
   image = gimp_create_image (gimp, width, height, type,
-                             GIMP_PRECISION_U8_GAMMA, FALSE);
+                             GIMP_PRECISION_U8_NON_LINEAR, FALSE);
 
   if (! image)
     success = FALSE;
@@ -132,9 +132,10 @@ sub image_new_with_precision {
     $blurb = 'Creates a new image with the specified width, height, type and precision.';
 
     $help = <<'HELP';
-Creates a new image, undisplayed with the specified extents, type
-and precision. Indexed images can only be created at GIMP_PRECISION_U8_GAMMA
-precision. See gimp_image_new() for further details.
+Creates a new image, undisplayed with the specified extents, type and
+precision. Indexed images can only be created at
+GIMP_PRECISION_U8_NON_LINEAR precision. See gimp_image_new() for
+further details.
 HELP
 
     &mitch_pdb_misc('2012', '2.10');
@@ -876,6 +877,10 @@ HELP
       if (position == -1 && parent == NULL)
         parent = GIMP_IMAGE_ACTIVE_PARENT;
 
+      /* see layer-new */
+      if (gimp_drawable_is_gray (GIMP_DRAWABLE (layer)))
+        gimp_layer_fix_format_space (layer, TRUE, FALSE);
+
       success = gimp_image_add_layer (image, layer,
                                       parent, MAX (position, -1), TRUE);
     }
diff --git a/pdb/groups/image_color_profile.pdb b/pdb/groups/image_color_profile.pdb
index f82e63a70d..cf0bac7da1 100644
--- a/pdb/groups/image_color_profile.pdb
+++ b/pdb/groups/image_color_profile.pdb
@@ -112,6 +112,9 @@ sub image_set_color_profile {
     $help = <<'HELP';
 This procedure sets the image's color profile, or unsets it if NULL is
 passed as 'color_profile'. This procedure does no color conversion.
+However, it will change the pixel format of all layers to contain the
+babl space matching the profile. You must call this procedure before
+adding layers to the image.
 HELP
 
     &mitch_pdb_misc('2015', '2.10');
@@ -138,7 +141,8 @@ HELP
 
       if (profile)
         {
-          success = gimp_image_set_color_profile (image, profile, error);
+          success = gimp_image_assign_color_profile (image, profile,
+                                                     progress, error);
           g_object_unref (profile);
         }
       else
@@ -146,7 +150,8 @@ HELP
     }
   else
     {
-      success = gimp_image_set_color_profile (image, NULL, error);
+      success = gimp_image_assign_color_profile (image, NULL,
+                                                 progress, error);
     }
 }
 CODE
@@ -159,7 +164,10 @@ sub image_set_color_profile_from_file {
     $help = <<'HELP';
 This procedure sets the image's color profile from a file containing
 an ICC profile, or unsets it if NULL is passed as 'uri'. This
-procedure does no color conversion.
+procedure does no color conversion. However, it will change the pixel
+format of all layers to contain the babl space matching the
+profile. You must call this procedure before adding layers to the
+image.
 HELP
 
     &mitch_pdb_misc('2015', '2.10');
@@ -183,7 +191,8 @@ HELP
 
       if (profile)
         {
-          success = gimp_image_set_color_profile (image, profile, error);
+          success = gimp_image_assign_color_profile (image, profile,
+                                                     progress, error);
           g_object_unref (profile);
         }
       else
@@ -193,7 +202,8 @@ HELP
     }
   else
     {
-      success = gimp_image_set_color_profile (image, NULL, error);
+      success = gimp_image_assign_color_profile (image, NULL,
+                                                 progress, error);
     }
 }
 CODE
diff --git a/pdb/groups/image_convert.pdb b/pdb/groups/image_convert.pdb
index 53a6b50d3b..02ed05e2be 100644
--- a/pdb/groups/image_convert.pdb
+++ b/pdb/groups/image_convert.pdb
@@ -128,9 +128,9 @@ HELP
 {
   GimpPalette *pal = NULL;
 
-  if (gimp_pdb_image_is_not_base_type (image, GIMP_INDEXED, error)        &&
-      gimp_pdb_image_is_precision (image, GIMP_PRECISION_U8_GAMMA, error) &&
-      gimp_babl_is_valid (GIMP_INDEXED, gimp_image_get_precision (image)) &&
+  if (gimp_pdb_image_is_not_base_type (image, GIMP_INDEXED, error)             &&
+      gimp_pdb_image_is_precision (image, GIMP_PRECISION_U8_NON_LINEAR, error) &&
+      gimp_babl_is_valid (GIMP_INDEXED, gimp_image_get_precision (image))      &&
       gimp_item_stack_is_flat (GIMP_ITEM_STACK (gimp_image_get_layers (image))))
     {
       switch (palette_type)
diff --git a/pdb/groups/layer.pdb b/pdb/groups/layer.pdb
index 79b3372a22..426f450d42 100644
--- a/pdb/groups/layer.pdb
+++ b/pdb/groups/layer.pdb
@@ -96,12 +96,21 @@ HELP
       break;
     }
 
-  /* do not use gimp_image_get_layer_format() because it might
-   * be the floating selection of a channel or mask
-   */
-  format = gimp_image_get_format (image, base_type,
-                                  gimp_image_get_precision (image),
-                                  has_alpha);
+  if (base_type == GIMP_GRAY)
+    {
+      /* do not use gimp_image_get_layer_format() because it might
+       * be the floating selection of a channel or mask, we will
+       * fix the format in image-add-layer and floating-sel-attach
+       */
+      format = gimp_image_get_format (image, base_type,
+                                      gimp_image_get_precision (image),
+                                      has_alpha,
+                                      NULL /* will fix later */);
+    }
+  else
+    {
+      format = gimp_image_get_layer_format (image, has_alpha);
+    }
 
   layer = gimp_layer_new (image, width, height,
                           format, name, opacity / 100.0, mode);
diff --git a/pdb/groups/plug_in_compat.pdb b/pdb/groups/plug_in_compat.pdb
index 6e17b738c5..ba843deae5 100644
--- a/pdb/groups/plug_in_compat.pdb
+++ b/pdb/groups/plug_in_compat.pdb
@@ -4392,7 +4392,7 @@ static GeglNode *
 wrap_in_gamma_cast (GeglNode     *node,
                     GimpDrawable *drawable)
 {
-  if (! gimp_drawable_get_linear (drawable))
+  if (gimp_drawable_get_trc (drawable) != GIMP_TRC_LINEAR)
     {
       const Babl *drawable_format;
       const Babl *cast_format;
@@ -4408,7 +4408,8 @@ wrap_in_gamma_cast (GeglNode     *node,
         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
                           gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
                                                TRUE),
-                          babl_format_has_alpha (drawable_format));
+                          babl_format_has_alpha (drawable_format),
+                          babl_format_get_space (drawable_format));
 
       new_node = gegl_node_new ();
 
diff --git a/plug-ins/common/file-gegl.c b/plug-ins/common/file-gegl.c
index 81943f5398..c77c8ea0c3 100644
--- a/plug-ins/common/file-gegl.c
+++ b/plug-ins/common/file-gegl.c
@@ -353,7 +353,7 @@ load_image (const gchar  *filename,
       else
         image_type = GIMP_INDEXED_IMAGE;
 
-      precision = GIMP_PRECISION_U8_GAMMA;
+      precision = GIMP_PRECISION_U8_NON_LINEAR;
     }
   else
     {
@@ -407,15 +407,15 @@ load_image (const gchar  *filename,
       else
         {
           if (type == babl_type ("u8"))
-            precision = GIMP_PRECISION_U8_GAMMA;
+            precision = GIMP_PRECISION_U8_NON_LINEAR;
           else if (type == babl_type ("u16"))
-            precision = GIMP_PRECISION_U16_GAMMA;
+            precision = GIMP_PRECISION_U16_NON_LINEAR;
           else if (type == babl_type ("u32"))
-            precision = GIMP_PRECISION_U32_GAMMA;
+            precision = GIMP_PRECISION_U32_NON_LINEAR;
           else if (type == babl_type ("half"))
-            precision = GIMP_PRECISION_HALF_GAMMA;
+            precision = GIMP_PRECISION_HALF_NON_LINEAR;
           else
-            precision = GIMP_PRECISION_FLOAT_GAMMA;
+            precision = GIMP_PRECISION_FLOAT_NON_LINEAR;
         }
     }
 
diff --git a/plug-ins/common/file-jp2-load.c b/plug-ins/common/file-jp2-load.c
index 9d2ec66d1f..5c6c6e21b3 100644
--- a/plug-ins/common/file-jp2-load.c
+++ b/plug-ins/common/file-jp2-load.c
@@ -908,15 +908,15 @@ get_image_precision (gint     precision,
       case 32:
         if (linear)
           return GIMP_PRECISION_U32_LINEAR;
-        return GIMP_PRECISION_U32_GAMMA;
+        return GIMP_PRECISION_U32_NON_LINEAR;
       case 16:
         if (linear)
           return GIMP_PRECISION_U16_LINEAR;
-        return GIMP_PRECISION_U16_GAMMA;
+        return GIMP_PRECISION_U16_NON_LINEAR;
       default:
          if (linear)
           return GIMP_PRECISION_U8_LINEAR;
-        return GIMP_PRECISION_U8_GAMMA;
+        return GIMP_PRECISION_U8_NON_LINEAR;
     }
 }
 
diff --git a/plug-ins/common/file-png.c b/plug-ins/common/file-png.c
index 781f727fd5..4fdaefb045 100644
--- a/plug-ins/common/file-png.c
+++ b/plug-ins/common/file-png.c
@@ -959,14 +959,14 @@ load_image (const gchar  *filename,
       if (linear)
         image_precision = GIMP_PRECISION_U16_LINEAR;
       else
-        image_precision = GIMP_PRECISION_U16_GAMMA;
+        image_precision = GIMP_PRECISION_U16_NON_LINEAR;
     }
   else
     {
       if (linear)
         image_precision = GIMP_PRECISION_U8_LINEAR;
       else
-        image_precision = GIMP_PRECISION_U8_GAMMA;
+        image_precision = GIMP_PRECISION_U8_NON_LINEAR;
     }
 
   if (png_get_bit_depth (pp, info) < 8)
@@ -1519,14 +1519,11 @@ save_image (const gchar  *filename,
         linear = FALSE;
       break;
 
-    case GIMP_PRECISION_U8_GAMMA:
+    case GIMP_PRECISION_U8_NON_LINEAR:
+    case GIMP_PRECISION_U8_PERCEPTUAL:
       bit_depth = 8;
 
-    case GIMP_PRECISION_U16_GAMMA:
-    case GIMP_PRECISION_U32_GAMMA:
-    case GIMP_PRECISION_HALF_GAMMA:
-    case GIMP_PRECISION_FLOAT_GAMMA:
-    case GIMP_PRECISION_DOUBLE_GAMMA:
+    default:
       linear = FALSE;
       break;
     }
diff --git a/plug-ins/common/file-pnm.c b/plug-ins/common/file-pnm.c
index 3cd17a9514..6131efde61 100644
--- a/plug-ins/common/file-pnm.c
+++ b/plug-ins/common/file-pnm.c
@@ -661,16 +661,16 @@ load_image (GFile   *file,
                        pnminfo->jmpbuf, _("Unsupported maximum value."));
       if (pnminfo->maxval < 256)
         {
-          precision = GIMP_PRECISION_U8_GAMMA;
+          precision = GIMP_PRECISION_U8_NON_LINEAR;
         }
       else
         {
-          precision = GIMP_PRECISION_U16_GAMMA;
+          precision = GIMP_PRECISION_U16_NON_LINEAR;
         }
     }
   else
     {
-      precision = GIMP_PRECISION_U8_GAMMA;
+      precision = GIMP_PRECISION_U8_NON_LINEAR;
     }
 
   /* Create a new image of the proper size and associate the filename
@@ -1263,7 +1263,8 @@ save_image (GFile     *file,
   switch (gimp_image_get_precision (image_ID))
     {
     case GIMP_PRECISION_U8_LINEAR:
-    case GIMP_PRECISION_U8_GAMMA:
+    case GIMP_PRECISION_U8_NON_LINEAR:
+    case GIMP_PRECISION_U8_PERCEPTUAL:
       rowinfo.bpc = 1;
       break;
     default:
diff --git a/plug-ins/common/file-ps.c b/plug-ins/common/file-ps.c
index 73de9846df..a1beed58a4 100644
--- a/plug-ins/common/file-ps.c
+++ b/plug-ins/common/file-ps.c
@@ -1876,7 +1876,7 @@ create_new_image (const gchar        *filename,
     }
 
   image_ID = gimp_image_new_with_precision (width, height, type,
-                                            GIMP_PRECISION_U8_GAMMA);
+                                            GIMP_PRECISION_U8_NON_LINEAR);
   gimp_image_undo_disable (image_ID);
 
   tmp = g_strdup_printf ("%s-%d", filename, pagenum);
diff --git a/plug-ins/common/file-raw-data.c b/plug-ins/common/file-raw-data.c
index bdd839c1f0..7a8b7d06a0 100644
--- a/plug-ins/common/file-raw-data.c
+++ b/plug-ins/common/file-raw-data.c
@@ -1383,7 +1383,7 @@ load_image (const gchar  *filename,
     data->image_id = gimp_image_new_with_precision (runtime->image_width,
                                                     runtime->image_height,
                                                     itype,
-                                                    GIMP_PRECISION_U16_GAMMA);
+                                                    GIMP_PRECISION_U16_NON_LINEAR);
   else
     data->image_id = gimp_image_new (runtime->image_width,
                                      runtime->image_height,
diff --git a/plug-ins/common/wavelet-decompose.c b/plug-ins/common/wavelet-decompose.c
index f41c6e0f84..7c9e50eea9 100644
--- a/plug-ins/common/wavelet-decompose.c
+++ b/plug-ins/common/wavelet-decompose.c
@@ -216,21 +216,27 @@ run (const gchar      *name,
       switch (gimp_image_get_precision (image_id))
         {
         case GIMP_PRECISION_U8_LINEAR:
-        case GIMP_PRECISION_U8_GAMMA:
+        case GIMP_PRECISION_U8_NON_LINEAR:
+        case GIMP_PRECISION_U8_PERCEPTUAL:
         case GIMP_PRECISION_U16_LINEAR:
-        case GIMP_PRECISION_U16_GAMMA:
+        case GIMP_PRECISION_U16_NON_LINEAR:
+        case GIMP_PRECISION_U16_PERCEPTUAL:
         case GIMP_PRECISION_U32_LINEAR:
-        case GIMP_PRECISION_U32_GAMMA:
+        case GIMP_PRECISION_U32_NON_LINEAR:
+        case GIMP_PRECISION_U32_PERCEPTUAL:
           grain_extract_mode = GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY;
           grain_merge_mode   = GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY;
           break;
 
         case GIMP_PRECISION_HALF_LINEAR:
-        case GIMP_PRECISION_HALF_GAMMA:
+        case GIMP_PRECISION_HALF_NON_LINEAR:
+        case GIMP_PRECISION_HALF_PERCEPTUAL:
         case GIMP_PRECISION_FLOAT_LINEAR:
-        case GIMP_PRECISION_FLOAT_GAMMA:
+        case GIMP_PRECISION_FLOAT_NON_LINEAR:
+        case GIMP_PRECISION_FLOAT_PERCEPTUAL:
         case GIMP_PRECISION_DOUBLE_LINEAR:
-        case GIMP_PRECISION_DOUBLE_GAMMA:
+        case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+        case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
           grain_extract_mode = GIMP_LAYER_MODE_GRAIN_EXTRACT;
           grain_merge_mode   = GIMP_LAYER_MODE_GRAIN_MERGE;
           break;
diff --git a/plug-ins/file-fits/fits.c b/plug-ins/file-fits/fits.c
index acea82ff4d..4f434702e0 100644
--- a/plug-ins/file-fits/fits.c
+++ b/plug-ins/file-fits/fits.c
@@ -573,13 +573,13 @@ load_fits (const gchar *filename,
   switch (hdulist->bitpix)
     {
     case 8:
-      iprecision = GIMP_PRECISION_U8_GAMMA;
+      iprecision = GIMP_PRECISION_U8_NON_LINEAR;
       type = babl_type ("u8");
       datamax = 255.0;
       replacetransform = 1.0;
       break;
     case 16:
-      iprecision = GIMP_PRECISION_U16_GAMMA; /* FIXME precision */
+      iprecision = GIMP_PRECISION_U16_NON_LINEAR; /* FIXME precision */
       type = babl_type ("u16");
       datamax = 65535.0;
       replacetransform = 257;
diff --git a/plug-ins/file-jpeg/jpeg-load.c b/plug-ins/file-jpeg/jpeg-load.c
index 68d8a7078d..69298a2e33 100644
--- a/plug-ins/file-jpeg/jpeg-load.c
+++ b/plug-ins/file-jpeg/jpeg-load.c
@@ -219,7 +219,7 @@ load_image (const gchar  *filename,
       image_ID = gimp_image_new_with_precision (cinfo.output_width,
                                                 cinfo.output_height,
                                                 image_type,
-                                                GIMP_PRECISION_U8_GAMMA);
+                                                GIMP_PRECISION_U8_NON_LINEAR);
 
       gimp_image_undo_disable (image_ID);
       gimp_image_set_filename (image_ID, filename);
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index fbb7d2f169..bab190a975 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -1002,16 +1002,16 @@ create_gimp_image (PSDimage    *img_a,
     switch (img_a->bps)
       {
       case 32:
-        precision = GIMP_PRECISION_U32_GAMMA;
+        precision = GIMP_PRECISION_U32_NON_LINEAR;
         break;
 
       case 16:
-        precision = GIMP_PRECISION_U16_GAMMA;
+        precision = GIMP_PRECISION_U16_NON_LINEAR;
         break;
 
       case 8:
       case 1:
-        precision = GIMP_PRECISION_U8_GAMMA;
+        precision = GIMP_PRECISION_U8_NON_LINEAR;
         break;
 
       default:
diff --git a/plug-ins/file-tiff/file-tiff-load.c b/plug-ins/file-tiff/file-tiff-load.c
index ef73d2f5a3..6d68495385 100644
--- a/plug-ins/file-tiff/file-tiff-load.c
+++ b/plug-ins/file-tiff/file-tiff-load.c
@@ -295,7 +295,7 @@ load_image (GFile              *file,
           if (profile_linear)
             image_precision = GIMP_PRECISION_U8_LINEAR;
           else
-            image_precision = GIMP_PRECISION_U8_GAMMA;
+            image_precision = GIMP_PRECISION_U8_NON_LINEAR;
 
           type = babl_type ("u8");
           break;
@@ -306,7 +306,7 @@ load_image (GFile              *file,
               if (profile_linear)
                 image_precision = GIMP_PRECISION_HALF_LINEAR;
               else
-                image_precision = GIMP_PRECISION_HALF_GAMMA;
+                image_precision = GIMP_PRECISION_HALF_NON_LINEAR;
 
               type = babl_type ("half");
             }
@@ -315,7 +315,7 @@ load_image (GFile              *file,
               if (profile_linear)
                 image_precision = GIMP_PRECISION_U16_LINEAR;
               else
-                image_precision = GIMP_PRECISION_U16_GAMMA;
+                image_precision = GIMP_PRECISION_U16_NON_LINEAR;
 
               type = babl_type ("u16");
             }
@@ -327,7 +327,7 @@ load_image (GFile              *file,
               if (profile_linear)
                 image_precision = GIMP_PRECISION_FLOAT_LINEAR;
               else
-                image_precision = GIMP_PRECISION_FLOAT_GAMMA;
+                image_precision = GIMP_PRECISION_FLOAT_NON_LINEAR;
 
               type = babl_type ("float");
             }
@@ -336,7 +336,7 @@ load_image (GFile              *file,
               if (profile_linear)
                 image_precision = GIMP_PRECISION_U32_LINEAR;
               else
-                image_precision = GIMP_PRECISION_U32_GAMMA;
+                image_precision = GIMP_PRECISION_U32_NON_LINEAR;
 
               type = babl_type ("u32");
             }
@@ -346,7 +346,7 @@ load_image (GFile              *file,
           if (profile_linear)
             image_precision = GIMP_PRECISION_DOUBLE_LINEAR;
           else
-            image_precision = GIMP_PRECISION_DOUBLE_GAMMA;
+            image_precision = GIMP_PRECISION_DOUBLE_NON_LINEAR;
 
           type = babl_type ("double");
           break;
@@ -355,7 +355,7 @@ load_image (GFile              *file,
           if (profile_linear)
             image_precision = GIMP_PRECISION_U16_LINEAR;
           else
-            image_precision = GIMP_PRECISION_U16_GAMMA;
+            image_precision = GIMP_PRECISION_U16_NON_LINEAR;
 
           type = babl_type ("u16");
         }
diff --git a/plug-ins/file-tiff/file-tiff-save.c b/plug-ins/file-tiff/file-tiff-save.c
index 0764872aae..06441fd3b0 100644
--- a/plug-ins/file-tiff/file-tiff-save.c
+++ b/plug-ins/file-tiff/file-tiff-save.c
@@ -344,38 +344,44 @@ save_image (GFile        *file,
         }
       break;
 
-    case GIMP_PRECISION_U8_GAMMA:
+    case GIMP_PRECISION_U8_NON_LINEAR:
+    case GIMP_PRECISION_U8_PERCEPTUAL:
       bitspersample = 8;
       sampleformat  = SAMPLEFORMAT_UINT;
       break;
 
     case GIMP_PRECISION_U16_LINEAR:
-    case GIMP_PRECISION_U16_GAMMA:
+    case GIMP_PRECISION_U16_NON_LINEAR:
+    case GIMP_PRECISION_U16_PERCEPTUAL:
       bitspersample = 16;
       sampleformat  = SAMPLEFORMAT_UINT;
       break;
 
     case GIMP_PRECISION_U32_LINEAR:
-    case GIMP_PRECISION_U32_GAMMA:
+    case GIMP_PRECISION_U32_NON_LINEAR:
+    case GIMP_PRECISION_U32_PERCEPTUAL:
       bitspersample = 32;
       sampleformat  = SAMPLEFORMAT_UINT;
       break;
 
     case GIMP_PRECISION_HALF_LINEAR:
-    case GIMP_PRECISION_HALF_GAMMA:
+    case GIMP_PRECISION_HALF_NON_LINEAR:
+    case GIMP_PRECISION_HALF_PERCEPTUAL:
       bitspersample = 16;
       sampleformat  = SAMPLEFORMAT_IEEEFP;
       break;
 
     default:
     case GIMP_PRECISION_FLOAT_LINEAR:
-    case GIMP_PRECISION_FLOAT_GAMMA:
+    case GIMP_PRECISION_FLOAT_NON_LINEAR:
+    case GIMP_PRECISION_FLOAT_PERCEPTUAL:
       bitspersample = 32;
       sampleformat  = SAMPLEFORMAT_IEEEFP;
       break;
 
     case GIMP_PRECISION_DOUBLE_LINEAR:
-    case GIMP_PRECISION_DOUBLE_GAMMA:
+    case GIMP_PRECISION_DOUBLE_NON_LINEAR:
+    case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
       bitspersample = 64;
       sampleformat  = SAMPLEFORMAT_IEEEFP;
       break;
@@ -399,12 +405,6 @@ save_image (GFile        *file,
       break;
 
     default:
-    case GIMP_PRECISION_U8_GAMMA:
-    case GIMP_PRECISION_U16_GAMMA:
-    case GIMP_PRECISION_U32_GAMMA:
-    case GIMP_PRECISION_HALF_GAMMA:
-    case GIMP_PRECISION_FLOAT_GAMMA:
-    case GIMP_PRECISION_DOUBLE_GAMMA:
       linear = FALSE;
       break;
     }



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