[gimp/soc/2022/cmyk] core: Add softproof profile to GimpImage




commit c16d6a730c00a398c21e5093abf8b7c7f15ff69b
Author: Alx Sa <cmyk student gmail com>
Date:   Tue May 31 20:59:31 2022 +0000

    core: Add softproof profile to GimpImage
    
    Adds a simulation_profile to GimpImage to allow plug-ins to access it
    for CMYK import/export.
    Two pdb functions were added to enable this access:
    image_get_simulation_profile () and image_set_simulation_profile()
    Next, it updates menu options and code to support GimpImage's
    internal simulation profile. Menu items are moved from View to Image's
    Color Management section.
    New 'simulation-profile-changed' signal is emitted via
    GimpColorManagedInterface so that relevant tools (such as the
    CYMK color picker, GimpColorFrame, and future dockable
    dialogue) are aware of these changes.

 app/actions/image-actions.c             | 119 +++++++++++++++--
 app/actions/image-commands.c            | 112 ++++++++++++++++
 app/actions/image-commands.h            |   9 ++
 app/actions/view-actions.c              |  93 +------------
 app/actions/view-commands.c             | 121 -----------------
 app/actions/view-commands.h             |   9 --
 app/core/gimpimage-color-profile.c      |  26 ++++
 app/core/gimpimage-color-profile.h      |   4 +
 app/core/gimpimage-private.h            |   1 +
 app/core/gimpimage.c                    |  33 ++++-
 app/display/gimpdisplayshell-handlers.c |  18 ++-
 app/display/gimpdisplayshell-profile.c  |  41 +-----
 app/display/gimpdisplayshell.c          |  19 ++-
 app/pdb/image-color-profile-cmds.c      | 229 ++++++++++++++++++++++++++++++++
 app/widgets/gimpfgbgeditor.c            |   3 +-
 app/widgets/gimpfgbgview.c              |   3 +-
 app/widgets/gimpviewrenderer.c          |  13 +-
 libgimp/gimp.def                        |   3 +
 libgimp/gimpimagecolorprofile.c         |  69 ++++++++++
 libgimp/gimpimagecolorprofile.h         |   4 +
 libgimp/gimpimagecolorprofile_pdb.c     | 135 +++++++++++++++++++
 libgimp/gimpimagecolorprofile_pdb.h     |  43 +++---
 libgimpcolor/gimpcolor.def              |   2 +
 libgimpcolor/gimpcolormanaged.c         |  53 +++++++-
 libgimpcolor/gimpcolormanaged.h         |  25 ++--
 libgimpwidgets/gimpcolorarea.c          |   3 +-
 libgimpwidgets/gimpcolorscale.c         |   3 +-
 libgimpwidgets/gimpcolorselect.c        |   3 +-
 libgimpwidgets/gimppreviewarea.c        |   3 +-
 libgimpwidgets/gimpwidgetsutils.c       |  14 +-
 libgimpwidgets/gimpwidgetsutils.h       |   3 +-
 menus/image-menu.xml.in                 |  19 +--
 modules/color-selector-water.c          |   3 +-
 modules/gimpcolorwheel.c                |   3 +-
 pdb/groups/image_color_profile.pdb      | 146 ++++++++++++++++++++
 pdb/stddefs.pdb                         |   4 +
 36 files changed, 1066 insertions(+), 325 deletions(-)
---
diff --git a/app/actions/image-actions.c b/app/actions/image-actions.c
index cdfdef7d4b..7ef19056e9 100644
--- a/app/actions/image-actions.c
+++ b/app/actions/image-actions.c
@@ -20,6 +20,7 @@
 #include <gegl.h>
 #include <gtk/gtk.h>
 
+#include "libgimpconfig/gimpconfig.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
 #include "actions-types.h"
@@ -35,6 +36,9 @@
 #include "core/gimpimage-color-profile.h"
 #include "core/gimpitemstack.h"
 
+#include "display/gimpdisplay.h"
+#include "display/gimpdisplayshell.h"
+
 #include "widgets/gimpactiongroup.h"
 #include "widgets/gimphelp-ids.h"
 
@@ -102,12 +106,21 @@ static const GimpActionEntry image_actions[] =
     image_color_profile_discard_cmd_callback,
     GIMP_HELP_IMAGE_COLOR_PROFILE_DISCARD },
 
+  { "image-softproof-profile", NULL,
+    NC_("image-action", "_Softproof Profile..."), NULL,
+    NC_("image-action", "Set the softproofing profile"),
+    image_softproof_profile_cmd_callback,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
+
   { "image-color-profile-save", NULL,
     NC_("image-action", "_Save Color Profile to File..."), NULL,
     NC_("image-action", "Save the image's color profile to an ICC file"),
     image_color_profile_save_cmd_callback,
     GIMP_HELP_IMAGE_COLOR_PROFILE_SAVE },
 
+  { "image-softproof-intent-menu", NULL,
+    NC_("image-action", "Soft-Proofing Re_ndering Intent") },
+
   { "image-resize", GIMP_ICON_OBJECT_RESIZE,
     NC_("image-action", "Can_vas Size..."), NULL,
     NC_("image-action", "Adjust the image dimensions"),
@@ -184,7 +197,14 @@ static const GimpToggleActionEntry image_toggle_actions[] =
         "allows to easily restore the profile."),
     image_color_profile_use_srgb_cmd_callback,
     TRUE,
-    GIMP_HELP_IMAGE_COLOR_PROFILE_USE_SRGB }
+    GIMP_HELP_IMAGE_COLOR_PROFILE_USE_SRGB },
+
+  { "image-softproof-black-point-compensation", NULL,
+    NC_("image-action", "_Black Point Compensation"), NULL,
+    NC_("image-action", "Use black point compensation for soft-proofing"),
+    image_softproof_bpc_cmd_callback,
+    TRUE,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT }
 };
 
 static const GimpRadioActionEntry image_convert_base_type_actions[] =
@@ -301,6 +321,33 @@ static const GimpEnumActionEntry image_rotate_actions[] =
     GIMP_HELP_IMAGE_ROTATE_270 }
 };
 
