[gimp] Bug 766988 - Colors applied to images are not color managed



commit 483c282687375a4a4161833c1b49349034746742
Author: Michael Natterer <mitch gimp org>
Date:   Mon Nov 7 15:39:48 2016 +0100

    Bug 766988 - Colors applied to images are not color managed
    
    Add color management to GimpDrawableFilter and GimpFilterTool, GEGL
    ops applied to drawables can be applied in color managed space
    now. Sadly, this is very slow, so disabled by default.
    
    I'm sure the profile guessing based on the operation's format doesn't
    always work, but this general bug counts as fixed now.

 app/core/gimpdrawablefilter.c |   98 +++++++++++++++++++++++++++++++++++++++++
 app/core/gimpdrawablefilter.h |    3 +
 app/tools/gimpfilteroptions.c |   17 +++++++
 app/tools/gimpfilteroptions.h |    1 +
 app/tools/gimpfiltertool.c    |   43 +++++++++++++++---
 5 files changed, 156 insertions(+), 6 deletions(-)
---
diff --git a/app/core/gimpdrawablefilter.c b/app/core/gimpdrawablefilter.c
index 64ba871..032f95e 100644
--- a/app/core/gimpdrawablefilter.c
+++ b/app/core/gimpdrawablefilter.c
@@ -32,11 +32,13 @@
 #include <gegl.h>
 
 #include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
 
 #include "core-types.h"
 
 #include "gegl/gimp-babl.h"
 #include "gegl/gimpapplicator.h"
+#include "gegl/gimp-gegl-utils.h"
 
 #include "gimpchannel.h"
 #include "gimpdrawable-filters.h"
@@ -66,6 +68,7 @@ struct _GimpDrawableFilter
   gdouble               preview_position;
   gdouble               opacity;
   GimpLayerModeEffects  paint_mode;
+  gboolean              color_managed;
   gboolean              gamma_hack;
 
   GeglRectangle         filter_area;
@@ -73,6 +76,8 @@ struct _GimpDrawableFilter
   GeglNode             *translate;
   GeglNode             *crop;
   GeglNode             *cast_before;
+  GeglNode             *transform_before;
+  GeglNode             *transform_after;
   GeglNode             *cast_after;
   GimpApplicator       *applicator;
 };
