[gimp] app, libgimpwidgets: new gimp_color_area_set_out_of_gamut().



commit 4be9b7a401b8f981b4720f090c887b494e890726
Author: Jehan <jehan girinstud io>
Date:   Wed Mar 6 16:14:32 2019 +0100

    app, libgimpwidgets: new gimp_color_area_set_out_of_gamut().
    
    This allows to force a GimpColorArea to display as out-of-gamut color.
    Current code was only considering the generic RGB case (outside of [0-1]
    range), and in particular not grayscale or indexed images.
    
    Ideally the GimpColorArea widget could be (optionally) made to follow a
    context, so that for instance it could update its representation when
    the context image changes, or when this image's type changes. Yet since
    it is a libgimpwidgets widget, it cannot get such update. Instead I add
    a new API function to display the color box with the out-of-gamut
    triangle. The decision code for this will have to be done elsewhere.
    
    Use this new API for GimpColorHistory to display non-gray colors in the
    history as out-of-gamut on grayscale images, or colors absent of the
    palette on indexed images.

 app/widgets/gimpcolorhistory.c | 107 ++++++++++++++++++++++++++++++++++++-----
 app/widgets/gimpcolorhistory.h |   1 +
 libgimpwidgets/gimpcolorarea.c |  41 ++++++++++++++--
 libgimpwidgets/gimpcolorarea.h |   2 +
 4 files changed, 135 insertions(+), 16 deletions(-)
---
diff --git a/app/widgets/gimpcolorhistory.c b/app/widgets/gimpcolorhistory.c
index 8e75570750..4e377dcc94 100644
--- a/app/widgets/gimpcolorhistory.c
+++ b/app/widgets/gimpcolorhistory.c
@@ -32,6 +32,8 @@
 #include "core/gimp.h"
 #include "core/gimp-palettes.h"
 #include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "app/core/gimpimage-colormap.h"
 #include "core/gimpmarshal.h"
 #include "core/gimppalettemru.h"
 
@@ -55,6 +57,7 @@ enum
 
 #define DEFAULT_HISTORY_SIZE 12
 #define COLOR_AREA_SIZE      20
+#define CHANNEL_EPSILON      1e-3
 
 /* GObject methods */
 static void   gimp_color_history_constructed                    (GObject           *object);
@@ -85,12 +88,15 @@ static void   gimp_color_history_size_allocate                  (GtkWidget
 static void   gimp_color_history_color_clicked                  (GtkWidget         *widget,
                                                                  GimpColorHistory  *history);
 
-static void   gimp_color_history_palette_dirty                  (GimpPalette       *palette,
-                                                                 GimpColorHistory  *history);
+static void   gimp_color_history_palette_dirty                  (GimpColorHistory  *history);
 
 static void   gimp_color_history_color_changed                  (GtkWidget         *widget,
                                                                  gpointer           data);
 
+static void   gimp_color_history_image_changed                  (GimpContext       *context,
+                                                                 GimpImage         *image,
+                                                                 GimpColorHistory  *history);
+
 /* Utils */
 static void   gimp_color_history_reorganize                     (GimpColorHistory  *history);
 
@@ -169,7 +175,7 @@ gimp_color_history_constructed (GObject *object)
 
   g_signal_connect_object (palette, "dirty",
                            G_CALLBACK (gimp_color_history_palette_dirty),
-                           G_OBJECT (history), 0);
+                           G_OBJECT (history), G_CONNECT_SWAPPED);
 }
 
 static void