+static const GimpRadioActionEntry image_softproof_intent_actions[] =
+{
+  { "image-softproof-intent-perceptual", NULL,
+    NC_("image-action", "_Perceptual"), NULL,
+    NC_("image-action", "Soft-proofing rendering intent is perceptual"),
+    GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
+
+  { "image-softproof-intent-relative-colorimetric", NULL,
+    NC_("image-action", "_Relative Colorimetric"), NULL,
+    NC_("image-action", "Soft-proofing rendering intent is relative colorimetric"),
+    GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
+
+  { "image-softproof-intent-saturation", NULL,
+    NC_("image-action", "_Saturation"), NULL,
+    NC_("image-action", "Soft-proofing rendering intent is saturation"),
+    GIMP_COLOR_RENDERING_INTENT_SATURATION,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
+
+  { "image-softproof-intent-absolute-colorimetric", NULL,
+    NC_("image-action", "_Absolute Colorimetric"), NULL,
+    NC_("image-action", "Soft-proofing rendering intent is absolute colorimetric"),
+    GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC,
+    GIMP_HELP_VIEW_COLOR_MANAGEMENT }
+};
+
 
 void
 image_actions_setup (GimpActionGroup *group)
@@ -313,6 +360,13 @@ image_actions_setup (GimpActionGroup *group)
                                         image_toggle_actions,
                                         G_N_ELEMENTS (image_toggle_actions));
 
+  gimp_action_group_add_radio_actions (group, "image-action",
+                                       image_softproof_intent_actions,
+                                       G_N_ELEMENTS (image_softproof_intent_actions),
+                                       NULL,
+                                       GIMP_COLOR_MANAGEMENT_DISPLAY,
+                                       image_softproof_intent_cmd_callback);
+
   gimp_action_group_add_radio_actions (group, "image-convert-action",
                                        image_convert_base_type_actions,
                                        G_N_ELEMENTS (image_convert_base_type_actions),
@@ -355,17 +409,21 @@ void
 image_actions_update (GimpActionGroup *group,
                       gpointer         data)
 {
-  GimpImage *image          = action_data_get_image (data);
-  gboolean   is_indexed     = FALSE;
-  gboolean   is_u8_gamma    = FALSE;
-  gboolean   is_double      = FALSE;
-  gboolean   aux            = FALSE;
-  gboolean   lp             = FALSE;
-  gboolean   sel            = FALSE;
-  gboolean   groups         = FALSE;
-  gboolean   profile_srgb   = FALSE;
-  gboolean   profile_hidden = FALSE;
-  gboolean   profile        = FALSE;
+  GimpImage        *image          = action_data_get_image (data);
+  GimpDisplay      *display        = action_data_get_display (data);
+  GimpDisplayShell *shell          = NULL;
+  GimpColorConfig  *color_config   = NULL;
+  gboolean          is_indexed     = FALSE;
+  gboolean          is_u8_gamma    = FALSE;
+  gboolean          is_double      = FALSE;
+  gboolean          aux            = FALSE;
+  gboolean          lp             = FALSE;
+  gboolean          sel            = FALSE;
+  gboolean          groups         = FALSE;
+  gboolean          profile_srgb   = FALSE;
+  gboolean          profile_hidden = FALSE;
+  gboolean          profile        = FALSE;
+  gboolean          s_bpc          = FALSE;
 
 #define SET_LABEL(action,label) \
         gimp_action_group_set_action_label (group, action, (label))
@@ -445,6 +503,35 @@ image_actions_update (GimpActionGroup *group,
 
       profile_srgb = gimp_image_get_use_srgb_profile (image, &profile_hidden);
       profile      = (gimp_image_get_color_profile (image) != NULL);
+
+      if (display)
+        {
+          shell        = gimp_display_get_shell (display);
+          color_config = gimp_display_shell_get_color_config (shell);
+
+          switch (gimp_color_config_get_simulation_intent (color_config))
+            {
+            case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
+              action = "image-softproof-intent-perceptual";
+              break;
+
+            case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
+              action = "image-softproof-intent-relative-colorimetric";
+              break;
+
+            case GIMP_COLOR_RENDERING_INTENT_SATURATION:
+              action = "image-softproof-intent-saturation";
+              break;
+
+            case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
+              action = "image-softproof-intent-absolute-colorimetric";
+              break;
+            }
+
+          gimp_action_group_set_action_active (group, action, TRUE);
+
+          s_bpc  = gimp_color_config_get_simulation_bpc (color_config);
+        }
     }
   else
     {
@@ -472,6 +559,14 @@ image_actions_update (GimpActionGroup *group,
   SET_SENSITIVE ("image-convert-grayscale", image);
   SET_SENSITIVE ("image-convert-indexed",   image && !groups && is_u8_gamma);
 
+  SET_SENSITIVE ("image-softproof-profile",                      image);
+  SET_SENSITIVE ("image-softproof-intent-perceptual",            image);
+  SET_SENSITIVE ("image-softproof-intent-relative-colorimetric", image);
+  SET_SENSITIVE ("image-softproof-intent-saturation",            image);
+  SET_SENSITIVE ("image-softproof-intent-absolute-colorimetric", image);
+  SET_SENSITIVE ("image-softproof-black-point-compensation",     image);
+  SET_ACTIVE    ("image-softproof-black-point-compensation",     s_bpc);
+
   SET_SENSITIVE ("image-convert-u8",     image);
   SET_SENSITIVE ("image-convert-u16",    image && !is_indexed);
   SET_SENSITIVE ("image-convert-u32",    image && !is_indexed);
diff --git a/app/actions/image-commands.c b/app/actions/image-commands.c
index 323cc60158..7857c2f3a1 100644
--- a/app/actions/image-commands.c
+++ b/app/actions/image-commands.c
@@ -22,6 +22,7 @@
 
 #include "libgimpbase/gimpbase.h"
 #include "libgimpcolor/gimpcolor.h"
+#include "libgimpconfig/gimpconfig.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
 #include "actions-types.h"
@@ -172,6 +173,15 @@ static void   image_merge_layers_callback      (GtkWidget              *dialog,
                                                 gboolean                discard_invisible,
                                                 gpointer                user_data);
 
+static void   image_softproof_profile_callback  (GtkWidget                *dialog,
+                                                 GimpImage                *image,
+                                                 GimpColorProfile         *new_profile,
+                                                 GFile                    *new_file,
+                                                 GimpColorRenderingIntent  intent,
+                                                 gboolean                  bpc,
+                                                 gpointer                  user_data);
+
+
 
 /*  private variables  */
 
@@ -1563,3 +1573,105 @@ image_merge_layers_callback (GtkWidget     *dialog,
 
   g_clear_pointer (&dialog, gtk_widget_destroy);
 }
+
+void
+image_softproof_profile_cmd_callback (GimpAction *action,
+                                      GVariant   *value,
+                                      gpointer    data)
+{
+  GimpImage        *image;
+  GimpDisplayShell *shell;
+  GtkWidget        *dialog;
+  return_if_no_image (image, data);
+  return_if_no_shell (shell, data);
+
+#define SOFTPROOF_PROFILE_DIALOG_KEY "gimp-softproof-profile-dialog"
+
+  dialog = dialogs_get_dialog (G_OBJECT (shell), SOFTPROOF_PROFILE_DIALOG_KEY);
+
+  if (! dialog)
+    {
+      GimpColorProfile *current_profile;
+
+      current_profile = gimp_image_get_simulation_profile (image);
+
+      dialog = color_profile_dialog_new (COLOR_PROFILE_DIALOG_SELECT_SOFTPROOF_PROFILE,
+                                         image,
+                                         action_data_get_context (data),
+                                         GTK_WIDGET (shell),
+                                         current_profile,
+                                         NULL,
+                                         0, 0,
+                                         image_softproof_profile_callback,
+                                         shell);
+
+      dialogs_attach_dialog (G_OBJECT (shell),
+                             SOFTPROOF_PROFILE_DIALOG_KEY, dialog);
+    }
+
+  gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+image_softproof_profile_callback (GtkWidget                *dialog,
+                                  GimpImage                *image,
+                                  GimpColorProfile         *new_profile,
+                                  GFile                    *new_file,
+                                  GimpColorRenderingIntent  intent,
+                                  gboolean                  bpc,
+                                  gpointer                  user_data)
+{
+  GimpDisplayShell *shell = user_data;
+
+  /* Update image's simulation profile */
+  gimp_image_set_simulation_profile (image, new_profile);
+  gimp_color_managed_simulation_profile_changed (GIMP_COLOR_MANAGED (shell));
+
+  gtk_widget_destroy (dialog);
+}
+
+void
+image_softproof_intent_cmd_callback (GimpAction *action,
+                                     GVariant   *value,
+                                     gpointer    data)
+{
+  GimpDisplayShell          *shell;
+  GimpColorConfig           *color_config;
+  GimpColorRenderingIntent   intent;
+  return_if_no_shell (shell, data);
+
+  intent = (GimpColorRenderingIntent) g_variant_get_int32 (value);
+
+  color_config = gimp_display_shell_get_color_config (shell);
+
+  if (intent != gimp_color_config_get_simulation_intent (color_config))
+    {
+      g_object_set (color_config,
+                    "simulation-rendering-intent", intent,
+                    NULL);
+      shell->color_config_set = TRUE;
+    }
+}
+
+void
+image_softproof_bpc_cmd_callback (GimpAction *action,
+                                  GVariant   *value,
+                                  gpointer    data)
+{
+  GimpDisplayShell *shell;
+  GimpColorConfig  *color_config;
+  gboolean          active;
+  return_if_no_shell (shell, data);
+
+  color_config = gimp_display_shell_get_color_config (shell);
+
+  active = g_variant_get_boolean (value);
+
+  if (active != gimp_color_config_get_simulation_bpc (color_config))
+    {
+      g_object_set (color_config,
+                    "simulation-use-black-point-compensation", active,
+                    NULL);
+      shell->color_config_set = TRUE;
+    }
+}
diff --git a/app/actions/image-commands.h b/app/actions/image-commands.h
index 964ffb2ec5..0cc6f5abc7 100644
--- a/app/actions/image-commands.h
+++ b/app/actions/image-commands.h
@@ -97,5 +97,14 @@ void   image_properties_cmd_callback               (GimpAction *action,
                                                     GVariant   *value,
                                                     gpointer    data);
 
+void   image_softproof_profile_cmd_callback          (GimpAction *action,
+                                                      GVariant   *value,
+                                                      gpointer    data);
+void   image_softproof_intent_cmd_callback           (GimpAction *action,
+                                                      GVariant   *value,
+                                                      gpointer    data);
+void   image_softproof_bpc_cmd_callback              (GimpAction *action,
+                                                      GVariant   *value,
+                                                      gpointer    data);
 
 #endif /* __IMAGE_COMMANDS_H__ */
diff --git a/app/actions/view-actions.c b/app/actions/view-actions.c
index 3943eec056..e738ca90b5 100644
--- a/app/actions/view-actions.c
+++ b/app/actions/view-actions.c
@@ -77,9 +77,6 @@ static const GimpActionEntry view_actions[] =
   { "view-display-intent-menu", NULL,
     NC_("view-action", "Display _Rendering Intent") },
 
-  { "view-softproof-intent-menu", NULL,
-    NC_("view-action", "Soft-Proofing Re_ndering Intent") },
-
   { "view-move-to-screen-menu", GIMP_ICON_WINDOW_MOVE_TO_SCREEN,
     NC_("view-action", "Move to Screen"), NULL, NULL, NULL,
     GIMP_HELP_VIEW_CHANGE_SCREEN },
@@ -165,12 +162,6 @@ static const GimpActionEntry view_actions[] =
     view_color_management_reset_cmd_callback,
     GIMP_HELP_VIEW_COLOR_MANAGEMENT },
 
-  { "view-softproof-profile", NULL,
-    NC_("view-action", "Soft-_Proofing Profile..."), NULL,
-    NC_("view-action", "Set the soft-proofing profile"),
-    view_softproof_profile_cmd_callback,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
-
   { "view-shrink-wrap", GIMP_ICON_ZOOM_FIT_BEST,
     NC_("view-action", "Shrink _Wrap"), "<primary>J",
     NC_("view-action", "Reduce the image window to the size of the image display"),
@@ -222,13 +213,6 @@ static const GimpToggleActionEntry view_toggle_actions[] =
     TRUE,
     GIMP_HELP_VIEW_COLOR_MANAGEMENT },
 
-  { "view-softproof-black-point-compensation", NULL,
-    NC_("view-action", "_Black Point Compensation"), NULL,
-    NC_("view-action", "Use black point compensation for soft-proofing"),
-    view_softproof_bpc_cmd_callback,
-    TRUE,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
-
   { "view-softproof-gamut-check", NULL,
     NC_("view-action", "_Mark Out Of Gamut Colors"), NULL,
     NC_("view-action", "When soft-proofing, mark colors which cannot "
@@ -580,33 +564,6 @@ static const GimpRadioActionEntry view_display_intent_actions[] =
     GIMP_HELP_VIEW_COLOR_MANAGEMENT }
 };
 
-static const GimpRadioActionEntry view_softproof_intent_actions[] =
-{
-  { "view-softproof-intent-perceptual", NULL,
-    NC_("view-action", "_Perceptual"), NULL,
-    NC_("view-action", "Soft-proofing rendering intent is perceptual"),
-    GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
-
-  { "view-softproof-intent-relative-colorimetric", NULL,
-    NC_("view-action", "_Relative Colorimetric"), NULL,
-    NC_("view-action", "Soft-proofing rendering intent is relative colorimetric"),
-    GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
-
-  { "view-softproof-intent-saturation", NULL,
-    NC_("view-action", "_Saturation"), NULL,
-    NC_("view-action", "Soft-proofing rendering intent is saturation"),
-    GIMP_COLOR_RENDERING_INTENT_SATURATION,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT },
-
-  { "view-softproof-intent-absolute-colorimetric", NULL,
-    NC_("view-action", "_Absolute Colorimetric"), NULL,
-    NC_("view-action", "Soft-proofing rendering intent is absolute colorimetric"),
-    GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC,
-    GIMP_HELP_VIEW_COLOR_MANAGEMENT }
-};
-
 static const GimpEnumActionEntry view_padding_color_actions[] =
 {
   { "view-padding-color-theme", NULL,
@@ -775,13 +732,6 @@ view_actions_setup (GimpActionGroup *group)
                                        GIMP_COLOR_MANAGEMENT_DISPLAY,
                                        view_display_intent_cmd_callback);
 
-  gimp_action_group_add_radio_actions (group, "view-action",
-                                       view_softproof_intent_actions,
-                                       G_N_ELEMENTS (view_softproof_intent_actions),
-                                       NULL,
-                                       GIMP_COLOR_MANAGEMENT_DISPLAY,
-                                       view_softproof_intent_cmd_callback);
-
   gimp_action_group_add_enum_actions (group, "view-padding-color",
                                       view_padding_color_actions,
                                       G_N_ELEMENTS (view_padding_color_actions),
@@ -813,12 +763,6 @@ view_actions_setup (GimpActionGroup *group)
   g_signal_connect_object (group->gimp->config, "notify::check-type",
                            G_CALLBACK (view_actions_check_type_notify),
                            group, 0);
-  g_signal_connect_object (group->gimp->config, "notify::check-custom-color1",
-                           G_CALLBACK (view_actions_check_type_notify),
-                           group, 0);
-  g_signal_connect_object (group->gimp->config, "notify::check-custom-color2",
-                           G_CALLBACK (view_actions_check_type_notify),
-                           group, 0);
   view_actions_check_type_notify (GIMP_DISPLAY_CONFIG (group->gimp->config),
                                   NULL, group);
 
@@ -851,8 +795,7 @@ view_actions_update (GimpActionGroup *group,
   gboolean            cm                = FALSE;
   gboolean            sp                = FALSE;
   gboolean            d_bpc             = FALSE;
-  gboolean            s_bpc             = FALSE;
-  gboolean            gammut            = FALSE;
+  gboolean            gamut             = FALSE;
 
   if (display)
     {
@@ -913,30 +856,8 @@ view_actions_update (GimpActionGroup *group,
 
       gimp_action_group_set_action_active (group, action, TRUE);
 
-      switch (gimp_color_config_get_simulation_intent (color_config))
-        {
-        case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
-          action = "view-softproof-intent-perceptual";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
-          action = "view-softproof-intent-relative-colorimetric";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_SATURATION:
-          action = "view-softproof-intent-saturation";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
-          action = "view-softproof-intent-absolute-colorimetric";
-          break;
-        }
-
-      gimp_action_group_set_action_active (group, action, TRUE);
-
       d_bpc  = gimp_color_config_get_display_bpc (color_config);
-      s_bpc  = gimp_color_config_get_simulation_bpc (color_config);
-      gammut = gimp_color_config_get_simulation_gamut_check (color_config);
+      gamut  = gimp_color_config_get_simulation_gamut_check (color_config);
     }
 
 #define SET_ACTIVE(action,condition) \
@@ -1038,15 +959,7 @@ view_actions_update (GimpActionGroup *group,
   SET_SENSITIVE ("view-display-intent-absolute-colorimetric",   cm);
   SET_SENSITIVE ("view-display-black-point-compensation",       cm);
   SET_ACTIVE    ("view-display-black-point-compensation",       d_bpc);
-  SET_SENSITIVE ("view-softproof-profile",                      sp);
-  SET_SENSITIVE ("view-softproof-intent-perceptual",            sp);
-  SET_SENSITIVE ("view-softproof-intent-relative-colorimetric", sp);
-  SET_SENSITIVE ("view-softproof-intent-saturation",            sp);
-  SET_SENSITIVE ("view-softproof-intent-absolute-colorimetric", sp);
-  SET_SENSITIVE ("view-softproof-black-point-compensation",     sp);
-  SET_ACTIVE    ("view-softproof-black-point-compensation",     s_bpc);
-  SET_SENSITIVE ("view-softproof-gamut-check",                  sp);
-  SET_ACTIVE    ("view-softproof-gamut-check",                  gammut);
+  SET_ACTIVE    ("view-softproof-gamut-check",                  gamut);
   SET_SENSITIVE ("view-color-management-reset",                 image);
 
   SET_SENSITIVE ("view-show-selection",       image);
diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c
index 0f6fdc0b7e..ecb0f4a129 100644
--- a/app/actions/view-commands.c
+++ b/app/actions/view-commands.c
@@ -76,13 +76,6 @@
 
 /*  local function prototypes  */
 
-static void   view_softproof_profile_callback  (GtkWidget                *dialog,
-                                                GimpImage                *image,
-                                                GimpColorProfile         *new_profile,
-                                                GFile                    *new_file,
-                                                GimpColorRenderingIntent  intent,
-                                                gboolean                  bpc,
-                                                gpointer                  user_data);
 static void   view_padding_color_dialog_update (GimpColorDialog          *dialog,
                                                 const GimpRGB            *color,
                                                 GimpColorDialogState      state,
@@ -737,94 +730,6 @@ view_display_bpc_cmd_callback (GimpAction *action,
     }
 }
 
-void
-view_softproof_profile_cmd_callback (GimpAction *action,
-                                     GVariant   *value,
-                                     gpointer    data)
-{
-  GimpImage        *image;
-  GimpDisplayShell *shell;
-  GimpColorConfig  *color_config;
-  GtkWidget        *dialog;
-  return_if_no_image (image, data);
-  return_if_no_shell (shell, data);
-
-  color_config = gimp_display_shell_get_color_config (shell);
-
-#define SOFTPROOF_PROFILE_DIALOG_KEY "gimp-softproof-profile-dialog"
-
-  dialog = dialogs_get_dialog (G_OBJECT (shell), SOFTPROOF_PROFILE_DIALOG_KEY);
-
-  if (! dialog)
-    {
-      GimpColorProfile *current_profile;
-
-      current_profile = gimp_color_config_get_simulation_color_profile (color_config,
-                                                                        NULL);
-
-      dialog = color_profile_dialog_new (COLOR_PROFILE_DIALOG_SELECT_SOFTPROOF_PROFILE,
-                                         image,
-                                         action_data_get_context (data),
-                                         GTK_WIDGET (shell),
-                                         current_profile,
-                                         NULL,
-                                         0, 0,
-                                         view_softproof_profile_callback,
-                                         shell);
-
-      dialogs_attach_dialog (G_OBJECT (shell),
-                             SOFTPROOF_PROFILE_DIALOG_KEY, dialog);
-    }
-
-  gtk_window_present (GTK_WINDOW (dialog));
-}
-
-void
-view_softproof_intent_cmd_callback (GimpAction *action,
-                                    GVariant   *value,
-                                    gpointer    data)
-{
-  GimpDisplayShell          *shell;
-  GimpColorConfig           *color_config;
-  GimpColorRenderingIntent   intent;
-  return_if_no_shell (shell, data);
-
-  intent = (GimpColorRenderingIntent) g_variant_get_int32 (value);
-
-  color_config = gimp_display_shell_get_color_config (shell);
-
-  if (intent != gimp_color_config_get_simulation_intent (color_config))
-    {
-      g_object_set (color_config,
-                    "simulation-rendering-intent", intent,
-                    NULL);
-      shell->color_config_set = TRUE;
-    }
-}
-
-void
-view_softproof_bpc_cmd_callback (GimpAction *action,
-                                 GVariant   *value,
-                                 gpointer    data)
-{
-  GimpDisplayShell *shell;
-  GimpColorConfig  *color_config;
-  gboolean          active;
-  return_if_no_shell (shell, data);
-
-  color_config = gimp_display_shell_get_color_config (shell);
-
-  active = g_variant_get_boolean (value);
-
-  if (active != gimp_color_config_get_simulation_bpc (color_config))
-    {
-      g_object_set (color_config,
-                    "simulation-use-black-point-compensation", active,
-                    NULL);
-      shell->color_config_set = TRUE;
-    }
-}
-
 void
 view_softproof_gamut_check_cmd_callback (GimpAction *action,
                                          GVariant   *value,
@@ -1247,32 +1152,6 @@ view_fullscreen_cmd_callback (GimpAction *action,
 
 /*  private functions  */
 
-static void
-view_softproof_profile_callback (GtkWidget                *dialog,
-                                 GimpImage                *image,
-                                 GimpColorProfile         *new_profile,
-                                 GFile                    *new_file,
-                                 GimpColorRenderingIntent  intent,
-                                 gboolean                  bpc,
-                                 gpointer                  user_data)
-{
-  GimpDisplayShell *shell = user_data;
-  GimpColorConfig  *color_config;
-  gchar            *path  = NULL;
-
-  color_config = gimp_display_shell_get_color_config (shell);
-
-  if (new_file)
-    path = g_file_get_path (new_file);
-
-  g_object_set (color_config,
-                "simulation-profile", path,
-                NULL);
-  shell->color_config_set = TRUE;
-
-  gtk_widget_destroy (dialog);
-}
-
 static void
 view_padding_color_dialog_update (GimpColorDialog      *dialog,
                                   const GimpRGB        *color,
diff --git a/app/actions/view-commands.h b/app/actions/view-commands.h
index b1c8d36679..51af901bb7 100644
--- a/app/actions/view-commands.h
+++ b/app/actions/view-commands.h
@@ -114,15 +114,6 @@ void   view_display_intent_cmd_callback             (GimpAction *action,
 void   view_display_bpc_cmd_callback                (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
-void   view_softproof_profile_cmd_callback          (GimpAction *action,
-                                                     GVariant   *value,
-                                                     gpointer    data);
-void   view_softproof_intent_cmd_callback           (GimpAction *action,
-                                                     GVariant   *value,
-                                                     gpointer    data);
-void   view_softproof_bpc_cmd_callback              (GimpAction *action,
-                                                     GVariant   *value,
-                                                     gpointer    data);
 void   view_softproof_gamut_check_cmd_callback      (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
diff --git a/app/core/gimpimage-color-profile.c b/app/core/gimpimage-color-profile.c
index f3e5c8dfdd..64f868818d 100644
--- a/app/core/gimpimage-color-profile.c
+++ b/app/core/gimpimage-color-profile.c
@@ -391,6 +391,32 @@ gimp_image_set_color_profile (GimpImage         *image,
   return gimp_image_set_icc_profile (image, data, length, error);
 }
 
+GimpColorProfile *
+gimp_image_get_simulation_profile (GimpImage *image)
+{
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  return GIMP_IMAGE_GET_PRIVATE (image)->simulation_profile;
+}
+
+void
+gimp_image_set_simulation_profile (GimpImage         *image,
+                                   GimpColorProfile  *profile)
+{
+  GimpImagePrivate *private;
+
+  g_return_if_fail (GIMP_IS_IMAGE (image));
+  g_return_if_fail (profile == NULL || GIMP_IS_COLOR_PROFILE (profile));
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  if (profile != private->simulation_profile)
+    {
+      g_set_object (&private->simulation_profile, profile);
+      gimp_color_managed_simulation_profile_changed (GIMP_COLOR_MANAGED (image));
+    }
+}
+
 gboolean
 gimp_image_validate_color_profile_by_format (const Babl         *format,
                                              GimpColorProfile   *profile,
diff --git a/app/core/gimpimage-color-profile.h b/app/core/gimpimage-color-profile.h
index 863c41bda7..6548d36c1e 100644
--- a/app/core/gimpimage-color-profile.h
+++ b/app/core/gimpimage-color-profile.h
@@ -64,6 +64,10 @@ gboolean             gimp_image_set_color_profile      (GimpImage           *ima
                                                         GimpColorProfile    *profile,
                                                         GError             **error);
 
+GimpColorProfile   * gimp_image_get_simulation_profile (GimpImage           *image);
+void                 gimp_image_set_simulation_profile (GimpImage           *image,
+                                                        GimpColorProfile    *profile);
+
 gboolean             gimp_image_validate_color_profile_by_format
                                                        (const Babl          *format,
                                                         GimpColorProfile    *profile,
diff --git a/app/core/gimpimage-private.h b/app/core/gimpimage-private.h
index 80e42dbd32..2beda44946 100644
--- a/app/core/gimpimage-private.h
+++ b/app/core/gimpimage-private.h
@@ -63,6 +63,7 @@ struct _GimpImagePrivate
   GimpColorProfile  *color_profile;         /*  image's color profile        */
   const Babl        *layer_space;           /*  image's Babl layer space     */
   GimpColorProfile  *hidden_profile;        /*  hidden by "use sRGB"         */
+  GimpColorProfile  *simulation_profile;    /*  image's softproof profile    */
 
   /*  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 a249e3dc4d..1e5d4d9b00 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -198,6 +198,11 @@ static GimpColorProfile *
 static void
         gimp_image_color_managed_profile_changed (GimpColorManaged  *managed);
 
+static GimpColorProfile *
+      gimp_image_color_managed_get_simulation_profile     (GimpColorManaged  *managed);
+static void
+      gimp_image_color_managed_simulation_profile_changed (GimpColorManaged  *managed);
+
 static void        gimp_image_projectable_flush  (GimpProjectable   *projectable,
                                                   gboolean           invalidate_preview);
 static GeglRectangle gimp_image_get_bounding_box (GimpProjectable   *projectable);
@@ -697,9 +702,11 @@ gimp_image_class_init (GimpImageClass *klass)
 static void
 gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
 {
-  iface->get_icc_profile   = gimp_image_color_managed_get_icc_profile;
-  iface->get_color_profile = gimp_image_color_managed_get_color_profile;
-  iface->profile_changed   = gimp_image_color_managed_profile_changed;
+  iface->get_icc_profile            = gimp_image_color_managed_get_icc_profile;
+  iface->get_color_profile          = gimp_image_color_managed_get_color_profile;
+  iface->profile_changed            = gimp_image_color_managed_profile_changed;
+  iface->get_simulation_profile     = gimp_image_color_managed_get_simulation_profile;
+  iface->simulation_profile_changed = gimp_image_color_managed_simulation_profile_changed;
 }
 
 static void
@@ -1438,6 +1445,26 @@ gimp_image_color_managed_profile_changed (GimpColorManaged *managed)
   gimp_item_stack_profile_changed (layers);
 }
 
+static GimpColorProfile *
+gimp_image_color_managed_get_simulation_profile (GimpColorManaged *managed)
+{
+  GimpImage        *image = GIMP_IMAGE (managed);
+  GimpColorProfile *profile;
+
+  profile = gimp_image_get_simulation_profile (image);
+
+  return profile;
+}
+
+static void
+gimp_image_color_managed_simulation_profile_changed (GimpColorManaged *managed)
+{
+  GimpImage *image = GIMP_IMAGE (managed);
+
+  gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
+  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (image));
+}
+
 static void
 gimp_image_projectable_flush (GimpProjectable *projectable,
                               gboolean         invalidate_preview)
diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c
index 0cc0915456..ad8f69b0e0 100644
--- a/app/display/gimpdisplayshell-handlers.c
+++ b/app/display/gimpdisplayshell-handlers.c
@@ -129,6 +129,9 @@ static void   gimp_display_shell_precision_changed_handler  (GimpImage        *i
                                                              GimpDisplayShell *shell);
 static void   gimp_display_shell_profile_changed_handler    (GimpColorManaged *image,
                                                              GimpDisplayShell *shell);
+static void   gimp_display_shell_simulation_profile_changed_handler
+                                                            (GimpColorManaged *image,
+                                                             GimpDisplayShell *shell);
 static void   gimp_display_shell_saved_handler              (GimpImage        *image,
                                                              GFile            *file,
                                                              GimpDisplayShell *shell);
@@ -282,6 +285,9 @@ gimp_display_shell_connect (GimpDisplayShell *shell)
   g_signal_connect (image, "profile-changed",
                     G_CALLBACK (gimp_display_shell_profile_changed_handler),
                     shell);
+  g_signal_connect (image, "simulation-profile-changed",
+                    G_CALLBACK (gimp_display_shell_simulation_profile_changed_handler),
+                    shell);
   g_signal_connect (image, "saved",
                     G_CALLBACK (gimp_display_shell_saved_handler),
                     shell);
@@ -519,6 +525,9 @@ gimp_display_shell_disconnect (GimpDisplayShell *shell)
   g_signal_handlers_disconnect_by_func (image,
                                         gimp_display_shell_profile_changed_handler,
                                         shell);
+  g_signal_handlers_disconnect_by_func (image,
+                                        gimp_display_shell_simulation_profile_changed_handler,
+                                        shell);
   g_signal_handlers_disconnect_by_func (image,
                                         gimp_display_shell_precision_changed_handler,
                                         shell);
@@ -923,6 +932,14 @@ gimp_display_shell_profile_changed_handler (GimpColorManaged *image,
   gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell));
 }
 
+static void
+gimp_display_shell_simulation_profile_changed_handler (GimpColorManaged *image,
+                                                       GimpDisplayShell *shell)
+{
+  gimp_display_shell_profile_update (shell);
+  gimp_color_managed_simulation_profile_changed (GIMP_COLOR_MANAGED (shell));
+}
+
 static void
 gimp_display_shell_saved_handler (GimpImage        *image,
                                   GFile            *file,
@@ -1190,7 +1207,6 @@ gimp_display_shell_color_config_notify_handler (GObject          *config,
       if (! strcmp (param_spec->name, "mode")                                 ||
           ! strcmp (param_spec->name, "display-rendering-intent")             ||
           ! strcmp (param_spec->name, "display-use-black-point-compensation") ||
-          ! strcmp (param_spec->name, "simulation-profile")                   ||
           ! strcmp (param_spec->name, "simulation-rendering-intent")          ||
           ! strcmp (param_spec->name, "simulation-use-black-point-compensation") ||
           ! strcmp (param_spec->name, "simulation-gamut-check"))
diff --git a/app/display/gimpdisplayshell-profile.c b/app/display/gimpdisplayshell-profile.c
index df6c4b144b..2eb457bde3 100644
--- a/app/display/gimpdisplayshell-profile.c
+++ b/app/display/gimpdisplayshell-profile.c
@@ -89,6 +89,7 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
   GimpColorProfile *filter_profile;
   const Babl       *filter_format;
   const Babl       *dest_format;
+  GimpColorProfile *proof_profile;
 
   gimp_display_shell_profile_free (shell);
 
@@ -102,6 +103,8 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
   if (! src_profile)
     return;
 
+  proof_profile = gimp_color_managed_get_simulation_profile (GIMP_COLOR_MANAGED (image));
+
   src_format = gimp_projectable_get_format (GIMP_PROJECTABLE (image));
 
   if (gimp_display_shell_has_filter (shell))
@@ -154,7 +157,8 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
                                      gimp_display_shell_get_color_config (shell),
                                      filter_profile,
                                      filter_format,
-                                     dest_format);
+                                     dest_format,
+                                     proof_profile);
 
   if (shell->filter_transform || shell->profile_transform)
     {
@@ -261,7 +265,7 @@ gimp_display_shell_color_config_notify (GimpColorConfig  *config,
           break;
         }
 
-      SET_ACTIVE ("view-color-management-enable",    managed);
+      SET_ACTIVE ("view-color-management-enable", managed);
       SET_ACTIVE ("view-color-management-softproof", softproof);
 
       switch (gimp_color_config_get_display_intent (config))
@@ -293,39 +297,6 @@ gimp_display_shell_color_config_notify (GimpColorConfig  *config,
       SET_SENSITIVE ("view-display-black-point-compensation", managed);
       SET_ACTIVE    ("view-display-black-point-compensation",
                      gimp_color_config_get_display_bpc (config));
-
-      SET_SENSITIVE ("view-softproof-profile", softproof);
-
-      switch (gimp_color_config_get_simulation_intent (config))
-        {
-        case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
-          action = "view-softproof-intent-perceptual";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
-          action = "view-softproof-intent-relative-colorimetric";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_SATURATION:
-          action = "view-softproof-intent-saturation";
-          break;
-
-        case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
-          action = "view-softproof-intent-absolute-colorimetric";
-          break;
-        }
-
-      SET_SENSITIVE ("view-softproof-intent-perceptual",            softproof);
-      SET_SENSITIVE ("view-softproof-intent-relative-colorimetric", softproof);
-      SET_SENSITIVE ("view-softproof-intent-saturation",            softproof);
-      SET_SENSITIVE ("view-softproof-intent-absolute-colorimetric", softproof);
-
-      SET_ACTIVE (action, TRUE);
-
-      SET_SENSITIVE ("view-softproof-black-point-compensation", softproof);
-      SET_ACTIVE    ("view-softproof-black-point-compensation",
-                     gimp_color_config_get_simulation_bpc (config));
-
       SET_SENSITIVE ("view-softproof-gamut-check", softproof);
       SET_ACTIVE    ("view-softproof-gamut-check",
                      gimp_color_config_get_simulation_gamut_check (config));
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 066d935c25..1cd00c5c21 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -162,6 +162,8 @@ static const guint8 *
 static GimpColorProfile *
                gimp_display_shell_get_color_profile(GimpColorManaged *managed);
 static void      gimp_display_shell_profile_changed(GimpColorManaged *managed);
+static void    gimp_display_shell_simulation_profile_changed
+                                                   (GimpColorManaged *managed);
 
 static void      gimp_display_shell_zoom_button_callback
                                                    (GimpDisplayShell *shell,
@@ -303,9 +305,10 @@ gimp_display_shell_class_init (GimpDisplayShellClass *klass)
 static void
 gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
 {
-  iface->get_icc_profile   = gimp_display_shell_get_icc_profile;
-  iface->get_color_profile = gimp_display_shell_get_color_profile;
-  iface->profile_changed   = gimp_display_shell_profile_changed;
+  iface->get_icc_profile            = gimp_display_shell_get_icc_profile;
+  iface->get_color_profile          = gimp_display_shell_get_color_profile;
+  iface->profile_changed            = gimp_display_shell_profile_changed;
+  iface->simulation_profile_changed = gimp_display_shell_simulation_profile_changed;
 }
 
 static void
@@ -1084,6 +1087,15 @@ gimp_display_shell_profile_changed (GimpColorManaged *managed)
   gimp_display_shell_render_invalidate_full (shell);
 }
 
+static void
+gimp_display_shell_simulation_profile_changed (GimpColorManaged *managed)
+{
+  GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (managed);
+
+  gimp_display_shell_expose_full (shell);
+  gimp_display_shell_render_invalidate_full (shell);
+}
+
 static void
 gimp_display_shell_zoom_button_callback (GimpDisplayShell *shell,
                                          GtkWidget        *zoom_button)
@@ -1356,6 +1368,7 @@ gimp_display_shell_reconnect (GimpDisplayShell *shell)
   g_signal_emit (shell, display_shell_signals[RECONNECT], 0);
 
   gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell));
+  gimp_display_shell_simulation_profile_changed (GIMP_COLOR_MANAGED (shell));
 
   gimp_display_shell_scroll_clamp_and_update (shell);
 
diff --git a/app/pdb/image-color-profile-cmds.c b/app/pdb/image-color-profile-cmds.c
index ba57055d31..4c88157515 100644
--- a/app/pdb/image-color-profile-cmds.c
+++ b/app/pdb/image-color-profile-cmds.c
@@ -226,6 +226,138 @@ image_set_color_profile_from_file_invoker (GimpProcedure         *procedure,
                                            error ? *error : NULL);
 }
 
+static GimpValueArray *
+image_get_simulation_profile_invoker (GimpProcedure         *procedure,
+                                      Gimp                  *gimp,
+                                      GimpContext           *context,
+                                      GimpProgress          *progress,
+                                      const GimpValueArray  *args,
+                                      GError               **error)
+{
+  gboolean success = TRUE;
+  GimpValueArray *return_vals;
+  GimpImage *image;
+  gint num_bytes = 0;
+  guint8 *profile_data = NULL;
+
+  image = g_value_get_object (gimp_value_array_index (args, 0));
+
+  if (success)
+    {
+      GimpColorProfile *profile;
+
+      profile = gimp_image_get_simulation_profile (image);
+
+      if (profile)
+        {
+          const guint8 *data;
+          gsize         length;
+
+          data = gimp_color_profile_get_icc_profile (profile, &length);
+
+          profile_data = g_memdup2 (data, length);
+          num_bytes = length;
+        }
+    }
+
+  return_vals = gimp_procedure_get_return_values (procedure, success,
+                                                  error ? *error : NULL);
+
+  if (success)
+    {
+      g_value_set_int (gimp_value_array_index (return_vals, 1), num_bytes);
+      gimp_value_take_uint8_array (gimp_value_array_index (return_vals, 2), profile_data, num_bytes);
+    }
+
+  return return_vals;
+}
+
+static GimpValueArray *
+image_set_simulation_profile_invoker (GimpProcedure         *procedure,
+                                      Gimp                  *gimp,
+                                      GimpContext           *context,
+                                      GimpProgress          *progress,
+                                      const GimpValueArray  *args,
+                                      GError               **error)
+{
+  gboolean success = TRUE;
+  GimpImage *image;
+  gint num_bytes;
+  const guint8 *color_profile;
+
+  image = g_value_get_object (gimp_value_array_index (args, 0));
+  num_bytes = g_value_get_int (gimp_value_array_index (args, 1));
+  color_profile = gimp_value_get_uint8_array (gimp_value_array_index (args, 2));
+
+  if (success)
+    {
+      if (color_profile)
+        {
+          GimpColorProfile *profile;
+
+          profile = gimp_color_profile_new_from_icc_profile (color_profile,
+                                                             num_bytes,
+                                                             error);
+
+          if (profile)
+            {
+              gimp_image_set_simulation_profile (image, profile);
+              g_object_unref (profile);
+            }
+          else
+            success = FALSE;
+        }
+      else
+        {
+          gimp_image_set_simulation_profile (image, NULL);
+        }
+    }
+
+  return gimp_procedure_get_return_values (procedure, success,
+                                           error ? *error : NULL);
+}
+
+static GimpValueArray *
+image_set_simulation_profile_from_file_invoker (GimpProcedure         *procedure,
+                                                Gimp                  *gimp,
+                                                GimpContext           *context,
+                                                GimpProgress          *progress,
+                                                const GimpValueArray  *args,
+                                                GError               **error)
+{
+  gboolean success = TRUE;
+  GimpImage *image;
+  GFile *file;
+
+  image = g_value_get_object (gimp_value_array_index (args, 0));
+  file = g_value_get_object (gimp_value_array_index (args, 1));
+
+  if (success)
+    {
+      if (file)
+        {
+          GimpColorProfile *profile;
+
+          profile = gimp_color_profile_new_from_file (file, error);
+
+          if (profile)
+            {
+              gimp_image_set_simulation_profile (image, profile);
+              g_object_unref (profile);
+            }
+          else
+            success = FALSE;
+        }
+      else
+        {
+          gimp_image_set_simulation_profile (image, NULL);
+        }
+    }
+
+  return gimp_procedure_get_return_values (procedure, success,
+                                           error ? *error : NULL);
+}
+
 static GimpValueArray *
 image_convert_color_profile_invoker (GimpProcedure         *procedure,
                                      Gimp                  *gimp,
@@ -456,6 +588,103 @@ register_image_color_profile_procs (GimpPDB *pdb)
   gimp_pdb_register_procedure (pdb, procedure);
   g_object_unref (procedure);
 
+  /*
+   * gimp-image-get-simulation-profile
+   */
+  procedure = gimp_procedure_new (image_get_simulation_profile_invoker);
+  gimp_object_set_static_name (GIMP_OBJECT (procedure),
+                               "gimp-image-get-simulation-profile");
+  gimp_procedure_set_static_help (procedure,
+                                  "Returns the image's simulation color profile",
+                                  "This procedure returns the image's simulation color profile, or NULL if 
the image has no simulation color profile assigned.",
+                                  NULL);
+  gimp_procedure_set_static_attribution (procedure,
+                                         "Alex S.",
+                                         "Alex S.",
+                                         "2022");
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_image ("image",
+                                                      "image",
+                                                      "The image",
+                                                      FALSE,
+                                                      GIMP_PARAM_READWRITE));
+  gimp_procedure_add_return_value (procedure,
+                                   g_param_spec_int ("num-bytes",
+                                                     "num bytes",
+                                                     "Number of bytes in the color_profile array",
+                                                     0, G_MAXINT32, 0,
+                                                     GIMP_PARAM_READWRITE));
+  gimp_procedure_add_return_value (procedure,
+                                   gimp_param_spec_uint8_array ("profile-data",
+                                                                "profile data",
+                                                                "The image's serialized simulation color 
profile.",
+                                                                GIMP_PARAM_READWRITE));
+  gimp_pdb_register_procedure (pdb, procedure);
+  g_object_unref (procedure);
+
+  /*
+   * gimp-image-set-simulation-profile
+   */
+  procedure = gimp_procedure_new (image_set_simulation_profile_invoker);
+  gimp_object_set_static_name (GIMP_OBJECT (procedure),
+                               "gimp-image-set-simulation-profile");
+  gimp_procedure_set_static_help (procedure,
+                                  "Sets the image's simulation color profile",
+                                  "This procedure sets the image's simulation 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.",
+                                  NULL);
+  gimp_procedure_set_static_attribution (procedure,
+                                         "Alex S.",
+                                         "Alex S.",
+                                         "2022");
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_image ("image",
+                                                      "image",
+                                                      "The image",
+                                                      FALSE,
+                                                      GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               g_param_spec_int ("num-bytes",
+                                                 "num bytes",
+                                                 "Number of bytes in the color_profile array",
+                                                 0, G_MAXINT32, 0,
+                                                 GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_uint8_array ("color-profile",
+                                                            "color profile",
+                                                            "The new serialized simulation color profile",
+                                                            GIMP_PARAM_READWRITE));
+  gimp_pdb_register_procedure (pdb, procedure);
+  g_object_unref (procedure);
+
+  /*
+   * gimp-image-set-simulation-profile-from-file
+   */
+  procedure = gimp_procedure_new (image_set_simulation_profile_from_file_invoker);
+  gimp_object_set_static_name (GIMP_OBJECT (procedure),
+                               "gimp-image-set-simulation-profile-from-file");
+  gimp_procedure_set_static_help (procedure,
+                                  "Sets the image's simulation color profile from an ICC file",
+                                  "This procedure sets the image's simulation color profile from a file 
containing an ICC profile, or unsets it if NULL is passed as 'file'. 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.",
+                                  NULL);
+  gimp_procedure_set_static_attribution (procedure,
+                                         "Alex S.",
+                                         "Alex S.",
+                                         "2022");
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_image ("image",
+                                                      "image",
+                                                      "The image",
+                                                      FALSE,
+                                                      GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               g_param_spec_object ("file",
+                                                    "file",
+                                                    "The file containing the new simulation color profile",
+                                                    G_TYPE_FILE,
+                                                    GIMP_PARAM_READWRITE));
+  gimp_pdb_register_procedure (pdb, procedure);
+  g_object_unref (procedure);
+
   /*
    * gimp-image-convert-color-profile
    */
diff --git a/app/widgets/gimpfgbgeditor.c b/app/widgets/gimpfgbgeditor.c
index c7f319292a..b0d51df77d 100644
--- a/app/widgets/gimpfgbgeditor.c
+++ b/app/widgets/gimpfgbgeditor.c
@@ -794,7 +794,8 @@ gimp_fg_bg_editor_create_transform (GimpFgBgEditor *editor)
                                          editor->color_config,
                                          profile,
                                          babl_format ("R'G'B'A double"),
-                                         babl_format ("R'G'B'A double"));
+                                         babl_format ("R'G'B'A double"),
+                                         NULL);
     }
 }
 
diff --git a/app/widgets/gimpfgbgview.c b/app/widgets/gimpfgbgview.c
index 9c60418211..7da1803dc6 100644
--- a/app/widgets/gimpfgbgview.c
+++ b/app/widgets/gimpfgbgview.c
@@ -255,7 +255,8 @@ gimp_fg_bg_view_create_transform (GimpFgBgView *view)
                                          view->color_config,
                                          profile,
                                          babl_format ("R'G'B'A double"),
-                                         babl_format ("R'G'B'A double"));
+                                         babl_format ("R'G'B'A double"),
+                                         NULL);
     }
 }
 
diff --git a/app/widgets/gimpviewrenderer.c b/app/widgets/gimpviewrenderer.c
index a5061f90b8..8edfe4d547 100644
--- a/app/widgets/gimpviewrenderer.c
+++ b/app/widgets/gimpviewrenderer.c
@@ -1029,6 +1029,8 @@ gimp_view_renderer_get_color_transform (GimpViewRenderer *renderer,
                                         const Babl       *dest_format)
 {
   GimpColorProfile *profile;
+  GimpColorProfile *proof_profile = NULL;
+  GimpImage        *image;
 
   g_return_val_if_fail (GIMP_IS_VIEW_RENDERER (renderer), NULL);
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
@@ -1060,12 +1062,21 @@ gimp_view_renderer_get_color_transform (GimpViewRenderer *renderer,
       profile = srgb_profile;
     }
 
+  if (renderer->context)
+    {
+      image = gimp_context_get_image (GIMP_CONTEXT (renderer->context));
+      if (image)
+        proof_profile =
+          gimp_color_managed_get_simulation_profile (GIMP_COLOR_MANAGED (image));
+    }
+
   renderer->priv->profile_transform =
     gimp_widget_get_color_transform (widget,
                                      renderer->priv->color_config,
                                      profile,
                                      src_format,
-                                     dest_format);
+                                     dest_format,
+                                     proof_profile);
 
   return renderer->priv->profile_transform;
 }
diff --git a/libgimp/gimp.def b/libgimp/gimp.def
index b05044bb11..0cde15376d 100644
--- a/libgimp/gimp.def
+++ b/libgimp/gimp.def
@@ -420,6 +420,7 @@ EXPORTS
        gimp_image_get_sample_point_position
        gimp_image_get_selected_layers
        gimp_image_get_selection
+       gimp_image_get_simulation_profile
        gimp_image_get_tattoo_state
        gimp_image_get_thumbnail
        gimp_image_get_thumbnail_data
@@ -498,6 +499,8 @@ EXPORTS
        gimp_image_set_metadata
        gimp_image_set_resolution
        gimp_image_set_selected_layers
+       gimp_image_set_simulation_profile
+       gimp_image_set_simulation_profile_from_file
        gimp_image_set_tattoo_state
        gimp_image_set_unit
        gimp_image_take_selected_layers
diff --git a/libgimp/gimpimagecolorprofile.c b/libgimp/gimpimagecolorprofile.c
index bb22bd5ce8..6850e410d7 100644
--- a/libgimp/gimpimagecolorprofile.c
+++ b/libgimp/gimpimagecolorprofile.c
@@ -92,6 +92,75 @@ gimp_image_set_color_profile (GimpImage        *image,
   return _gimp_image_set_color_profile (image, length, data);
 }
 
+/**
+ * gimp_image_get_simulation_profile:
+ * @image: The image.
+ *
+ * Returns the image's simulation color profile
+ *
+ * This procedure returns the image's simulation color profile, or NULL if
+ * the image has no simulation color profile assigned.
+ *
+ * Returns: (transfer full): The image's simulation color profile. The
+ *          returned value must be freed with g_object_unref().
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_image_get_simulation_profile (GimpImage *image)
+{
+  guint8 *data;
+  gint    length;
+
+  data = _gimp_image_get_simulation_profile (image, &length);
+
+  if (data)
+    {
+      GimpColorProfile *profile;
+
+      profile = gimp_color_profile_new_from_icc_profile (data, length, NULL);
+      g_free (data);
+
+      return profile;
+    }
+
+  return NULL;
+}
+
+/**
+ * gimp_image_set_simulation_profile:
+ * @image:   The image.
+ * @profile: A #GimpColorProfile, or %NULL.
+ *
+ * Sets the image's simulation color profile
+ *
+ * This procedure sets the image's simulation color profile.
+ *
+ * Returns: %TRUE on success.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_image_set_simulation_profile (GimpImage        *image,
+                                   GimpColorProfile *profile)
+{
+  const guint8 *data   = NULL;
+  gint          length = 0;
+
+  g_return_val_if_fail (profile == NULL || GIMP_IS_COLOR_PROFILE (profile),
+                        FALSE);
+
+  if (profile)
+    {
+      gsize l;
+
+      data = gimp_color_profile_get_icc_profile (profile, &l);
+      length = l;
+    }
+
+  return _gimp_image_set_simulation_profile (image, length, data);
+}
+
 /**
  * gimp_image_get_effective_color_profile:
  * @image: The image.
diff --git a/libgimp/gimpimagecolorprofile.h b/libgimp/gimpimagecolorprofile.h
index 63ae015f04..92e4e60123 100644
--- a/libgimp/gimpimagecolorprofile.h
+++ b/libgimp/gimpimagecolorprofile.h
@@ -34,6 +34,10 @@ GimpColorProfile * gimp_image_get_color_profile           (GimpImage
 gboolean           gimp_image_set_color_profile           (GimpImage                 *image,
                                                            GimpColorProfile          *profile);
 
+GimpColorProfile * gimp_image_get_simulation_profile      (GimpImage                 *image);
+gboolean           gimp_image_set_simulation_profile      (GimpImage                 *image,
+                                                           GimpColorProfile          *profile);
+
 GimpColorProfile * gimp_image_get_effective_color_profile (GimpImage                 *image);
 
 gboolean           gimp_image_convert_color_profile       (GimpImage                 *image,
diff --git a/libgimp/gimpimagecolorprofile_pdb.c b/libgimp/gimpimagecolorprofile_pdb.c
index e2f761d40b..d5c948c55d 100644
--- a/libgimp/gimpimagecolorprofile_pdb.c
+++ b/libgimp/gimpimagecolorprofile_pdb.c
@@ -220,6 +220,141 @@ gimp_image_set_color_profile_from_file (GimpImage *image,
   return success;
 }
 
+/**
+ * _gimp_image_get_simulation_profile:
+ * @image: The image.
+ * @num_bytes: (out): Number of bytes in the color_profile array.
+ *
+ * Returns the image's simulation color profile
+ *
+ * This procedure returns the image's simulation color profile, or NULL
+ * if the image has no simulation color profile assigned.
+ *
+ * Returns: (array length=num_bytes) (element-type guint8) (transfer full):
+ *          The image's serialized simulation color profile.
+ *          The returned value must be freed with g_free().
+ *
+ * Since: 3.0
+ **/
+guint8 *
+_gimp_image_get_simulation_profile (GimpImage *image,
+                                    gint      *num_bytes)
+{
+  GimpValueArray *args;
+  GimpValueArray *return_vals;
+  guint8 *profile_data = NULL;
+
+  args = gimp_value_array_new_from_types (NULL,
+                                          GIMP_TYPE_IMAGE, image,
+                                          G_TYPE_NONE);
+
+  return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (),
+                                              "gimp-image-get-simulation-profile",
+                                              args);
+  gimp_value_array_unref (args);
+
+  *num_bytes = 0;
+
+  if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS)
+    {
+      *num_bytes = GIMP_VALUES_GET_INT (return_vals, 1);
+      profile_data = GIMP_VALUES_DUP_UINT8_ARRAY (return_vals, 2);
+    }
+
+  gimp_value_array_unref (return_vals);
+
+  return profile_data;
+}
+
+/**
+ * _gimp_image_set_simulation_profile:
+ * @image: The image.
+ * @num_bytes: Number of bytes in the color_profile array.
+ * @color_profile: (array length=num_bytes) (element-type guint8): The new serialized simulation color 
profile.
+ *
+ * Sets the image's simulation color profile
+ *
+ * This procedure sets the image's simulation 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.
+ *
+ * Returns: TRUE on success.
+ *
+ * Since: 3.0
+ **/
+gboolean
+_gimp_image_set_simulation_profile (GimpImage    *image,
+                                    gint          num_bytes,
+                                    const guint8 *color_profile)
+{
+  GimpValueArray *args;
+  GimpValueArray *return_vals;
+  gboolean success = TRUE;
+
+  args = gimp_value_array_new_from_types (NULL,
+                                          GIMP_TYPE_IMAGE, image,
+                                          G_TYPE_INT, num_bytes,
+                                          GIMP_TYPE_UINT8_ARRAY, NULL,
+                                          G_TYPE_NONE);
+  gimp_value_set_uint8_array (gimp_value_array_index (args, 2), color_profile, num_bytes);
+
+  return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (),
+                                              "gimp-image-set-simulation-profile",
+                                              args);
+  gimp_value_array_unref (args);
+
+  success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
+
+  gimp_value_array_unref (return_vals);
+
+  return success;
+}
+
+/**
+ * gimp_image_set_simulation_profile_from_file:
+ * @image: The image.
+ * @file: The file containing the new simulation color profile.
+ *
+ * Sets the image's simulation color profile from an ICC file
+ *
+ * This procedure sets the image's simulation color profile from a file
+ * containing an ICC profile, or unsets it if NULL is passed as 'file'.
+ * 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.
+ *
+ * Returns: TRUE on success.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gimp_image_set_simulation_profile_from_file (GimpImage *image,
+                                             GFile     *file)
+{
+  GimpValueArray *args;
+  GimpValueArray *return_vals;
+  gboolean success = TRUE;
+
+  args = gimp_value_array_new_from_types (NULL,
+                                          GIMP_TYPE_IMAGE, image,
+                                          G_TYPE_FILE, file,
+                                          G_TYPE_NONE);
+
+  return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (),
+                                              "gimp-image-set-simulation-profile-from-file",
+                                              args);
+  gimp_value_array_unref (args);
+
+  success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
+
+  gimp_value_array_unref (return_vals);
+
+  return success;
+}
+
 /**
  * _gimp_image_convert_color_profile:
  * @image: The image.
diff --git a/libgimp/gimpimagecolorprofile_pdb.h b/libgimp/gimpimagecolorprofile_pdb.h
index 0731a9eb1e..ac49fc8f9f 100644
--- a/libgimp/gimpimagecolorprofile_pdb.h
+++ b/libgimp/gimpimagecolorprofile_pdb.h
@@ -32,24 +32,31 @@ G_BEGIN_DECLS
 /* For information look into the C source or the html documentation */
 
 
-G_GNUC_INTERNAL guint8*  _gimp_image_get_color_profile              (GimpImage                *image,
-                                                                     gint                     *num_bytes);
-G_GNUC_INTERNAL guint8*  _gimp_image_get_effective_color_profile    (GimpImage                *image,
-                                                                     gint                     *num_bytes);
-G_GNUC_INTERNAL gboolean _gimp_image_set_color_profile              (GimpImage                *image,
-                                                                     gint                      num_bytes,
-                                                                     const guint8             
*color_profile);
-gboolean                 gimp_image_set_color_profile_from_file     (GimpImage                *image,
-                                                                     GFile                    *file);
-G_GNUC_INTERNAL gboolean _gimp_image_convert_color_profile          (GimpImage                *image,
-                                                                     gint                      num_bytes,
-                                                                     const guint8             *color_profile,
-                                                                     GimpColorRenderingIntent  intent,
-                                                                     gboolean                  bpc);
-gboolean                 gimp_image_convert_color_profile_from_file (GimpImage                *image,
-                                                                     GFile                    *file,
-                                                                     GimpColorRenderingIntent  intent,
-                                                                     gboolean                  bpc);
+G_GNUC_INTERNAL guint8*  _gimp_image_get_color_profile               (GimpImage                *image,
+                                                                      gint                     *num_bytes);
+G_GNUC_INTERNAL guint8*  _gimp_image_get_effective_color_profile     (GimpImage                *image,
+                                                                      gint                     *num_bytes);
+G_GNUC_INTERNAL gboolean _gimp_image_set_color_profile               (GimpImage                *image,
+                                                                      gint                      num_bytes,
+                                                                      const guint8             
*color_profile);
+gboolean                 gimp_image_set_color_profile_from_file      (GimpImage                *image,
+                                                                      GFile                    *file);
+G_GNUC_INTERNAL guint8*  _gimp_image_get_simulation_profile          (GimpImage                *image,
+                                                                      gint                     *num_bytes);
+G_GNUC_INTERNAL gboolean _gimp_image_set_simulation_profile          (GimpImage                *image,
+                                                                      gint                      num_bytes,
+                                                                      const guint8             
*color_profile);
+gboolean                 gimp_image_set_simulation_profile_from_file (GimpImage                *image,
+                                                                      GFile                    *file);
+G_GNUC_INTERNAL gboolean _gimp_image_convert_color_profile           (GimpImage                *image,
+                                                                      gint                      num_bytes,
+                                                                      const guint8             
*color_profile,
+                                                                      GimpColorRenderingIntent  intent,
+                                                                      gboolean                  bpc);
+gboolean                 gimp_image_convert_color_profile_from_file  (GimpImage                *image,
+                                                                      GFile                    *file,
+                                                                      GimpColorRenderingIntent  intent,
+                                                                      gboolean                  bpc);
 
 
 G_END_DECLS
diff --git a/libgimpcolor/gimpcolor.def b/libgimpcolor/gimpcolor.def
index 47dbb99c57..7b40b20570 100644
--- a/libgimpcolor/gimpcolor.def
+++ b/libgimpcolor/gimpcolor.def
@@ -21,8 +21,10 @@ EXPORTS
        gimp_cmyka_set_uchar
        gimp_color_managed_get_color_profile
        gimp_color_managed_get_icc_profile
+       gimp_color_managed_get_simulation_profile
        gimp_color_managed_get_type
        gimp_color_managed_profile_changed
+       gimp_color_managed_simulation_profile_changed
        gimp_color_profile_get_copyright
        gimp_color_profile_get_description
        gimp_color_profile_get_format
diff --git a/libgimpcolor/gimpcolormanaged.c b/libgimpcolor/gimpcolormanaged.c
index dca1fdbae8..4dc5a3e213 100644
--- a/libgimpcolor/gimpcolormanaged.c
+++ b/libgimpcolor/gimpcolormanaged.c
@@ -42,6 +42,7 @@
 enum
 {
   PROFILE_CHANGED,
+  SIMULATION_PROFILE_CHANGED,
   LAST_SIGNAL
 };
 
@@ -66,6 +67,15 @@ gimp_color_managed_default_init (GimpColorManagedInterface *iface)
                                    profile_changed),
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 0);
+
+  gimp_color_managed_signals[SIMULATION_PROFILE_CHANGED] =
+    g_signal_new ("simulation-profile-changed",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpColorManagedInterface,
+                                   simulation_profile_changed),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
 }
 
 
@@ -128,9 +138,34 @@ gimp_color_managed_get_color_profile (GimpColorManaged *managed)
 }
 
 /**
- * gimp_color_managed_profile_changed:
+ * gimp_color_managed_get_simulation_profile:
  * @managed: an object the implements the #GimpColorManaged interface
  *
+ * This function always returns a #GimpColorProfile
+ *
+ * Returns: (transfer full): The @managed's simulation #GimpColorProfile.
+ *
+ * Since: 3.0
+ **/
+GimpColorProfile *
+gimp_color_managed_get_simulation_profile (GimpColorManaged *managed)
+{
+  GimpColorManagedInterface *iface;
+
+  g_return_val_if_fail (GIMP_IS_COLOR_MANAGED (managed), NULL);
+
+  iface = GIMP_COLOR_MANAGED_GET_IFACE (managed);
+
+  if (iface->get_simulation_profile)
+    return iface->get_simulation_profile (managed);
+
+  return NULL;
+}
+
+/**
+ * gimp_color_managed_profile_changed:
+ * @managed: an object that implements the #GimpColorManaged interface
+ *
  * Emits the "profile-changed" signal.
  *
  * Since: 2.4
@@ -142,3 +177,19 @@ gimp_color_managed_profile_changed (GimpColorManaged *managed)
 
   g_signal_emit (managed, gimp_color_managed_signals[PROFILE_CHANGED], 0);
 }
+
+/**
+ * gimp_color_managed_simulation_profile_changed:
+ * @managed: an object that implements the #GimpColorManaged interface
+ *
+ * Emits the "simulation-profile-changed" signal.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_color_managed_simulation_profile_changed (GimpColorManaged *managed)
+{
+  g_return_if_fail (GIMP_IS_COLOR_MANAGED (managed));
+
+  g_signal_emit (managed, gimp_color_managed_signals[SIMULATION_PROFILE_CHANGED], 0);
+}
diff --git a/libgimpcolor/gimpcolormanaged.h b/libgimpcolor/gimpcolormanaged.h
index b6a473b509..cf36ffad7c 100644
--- a/libgimpcolor/gimpcolormanaged.h
+++ b/libgimpcolor/gimpcolormanaged.h
@@ -43,6 +43,8 @@ G_DECLARE_INTERFACE (GimpColorManaged, gimp_color_managed, GIMP, COLOR_MANAGED,
  *                   has changed
  * @get_color_profile: Returns the #GimpColorProfile of the pixels managed
  *                     by the object
+ * @get_simulation_profile: Returns the simulation #GimpColorProfile of the
+ *                          pixels managed by the object
  **/
 struct _GimpColorManagedInterface
 {
@@ -58,22 +60,29 @@ struct _GimpColorManagedInterface
    *
    * Since: 2.4
    */
-  const guint8     * (* get_icc_profile)   (GimpColorManaged *managed,
-                                            gsize            *len);
+  const guint8     * (* get_icc_profile)            (GimpColorManaged *managed,
+                                                     gsize            *len);
 
   /*  signals  */
-  void               (* profile_changed)   (GimpColorManaged *managed);
+  void               (* profile_changed)            (GimpColorManaged *managed);
+
+  void               (* simulation_profile_changed) (GimpColorManaged *managed);
 
   /*  virtual functions  */
-  GimpColorProfile * (* get_color_profile) (GimpColorManaged *managed);
+  GimpColorProfile * (* get_color_profile)      (GimpColorManaged *managed);
+  GimpColorProfile * (* get_simulation_profile) (GimpColorManaged *managed);
 };
 
 
-const guint8     * gimp_color_managed_get_icc_profile   (GimpColorManaged *managed,
-                                                         gsize            *len);
-GimpColorProfile * gimp_color_managed_get_color_profile (GimpColorManaged *managed);
+const guint8     * gimp_color_managed_get_icc_profile            (GimpColorManaged *managed,
+                                                                  gsize            *len);
+GimpColorProfile * gimp_color_managed_get_color_profile          (GimpColorManaged *managed);
+
+GimpColorProfile * gimp_color_managed_get_simulation_profile     (GimpColorManaged *managed);
+
+void               gimp_color_managed_profile_changed            (GimpColorManaged *managed);
 
-void               gimp_color_managed_profile_changed   (GimpColorManaged *managed);
+void               gimp_color_managed_simulation_profile_changed (GimpColorManaged *managed);
 
 
 G_END_DECLS
diff --git a/libgimpwidgets/gimpcolorarea.c b/libgimpwidgets/gimpcolorarea.c
index 0ea20d82ba..604d2e9c23 100644
--- a/libgimpwidgets/gimpcolorarea.c
+++ b/libgimpwidgets/gimpcolorarea.c
@@ -1024,7 +1024,8 @@ gimp_color_area_create_transform (GimpColorArea *area)
                                                          priv->config,
                                                          profile,
                                                          format,
-                                                         format);
+                                                         format,
+                                                         NULL);
     }
 }
 
diff --git a/libgimpwidgets/gimpcolorscale.c b/libgimpwidgets/gimpcolorscale.c
index 7d4f6ffc45..0bf7f665fe 100644
--- a/libgimpwidgets/gimpcolorscale.c
+++ b/libgimpwidgets/gimpcolorscale.c
@@ -942,7 +942,8 @@ gimp_color_scale_create_transform (GimpColorScale *scale)
                                                          priv->config,
                                                          profile,
                                                          format,
-                                                         format);
+                                                         format,
+                                                         NULL);
     }
 }
 
