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




commit 9456f4968d4715295b6404d859cf04126ccd420f
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      | 233 ++++++++++++++++++++++++++++++++
 app/pdb/internal-procs.c                |   2 +-
 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     | 130 ++++++++++++++++++
 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 +
 37 files changed, 1066 insertions(+), 326 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..bba265d574 100644
--- a/app/pdb/image-color-profile-cmds.c
+++ b/app/pdb/image-color-profile-cmds.c
@@ -226,6 +226,142 @@ 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 +592,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.",
+                                  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.",
+                                  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/pdb/internal-procs.c b/app/pdb/internal-procs.c
index 9671f5263b..1fa6c26fde 100644
--- a/app/pdb/internal-procs.c
+++ b/app/pdb/internal-procs.c
@@ -30,7 +30,7 @@
 #include "internal-procs.h"
 
 
-/* 762 procedures registered total */
+/* 765 procedures registered total */
 
 void
 internal_procs_init (GimpPDB *pdb)
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..08504f6e01 100644
--- a/libgimp/gimpimagecolorprofile_pdb.c
+++ b/libgimp/gimpimagecolorprofile_pdb.c
@@ -220,6 +220,136 @@ 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.
+ *
+ * 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.
+ *
+ * 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]