@@ -90,6 +95,7 @@ static void       gimp_drawable_filter_sync_opacity     (GimpDrawableFilter  *fi
 static void       gimp_drawable_filter_sync_mode        (GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_sync_affect      (GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_sync_mask        (GimpDrawableFilter  *filter);
+static void       gimp_drawable_filter_sync_transform   (GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_sync_gamma_hack  (GimpDrawableFilter  *filter);
 
 static gboolean   gimp_drawable_filter_is_filtering     (GimpDrawableFilter  *filter);
@@ -104,6 +110,8 @@ static void       gimp_drawable_filter_affect_changed   (GimpImage           *im
                                                          GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_mask_changed     (GimpImage           *image,
                                                          GimpDrawableFilter  *filter);
+static void       gimp_drawable_filter_profile_changed  (GimpColorManaged    *managed,
+                                                         GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_drawable_removed (GimpDrawable        *drawable,
                                                          GimpDrawableFilter  *filter);
 
@@ -223,6 +231,12 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
   filter->cast_before = gegl_node_new_child (node,
                                              "operation", "gegl:nop",
                                              NULL);
+  filter->transform_before = gegl_node_new_child (node,
+                                                  "operation", "gegl:nop",
+                                                  NULL);
+  filter->transform_after = gegl_node_new_child (node,
+                                                 "operation", "gegl:nop",
+                                                 NULL);
   filter->cast_after = gegl_node_new_child (node,
                                             "operation", "gegl:nop",
                                             NULL);
@@ -235,11 +249,13 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
                            filter->translate,
                            filter->crop,
                            filter->cast_before,
+                           filter->transform_before,
                            filter->operation,
                            NULL);
     }
 
   gegl_node_link_many (filter->operation,
+                       filter->transform_after,
                        filter->cast_after,
                        NULL);
 
@@ -333,6 +349,23 @@ gimp_drawable_filter_set_mode (GimpDrawableFilter   *filter,
 }
 
 void
+gimp_drawable_filter_set_color_managed (GimpDrawableFilter *filter,
+                                        gboolean            color_managed)
+{
+  g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
+
+  if (color_managed != filter->color_managed)
+    {
+      filter->color_managed = color_managed;
+
+      gimp_drawable_filter_sync_transform (filter);
+
+      if (gimp_drawable_filter_is_filtering (filter))
+        gimp_drawable_filter_update_drawable (filter, NULL);
+    }
+}
+
+void
 gimp_drawable_filter_set_gamma_hack (GimpDrawableFilter *filter,
                                      gboolean            gamma_hack)
 {
@@ -605,6 +638,56 @@ gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter)
 }
 
 static void
+gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter)
+{
+  GimpColorManaged *managed = GIMP_COLOR_MANAGED (filter->drawable);
+
+  if (filter->color_managed)
+    {
+      const Babl       *filter_format;
+      GimpColorProfile *filter_profile;
+      GimpColorProfile *drawable_profile;
+
+      filter_format = gimp_gegl_node_get_format (filter->operation, "output");
+
+      g_printerr ("filter format: %s\n", babl_get_name (filter_format));
+
+      filter_profile   = gimp_babl_format_get_color_profile (filter_format);
+      drawable_profile = gimp_color_managed_get_color_profile (managed);
+
+      if (! gimp_color_transform_can_gegl_copy (filter_profile,
+                                                drawable_profile))
+        {
+          g_printerr ("using gimp:profile-transform\n");
+
+          gegl_node_set (filter->transform_before,
+                         "operation",    "gimp:profile-transform",
+                         "src-profile",  drawable_profile,
+                         "dest-profile", filter_profile,
+                         NULL);
+
+          gegl_node_set (filter->transform_after,
+                         "operation",    "gimp:profile-transform",
+                         "src-profile",  filter_profile,
+                         "dest-profile", drawable_profile,
+                         NULL);
+
+          return;
+        }
+    }
+
+  g_printerr ("using gegl copy\n");
+
+  gegl_node_set (filter->transform_before,
+                 "operation", "gegl:nop",
+                 NULL);
+
+  gegl_node_set (filter->transform_after,
+                 "operation", "gegl:nop",
+                 NULL);
+}
+
+static void
 gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter)
 {
   if (filter->gamma_hack)
@@ -670,6 +753,7 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
       gimp_drawable_filter_sync_opacity (filter);
       gimp_drawable_filter_sync_mode (filter);
       gimp_drawable_filter_sync_affect (filter);
+      gimp_drawable_filter_sync_transform (filter);
       gimp_drawable_filter_sync_gamma_hack (filter);
 
       gimp_drawable_add_filter (filter->drawable,
@@ -681,6 +765,9 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
       g_signal_connect (image, "mask-changed",
                         G_CALLBACK (gimp_drawable_filter_mask_changed),
                         filter);
+      g_signal_connect (image, "profile-changed",
+                        G_CALLBACK (gimp_drawable_filter_profile_changed),
+                        filter);
       g_signal_connect (filter->drawable, "removed",
                         G_CALLBACK (gimp_drawable_filter_drawable_removed),
                         filter);
@@ -702,6 +789,9 @@ gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
                                             gimp_drawable_filter_drawable_removed,
                                             filter);
       g_signal_handlers_disconnect_by_func (image,
+                                            gimp_drawable_filter_profile_changed,
+                                            filter);
+      g_signal_handlers_disconnect_by_func (image,
                                             gimp_drawable_filter_mask_changed,
                                             filter);
       g_signal_handlers_disconnect_by_func (image,
@@ -783,6 +873,14 @@ gimp_drawable_filter_mask_changed (GimpImage          *image,
 }
 
 static void
+gimp_drawable_filter_profile_changed (GimpColorManaged   *managed,
+                                      GimpDrawableFilter *filter)
+{
+  gimp_drawable_filter_sync_transform (filter);
+  gimp_drawable_filter_update_drawable (filter, NULL);
+}
+
+static void
 gimp_drawable_filter_drawable_removed (GimpDrawable       *drawable,
                                        GimpDrawableFilter *filter)
 {
diff --git a/app/core/gimpdrawablefilter.h b/app/core/gimpdrawablefilter.h
index d0bcf94..87630aa 100644
--- a/app/core/gimpdrawablefilter.h
+++ b/app/core/gimpdrawablefilter.h
@@ -66,6 +66,9 @@ void       gimp_drawable_filter_set_opacity    (GimpDrawableFilter   *filter,
 void       gimp_drawable_filter_set_mode       (GimpDrawableFilter   *filter,
                                                 GimpLayerModeEffects  paint_mode);
 
+void       gimp_drawable_filter_set_color_managed
+                                               (GimpDrawableFilter   *filter,
+                                                gboolean              managed);
 void       gimp_drawable_filter_set_gamma_hack (GimpDrawableFilter   *filter,
                                                 gboolean              gamma_hack);
 
diff --git a/app/tools/gimpfilteroptions.c b/app/tools/gimpfilteroptions.c
index 406dea4..ef6933a 100644
--- a/app/tools/gimpfilteroptions.c
+++ b/app/tools/gimpfilteroptions.c
@@ -37,6 +37,7 @@ enum
   PROP_PREVIEW_ALIGNMENT,
   PROP_PREVIEW_POSITION,
   PROP_REGION,
+  PROP_COLOR_MANAGED,
   PROP_GAMMA_HACK,
   PROP_SETTINGS
 };
@@ -106,6 +107,14 @@ gimp_filter_options_class_init (GimpFilterOptionsClass *klass)
                                                       GIMP_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (object_class, PROP_COLOR_MANAGED,
+                                   g_param_spec_boolean ("color-managed",
+                                                         _("Color _managed"),
+                                                         NULL,
+                                                         FALSE,
+                                                         GIMP_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT));
+
   g_object_class_install_property (object_class, PROP_GAMMA_HACK,
                                    g_param_spec_boolean ("gamma-hack",
                                                          "Gamma hack (temp hack, please ignore)",
@@ -171,6 +180,10 @@ gimp_filter_options_set_property (GObject      *object,
       options->region = g_value_get_enum (value);
       break;
 
+    case PROP_COLOR_MANAGED:
+      options->color_managed = g_value_get_boolean (value);
+      break;
+
     case PROP_GAMMA_HACK:
       options->gamma_hack = g_value_get_boolean (value);
       break;
@@ -217,6 +230,10 @@ gimp_filter_options_get_property (GObject    *object,
       g_value_set_enum (value, options->region);
       break;
 
+    case PROP_COLOR_MANAGED:
+      g_value_set_boolean (value, options->color_managed);
+      break;
+
     case PROP_GAMMA_HACK:
       g_value_set_boolean (value, options->gamma_hack);
       break;
diff --git a/app/tools/gimpfilteroptions.h b/app/tools/gimpfilteroptions.h
index 7916ccf..758d646 100644
--- a/app/tools/gimpfilteroptions.h
+++ b/app/tools/gimpfilteroptions.h
@@ -41,6 +41,7 @@ struct _GimpFilterOptions
   GimpAlignmentType   preview_alignment;
   gdouble             preview_position;
   GimpFilterRegion    region;
+  gboolean            color_managed;
   gboolean            gamma_hack;
 
   GFile              *settings;
diff --git a/app/tools/gimpfiltertool.c b/app/tools/gimpfiltertool.c
index 4858e70..37f6a9b 100644
--- a/app/tools/gimpfiltertool.c
+++ b/app/tools/gimpfiltertool.c
@@ -332,6 +332,10 @@ gimp_filter_tool_initialize (GimpTool     *tool,
       GtkWidget           *vbox;
       GtkWidget           *hbox;
       GtkWidget           *toggle;
+      GtkWidget           *expander;
+      GtkWidget           *frame;
+      GtkWidget           *vbox2;
+      GtkWidget           *combo;
       gchar               *operation_name;
 
       /*  disabled for at least GIMP 2.8  */
@@ -400,12 +404,6 @@ gimp_filter_tool_initialize (GimpTool     *tool,
           gtk_widget_show (settings_ui);
         }
 
-      /*  The gamma hack toggle  */
-      toggle = gimp_prop_check_button_new (G_OBJECT (tool_info->tool_options),
-                                           "gamma-hack", NULL);
-      gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
-      gtk_widget_show (toggle);
-
       /*  The preview and split view toggles  */
       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
       gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
@@ -425,6 +423,33 @@ gimp_filter_tool_initialize (GimpTool     *tool,
                               toggle,                             "sensitive",
                               G_BINDING_SYNC_CREATE);
 
+      /*  The Color Options expander  */
+      expander = gtk_expander_new (_("Advanced Color Options"));
+      gtk_box_pack_end (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
+      gtk_widget_show (expander);
+
+      frame = gimp_frame_new (NULL);
+      gtk_container_add (GTK_CONTAINER (expander), frame);
+      gtk_widget_show (frame);
+
+      vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+      gtk_container_add (GTK_CONTAINER (frame), vbox2);
+      gtk_widget_show (vbox2);
+
+      /*  The color managed combo  */
+      combo = gimp_prop_boolean_combo_box_new
+        (G_OBJECT (tool_info->tool_options), "color-managed",
+         _("Apply filter in color managed space (slow)"),
+         _("Apply filter to the layer's raw pixels"));
+      gtk_box_pack_start (GTK_BOX (vbox2), combo, FALSE, FALSE, 0);
+      gtk_widget_show (combo);
+
+      /*  The gamma hack toggle  */
+      toggle = gimp_prop_check_button_new (G_OBJECT (tool_info->tool_options),
+                                           "gamma-hack", NULL);
+      gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
+      gtk_widget_show (toggle);
+
       /*  The area combo  */
       gegl_node_get (filter_tool->operation,
                      "operation", &operation_name,
@@ -780,6 +805,12 @@ gimp_filter_tool_options_notify (GimpTool         *tool,
       gimp_drawable_filter_set_region (filter_tool->filter,
                                        filter_options->region);
     }
+  else if (! strcmp (pspec->name, "color-managed") &&
+           filter_tool->filter)
+    {
+      gimp_drawable_filter_set_color_managed (filter_tool->filter,
+                                              filter_options->color_managed);
+    }
   else if (! strcmp (pspec->name, "gamma-hack") &&
            filter_tool->filter)
     {


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