diff --git a/libgimpwidgets/gimpcolorselect.c b/libgimpwidgets/gimpcolorselect.c
index d4b2b1ad03..af7a119f29 100644
--- a/libgimpwidgets/gimpcolorselect.c
+++ b/libgimpwidgets/gimpcolorselect.c
@@ -1956,7 +1956,8 @@ gimp_color_select_create_transform (GimpColorSelect *select)
                                                            select->config,
                                                            profile,
                                                            format,
-                                                           format);
+                                                           format,
+                                                           NULL);
     }
 }
 
diff --git a/libgimpwidgets/gimppreviewarea.c b/libgimpwidgets/gimppreviewarea.c
index 7bc7bc393b..424d0c1246 100644
--- a/libgimpwidgets/gimppreviewarea.c
+++ b/libgimpwidgets/gimppreviewarea.c
@@ -437,7 +437,8 @@ gimp_preview_area_create_transform (GimpPreviewArea *area)
                                                          priv->config,
                                                          profile,
                                                          format,
-                                                         format);
+                                                         format,
+                                                         NULL);
     }
 }
 
diff --git a/libgimpwidgets/gimpwidgetsutils.c b/libgimpwidgets/gimpwidgetsutils.c
index 4c46e83d04..bc7038bf9a 100644
--- a/libgimpwidgets/gimpwidgetsutils.c
+++ b/libgimpwidgets/gimpwidgetsutils.c
@@ -870,11 +870,12 @@ gimp_widget_get_color_transform (GtkWidget        *widget,
                                  GimpColorConfig  *config,
                                  GimpColorProfile *src_profile,
                                  const Babl       *src_format,
-                                 const Babl       *dest_format)
+                                 const Babl       *dest_format,
+                                 GimpColorProfile *softproof_profile)
 {
   static gboolean     initialized   = FALSE;
-  GimpColorProfile   *dest_profile  = NULL;
   GimpColorProfile   *proof_profile = NULL;
+  GimpColorProfile   *dest_profile  = NULL;
   TransformCache     *cache;
 
   g_return_val_if_fail (widget == NULL || GTK_IS_WIDGET (widget), NULL);
@@ -896,8 +897,11 @@ gimp_widget_get_color_transform (GtkWidget        *widget,
       return NULL;
 
     case GIMP_COLOR_MANAGEMENT_SOFTPROOF:
-      proof_profile = gimp_color_config_get_simulation_color_profile (config,
-                                                                      NULL);
+      if (! softproof_profile)
+        proof_profile = gimp_color_config_get_simulation_color_profile (config,
+                                                                        NULL);
+      else
+        proof_profile = softproof_profile;
       /*  fallthru  */
 
     case GIMP_COLOR_MANAGEMENT_DISPLAY:
@@ -943,7 +947,7 @@ gimp_widget_get_color_transform (GtkWidget        *widget,
   cache->src_format    = src_format;
   cache->dest_profile  = dest_profile;
   cache->dest_format   = dest_format;
-  cache->proof_profile = proof_profile;
+  cache->proof_profile = g_object_ref (proof_profile);
 
   cache->notify_id =
     g_signal_connect (cache->config, "notify",
diff --git a/libgimpwidgets/gimpwidgetsutils.h b/libgimpwidgets/gimpwidgetsutils.h
index b75d60808a..7de3e18cd4 100644
--- a/libgimpwidgets/gimpwidgetsutils.h
+++ b/libgimpwidgets/gimpwidgetsutils.h
@@ -60,7 +60,8 @@ GimpColorTransform * gimp_widget_get_color_transform (GtkWidget         *widget,
                                                       GimpColorConfig   *config,
                                                       GimpColorProfile  *src_profile,
                                                       const Babl        *src_format,
-                                                      const Babl        *dest_format);
+                                                      const Babl        *dest_format,
+                                                      GimpColorProfile  *softproof_profile);
 
 
 G_END_DECLS
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index f9b7b5c262..4216acf6b3 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -320,16 +320,7 @@
        </menu>
         <menuitem action="view-display-black-point-compensation" />
         <separator />
-        <menuitem action="view-softproof-profile" />
-       <menu action="view-softproof-intent-menu" name="Softproof Rendering Intent">
-          <menuitem action="view-softproof-intent-perceptual" />
-          <menuitem action="view-softproof-intent-relative-colorimetric" />
-          <menuitem action="view-softproof-intent-saturation" />
-          <menuitem action="view-softproof-intent-absolute-colorimetric" />
-       </menu>
-        <menuitem action="view-softproof-black-point-compensation" />
         <menuitem action="view-softproof-gamut-check" />
-        <separator />
         <menuitem action="view-color-management-reset" />
       </menu>
       <separator />
@@ -394,6 +385,16 @@
         <menuitem action="image-color-profile-discard" />
         <separator />
         <menuitem action="image-color-profile-save" />
+        <separator />
+        <menuitem action="image-softproof-profile" />
+        <separator />
+    <menu action="image-softproof-intent-menu" name="Softproof Rendering Intent">
+          <menuitem action="image-softproof-intent-perceptual" />
+          <menuitem action="image-softproof-intent-relative-colorimetric" />
+          <menuitem action="image-softproof-intent-saturation" />
+          <menuitem action="image-softproof-intent-absolute-colorimetric" />
+       </menu>
+        <menuitem action="image-softproof-black-point-compensation" />
      </menu>
       <separator />
       <menu action="image-transform-menu" name="Transform">
diff --git a/modules/color-selector-water.c b/modules/color-selector-water.c
index 65a207486d..ee04e6e48b 100644
--- a/modules/color-selector-water.c
+++ b/modules/color-selector-water.c
@@ -268,7 +268,8 @@ colorsel_water_create_transform (ColorselWater *water)
                                                           water->config,
                                                           profile,
                                                           format,
-                                                          format);
+                                                          format,
+                                                          NULL);
     }
 }
 
