app, libgimp*: more GeglColor's space invasion.

- New function gimp_cairo_set_source_color() which is meant to replace
  gimp_cairo_set_source_rgb(a?)() eventually. This new function sets the Cairo
  source color, using the target monitor's profile of the widget where the Cairo
  surface is meant to be drawn on. It also uses the color management settings
  (such as whether a custom profile was set, instead of using system profile, or
  also simply whether color management was disabled at all). It doesn't
  soft-proof the color yet.
- Padding and out-of-gamut colors drawing now use the new
  gimp_cairo_set_source_color(). These don't need any soft-proofing anyway.
- Out-of-gamut color property in GimpColorConfig is now a GeglColor property.
This commit is contained in:
Jehan 2023-11-22 23:38:25 +01:00
parent b06fe36970
commit 559297a5cb
14 changed files with 225 additions and 97 deletions

View File

@ -1527,11 +1527,11 @@ prefs_dialog_new (Gimp *gimp,
_("Mar_k out of gamut colors"));
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
button = gimp_prop_color_button_new (color_config, "out-of-gamut-color",
_("Select Warning Color"),
PREFS_COLOR_BUTTON_WIDTH,
PREFS_COLOR_BUTTON_HEIGHT,
GIMP_COLOR_AREA_FLAT);
button = gimp_prop_gegl_color_button_new (color_config, "out-of-gamut-color",
_("Select Warning Color"),
PREFS_COLOR_BUTTON_WIDTH,
PREFS_COLOR_BUTTON_HEIGHT,
GIMP_COLOR_AREA_FLAT);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gimp_color_panel_set_context (GIMP_COLOR_PANEL (button),

View File

@ -89,10 +89,13 @@ gimp_display_shell_draw_background (GimpDisplayShell *shell,
if (canvas->padding_mode != GIMP_CANVAS_PADDING_MODE_DEFAULT)
{
GimpRGB rgb;
GimpColorConfig *config = gimp_display_shell_get_color_config (shell);
gegl_color_get_pixel (canvas->padding_color, babl_format ("R'G'B'A double"), &rgb);
gimp_cairo_set_source_rgb (cr, &rgb);
/* Padding color is color-managed to shell's monitor profile but not
* soft-proofed.
*/
gimp_cairo_set_source_color (cr, canvas->padding_color, config, FALSE,
GTK_WIDGET (shell));
cairo_paint (cr);
}
}

View File

@ -892,7 +892,6 @@ gimp_fg_bg_editor_draw_color_frame (GimpFgBgEditor *editor,
gdouble srgb_color[4];
gdouble transformed_color[4];
gboolean is_out_of_gamut;
const Babl *target_space = NULL;
if (editor->active_image)
{
@ -931,53 +930,58 @@ gimp_fg_bg_editor_draw_color_frame (GimpFgBgEditor *editor,
cairo_fill (cr);
if (editor->active_image)
target_space = gimp_image_get_layer_space (editor->active_image);
else
target_space = babl_space ("sRGB");
if (base_type == GIMP_GRAY)
{
gfloat gray[1];
const Babl *target_space = gimp_image_get_layer_space (editor->active_image);
gegl_color_get_pixel (color,
babl_format_with_space ("Y' float", target_space),
gray);
is_out_of_gamut = ((gray[0] < 0.0 && -gray[0] > CHANNEL_EPSILON) ||
(gray[0] > 1.0 && gray[0] - 1.0 > CHANNEL_EPSILON));
if (base_type == GIMP_GRAY)
{
gfloat gray[1];
if (! is_out_of_gamut)
gegl_color_get_pixel (color,
babl_format_with_space ("Y' float", target_space),
gray);
is_out_of_gamut = ((gray[0] < 0.0 && -gray[0] > CHANNEL_EPSILON) ||
(gray[0] > 1.0 && gray[0] - 1.0 > CHANNEL_EPSILON));
if (! is_out_of_gamut)
{
gdouble rgb[3];
/* Grayscale colors can be out of gamut if the color is out of the [0;
* 1] range in the target space and also if they can be converted to
* RGB with non-equal components.
*/
gegl_color_get_pixel (color,
babl_format_with_space ("R'G'B' double", target_space),
rgb);
is_out_of_gamut = (ABS (rgb[0] - rgb[0]) > CHANNEL_EPSILON ||
ABS (rgb[1] - rgb[1]) > CHANNEL_EPSILON ||
ABS (rgb[2] - rgb[2]) > CHANNEL_EPSILON);
}
}
else
{
gdouble rgb[3];
/* Grayscale colors can be out of gamut if the color is out of the [0;
* 1] range in the target space and also if they can be converted to
* RGB with non-equal components.
*/
gegl_color_get_pixel (color,
babl_format_with_space ("R'G'B' float", target_space),
babl_format_with_space ("R'G'B' double", target_space),
rgb);
is_out_of_gamut = (ABS (rgb[0] - rgb[0]) > CHANNEL_EPSILON ||
ABS (rgb[1] - rgb[1]) > CHANNEL_EPSILON ||
ABS (rgb[2] - rgb[2]) > CHANNEL_EPSILON);
/* We make sure that each component is within [0; 1], but accept a small
* error of margin (we don't want to show small precision errors as
* out-of-gamut colors).
*/
is_out_of_gamut = ((rgb[0] < 0.0 && -rgb[0] > CHANNEL_EPSILON) ||
(rgb[0] > 1.0 && rgb[0] - 1.0 > CHANNEL_EPSILON) ||
(rgb[1] < 0.0 && -rgb[1] > CHANNEL_EPSILON) ||
(rgb[1] > 1.0 && rgb[1] - 1.0 > CHANNEL_EPSILON) ||
(rgb[2] < 0.0 && -rgb[2] > CHANNEL_EPSILON) ||
(rgb[2] > 1.0 && rgb[2] - 1.0 > CHANNEL_EPSILON));
}
}
else
{
gdouble rgb[3];
gegl_color_get_pixel (color,
babl_format_with_space ("R'G'B' float", target_space),
rgb);
/* We make sure that each component is within [0; 1], but accept a small
* error of margin (we don't want to show small precision errors as
* out-of-gamut colors).
*/
is_out_of_gamut = ((rgb[0] < 0.0 && -rgb[0] > CHANNEL_EPSILON) ||
(rgb[0] > 1.0 && rgb[0] - 1.0 > CHANNEL_EPSILON) ||
(rgb[1] < 0.0 && -rgb[1] > CHANNEL_EPSILON) ||
(rgb[1] > 1.0 && rgb[1] - 1.0 > CHANNEL_EPSILON) ||
(rgb[2] < 0.0 && -rgb[2] > CHANNEL_EPSILON) ||
(rgb[2] > 1.0 && rgb[2] - 1.0 > CHANNEL_EPSILON));
/* Without active image, we are never out of gamut. */
is_out_of_gamut = FALSE;
}
if (editor->color_config &&
@ -987,20 +991,24 @@ gimp_fg_bg_editor_draw_color_frame (GimpFgBgEditor *editor,
(colormap_palette &&
! gimp_palette_find_entry (colormap_palette, color, NULL))))
{
gint corner_x = x + 0.5 * (1.0 - corner_dx) * width;
gint corner_y = y + 0.5 * (1.0 - corner_dy) * height;
gint side = MIN (width, height) * 2 / 3;
GimpRGB out_of_gamut_color;
GeglColor *out_of_gamut_color;
gint corner_x = x + 0.5 * (1.0 - corner_dx) * width;
gint corner_y = y + 0.5 * (1.0 - corner_dy) * height;
gint side = MIN (width, height) * 2 / 3;
cairo_move_to (cr, corner_x, corner_y);
cairo_line_to (cr, corner_x + side * corner_dx, corner_y);
cairo_line_to (cr, corner_x, corner_y + side * corner_dy);
cairo_close_path (cr);
gimp_color_config_get_out_of_gamut_color (editor->color_config,
&out_of_gamut_color);
gimp_cairo_set_source_rgb (cr, &out_of_gamut_color);
out_of_gamut_color = gimp_color_config_get_out_of_gamut_color (editor->color_config);
/* Out-of-gamut color is color-managed to FG/BG editor's monitor profile
* but not soft-proofed.
*/
gimp_cairo_set_source_color (cr, out_of_gamut_color, editor->color_config, FALSE, GTK_WIDGET (editor));
cairo_fill (cr);
g_object_unref (out_of_gamut_color);
}
cairo_set_line_width (cr, 1.0);

View File

@ -160,7 +160,7 @@ struct _GimpColorConfigPrivate
gboolean simulation_use_black_point_compensation;
gboolean simulation_optimize;
gboolean simulation_gamut_check;
GimpRGB out_of_gamut_color;
GeglColor *out_of_gamut_color;
gboolean show_rgb_u8;
gboolean show_hsv;
@ -209,9 +209,13 @@ static void
gimp_color_config_class_init (GimpColorConfigClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpRGB color;
GeglColor *magenta;
gimp_rgba_set (&color, 1.0, 0.0, 1.0, 1.0); /* magenta */
babl_init ();
/* Magenta (sRGB space). */
magenta = gegl_color_new (NULL);
gegl_color_set_rgba (magenta, 1.0, 0.0, 1.0, 1.0);
object_class->finalize = gimp_color_config_finalize;
object_class->set_property = gimp_color_config_set_property;
@ -318,12 +322,12 @@ gimp_color_config_class_init (GimpColorConfigClass *klass)
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_RGB (object_class, PROP_OUT_OF_GAMUT_COLOR,
"out-of-gamut-color",
_("Out of gamut warning color"),
OUT_OF_GAMUT_COLOR_BLURB,
FALSE, &color,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_COLOR (object_class, PROP_OUT_OF_GAMUT_COLOR,
"out-of-gamut-color",
_("Out of gamut warning color"),
OUT_OF_GAMUT_COLOR_BLURB,
magenta,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_RGB_U8,
"show-rgb-u8",
@ -338,12 +342,20 @@ gimp_color_config_class_init (GimpColorConfigClass *klass)
_("Show HSV instead of LCH"),
FALSE,
GIMP_PARAM_STATIC_STRINGS);
g_object_unref (magenta);
}
static void
gimp_color_config_init (GimpColorConfig *config)
{
GeglColor *magenta = gegl_color_new (NULL);
config->priv = gimp_color_config_get_instance_private (config);
/* Magenta (sRGB space). */
gegl_color_set_rgba (magenta, 1.0, 0.0, 1.0, 1.0);
config->priv->out_of_gamut_color = magenta;
}
static void
@ -425,7 +437,8 @@ gimp_color_config_set_property (GObject *object,
priv->simulation_gamut_check = g_value_get_boolean (value);
break;
case PROP_OUT_OF_GAMUT_COLOR:
priv->out_of_gamut_color = *(GimpRGB *) g_value_get_boxed (value);
g_clear_object (&priv->out_of_gamut_color);
priv->out_of_gamut_color = gegl_color_duplicate (g_value_get_object (value));
break;
case PROP_SHOW_RGB_U8:
priv->show_rgb_u8 = g_value_get_boolean (value);
@ -499,7 +512,7 @@ gimp_color_config_get_property (GObject *object,
g_value_set_boolean (value, priv->simulation_gamut_check);
break;
case PROP_OUT_OF_GAMUT_COLOR:
g_value_set_boxed (value, &priv->out_of_gamut_color);
g_value_set_object (value, priv->out_of_gamut_color);
break;
case PROP_SHOW_RGB_U8:
g_value_set_boolean (value, priv->show_rgb_u8);
@ -649,18 +662,17 @@ gimp_color_config_get_simulation_gamut_check (GimpColorConfig *config)
/**
* gimp_color_config_get_out_of_gamut_color:
* @config: a #GimpColorConfig
* @color: return location for a #GimpRGB
*
* Returns: (transfer full): the [class@Gegl.Color] to use to represent
* out-of-gamut pixels.
* Since: 3.0
**/
void
gimp_color_config_get_out_of_gamut_color (GimpColorConfig *config,
GimpRGB *color)
GeglColor *
gimp_color_config_get_out_of_gamut_color (GimpColorConfig *config)
{
g_return_if_fail (GIMP_IS_COLOR_CONFIG (config));
g_return_if_fail (color != NULL);
g_return_val_if_fail (GIMP_IS_COLOR_CONFIG (config), NULL);
*color = GET_PRIVATE (config)->out_of_gamut_color;
return gegl_color_duplicate (GET_PRIVATE (config)->out_of_gamut_color);
}
/**

View File

@ -75,8 +75,7 @@ GimpColorRenderingIntent
gboolean gimp_color_config_get_simulation_bpc (GimpColorConfig *config);
gboolean gimp_color_config_get_simulation_optimize (GimpColorConfig *config);
gboolean gimp_color_config_get_simulation_gamut_check (GimpColorConfig *config);
void gimp_color_config_get_out_of_gamut_color (GimpColorConfig *config,
GimpRGB *color);
GeglColor * gimp_color_config_get_out_of_gamut_color (GimpColorConfig *config);
GimpColorProfile * gimp_color_config_get_rgb_color_profile (GimpColorConfig *config,
GError **error);

View File

@ -19,6 +19,8 @@
#ifndef __GIMP_CONFIG_H__
#define __GIMP_CONFIG_H__
#include <gegl.h>
#define __GIMP_CONFIG_H_INSIDE__
#include <libgimpconfig/gimpconfigtypes.h>

View File

@ -28,8 +28,10 @@
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpconfig/gimpconfig.h"
#include "gimpcairo-utils.h"
#include "gimpwidgetsutils.h"
/**
@ -200,3 +202,55 @@ gimp_cairo_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
return surface;
}
/**
* gimp_cairo_set_source_color:
* @cr: Cairo context.
* @color: the [class@Gegl.Color] to use as source pattern within @cr.
* @config: the color management settings.
* @softproof: whether the color must also be soft-proofed.
* @widget: (nullable): [class@Gtk.Widget] to draw the focus indicator on.
*
* Sets @color as the source pattern within @cr, taking into account the profile
* of the [class@Gdk.Monitor] which @widget is displayed on.
*
* If @config is set, the color configuration as set by the user will be used,
* in particular using any custom monitor profile set in preferences (overriding
* system-set profile). If no such custom profile is set, it will use the
* profile of the monitor @widget is displayed on and will default to sRGB if
* @widget is %NULL.
*
* Use [func@Gimp.get_color_configuration] to retrieve the user
* [class@Gimp.ColorConfig].
*
* TODO: @softproof is currently unused.
*
* Since: 3.0
**/
void
gimp_cairo_set_source_color (cairo_t *cr,
GeglColor *color,
GimpColorConfig *config,
gboolean softproof,
GtkWidget *widget)
{
GimpColorProfile *proof_profile = NULL;
GimpColorProfile *dest_profile = NULL;
const Babl *space = NULL;
gdouble rgba[4];
g_return_if_fail (GEGL_IS_COLOR (color));
g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
_gimp_widget_get_profiles (widget, config,
softproof ? &proof_profile : NULL,
&dest_profile);
if (dest_profile)
space = gimp_color_profile_get_space (dest_profile,
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
NULL);
gegl_color_get_pixel (color, babl_format_with_space ("R'G'B'A double", space), rgba);
cairo_set_source_rgba (cr, rgba[0], rgba[1], rgba[2], rgba[3]);
}

View File

@ -32,5 +32,11 @@ gboolean gimp_cairo_set_focus_line_pattern (cairo_t *cr,
cairo_surface_t * gimp_cairo_surface_create_from_pixbuf (GdkPixbuf *pixbuf);
void gimp_cairo_set_source_color (cairo_t *cr,
GeglColor *color,
GimpColorConfig *config,
gboolean softproof,
GtkWidget *widget);
#endif /* __GIMP_CAIRO_UTILS_H__ */

View File

@ -464,18 +464,20 @@ gimp_color_area_draw (GtkWidget *widget,
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;
GeglColor *oog_color;
gint side = MIN (priv->width, priv->height) * 2 / 3;
cairo_move_to (cr, priv->width, 0);
cairo_line_to (cr, priv->width - side, 0);
cairo_line_to (cr, priv->width, side);
cairo_line_to (cr, priv->width, 0);
gimp_color_config_get_out_of_gamut_color (priv->config, &color);
gimp_cairo_set_source_rgb (cr, &color);
oog_color = gimp_color_config_get_out_of_gamut_color (priv->config);
gimp_cairo_set_source_color (cr, oog_color, priv->config, FALSE, widget);
cairo_fill (cr);
g_object_unref (oog_color);
}
if (priv->draw_border)

View File

@ -969,14 +969,16 @@ gimp_color_scale_notify_config (GimpColorConfig *config,
GimpColorScale *scale)
{
GimpColorScalePrivate *priv = GET_PRIVATE (scale);
GimpRGB color;
GeglColor *color;
gimp_color_scale_destroy_transform (scale);
gimp_color_config_get_out_of_gamut_color (config, &color);
gimp_rgb_get_uchar (&color,
priv->oog_color,
priv->oog_color + 1,
priv->oog_color + 2);
color = gimp_color_config_get_out_of_gamut_color (config);
/* TODO: shouldn't this be color-managed too, using the target space into
* consideration?
*/
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), priv->oog_color);
priv->needs_render = TRUE;
g_object_unref (color);
}

View File

@ -1981,15 +1981,17 @@ gimp_color_select_notify_config (GimpColorConfig *config,
const GParamSpec *pspec,
GimpColorSelect *select)
{
GimpRGB color;
GeglColor *color;
gimp_color_select_destroy_transform (select);
gimp_color_config_get_out_of_gamut_color (config, &color);
gimp_rgb_get_uchar (&color,
select->oog_color,
select->oog_color + 1,
select->oog_color + 2);
color = gimp_color_config_get_out_of_gamut_color (config);
/* TODO: shouldn't this be color-managed too, using the target space into
* consideration?
*/
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), select->oog_color);
select->xy_needs_render = TRUE;
select->z_needs_render = TRUE;
g_object_unref (color);
}

View File

@ -16,6 +16,7 @@ EXPORTS
gimp_button_get_type
gimp_button_new
gimp_cairo_set_focus_line_pattern
gimp_cairo_set_source_color
gimp_cairo_surface_create_from_pixbuf
gimp_cell_renderer_color_get_type
gimp_cell_renderer_color_new

View File

@ -1005,20 +1005,19 @@ gimp_widget_get_color_transform (GtkWidget *widget,
if (gimp_color_config_get_simulation_gamut_check (config))
{
GimpRGB color;
cmsUInt16Number alarmCodes[cmsMAXCHANNELS] = { 0, };
guchar r, g, b;
GeglColor *color;
cmsUInt16Number alarmCodes[cmsMAXCHANNELS] = { 0, };
flags |= GIMP_COLOR_TRANSFORM_FLAGS_GAMUT_CHECK;
gimp_color_config_get_out_of_gamut_color (config, &color);
gimp_rgb_get_uchar (&color, &r, &g, &b);
alarmCodes[0] = (cmsUInt16Number) r * 256;
alarmCodes[1] = (cmsUInt16Number) g * 256;
alarmCodes[2] = (cmsUInt16Number) b * 256;
color = gimp_color_config_get_out_of_gamut_color (config);
/* Little-CMS documentation doesn't say which space should the
* out-of-gamut color be. Let's just give sRGB data.
*/
gegl_color_get_pixel (color, babl_format ("R'G'B' u16"), alarmCodes);
cmsSetAlarmCodes (alarmCodes);
g_object_unref (color);
}
cache->transform =
@ -1107,6 +1106,35 @@ gimp_widget_set_native_handle (GtkWidget *widget,
}
/* Internal functions */
void
_gimp_widget_get_profiles (GtkWidget *widget,
GimpColorConfig *config,
GimpColorProfile **proof_profile,
GimpColorProfile **dest_profile)
{
g_return_if_fail (dest_profile != NULL && *dest_profile == NULL);
g_return_if_fail (proof_profile == NULL || *proof_profile == NULL);
switch (gimp_color_config_get_mode (config))
{
case GIMP_COLOR_MANAGEMENT_OFF:
return;
case GIMP_COLOR_MANAGEMENT_SOFTPROOF:
if (proof_profile)
*proof_profile = gimp_color_config_get_simulation_color_profile (config, NULL);
/* fallthru */
case GIMP_COLOR_MANAGEMENT_DISPLAY:
*dest_profile = get_display_profile (widget, config);
break;
}
}
/* Private functions */
#ifdef GDK_WINDOWING_WAYLAND

View File

@ -68,6 +68,15 @@ GimpColorTransform * gimp_widget_get_color_transform (GtkWidget *widget,
void gimp_widget_set_native_handle (GtkWidget *widget,
GBytes **handle);
/* Internal use */
G_GNUC_INTERNAL void _gimp_widget_get_profiles (GtkWidget *widget,
GimpColorConfig *config,
GimpColorProfile **proof_profile,
GimpColorProfile **dest_profile);
G_END_DECLS
#endif /* __GIMP_WIDGETS_UTILS_H__ */