[gimp] Bug 749902 - Add Hue-Chroma operation/tool and LCH color selector
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Bug 749902 - Add Hue-Chroma operation/tool and LCH color selector
- Date: Wed, 17 May 2017 17:33:07 +0000 (UTC)
commit 2b167d63372e79a990383f7f9f52ccb8ca730e13
Author: Michael Natterer <mitch gimp org>
Date: Wed May 17 19:28:40 2017 +0200
Bug 749902 - Add Hue-Chroma operation/tool and LCH color selector
Add LCH to the color selectors, patch by Elle Stone and myself.
- Extend enum GimpColorSelectorChannel by LCH channels
- Support them in GimpColorScale, GimpColorScales and GimpColorSelect
- Did not yet remove the HSV channels until things are working 100% ok
- Change drawing in GimpColorSelect to be much faster, to compensate
for babl_process() making the LCH modes pretty slow
- Clean up stuff in GimpColorSelect
This is WIP and should not be considered finished, biggest TODO is
displaying out-of-gamut values in GimpColorScales' spinbuttons.
libgimpwidgets/gimpcolorscale.c | 138 ++++++--
libgimpwidgets/gimpcolorscales.c | 140 +++++---
libgimpwidgets/gimpcolorselect.c | 743 ++++++++++++++++++++++++++++++++-----
libgimpwidgets/gimpwidgetsenums.c | 12 +-
libgimpwidgets/gimpwidgetsenums.h | 34 +-
5 files changed, 898 insertions(+), 169 deletions(-)
---
diff --git a/libgimpwidgets/gimpcolorscale.c b/libgimpwidgets/gimpcolorscale.c
index 4064659..5c6d429 100644
--- a/libgimpwidgets/gimpcolorscale.c
+++ b/libgimpwidgets/gimpcolorscale.c
@@ -54,12 +54,21 @@ enum
};
+typedef struct _GimpLCH GimpLCH;
+
+struct _GimpLCH
+{
+ gdouble l, c, h, a;
+};
+
+
typedef struct _GimpColorScalePrivate GimpColorScalePrivate;
struct _GimpColorScalePrivate
{
GimpColorConfig *config;
GimpColorTransform *transform;
+ guchar oog_color[3];
};
#define GET_PRIVATE(obj) \
@@ -98,12 +107,18 @@ static void gimp_color_scale_render_stipple (GimpColorScale *scale);
static void gimp_color_scale_create_transform (GimpColorScale *scale);
static void gimp_color_scale_destroy_transform (GimpColorScale *scale);
+static void gimp_color_scale_notify_config (GimpColorConfig *config,
+ const GParamSpec *pspec,
+ GimpColorScale *scale);
G_DEFINE_TYPE (GimpColorScale, gimp_color_scale, GTK_TYPE_SCALE)
#define parent_class gimp_color_scale_parent_class
+static const Babl *fish_rgb_to_lch = NULL;
+static const Babl *fish_lch_to_rgb = NULL;
+
static void
gimp_color_scale_class_init (GimpColorScaleClass *klass)
@@ -138,6 +153,18 @@ gimp_color_scale_class_init (GimpColorScaleClass *klass)
G_PARAM_CONSTRUCT));
g_type_class_add_private (object_class, sizeof (GimpColorScalePrivate));
+
+ /* This is so ugly... we have to babl_init() here so the binary
+ * generated by gtk-doc to scan libgimpwidgets' types won't crash.
+ * I didn't find a way to inject this line of code into the
+ * generated source.
+ */
+ babl_init ();
+
+ fish_rgb_to_lch = babl_fish (babl_format ("R'G'B'A double"),
+ babl_format ("CIE LCH(ab) double"));
+ fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) double"),
+ babl_format ("R'G'B' double"));
}
static void
@@ -706,7 +733,7 @@ gimp_color_scale_set_color_config (GimpColorScale *scale,
if (priv->config)
{
g_signal_handlers_disconnect_by_func (priv->config,
- gimp_color_scale_destroy_transform,
+ gimp_color_scale_notify_config,
scale);
g_object_unref (priv->config);
@@ -719,9 +746,11 @@ gimp_color_scale_set_color_config (GimpColorScale *scale,
{
g_object_ref (priv->config);
- g_signal_connect_swapped (priv->config, "notify",
- G_CALLBACK (gimp_color_scale_destroy_transform),
- scale);
+ g_signal_connect (priv->config, "notify",
+ G_CALLBACK (gimp_color_scale_notify_config),
+ scale);
+
+ gimp_color_scale_notify_config (priv->config, NULL, scale);
}
}
}
@@ -753,15 +782,19 @@ should_invert (GtkRange *range)
static void
gimp_color_scale_render (GimpColorScale *scale)
{
- GtkRange *range = GTK_RANGE (scale);
- GimpRGB rgb;
- GimpHSV hsv;
- guint x, y;
- gdouble *channel_value = NULL; /* shut up compiler */
- gboolean to_rgb = FALSE;
- gboolean invert;
- guchar *buf;
- guchar *d;
+ GimpColorScalePrivate *priv = GET_PRIVATE (scale);
+ GtkRange *range = GTK_RANGE (scale);
+ GimpRGB rgb;
+ GimpHSV hsv;
+ GimpLCH lch;
+ gint multiplier = 1;
+ guint x, y;
+ gdouble *channel_value = NULL; /* shut up compiler */
+ gboolean from_hsv = FALSE;
+ gboolean from_lch = FALSE;
+ gboolean invert;
+ guchar *buf;
+ guchar *d;
if ((buf = scale->buf) == NULL)
return;
@@ -774,16 +807,22 @@ gimp_color_scale_render (GimpColorScale *scale)
rgb = scale->rgb;
hsv = scale->hsv;
+ babl_process (fish_rgb_to_lch, &rgb, &lch, 1);
switch (scale->channel)
{
case GIMP_COLOR_SELECTOR_HUE: channel_value = &hsv.h; break;
case GIMP_COLOR_SELECTOR_SATURATION: channel_value = &hsv.s; break;
case GIMP_COLOR_SELECTOR_VALUE: channel_value = &hsv.v; break;
+
case GIMP_COLOR_SELECTOR_RED: channel_value = &rgb.r; break;
case GIMP_COLOR_SELECTOR_GREEN: channel_value = &rgb.g; break;
case GIMP_COLOR_SELECTOR_BLUE: channel_value = &rgb.b; break;
case GIMP_COLOR_SELECTOR_ALPHA: channel_value = &rgb.a; break;
+
+ case GIMP_COLOR_SELECTOR_LCH_LIGHTNESS: channel_value = &lch.l; break;
+ case GIMP_COLOR_SELECTOR_LCH_CHROMA: channel_value = &lch.c; break;
+ case GIMP_COLOR_SELECTOR_LCH_HUE: channel_value = &lch.h; break;
}
switch (scale->channel)
@@ -791,7 +830,20 @@ gimp_color_scale_render (GimpColorScale *scale)
case GIMP_COLOR_SELECTOR_HUE:
case GIMP_COLOR_SELECTOR_SATURATION:
case GIMP_COLOR_SELECTOR_VALUE:
- to_rgb = TRUE;
+ from_hsv = TRUE;
+ break;
+
+ case GIMP_COLOR_SELECTOR_LCH_LIGHTNESS:
+ multiplier = 100;
+ from_lch = TRUE;
+ break;
+ case GIMP_COLOR_SELECTOR_LCH_CHROMA:
+ multiplier = 100;
+ from_lch = TRUE;
+ break;
+ case GIMP_COLOR_SELECTOR_LCH_HUE:
+ multiplier = 360;
+ from_lch = TRUE;
break;
default:
@@ -805,18 +857,31 @@ gimp_color_scale_render (GimpColorScale *scale)
case GTK_ORIENTATION_HORIZONTAL:
for (x = 0, d = buf; x < scale->width; x++, d += 4)
{
- gdouble value = (gdouble) x / (gdouble) (scale->width - 1);
+ gdouble value = (gdouble) x * multiplier / (gdouble) (scale->width - 1);
guchar r, g, b;
if (invert)
- value = 1.0 - value;
+ value = multiplier - value;
*channel_value = value;
- if (to_rgb)
+ if (from_hsv)
gimp_hsv_to_rgb (&hsv, &rgb);
+ else if (from_lch)
+ babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
- gimp_rgb_get_uchar (&rgb, &r, &g, &b);
+ if (rgb.r < 0.0 || rgb.r > 1.0 ||
+ rgb.g < 0.0 || rgb.g > 1.0 ||
+ rgb.b < 0.0 || rgb.b > 1.0)
+ {
+ r = priv->oog_color[0];
+ g = priv->oog_color[1];
+ b = priv->oog_color[2];
+ }
+ else
+ {
+ gimp_rgb_get_uchar (&rgb, &r, &g, &b);
+ }
GIMP_CAIRO_RGB24_SET_PIXEL (d, r, g, b);
}
@@ -832,18 +897,31 @@ gimp_color_scale_render (GimpColorScale *scale)
case GTK_ORIENTATION_VERTICAL:
for (y = 0; y < scale->height; y++)
{
- gdouble value = (gdouble) y / (gdouble) (scale->height - 1);
+ gdouble value = (gdouble) y * multiplier / (gdouble) (scale->height - 1);
guchar r, g, b;
if (invert)
- value = 1.0 - value;
+ value = multiplier - value;
*channel_value = value;
- if (to_rgb)
+ if (from_hsv)
gimp_hsv_to_rgb (&hsv, &rgb);
+ else if (from_lch)
+ babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
- gimp_rgb_get_uchar (&rgb, &r, &g, &b);
+ if (rgb.r < 0.0 || rgb.r > 1.0 ||
+ rgb.g < 0.0 || rgb.g > 1.0 ||
+ rgb.b < 0.0 || rgb.b > 1.0)
+ {
+ r = priv->oog_color[0];
+ g = priv->oog_color[1];
+ b = priv->oog_color[2];
+ }
+ else
+ {
+ gimp_rgb_get_uchar (&rgb, &r, &g, &b);
+ }
for (x = 0, d = buf; x < scale->width; x++, d += 4)
{
@@ -1053,3 +1131,19 @@ gimp_color_scale_destroy_transform (GimpColorScale *scale)
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
+
+static void
+gimp_color_scale_notify_config (GimpColorConfig *config,
+ const GParamSpec *pspec,
+ GimpColorScale *scale)
+{
+ GimpColorScalePrivate *priv = GET_PRIVATE (scale);
+
+ gimp_color_scale_destroy_transform (scale);
+
+ gimp_rgb_get_uchar (&config->out_of_gamut_color,
+ priv->oog_color,
+ priv->oog_color + 1,
+ priv->oog_color + 2);
+ scale->needs_render = TRUE;
+}
diff --git a/libgimpwidgets/gimpcolorscales.c b/libgimpwidgets/gimpcolorscales.c
index c583f3c..6b8e489 100644
--- a/libgimpwidgets/gimpcolorscales.c
+++ b/libgimpwidgets/gimpcolorscales.c
@@ -49,10 +49,18 @@
*
* The #GimpColorScales widget is an implementation of a
* #GimpColorSelector. It shows a group of #GimpColorScale widgets
- * that allow to adjust the HSV and RGB color channels.
+ * that allow to adjust the HSV, LCH, and RGB color channels.
**/
+typedef struct _GimpLCH GimpLCH;
+
+struct _GimpLCH
+{
+ gdouble l, c, h, a;
+};
+
+
#define GIMP_COLOR_SCALES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_COLOR_SCALES,
GimpColorScalesClass))
#define GIMP_IS_COLOR_SCALES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_COLOR_SCALES))
#define GIMP_COLOR_SCALES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_COLOR_SCALES,
GimpColorScalesClass))
@@ -64,9 +72,9 @@ struct _GimpColorScales
{
GimpColorSelector parent_instance;
- GtkWidget *toggles[7];
- GtkWidget *sliders[7];
- GtkObject *slider_data[7];
+ GtkWidget *toggles[10];
+ GtkWidget *sliders[10];
+ GtkObject *slider_data[10];
};
struct _GimpColorScalesClass
@@ -92,9 +100,9 @@ static void gimp_color_scales_set_config (GimpColorSelector *selector,
static void gimp_color_scales_update_scales (GimpColorScales *scales,
gint skip);
-static void gimp_color_scales_toggle_update (GtkWidget *widget,
+static void gimp_color_scales_toggle_changed (GtkWidget *widget,
GimpColorScales *scales);
-static void gimp_color_scales_scale_update (GtkAdjustment *adjustment,
+static void gimp_color_scales_scale_changed (GtkAdjustment *adjustment,
GimpColorScales *scales);
@@ -102,6 +110,9 @@ G_DEFINE_TYPE (GimpColorScales, gimp_color_scales, GIMP_TYPE_COLOR_SELECTOR)
#define parent_class gimp_color_scales_parent_class
+static const Babl *fish_rgb_to_lch = NULL;
+static const Babl *fish_lch_to_rgb = NULL;
+
static void
gimp_color_scales_class_init (GimpColorScalesClass *klass)
@@ -117,6 +128,11 @@ gimp_color_scales_class_init (GimpColorScalesClass *klass)
selector_class->set_color = gimp_color_scales_set_color;
selector_class->set_channel = gimp_color_scales_set_channel;
selector_class->set_config = gimp_color_scales_set_config;
+
+ fish_rgb_to_lch = babl_fish (babl_format ("R'G'B'A double"),
+ babl_format ("CIE LCH(ab) double"));
+ fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) double"),
+ babl_format ("R'G'B' double"));
}
static void
@@ -129,19 +145,21 @@ gimp_color_scales_init (GimpColorScales *scales)
gint i;
static const gdouble slider_initial_vals[] =
- { 0, 0, 0, 0, 0, 0, 0 };
+ /*{ H, S, V, R, G, B, A, L, C, H }*/
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static const gdouble slider_max_vals[] =
- { 360, 100, 100, 100, 100, 100, 100 };
+ { 360, 100, 100, 100, 100, 100, 100, 100, 100, 360 };
static const gdouble slider_incs[] =
- { 30, 10, 10, 16, 16, 16, 10 };
+ { 30, 10, 10, 16, 16, 16, 10, 10, 10, 30 };
/* don't needs the toggles for our own operation */
selector->toggles_visible = FALSE;
- table = gtk_table_new (7, 4, FALSE);
+ table = gtk_table_new (11, 4, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 1);
- gtk_table_set_row_spacing (GTK_TABLE (table), 2, 5); /* hsv <-> rgb */
- gtk_table_set_row_spacing (GTK_TABLE (table), 5, 5); /* rgb <-> alpha */
+ gtk_table_set_row_spacing (GTK_TABLE (table), 2, 5); /* hsv <-> rgb */
+ gtk_table_set_row_spacing (GTK_TABLE (table), 5, 5); /* rgb <-> alpha */
+ gtk_table_set_row_spacing (GTK_TABLE (table), 6, 5); /* alpha <-> lch */
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacing (GTK_TABLE (table), 0, 0);
gtk_box_pack_start (GTK_BOX (scales), table, FALSE, FALSE, 0);
@@ -151,11 +169,9 @@ gimp_color_scales_init (GimpColorScales *scales)
group = NULL;
- for (i = GIMP_COLOR_SELECTOR_HUE; i <= GIMP_COLOR_SELECTOR_ALPHA; i++)
+ for (i = 0; i < 10; i++)
{
- GimpEnumDesc *enum_desc;
-
- enum_desc = gimp_enum_get_desc (enum_class, i);
+ GimpEnumDesc *enum_desc = gimp_enum_get_desc (enum_class, i);
if (i == GIMP_COLOR_SELECTOR_ALPHA)
{
@@ -176,7 +192,7 @@ gimp_color_scales_init (GimpColorScales *scales)
gettext (enum_desc->value_help), NULL);
g_signal_connect (scales->toggles[i], "toggled",
- G_CALLBACK (gimp_color_scales_toggle_update),
+ G_CALLBACK (gimp_color_scales_toggle_changed),
scales);
}
@@ -198,7 +214,7 @@ gimp_color_scales_init (GimpColorScales *scales)
gimp_color_scale_set_channel (GIMP_COLOR_SCALE (scales->sliders[i]), i);
g_signal_connect (scales->slider_data[i], "value-changed",
- G_CALLBACK (gimp_color_scales_scale_update),
+ G_CALLBACK (gimp_color_scales_scale_changed),
scales);
}
@@ -212,8 +228,9 @@ gimp_color_scales_togg_sensitive (GimpColorSelector *selector,
GimpColorScales *scales = GIMP_COLOR_SCALES (selector);
gint i;
- for (i = 0; i < 6; i++)
- gtk_widget_set_sensitive (scales->toggles[i], sensitive);
+ for (i = 0; i < 10; i++)
+ if (scales->toggles[i])
+ gtk_widget_set_sensitive (scales->toggles[i], sensitive);
}
static void
@@ -223,8 +240,9 @@ gimp_color_scales_togg_visible (GimpColorSelector *selector,
GimpColorScales *scales = GIMP_COLOR_SCALES (selector);
gint i;
- for (i = 0; i < 6; i++)
- gtk_widget_set_visible (scales->toggles[i], visible);
+ for (i = 0; i < 10; i++)
+ if (scales->toggles[i])
+ gtk_widget_set_visible (scales->toggles[i], visible);
}
static void
@@ -269,17 +287,17 @@ gimp_color_scales_set_channel (GimpColorSelector *selector,
{
GimpColorScales *scales = GIMP_COLOR_SCALES (selector);
- if (channel < 7)
+ if (scales->toggles[channel])
{
g_signal_handlers_block_by_func (scales->toggles[channel],
- gimp_color_scales_toggle_update,
+ gimp_color_scales_toggle_changed,
scales);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scales->toggles[channel]),
TRUE);
g_signal_handlers_unblock_by_func (scales->toggles[channel],
- gimp_color_scales_toggle_update,
+ gimp_color_scales_toggle_changed,
scales);
}
}
@@ -291,7 +309,7 @@ gimp_color_scales_set_config (GimpColorSelector *selector,
GimpColorScales *scales = GIMP_COLOR_SCALES (selector);
gint i;
- for (i = 0; i < 7; i++)
+ for (i = 0; i < 10; i++)
{
if (scales->sliders[i])
gimp_color_scale_set_color_config (GIMP_COLOR_SCALE (scales->sliders[i]),
@@ -304,30 +322,38 @@ gimp_color_scales_update_scales (GimpColorScales *scales,
gint skip)
{
GimpColorSelector *selector = GIMP_COLOR_SELECTOR (scales);
- gint values[7];
+ GimpLCH lch;
+ gdouble values[10];
gint i;
- values[GIMP_COLOR_SELECTOR_HUE] = ROUND (selector->hsv.h * 360.0);
- values[GIMP_COLOR_SELECTOR_SATURATION] = ROUND (selector->hsv.s * 100.0);
- values[GIMP_COLOR_SELECTOR_VALUE] = ROUND (selector->hsv.v * 100.0);
- values[GIMP_COLOR_SELECTOR_RED] = ROUND (selector->rgb.r * 100.0);
- values[GIMP_COLOR_SELECTOR_GREEN] = ROUND (selector->rgb.g * 100.0);
- values[GIMP_COLOR_SELECTOR_BLUE] = ROUND (selector->rgb.b * 100.0);
- values[GIMP_COLOR_SELECTOR_ALPHA] = ROUND (selector->rgb.a * 100.0);
+ babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
+
+ values[GIMP_COLOR_SELECTOR_HUE] = selector->hsv.h * 360.0;
+ values[GIMP_COLOR_SELECTOR_SATURATION] = selector->hsv.s * 100.0;
+ values[GIMP_COLOR_SELECTOR_VALUE] = selector->hsv.v * 100.0;
+
+ values[GIMP_COLOR_SELECTOR_RED] = selector->rgb.r * 100.0;
+ values[GIMP_COLOR_SELECTOR_GREEN] = selector->rgb.g * 100.0;
+ values[GIMP_COLOR_SELECTOR_BLUE] = selector->rgb.b * 100.0;
+ values[GIMP_COLOR_SELECTOR_ALPHA] = selector->rgb.a * 100.0;
+
+ values[GIMP_COLOR_SELECTOR_LCH_LIGHTNESS] = lch.l;
+ values[GIMP_COLOR_SELECTOR_LCH_CHROMA] = lch.c;
+ values[GIMP_COLOR_SELECTOR_LCH_HUE] = lch.h;
- for (i = 0; i < 7; i++)
+ for (i = 0; i < 10; i++)
{
if (i != skip)
{
g_signal_handlers_block_by_func (scales->slider_data[i],
- gimp_color_scales_scale_update,
+ gimp_color_scales_scale_changed,
scales);
gtk_adjustment_set_value (GTK_ADJUSTMENT (scales->slider_data[i]),
values[i]);
g_signal_handlers_unblock_by_func (scales->slider_data[i],
- gimp_color_scales_scale_update,
+ gimp_color_scales_scale_changed,
scales);
}
@@ -337,8 +363,8 @@ gimp_color_scales_update_scales (GimpColorScales *scales,
}
static void
-gimp_color_scales_toggle_update (GtkWidget *widget,
- GimpColorScales *scales)
+gimp_color_scales_toggle_changed (GtkWidget *widget,
+ GimpColorScales *scales)
{
GimpColorSelector *selector = GIMP_COLOR_SELECTOR (scales);
@@ -346,7 +372,7 @@ gimp_color_scales_toggle_update (GtkWidget *widget,
{
gint i;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 10; i++)
if (widget == scales->toggles[i])
{
selector->channel = (GimpColorSelectorChannel) i;
@@ -358,14 +384,15 @@ gimp_color_scales_toggle_update (GtkWidget *widget,
}
static void
-gimp_color_scales_scale_update (GtkAdjustment *adjustment,
- GimpColorScales *scales)
+gimp_color_scales_scale_changed (GtkAdjustment *adjustment,
+ GimpColorScales *scales)
{
GimpColorSelector *selector = GIMP_COLOR_SELECTOR (scales);
gdouble value = gtk_adjustment_get_value (adjustment);
+ GimpLCH lch;
gint i;
- for (i = 0; i < 7; i++)
+ for (i = 0; i < 10; i++)
if (scales->slider_data[i] == GTK_OBJECT (adjustment))
break;
@@ -398,13 +425,36 @@ gimp_color_scales_scale_update (GtkAdjustment *adjustment,
case GIMP_COLOR_SELECTOR_ALPHA:
selector->hsv.a = selector->rgb.a = value / 100.0;
break;
+
+ case GIMP_COLOR_SELECTOR_LCH_LIGHTNESS:
+ babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
+ lch.l = value;
+ break;
+
+ case GIMP_COLOR_SELECTOR_LCH_CHROMA:
+ babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
+ lch.c = value;
+ break;
+
+ case GIMP_COLOR_SELECTOR_LCH_HUE:
+ babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
+ lch.h = value;
+ break;
}
- if ((i >= GIMP_COLOR_SELECTOR_HUE) && (i <= GIMP_COLOR_SELECTOR_VALUE))
+ if ((i >= GIMP_COLOR_SELECTOR_HUE) &&
+ (i <= GIMP_COLOR_SELECTOR_VALUE))
{
gimp_hsv_to_rgb (&selector->hsv, &selector->rgb);
}
- else if ((i >= GIMP_COLOR_SELECTOR_RED) && (i <= GIMP_COLOR_SELECTOR_BLUE))
+ else if ((i >= GIMP_COLOR_SELECTOR_LCH_LIGHTNESS) &&
+ (i <= GIMP_COLOR_SELECTOR_LCH_HUE))
+ {
+ babl_process (fish_lch_to_rgb, &lch, &selector->rgb, 1);
+ gimp_rgb_to_hsv (&selector->rgb, &selector->hsv);
+ }
+ else if ((i >= GIMP_COLOR_SELECTOR_RED) &&
+ (i <= GIMP_COLOR_SELECTOR_BLUE))
{
gimp_rgb_to_hsv (&selector->rgb, &selector->hsv);
}
diff --git a/libgimpwidgets/gimpcolorselect.c b/libgimpwidgets/gimpcolorselect.c
index cbf1d92..e449c63 100644
--- a/libgimpwidgets/gimpcolorselect.c
+++ b/libgimpwidgets/gimpcolorselect.c
@@ -28,6 +28,7 @@
#include <gtk/gtk.h>
#include "libgimpbase/gimpbase.h"
+#include "libgimpconfig/gimpconfig.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
@@ -37,7 +38,7 @@
#include "gimpcolorselect.h"
#include "gimphelpui.h"
#include "gimpicons.h"
-#include "gimppreviewarea.h"
+#include "gimpwidgetsutils.h"
#include "gimp3migration.h"
#include "libgimp/libgimp-intl.h"
@@ -69,16 +70,27 @@ typedef enum
COLOR_SELECT_HUE = 0,
COLOR_SELECT_SATURATION,
COLOR_SELECT_VALUE,
+
COLOR_SELECT_RED,
COLOR_SELECT_GREEN,
COLOR_SELECT_BLUE,
COLOR_SELECT_ALPHA,
+
+ COLOR_SELECT_LCH_LIGHTNESS,
+ COLOR_SELECT_LCH_CHROMA,
+ COLOR_SELECT_LCH_HUE,
+
COLOR_SELECT_HUE_SATURATION,
COLOR_SELECT_HUE_VALUE,
COLOR_SELECT_SATURATION_VALUE,
+
COLOR_SELECT_RED_GREEN,
COLOR_SELECT_RED_BLUE,
- COLOR_SELECT_GREEN_BLUE
+ COLOR_SELECT_GREEN_BLUE,
+
+ COLOR_SELECT_LCH_HUE_CHROMA,
+ COLOR_SELECT_LCH_HUE_LIGHTNESS,
+ COLOR_SELECT_LCH_CHROMA_LIGHTNESS
} ColorSelectFillType;
typedef enum
@@ -98,6 +110,14 @@ typedef enum
} ColorSelectDragMode;
+typedef struct _GimpLCH GimpLCH;
+
+struct _GimpLCH
+{
+ gdouble l, c, h, a;
+};
+
+
#define GIMP_COLOR_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_COLOR_SELECT,
GimpColorSelectClass))
#define GIMP_IS_COLOR_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_COLOR_SELECT))
#define GIMP_COLOR_SELECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_COLOR_SELECT,
GimpColorSelectClass))
@@ -112,14 +132,28 @@ struct _GimpColorSelect
GtkWidget *toggle_box;
GtkWidget *xy_color;
+ ColorSelectFillType xy_color_fill;
+ guchar *xy_buf;
+ gint xy_width;
+ gint xy_height;
+ gint xy_rowstride;
+ gboolean xy_needs_render;
+
GtkWidget *z_color;
+ ColorSelectFillType z_color_fill;
+ guchar *z_buf;
+ gint z_width;
+ gint z_height;
+ gint z_rowstride;
+ gboolean z_needs_render;
gdouble pos[3];
- ColorSelectFillType z_color_fill;
- ColorSelectFillType xy_color_fill;
-
ColorSelectDragMode drag_mode;
+
+ GimpColorConfig *config;
+ GimpColorTransform *transform;
+ guchar oog_color[3];
};
struct _GimpColorSelectClass
@@ -130,7 +164,7 @@ struct _GimpColorSelectClass
typedef struct _ColorSelectFill ColorSelectFill;
-typedef void (* ColorSelectFillUpdateProc) (ColorSelectFill *color_select_fill);
+typedef void (* ColorSelectRenderFunc) (ColorSelectFill *color_select_fill);
struct _ColorSelectFill
{
@@ -140,11 +174,15 @@ struct _ColorSelectFill
gint height;
GimpRGB rgb;
GimpHSV hsv;
+ GimpLCH lch;
+ guchar oog_color[3];
- ColorSelectFillUpdateProc update;
+ ColorSelectRenderFunc render_line;
};
+static void gimp_color_select_finalize (GObject *object);
+
static void gimp_color_select_togg_visible (GimpColorSelector *selector,
gboolean visible);
static void gimp_color_select_togg_sensitive (GimpColorSelector *selector,
@@ -192,52 +230,92 @@ static gboolean gimp_color_select_z_events (GtkWidget *widget,
GdkEvent *event,
GimpColorSelect *select);
-static void gimp_color_select_image_fill (GtkWidget *widget,
+static void gimp_color_select_render (GtkWidget *widget,
+ guchar *buf,
+ gint width,
+ gint height,
+ gint rowstride,
ColorSelectFillType fill_type,
const GimpHSV *hsv,
- const GimpRGB *rgb);
-
-static void color_select_update_red (ColorSelectFill *csf);
-static void color_select_update_green (ColorSelectFill *csf);
-static void color_select_update_blue (ColorSelectFill *csf);
-static void color_select_update_hue (ColorSelectFill *csf);
-static void color_select_update_saturation (ColorSelectFill *csf);
-static void color_select_update_value (ColorSelectFill *csf);
-static void color_select_update_red_green (ColorSelectFill *csf);
-static void color_select_update_red_blue (ColorSelectFill *csf);
-static void color_select_update_green_blue (ColorSelectFill *csf);
-static void color_select_update_hue_saturation (ColorSelectFill *csf);
-static void color_select_update_hue_value (ColorSelectFill *csf);
-static void color_select_update_saturation_value (ColorSelectFill *csf);
+ const GimpRGB *rgb,
+ const guchar *oog_color);
+
+static void color_select_render_red (ColorSelectFill *csf);
+static void color_select_render_green (ColorSelectFill *csf);
+static void color_select_render_blue (ColorSelectFill *csf);
+
+static void color_select_render_hue (ColorSelectFill *csf);
+static void color_select_render_saturation (ColorSelectFill *csf);
+static void color_select_render_value (ColorSelectFill *csf);
+
+static void color_select_render_lch_lightness (ColorSelectFill *csf);
+static void color_select_render_lch_chroma (ColorSelectFill *csf);
+static void color_select_render_lch_hue (ColorSelectFill *csf);
+
+static void color_select_render_red_green (ColorSelectFill *csf);
+static void color_select_render_red_blue (ColorSelectFill *csf);
+static void color_select_render_green_blue (ColorSelectFill *csf);
+
+static void color_select_render_hue_saturation (ColorSelectFill *csf);
+static void color_select_render_hue_value (ColorSelectFill *csf);
+static void color_select_render_saturation_value (ColorSelectFill *csf);
+
+static void color_select_render_lch_chroma_lightness (ColorSelectFill *csf);
+static void color_select_render_lch_hue_lightness (ColorSelectFill *csf);
+static void color_select_render_lch_hue_chroma (ColorSelectFill *csf);
+
+static void gimp_color_select_create_transform (GimpColorSelect *select);
+static void gimp_color_select_destroy_transform (GimpColorSelect *select);
+static void gimp_color_select_notify_config (GimpColorConfig *config,
+ const GParamSpec *pspec,
+ GimpColorSelect *select);
G_DEFINE_TYPE (GimpColorSelect, gimp_color_select, GIMP_TYPE_COLOR_SELECTOR)
#define parent_class gimp_color_select_parent_class
-static const ColorSelectFillUpdateProc update_procs[] =
+static const ColorSelectRenderFunc render_funcs[] =
{
- color_select_update_hue,
- color_select_update_saturation,
- color_select_update_value,
- color_select_update_red,
- color_select_update_green,
- color_select_update_blue,
+ color_select_render_hue,
+ color_select_render_saturation,
+ color_select_render_value,
+
+ color_select_render_red,
+ color_select_render_green,
+ color_select_render_blue,
NULL, /* alpha */
- color_select_update_hue_saturation,
- color_select_update_hue_value,
- color_select_update_saturation_value,
- color_select_update_red_green,
- color_select_update_red_blue,
- color_select_update_green_blue,
+
+ color_select_render_lch_lightness,
+ color_select_render_lch_chroma,
+ color_select_render_lch_hue,
+
+ color_select_render_hue_saturation,
+ color_select_render_hue_value,
+ color_select_render_saturation_value,
+
+ color_select_render_red_green,
+ color_select_render_red_blue,
+ color_select_render_green_blue,
+
+ color_select_render_lch_hue_chroma,
+ color_select_render_lch_hue_lightness,
+ color_select_render_lch_chroma_lightness
};
+static const Babl *fish_rgb_to_lch = NULL;
+static const Babl *fish_lch_to_rgb = NULL;
+static const Babl *fish_lch_to_rgb_u8 = NULL;
+
static void
gimp_color_select_class_init (GimpColorSelectClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpColorSelectorClass *selector_class = GIMP_COLOR_SELECTOR_CLASS (klass);
+ object_class->finalize = gimp_color_select_finalize;
+
selector_class->name = "GIMP";
selector_class->help_id = "gimp-colorselector-gimp";
selector_class->icon_name = GIMP_ICON_WILBER;
@@ -246,13 +324,21 @@ gimp_color_select_class_init (GimpColorSelectClass *klass)
selector_class->set_color = gimp_color_select_set_color;
selector_class->set_channel = gimp_color_select_set_channel;
selector_class->set_config = gimp_color_select_set_config;
+
+ fish_rgb_to_lch = babl_fish (babl_format ("R'G'B'A double"),
+ babl_format ("CIE LCH(ab) double"));
+ fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) double"),
+ babl_format ("R'G'B' double"));
+ fish_lch_to_rgb_u8 = babl_fish (babl_format ("CIE LCH(ab) double"),
+ babl_format ("R'G'B' u8"));
}
static void
gimp_color_select_init (GimpColorSelect *select)
{
- GtkWidget *hbox;
- GtkWidget *frame;
+ GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
+ GtkWidget *hbox;
+ GtkWidget *frame;
select->z_color_fill = COLOR_SELECT_HUE;
select->xy_color_fill = COLOR_SELECT_SATURATION_VALUE;
@@ -268,7 +354,8 @@ gimp_color_select_init (GimpColorSelect *select)
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
- select->xy_color = gimp_preview_area_new ();
+ select->xy_color = gtk_event_box_new ();
+ gtk_event_box_set_visible_window (GTK_EVENT_BOX (select->xy_color), FALSE);
g_object_add_weak_pointer (G_OBJECT (select->xy_color),
(gpointer) &select->xy_color);
gtk_widget_set_size_request (select->xy_color,
@@ -299,7 +386,8 @@ gimp_color_select_init (GimpColorSelect *select)
gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
- select->z_color = gimp_preview_area_new ();
+ select->z_color = gtk_event_box_new ();
+ gtk_event_box_set_visible_window (GTK_EVENT_BOX (select->z_color), FALSE);
g_object_add_weak_pointer (G_OBJECT (select->z_color),
(gpointer) &select->z_color);
gtk_widget_set_size_request (select->z_color,
@@ -330,13 +418,16 @@ gimp_color_select_init (GimpColorSelect *select)
enum_class = g_type_class_ref (GIMP_TYPE_COLOR_SELECTOR_CHANNEL);
- for (channel = GIMP_COLOR_SELECTOR_HUE;
- channel < GIMP_COLOR_SELECTOR_ALPHA;
+ for (channel = GIMP_COLOR_SELECTOR_HUE;
+ channel <= GIMP_COLOR_SELECTOR_LCH_HUE;
channel++)
{
GimpEnumDesc *enum_desc;
GtkWidget *button;
+ if (channel == GIMP_COLOR_SELECTOR_ALPHA)
+ continue;
+
enum_desc = gimp_enum_get_desc (enum_class, channel);
button = gtk_radio_button_new_with_mnemonic (group,
@@ -350,7 +441,7 @@ gimp_color_select_init (GimpColorSelect *select)
g_object_set_data (G_OBJECT (button), "channel",
GINT_TO_POINTER (channel));
- if (channel == GIMP_COLOR_SELECTOR_HUE)
+ if (channel == selector->channel)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
gimp_help_set_help_data (button, gettext (enum_desc->value_help), NULL);
@@ -365,6 +456,32 @@ gimp_color_select_init (GimpColorSelect *select)
}
static void
+gimp_color_select_finalize (GObject *object)
+{
+ GimpColorSelect *select = GIMP_COLOR_SELECT (object);
+
+ if (select->xy_buf)
+ {
+ g_free (select->xy_buf);
+ select->xy_buf = NULL;
+ select->xy_width = 0;
+ select->xy_height = 0;
+ select->xy_rowstride = 0;
+ }
+
+ if (select->z_buf)
+ {
+ g_free (select->z_buf);
+ select->z_buf = NULL;
+ select->z_width = 0;
+ select->z_height = 0;
+ select->z_rowstride = 0;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
gimp_color_select_togg_visible (GimpColorSelector *selector,
gboolean visible)
{
@@ -431,6 +548,21 @@ gimp_color_select_set_channel (GimpColorSelector *selector,
select->xy_color_fill = COLOR_SELECT_RED_GREEN;
break;
+ case COLOR_SELECT_LCH_LIGHTNESS:
+ select->z_color_fill = COLOR_SELECT_LCH_LIGHTNESS;
+ select->xy_color_fill = COLOR_SELECT_LCH_HUE_CHROMA;
+ break;
+
+ case COLOR_SELECT_LCH_CHROMA:
+ select->z_color_fill = COLOR_SELECT_LCH_CHROMA;
+ select->xy_color_fill = COLOR_SELECT_LCH_HUE_LIGHTNESS;
+ break;
+
+ case COLOR_SELECT_LCH_HUE:
+ select->z_color_fill = COLOR_SELECT_LCH_HUE;
+ select->xy_color_fill = COLOR_SELECT_LCH_CHROMA_LIGHTNESS;
+ break;
+
default:
break;
}
@@ -445,13 +577,31 @@ gimp_color_select_set_config (GimpColorSelector *selector,
{
GimpColorSelect *select = GIMP_COLOR_SELECT (selector);
- if (select->xy_color)
- gimp_preview_area_set_color_config (GIMP_PREVIEW_AREA (select->xy_color),
- config);
+ if (config != select->config)
+ {
+ if (select->config)
+ {
+ g_signal_handlers_disconnect_by_func (select->config,
+ gimp_color_select_notify_config,
+ select);
+ g_object_unref (select->config);
+
+ gimp_color_select_destroy_transform (select);
+ }
+
+ select->config = config;
+
+ if (select->config)
+ {
+ g_object_ref (select->config);
- if (select->z_color)
- gimp_preview_area_set_color_config (GIMP_PREVIEW_AREA (select->z_color),
- config);
+ g_signal_connect (select->config, "notify",
+ G_CALLBACK (gimp_color_select_notify_config),
+ select);
+
+ gimp_color_select_notify_config (select->config, NULL, select);
+ }
+ }
}
static void
@@ -477,8 +627,6 @@ static void
gimp_color_select_update (GimpColorSelect *select,
ColorSelectUpdateType update)
{
- GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
-
if (update & UPDATE_POS)
gimp_color_select_update_pos (select);
@@ -487,15 +635,13 @@ gimp_color_select_update (GimpColorSelect *select,
if (update & UPDATE_XY_COLOR)
{
- gimp_color_select_image_fill (select->xy_color, select->xy_color_fill,
- &selector->hsv, &selector->rgb);
+ select->xy_needs_render = TRUE;
gtk_widget_queue_draw (select->xy_color);
}
if (update & UPDATE_Z_COLOR)
{
- gimp_color_select_image_fill (select->z_color, select->z_color_fill,
- &selector->hsv, &selector->rgb);
+ select->z_needs_render = TRUE;
gtk_widget_queue_draw (select->z_color);
}
@@ -507,6 +653,7 @@ static void
gimp_color_select_update_values (GimpColorSelect *select)
{
GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
+ GimpLCH lch;
switch (select->z_color_fill)
{
@@ -542,6 +689,22 @@ gimp_color_select_update_values (GimpColorSelect *select)
selector->hsv.v = select->pos[2];
break;
+ case COLOR_SELECT_LCH_LIGHTNESS:
+ lch.h = select->pos[0] * 360;
+ lch.c = select->pos[1] * 100;
+ lch.l = select->pos[2] * 100;
+ break;
+ case COLOR_SELECT_LCH_CHROMA:
+ lch.h = select->pos[0] * 360;
+ lch.l = select->pos[1] * 100;
+ lch.c = select->pos[2] * 100;
+ break;
+ case COLOR_SELECT_LCH_HUE:
+ lch.c = select->pos[0] * 100;
+ lch.l = select->pos[1] * 100;
+ lch.h = select->pos[2] * 360;
+ break;
+
default:
break;
}
@@ -560,6 +723,13 @@ gimp_color_select_update_values (GimpColorSelect *select)
gimp_hsv_to_rgb (&selector->hsv, &selector->rgb);
break;
+ case COLOR_SELECT_LCH_LIGHTNESS:
+ case COLOR_SELECT_LCH_CHROMA:
+ case COLOR_SELECT_LCH_HUE:
+ babl_process (fish_lch_to_rgb, &lch, &selector->rgb, 1);
+ gimp_rgb_to_hsv (&selector->rgb, &selector->hsv);
+ break;
+
default:
break;
}
@@ -569,6 +739,9 @@ static void
gimp_color_select_update_pos (GimpColorSelect *select)
{
GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
+ GimpLCH lch;
+
+ babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
switch (select->z_color_fill)
{
@@ -604,6 +777,22 @@ gimp_color_select_update_pos (GimpColorSelect *select)
select->pos[2] = CLAMP (selector->hsv.v, 0.0, 1.0);
break;
+ case COLOR_SELECT_LCH_LIGHTNESS:
+ select->pos[0] = CLAMP (lch.h / 360, 0.0, 1.0);
+ select->pos[1] = CLAMP (lch.c / 100, 0.0, 1.0);
+ select->pos[2] = CLAMP (lch.l / 100, 0.0, 1.0);
+ break;
+ case COLOR_SELECT_LCH_CHROMA:
+ select->pos[0] = CLAMP (lch.h / 360, 0.0, 1.0);
+ select->pos[1] = CLAMP (lch.l / 100, 0.0, 1.0);
+ select->pos[2] = CLAMP (lch.c / 100, 0.0, 1.0);
+ break;
+ case COLOR_SELECT_LCH_HUE:
+ select->pos[0] = CLAMP (lch.c / 100, 0.0, 1.0);
+ select->pos[1] = CLAMP (lch.l / 100, 0.0, 1.0);
+ select->pos[2] = CLAMP (lch.h / 360, 0.0, 1.0);
+ break;
+
default:
break;
}
@@ -622,6 +811,7 @@ gimp_color_select_drop_color (GtkWidget *widget,
select->rgb = *color;
gimp_color_select_update_hsv_values (select);
+ gimp_color_select_update_lch_values (select);
gimp_color_select_update (select,
UPDATE_POS | UPDATE_XY_COLOR | UPDATE_Z_COLOR |
@@ -634,6 +824,20 @@ gimp_color_select_xy_size_allocate (GtkWidget *widget,
GtkAllocation *allocation,
GimpColorSelect *select)
{
+ if (allocation->width != select->xy_width ||
+ allocation->height != select->xy_height)
+ {
+ select->xy_width = allocation->width;
+ select->xy_height = allocation->height;
+
+ select->xy_rowstride = (select->xy_width * 3 + 3) & ~3;
+
+ g_free (select->xy_buf);
+ select->xy_buf = g_new (guchar, select->xy_rowstride * select->xy_height);
+
+ select->xy_needs_render = TRUE;
+ }
+
gimp_color_select_update (select, UPDATE_XY_COLOR);
}
@@ -644,14 +848,84 @@ gimp_color_select_xy_expose (GtkWidget *widget,
{
GtkAllocation allocation;
cairo_t *cr;
+ GdkPixbuf *pixbuf;
gint x, y;
+ if (! select->xy_buf)
+ return FALSE;
+
+ if (select->xy_needs_render)
+ {
+ GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
+
+ gimp_color_select_render (select->xy_color,
+ select->xy_buf,
+ select->xy_width,
+ select->xy_height,
+ select->xy_rowstride,
+ select->xy_color_fill,
+ &selector->hsv,
+ &selector->rgb,
+ select->oog_color);
+ select->xy_needs_render = FALSE;
+ }
+
+ if (! select->transform)
+ gimp_color_select_create_transform (select);
+
+ if (select->transform)
+ {
+ const Babl *format = babl_format ("R'G'B' u8");
+ guchar *buf = g_new (guchar,
+ select->xy_rowstride * select->xy_height);
+ guchar *src = select->xy_buf;
+ guchar *dest = buf;
+ gint i;
+
+ for (i = 0; i < select->xy_height; i++)
+ {
+ gimp_color_transform_process_pixels (select->transform,
+ format, src,
+ format, dest,
+ select->xy_width);
+
+ src += select->xy_rowstride;
+ dest += select->xy_rowstride;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_data (buf,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ 8,
+ select->xy_width,
+ select->xy_height,
+ select->xy_rowstride,
+ (GdkPixbufDestroyNotify) g_free, NULL);
+ }
+ else
+ {
+ pixbuf = gdk_pixbuf_new_from_data (select->xy_buf,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ 8,
+ select->xy_width,
+ select->xy_height,
+ select->xy_rowstride,
+ NULL, NULL);
+ }
+
gtk_widget_get_allocation (select->xy_color, &allocation);
cr = gdk_cairo_create (gtk_widget_get_window (widget));
gdk_cairo_region (cr, event->region);
cairo_clip (cr);
+ cairo_translate (cr, allocation.x, allocation.y);
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ g_object_unref (pixbuf);
+ cairo_paint (cr);
+
x = (allocation.width - 1) * select->pos[0];
y = (allocation.height - 1) - (allocation.height - 1) * select->pos[1];
@@ -756,6 +1030,20 @@ gimp_color_select_z_size_allocate (GtkWidget *widget,
GtkAllocation *allocation,
GimpColorSelect *select)
{
+ if (allocation->width != select->z_width ||
+ allocation->height != select->z_height)
+ {
+ select->z_width = allocation->width;
+ select->z_height = allocation->height;
+
+ select->z_rowstride = (select->z_width * 3 + 3) & ~3;
+
+ g_free (select->z_buf);
+ select->z_buf = g_new (guchar, select->z_rowstride * select->z_height);
+
+ select->z_needs_render = TRUE;
+ }
+
gimp_color_select_update (select, UPDATE_Z_COLOR);
}
@@ -766,14 +1054,84 @@ gimp_color_select_z_expose (GtkWidget *widget,
{
GtkAllocation allocation;
cairo_t *cr;
+ GdkPixbuf *pixbuf;
gint y;
+ if (! select->z_buf)
+ return FALSE;
+
+ if (select->z_needs_render)
+ {
+ GimpColorSelector *selector = GIMP_COLOR_SELECTOR (select);
+
+ gimp_color_select_render (select->z_color,
+ select->z_buf,
+ select->z_width,
+ select->z_height,
+ select->z_rowstride,
+ select->z_color_fill,
+ &selector->hsv,
+ &selector->rgb,
+ select->oog_color);
+ select->z_needs_render = FALSE;
+ }
+
gtk_widget_get_allocation (widget, &allocation);
cr = gdk_cairo_create (gtk_widget_get_window (widget));
gdk_cairo_region (cr, event->region);
cairo_clip (cr);
+ if (! select->transform)
+ gimp_color_select_create_transform (select);
+
+ if (select->transform)
+ {
+ const Babl *format = babl_format ("R'G'B' u8");
+ guchar *buf = g_new (guchar,
+ select->z_rowstride * select->z_height);
+ guchar *src = select->z_buf;
+ guchar *dest = buf;
+ gint i;
+
+ for (i = 0; i < select->z_height; i++)
+ {
+ gimp_color_transform_process_pixels (select->transform,
+ format, src,
+ format, dest,
+ select->z_width);
+
+ src += select->z_rowstride;
+ dest += select->z_rowstride;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_data (buf,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ 8,
+ select->z_width,
+ select->z_height,
+ select->z_rowstride,
+ (GdkPixbufDestroyNotify) g_free, NULL);
+ }
+ else
+ {
+ pixbuf = gdk_pixbuf_new_from_data (select->z_buf,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ 8,
+ select->z_width,
+ select->z_height,
+ select->z_rowstride,
+ NULL, NULL);
+ }
+
+ cairo_translate (cr, allocation.x, allocation.y);
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ g_object_unref (pixbuf);
+ cairo_paint (cr);
+
y = (allocation.height - 1) - (allocation.height - 1) * select->pos[2];
cairo_move_to (cr, 0, y + 0.5);
@@ -864,37 +1222,42 @@ gimp_color_select_z_events (GtkWidget *widget,
}
static void
-gimp_color_select_image_fill (GtkWidget *preview,
- ColorSelectFillType fill_type,
- const GimpHSV *hsv,
- const GimpRGB *rgb)
+gimp_color_select_render (GtkWidget *preview,
+ guchar *buf,
+ gint width,
+ gint height,
+ gint rowstride,
+ ColorSelectFillType fill_type,
+ const GimpHSV *hsv,
+ const GimpRGB *rgb,
+ const guchar *oog_color)
{
- GtkAllocation allocation;
- ColorSelectFill csf;
+ ColorSelectFill csf;
- gtk_widget_get_allocation (preview, &allocation);
+ csf.width = width;
+ csf.height = height;
+ csf.hsv = *hsv;
+ csf.rgb = *rgb;
+ csf.render_line = render_funcs[fill_type];
- csf.buffer = g_alloca (allocation.width * 3);
- csf.width = allocation.width;
- csf.height = allocation.height;
- csf.hsv = *hsv;
- csf.rgb = *rgb;
- csf.update = update_procs[fill_type];
+ csf.oog_color[0] = oog_color[0];
+ csf.oog_color[1] = oog_color[1];
+ csf.oog_color[2] = oog_color[2];
+
+ babl_process (fish_rgb_to_lch, rgb, &csf.lch, 1);
for (csf.y = 0; csf.y < csf.height; csf.y++)
{
- if (csf.update)
- (* csf.update) (&csf);
+ csf.buffer = buf;
+
+ csf.render_line (&csf);
- gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
- 0, csf.y, csf.width, 1,
- GIMP_RGB_IMAGE,
- csf.buffer, csf.width * 3);
+ buf += rowstride;
}
}
static void
-color_select_update_red (ColorSelectFill *csf)
+color_select_render_red (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, r;
@@ -911,7 +1274,7 @@ color_select_update_red (ColorSelectFill *csf)
}
static void
-color_select_update_green (ColorSelectFill *csf)
+color_select_render_green (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, g;
@@ -928,7 +1291,7 @@ color_select_update_green (ColorSelectFill *csf)
}
static void
-color_select_update_blue (ColorSelectFill *csf)
+color_select_render_blue (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, b;
@@ -945,7 +1308,7 @@ color_select_update_blue (ColorSelectFill *csf)
}
static void
-color_select_update_hue (ColorSelectFill *csf)
+color_select_render_hue (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gfloat h, f;
@@ -1003,7 +1366,7 @@ color_select_update_hue (ColorSelectFill *csf)
}
static void
-color_select_update_saturation (ColorSelectFill *csf)
+color_select_render_saturation (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint s;
@@ -1023,7 +1386,7 @@ color_select_update_saturation (ColorSelectFill *csf)
}
static void
-color_select_update_value (ColorSelectFill *csf)
+color_select_render_value (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint v;
@@ -1043,7 +1406,64 @@ color_select_update_value (ColorSelectFill *csf)
}
static void
-color_select_update_red_green (ColorSelectFill *csf)
+color_select_render_lch_lightness (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch = { 0.0, 0.0, 0.0, 1.0 };
+ guchar rgb[3];
+ gint i;
+
+ lch.l = (csf->height - 1 - csf->y) * 100.0 / csf->height;
+ babl_process (fish_lch_to_rgb_u8, &lch, &rgb, 1);
+
+ for (i = 0; i < csf->width; i++)
+ {
+ *p++ = rgb[0];
+ *p++ = rgb[1];
+ *p++ = rgb[2];
+ }
+}
+
+static void
+color_select_render_lch_chroma (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch = { 80.0, 0.0, 0.0, 1.0 };
+ guchar rgb[3];
+ gint i;
+
+ lch.c = (csf->height - 1 - csf->y) * 100.0 / csf->height ;
+ babl_process (fish_lch_to_rgb_u8, &lch, &rgb, 1);
+
+ for (i = 0; i < csf->width; i++)
+ {
+ *p++ = rgb[0];
+ *p++ = rgb[1];
+ *p++ = rgb[2];
+ }
+}
+
+static void
+color_select_render_lch_hue (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch = { 80.0, 200.0, 0.0, 1.0 };
+ guchar rgb[3];
+ gint i;
+
+ lch.h = (csf->height - 1 - csf->y) * 360.0 / csf->height;
+ babl_process (fish_lch_to_rgb_u8, &lch, &rgb, 1);
+
+ for (i = 0; i < csf->width; i++)
+ {
+ *p++ = rgb[0];
+ *p++ = rgb[1];
+ *p++ = rgb[2];
+ }
+}
+
+static void
+color_select_render_red_green (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, g, b;
@@ -1068,7 +1488,7 @@ color_select_update_red_green (ColorSelectFill *csf)
}
static void
-color_select_update_red_blue (ColorSelectFill *csf)
+color_select_render_red_blue (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, g, b;
@@ -1093,7 +1513,7 @@ color_select_update_red_blue (ColorSelectFill *csf)
}
static void
-color_select_update_green_blue (ColorSelectFill *csf)
+color_select_render_green_blue (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gint i, r, b;
@@ -1118,7 +1538,7 @@ color_select_update_green_blue (ColorSelectFill *csf)
}
static void
-color_select_update_hue_saturation (ColorSelectFill *csf)
+color_select_render_hue_saturation (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gfloat h, dh, s, v;
@@ -1177,7 +1597,7 @@ color_select_update_hue_saturation (ColorSelectFill *csf)
}
static void
-color_select_update_hue_value (ColorSelectFill *csf)
+color_select_render_hue_value (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gfloat h, dh, s, v;
@@ -1236,7 +1656,7 @@ color_select_update_hue_value (ColorSelectFill *csf)
}
static void
-color_select_update_saturation_value (ColorSelectFill *csf)
+color_select_render_saturation_value (ColorSelectFill *csf)
{
guchar *p = csf->buffer;
gfloat h, s, ds, v;
@@ -1320,3 +1740,156 @@ color_select_update_saturation_value (ColorSelectFill *csf)
break;
}
}
+
+static void
+color_select_render_lch_chroma_lightness (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch;
+ gint i;
+
+ lch.l = (csf->height - 1 - csf->y) * 100.0 / csf->height;
+ lch.h = csf->lch.h;
+
+ for (i = 0; i < csf->width; i++)
+ {
+ GimpRGB rgb;
+
+ lch.c = i * 100.0 / csf->width;
+
+ babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
+
+ if (rgb.r < 0.0 || rgb.r > 1.0 ||
+ rgb.g < 0.0 || rgb.g > 1.0 ||
+ rgb.b < 0.0 || rgb.b > 1.0)
+ {
+ p[0] = csf->oog_color[0];
+ p[1] = csf->oog_color[1];
+ p[2] = csf->oog_color[2];
+ }
+ else
+ {
+ gimp_rgb_get_uchar (&rgb, p, p + 1, p + 2);
+ }
+
+ p += 3;
+ }
+}
+
+static void
+color_select_render_lch_hue_lightness (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch;
+ gint i;
+
+ lch.l = (csf->height - 1 - csf->y) * 100.0 / csf->height;
+ lch.c = csf->lch.c;
+
+ for (i = 0; i < csf->width; i++)
+ {
+ GimpRGB rgb;
+
+ lch.h = i * 360.0 / csf->width;
+
+ babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
+
+ if (rgb.r < 0.0 || rgb.r > 1.0 ||
+ rgb.g < 0.0 || rgb.g > 1.0 ||
+ rgb.b < 0.0 || rgb.b > 1.0)
+ {
+ p[0] = csf->oog_color[0];
+ p[1] = csf->oog_color[1];
+ p[2] = csf->oog_color[2];
+ }
+ else
+ {
+ gimp_rgb_get_uchar (&rgb, p, p + 1, p + 2);
+ }
+
+ p += 3;
+ }
+}
+
+static void
+color_select_render_lch_hue_chroma (ColorSelectFill *csf)
+{
+ guchar *p = csf->buffer;
+ GimpLCH lch;
+ gint i;
+
+ lch.l = csf->lch.l;
+ lch.c = (csf->height - 1 - csf->y) * 100.0 / csf->height;
+
+ for (i = 0; i < csf->width; i++)
+ {
+ GimpRGB rgb;
+
+ lch.h = i * 360.0 / csf->width;
+
+ babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
+
+ if (rgb.r < 0.0 || rgb.r > 1.0 ||
+ rgb.g < 0.0 || rgb.g > 1.0 ||
+ rgb.b < 0.0 || rgb.b > 1.0)
+ {
+ p[0] = csf->oog_color[0];
+ p[1] = csf->oog_color[1];
+ p[2] = csf->oog_color[2];
+ }
+ else
+ {
+ gimp_rgb_get_uchar (&rgb, p, p + 1, p + 2);
+ }
+
+ p += 3;
+ }
+}
+
+static void
+gimp_color_select_create_transform (GimpColorSelect *select)
+{
+ if (select->config)
+ {
+ static GimpColorProfile *profile = NULL;
+
+ const Babl *format = babl_format ("cairo-RGB24");
+
+ if (G_UNLIKELY (! profile))
+ profile = gimp_color_profile_new_rgb_srgb ();
+
+ select->transform = gimp_widget_get_color_transform (GTK_WIDGET (select),
+ select->config,
+ profile,
+ format,
+ format);
+ }
+}
+
+static void
+gimp_color_select_destroy_transform (GimpColorSelect *select)
+{
+ if (select->transform)
+ {
+ g_object_unref (select->transform);
+ select->transform = NULL;
+ }
+
+ gtk_widget_queue_draw (select->xy_color);
+ gtk_widget_queue_draw (select->z_color);
+}
+
+static void
+gimp_color_select_notify_config (GimpColorConfig *config,
+ const GParamSpec *pspec,
+ GimpColorSelect *select)
+{
+ gimp_color_select_destroy_transform (select);
+
+ gimp_rgb_get_uchar (&config->out_of_gamut_color,
+ select->oog_color,
+ select->oog_color + 1,
+ select->oog_color + 2);
+ select->xy_needs_render = TRUE;
+ select->z_needs_render = TRUE;
+}
diff --git a/libgimpwidgets/gimpwidgetsenums.c b/libgimpwidgets/gimpwidgetsenums.c
index fa6bfff..829c284 100644
--- a/libgimpwidgets/gimpwidgetsenums.c
+++ b/libgimpwidgets/gimpwidgetsenums.c
@@ -118,18 +118,24 @@ gimp_color_selector_channel_get_type (void)
{ GIMP_COLOR_SELECTOR_GREEN, "GIMP_COLOR_SELECTOR_GREEN", "green" },
{ GIMP_COLOR_SELECTOR_BLUE, "GIMP_COLOR_SELECTOR_BLUE", "blue" },
{ GIMP_COLOR_SELECTOR_ALPHA, "GIMP_COLOR_SELECTOR_ALPHA", "alpha" },
+ { GIMP_COLOR_SELECTOR_LCH_LIGHTNESS, "GIMP_COLOR_SELECTOR_LCH_LIGHTNESS", "lch-lightness" },
+ { GIMP_COLOR_SELECTOR_LCH_CHROMA, "GIMP_COLOR_SELECTOR_LCH_CHROMA", "lch-chroma" },
+ { GIMP_COLOR_SELECTOR_LCH_HUE, "GIMP_COLOR_SELECTOR_LCH_HUE", "lch-hue" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
- { GIMP_COLOR_SELECTOR_HUE, NC_("color-selector-channel", "_H"), N_("Hue") },
- { GIMP_COLOR_SELECTOR_SATURATION, NC_("color-selector-channel", "_S"), N_("Saturation") },
- { GIMP_COLOR_SELECTOR_VALUE, NC_("color-selector-channel", "_V"), N_("Value") },
+ { GIMP_COLOR_SELECTOR_HUE, NC_("color-selector-channel", "_H"), N_("HSV Hue") },
+ { GIMP_COLOR_SELECTOR_SATURATION, NC_("color-selector-channel", "_S"), N_("HSV Saturation") },
+ { GIMP_COLOR_SELECTOR_VALUE, NC_("color-selector-channel", "_V"), N_("HSV Value") },
{ GIMP_COLOR_SELECTOR_RED, NC_("color-selector-channel", "_R"), N_("Red") },
{ GIMP_COLOR_SELECTOR_GREEN, NC_("color-selector-channel", "_G"), N_("Green") },
{ GIMP_COLOR_SELECTOR_BLUE, NC_("color-selector-channel", "_B"), N_("Blue") },
{ GIMP_COLOR_SELECTOR_ALPHA, NC_("color-selector-channel", "_A"), N_("Alpha") },
+ { GIMP_COLOR_SELECTOR_LCH_LIGHTNESS, NC_("color-selector-channel", "_L"), N_("LCH Lightness") },
+ { GIMP_COLOR_SELECTOR_LCH_CHROMA, NC_("color-selector-channel", "_C"), N_("LCH Chroma") },
+ { GIMP_COLOR_SELECTOR_LCH_HUE, NC_("color-selector-channel", "_H"), N_("LCH Hue") },
{ 0, NULL, NULL }
};
diff --git a/libgimpwidgets/gimpwidgetsenums.h b/libgimpwidgets/gimpwidgetsenums.h
index a93c24d..0d8ca48 100644
--- a/libgimpwidgets/gimpwidgetsenums.h
+++ b/libgimpwidgets/gimpwidgetsenums.h
@@ -89,13 +89,16 @@ typedef enum
/**
* GimpColorSelectorChannel:
- * @GIMP_COLOR_SELECTOR_HUE: the hue channel
- * @GIMP_COLOR_SELECTOR_SATURATION: the saturation channel
- * @GIMP_COLOR_SELECTOR_VALUE: the value channel
- * @GIMP_COLOR_SELECTOR_RED: the red channel
- * @GIMP_COLOR_SELECTOR_GREEN: the green channel
- * @GIMP_COLOR_SELECTOR_BLUE: the blue channel
- * @GIMP_COLOR_SELECTOR_ALPHA: the alpha channel
+ * @GIMP_COLOR_SELECTOR_HUE: the hue channel
+ * @GIMP_COLOR_SELECTOR_SATURATION: the saturation channel
+ * @GIMP_COLOR_SELECTOR_VALUE: the value channel
+ * @GIMP_COLOR_SELECTOR_RED: the red channel
+ * @GIMP_COLOR_SELECTOR_GREEN: the green channel
+ * @GIMP_COLOR_SELECTOR_BLUE: the blue channel
+ * @GIMP_COLOR_SELECTOR_ALPHA: the alpha channel
+ * @GIMP_COLOR_SELECTOR_LCH_LIGHTNESS: the lightness channel
+ * @GIMP_COLOR_SELECTOR_LCH_CHOMA: the chroma channel
+ * @GIMP_COLOR_SELECTOR_LCH_HUE: the hue channel
*
* An enum to specify the types of color channels edited in
* #GimpColorSelector widgets.
@@ -106,13 +109,16 @@ GType gimp_color_selector_channel_get_type (void) G_GNUC_CONST;
typedef enum
{
- GIMP_COLOR_SELECTOR_HUE, /*< desc="_H", help="Hue" >*/
- GIMP_COLOR_SELECTOR_SATURATION, /*< desc="_S", help="Saturation" >*/
- GIMP_COLOR_SELECTOR_VALUE, /*< desc="_V", help="Value" >*/
- GIMP_COLOR_SELECTOR_RED, /*< desc="_R", help="Red" >*/
- GIMP_COLOR_SELECTOR_GREEN, /*< desc="_G", help="Green" >*/
- GIMP_COLOR_SELECTOR_BLUE, /*< desc="_B", help="Blue" >*/
- GIMP_COLOR_SELECTOR_ALPHA /*< desc="_A", help="Alpha" >*/
+ GIMP_COLOR_SELECTOR_HUE, /*< desc="_H", help="HSV Hue" >*/
+ GIMP_COLOR_SELECTOR_SATURATION, /*< desc="_S", help="HSV Saturation" >*/
+ GIMP_COLOR_SELECTOR_VALUE, /*< desc="_V", help="HSV Value" >*/
+ GIMP_COLOR_SELECTOR_RED, /*< desc="_R", help="Red" >*/
+ GIMP_COLOR_SELECTOR_GREEN, /*< desc="_G", help="Green" >*/
+ GIMP_COLOR_SELECTOR_BLUE, /*< desc="_B", help="Blue" >*/
+ GIMP_COLOR_SELECTOR_ALPHA, /*< desc="_A", help="Alpha" >*/
+ GIMP_COLOR_SELECTOR_LCH_LIGHTNESS, /*< desc="_L", help="LCH Lightness" >*/
+ GIMP_COLOR_SELECTOR_LCH_CHROMA, /*< desc="_C", help="LCH Chroma" >*/
+ GIMP_COLOR_SELECTOR_LCH_HUE /*< desc="_H", help="LCH Hue" >*/
} GimpColorSelectorChannel;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]