diff --git a/modules/gimpcolorwheel.c b/modules/gimpcolorwheel.c
index 90d1ee95b2..3f35ef86bd 100644
--- a/modules/gimpcolorwheel.c
+++ b/modules/gimpcolorwheel.c
@@ -1551,7 +1551,8 @@ gimp_color_wheel_create_transform (GimpColorWheel *wheel)
                                                          priv->config,
                                                          profile,
                                                          format,
-                                                         format);
+                                                         format,
+                                                         NULL);
     }
 }
 
diff --git a/pdb/groups/image_color_profile.pdb b/pdb/groups/image_color_profile.pdb
index 1f9231ca13..3bf8e9abb0 100644
--- a/pdb/groups/image_color_profile.pdb
+++ b/pdb/groups/image_color_profile.pdb
@@ -213,6 +213,149 @@ CODE
     );
 }
 
+sub image_get_simulation_profile {
+    $blurb = "Returns the image's simulation color profile";
+
+    $help = <<'HELP';
+This procedure returns the image's simulation color profile, or NULL if the image
+has no simulation color profile assigned.
+HELP
+
+    &alxsa_pdb_misc('2022', '3.0');
+
+    $lib_private = 1;
+
+    @inargs = (
+        { name => 'image', type => 'image',
+          desc => 'The image' }
+    );
+
+    @outargs = (
+        { name => 'profile_data', type => 'int8array',
+          desc => "The image's serialized simulation color profile.",
+          array => { name => 'num_bytes',
+                     desc => 'Number of bytes in the color_profile array' } }
+    );
+
+    %invoke = (
+        code => <<'CODE'
+{
+  GimpColorProfile *profile;
+
+  profile = gimp_image_get_simulation_profile (image);
+
+  if (profile)
+    {
+      const guint8 *data;
+      gsize         length;
+
+      data = gimp_color_profile_get_icc_profile (profile, &length);
+
+      profile_data = g_memdup2 (data, length);
+      num_bytes = length;
+    }
+}
+CODE
+    );
+}
+
+sub image_set_simulation_profile {
+    $blurb = "Sets the image's simulation color profile";
+
+    $help = <<'HELP';
+This procedure sets the image's simulation color profile, or unsets it if NULL is
+passed as 'color_profile'. This procedure does no color conversion.
+HELP
+
+    &alxsa_pdb_misc('2022', '3.0');
+
+    $lib_private = 1;
+
+    @inargs = (
+        { name => 'image', type => 'image',
+          desc => 'The image' },
+        { name => 'color_profile', type => 'int8array',
+          desc => 'The new serialized simulation color profile',
+          array => { name => 'num_bytes',
+                     desc => 'Number of bytes in the color_profile array' } }
+    );
+
+    %invoke = (
+        code => <<'CODE'
+{
+  if (color_profile)
+    {
+      GimpColorProfile *profile;
+
+      profile = gimp_color_profile_new_from_icc_profile (color_profile,
+                                                         num_bytes,
+                                                         error);
+
+      if (profile)
+        {
+          gimp_image_set_simulation_profile (image, profile);
+          g_object_unref (profile);
+        }
+      else
+        {
+          success = FALSE;
+        }
+    }
+  else
+    {
+      gimp_image_set_simulation_profile (image, NULL);
+    }
+}
+CODE
+    );
+}
+
+sub image_set_simulation_profile_from_file {
+    $blurb = "Sets the image's simulation color profile from an ICC file";
+
+    $help = <<'HELP';
+This procedure sets the image's simulation color profile from a file containing
+an ICC profile, or unsets it if NULL is passed as 'file'. This
+procedure does no color conversion.
+HELP
+
+    &alxsa_pdb_misc('2022', '3.0');
+
+    @inargs = (
+        { name => 'image', type => 'image',
+          desc => 'The image' },
+        { name => 'file', type => 'file',
+          desc => 'The file containing the new simulation color profile' }
+    );
+
+    %invoke = (
+        code => <<'CODE'
+{
+  if (file)
+    {
+      GimpColorProfile *profile;
+
+      profile = gimp_color_profile_new_from_file (file, error);
+
+      if (profile)
+        {
+          gimp_image_set_simulation_profile (image, profile);
+          g_object_unref (profile);
+        }
+      else
+        {
+          success = FALSE;
+        }
+    }
+  else
+    {
+      gimp_image_set_simulation_profile (image, NULL);
+    }
+}
+CODE
+    );
+}
+
 sub image_convert_color_profile {
     $blurb = "Convert the image's layers to a color profile";
 
@@ -326,6 +469,9 @@ CODE
             image_get_effective_color_profile
             image_set_color_profile
             image_set_color_profile_from_file
+            image_get_simulation_profile
+            image_set_simulation_profile
+            image_set_simulation_profile_from_file
             image_convert_color_profile
             image_convert_color_profile_from_file);
 
diff --git a/pdb/stddefs.pdb b/pdb/stddefs.pdb
index 9c7a7ac49d..6e9fd4ce9c 100644
--- a/pdb/stddefs.pdb
+++ b/pdb/stddefs.pdb
@@ -165,6 +165,10 @@ sub yosh_pdb_misc {
     contrib_pdb_misc('Manish Singh', '', @_);
 }
 
+sub alxsa_pdb_misc {
+    contrib_pdb_misc('Alex S.', '', @_);
+}
+
 sub std_pdb_deprecated {
     if (@_) {
         $blurb = $help = '';


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