@@ -196,15 +202,41 @@ gimp_color_history_set_property (GObject      *object,
   switch (property_id)
     {
     case PROP_CONTEXT:
+      if (history->context)
+        g_signal_handlers_disconnect_by_func (history->context,
+                                              gimp_color_history_image_changed,
+                                              history);
+      if (history->active_image)
+        {
+          g_signal_handlers_disconnect_by_func (history->active_image,
+                                                G_CALLBACK (gimp_color_history_palette_dirty),
+                                                history);
+          history->active_image = NULL;
+        }
       history->context = g_value_get_object (value);
+      if (history->context)
+        {
+          g_signal_connect (history->context, "image-changed",
+                            G_CALLBACK (gimp_color_history_image_changed),
+                            history);
+          history->active_image = gimp_context_get_image (history->context);
+          if (history->active_image)
+            {
+              g_signal_connect_swapped (history->active_image, "notify::base-type",
+                                        G_CALLBACK (gimp_color_history_palette_dirty),
+                                        history);
+              g_signal_connect_swapped (history->active_image, "colormap-changed",
+                                        G_CALLBACK (gimp_color_history_palette_dirty),
+                                        history);
+            }
+        }
       break;
 
     case PROP_HISTORY_SIZE:
         {
-          GimpPalette *palette;
-          GtkWidget   *button;
-          GtkWidget   *color_area;
-          gint         i;
+          GtkWidget *button;
+          GtkWidget *color_area;
+          gint       i;
 
           history->history_size = g_value_get_int (value);
 
@@ -249,8 +281,7 @@ gimp_color_history_set_property (GObject      *object,
               history->color_areas[i] = color_area;
             }
 
-          palette = gimp_palettes_get_color_history (history->context->gimp);
-          gimp_color_history_palette_dirty (palette, history);
+          gimp_color_history_palette_dirty (history);
         }
       break;
 
@@ -426,22 +457,47 @@ gimp_color_history_color_clicked (GtkWidget        *widget,
 /* Color history palette callback. */
 
 static void
-gimp_color_history_palette_dirty (GimpPalette      *palette,
-                                  GimpColorHistory *history)
+gimp_color_history_palette_dirty (GimpColorHistory *history)
 {
-  gint i;
+  GimpPalette       *palette;
+  GimpPalette       *colormap_palette = NULL;
+  GimpImageBaseType  base_type        = GIMP_RGB;
+  gint               i;
+
+  palette = gimp_palettes_get_color_history (history->context->gimp);
+  if (history->active_image)
+    {
+      base_type = gimp_image_get_base_type (history->active_image);
+      if (base_type == GIMP_INDEXED)
+        colormap_palette = gimp_image_get_colormap_palette (history->active_image);
+    }
 
   for (i = 0; i < history->history_size; i++)
     {
       GimpPaletteEntry *entry = gimp_palette_get_entry (palette, i);
       GimpRGB           black = { 0.0, 0.0, 0.0, 1.0 };
+      GimpRGB           color = entry ? entry->color : black;
+      gboolean          oog   = FALSE;
 
       g_signal_handlers_block_by_func (history->color_areas[i],
                                        gimp_color_history_color_changed,
                                        GINT_TO_POINTER (i));
 
       gimp_color_area_set_color (GIMP_COLOR_AREA (history->color_areas[i]),
-                                 entry ? &entry->color : &black);
+                                 &color);
+      if (/* Common out-of-gamut case */
+          (color.r < 0.0 || color.r > 1.0 ||
+           color.g < 0.0 || color.g > 1.0 ||
+           color.b < 0.0 || color.b > 1.0) ||
+          /* Indexed images */
+          (colormap_palette && ! gimp_palette_find_entry (colormap_palette, &color, NULL)) ||
+          /* Grayscale images */
+          (base_type == GIMP_GRAY &&
+           (ABS (color.r - color.g) > CHANNEL_EPSILON ||
+            ABS (color.r - color.b) > CHANNEL_EPSILON ||
+            ABS (color.g - color.b) > CHANNEL_EPSILON)))
+        oog = TRUE;
+      gimp_color_area_set_out_of_gamut (GIMP_COLOR_AREA (history->color_areas[i]), oog);
 
       g_signal_handlers_unblock_by_func (history->color_areas[i],
                                          gimp_color_history_color_changed,
@@ -469,6 +525,31 @@ gimp_color_history_color_changed (GtkWidget *widget,
   gimp_palette_set_entry_color (palette, GPOINTER_TO_INT (data), &color);
 }
 
+static void
+gimp_color_history_image_changed (GimpContext      *context,
+                                  GimpImage        *image,
+                                  GimpColorHistory *history)
+{
+  /* Update active image. */
+  if (history->active_image)
+    g_signal_handlers_disconnect_by_func (history->active_image,
+                                          G_CALLBACK (gimp_color_history_palette_dirty),
+                                          history);
+  history->active_image = image;
+  if (image)
+    {
+      g_signal_connect_swapped (image, "notify::base-type",
+                                G_CALLBACK (gimp_color_history_palette_dirty),
+                                history);
+      g_signal_connect_swapped (image, "colormap-changed",
+                                G_CALLBACK (gimp_color_history_palette_dirty),
+                                history);
+    }
+
+  /* Update the palette. */
+  gimp_color_history_palette_dirty (history);
+}
+
 static void
 gimp_color_history_reorganize (GimpColorHistory *history)
 {
diff --git a/app/widgets/gimpcolorhistory.h b/app/widgets/gimpcolorhistory.h
index f0f5c65fd4..cd86196301 100644
--- a/app/widgets/gimpcolorhistory.h
+++ b/app/widgets/gimpcolorhistory.h
@@ -37,6 +37,7 @@ struct _GimpColorHistory
   GtkGrid       parent_instance;
 
   GimpContext  *context;
+  GimpImage    *active_image;
 
   GtkWidget   **color_areas;
   GtkWidget   **buttons;
diff --git a/libgimpwidgets/gimpcolorarea.c b/libgimpwidgets/gimpcolorarea.c
index d0acf3dcfd..7684f9056c 100644
--- a/libgimpwidgets/gimpcolorarea.c
+++ b/libgimpwidgets/gimpcolorarea.c
@@ -80,6 +80,8 @@ struct _GimpColorAreaPrivate
   GimpRGB             color;
   guint               draw_border  : 1;
   guint               needs_render : 1;
+
+  gboolean            out_of_gamut;
 };
 
 #define GET_PRIVATE(obj) (((GimpColorArea *) (obj))->priv)
@@ -457,9 +459,10 @@ gimp_color_area_draw (GtkWidget *widget,
     }
 
   if (priv->config &&
-      (priv->color.r < 0.0 || priv->color.r > 1.0 ||
-       priv->color.g < 0.0 || priv->color.g > 1.0 ||
-       priv->color.b < 0.0 || priv->color.b > 1.0))
+      ((priv->color.r < 0.0 || priv->color.r > 1.0 ||
+        priv->color.g < 0.0 || priv->color.g > 1.0 ||
+        priv->color.b < 0.0 || priv->color.b > 1.0) ||
+       priv->out_of_gamut))
     {
       GimpRGB color;
       gint    side = MIN (priv->width, priv->height) * 2 / 3;
@@ -652,6 +655,38 @@ gimp_color_area_set_draw_border (GimpColorArea *area,
     }
 }
 
+/**
+ * gimp_color_area_set_out_of_gamut:
+ * @area:   a #GimpColorArea widget.
+ * @config: a #GimpColorConfig object.
+ *
+ * Sets the color area to render as an out-of-gamut color, i.e. with a
+ * small triangle on a corner using the color management out of gamut
+ * color (as per gimp_color_area_set_color_config()).
+ *
+ * By default, @area will render as out-of-gamut for any RGB color with
+ * a channel out of the [0; 1] range. This function allows to consider
+ * more colors out of gamut (for instance non-gray colors on a grayscale
+ * image, or colors absent of palettes in indexed images, etc.)
+ *
+ * Since: 2.10.10
+ */
+void
+gimp_color_area_set_out_of_gamut (GimpColorArea *area,
+                                  gboolean       out_of_gamut)
+{
+  GimpColorAreaPrivate *priv;
+
+  g_return_if_fail (GIMP_IS_COLOR_AREA (area));
+
+  priv = GET_PRIVATE (area);
+  if (priv->out_of_gamut != out_of_gamut)
+    {
+      priv->out_of_gamut = out_of_gamut;
+      gtk_widget_queue_draw (GTK_WIDGET (area));
+    }
+}
+
 /**
  * gimp_color_area_set_color_config:
  * @area:   a #GimpColorArea widget.
diff --git a/libgimpwidgets/gimpcolorarea.h b/libgimpwidgets/gimpcolorarea.h
index aed62c4f58..693ae4e159 100644
--- a/libgimpwidgets/gimpcolorarea.h
+++ b/libgimpwidgets/gimpcolorarea.h
@@ -86,6 +86,8 @@ void        gimp_color_area_set_type         (GimpColorArea     *area,
                                               GimpColorAreaType  type);
 void        gimp_color_area_set_draw_border  (GimpColorArea     *area,
                                               gboolean           draw_border);
+void        gimp_color_area_set_out_of_gamut (GimpColorArea     *area,
+                                              gboolean           out_of_gamut);
 
 void        gimp_color_area_set_color_config (GimpColorArea     *area,
                                               GimpColorConfig   *config);


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