mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-03 17:33:25 +00:00
app, libgimpcolor: 2 new libgimpcolor functions.
Adding gimp_color_is_out_of_gamut() and gimp_color_is_out_of_self_gamut() and using them where relevant.
This commit is contained in:
parent
4a30f431fd
commit
ee19ad54d6
6 changed files with 197 additions and 132 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include "libgimpbase/gimpbase.h"
|
#include "libgimpbase/gimpbase.h"
|
||||||
|
#include "libgimpcolor/gimpcolor.h"
|
||||||
#include "libgimpwidgets/gimpwidgets.h"
|
#include "libgimpwidgets/gimpwidgets.h"
|
||||||
|
|
||||||
#include "widgets-types.h"
|
#include "widgets-types.h"
|
||||||
|
@ -504,24 +505,18 @@ gimp_color_history_palette_dirty (GimpColorHistory *history)
|
||||||
/* Now that palette colors can be any model and any space, just looking at
|
/* Now that palette colors can be any model and any space, just looking at
|
||||||
* whether they are out of [0; 1] range is not enough (a same color could
|
* whether they are out of [0; 1] range is not enough (a same color could
|
||||||
* be in or out range depending on the color space it is stored as).
|
* be in or out range depending on the color space it is stored as).
|
||||||
* I guess that what we are really looking for is whether a color is
|
* What we are really looking for is:
|
||||||
* out-of-gamut for the specifically active image.
|
* 1. Whether they are out of the palette (indexed image case);
|
||||||
* TODO
|
* 2. Whether they are out of the active image's space
|
||||||
|
* (independently of their own space).
|
||||||
*/
|
*/
|
||||||
#if 0
|
if (colormap_palette)
|
||||||
if (/* Common out-of-gamut case */
|
oog = (! gimp_palette_find_entry (colormap_palette, color, NULL));
|
||||||
(rgb.r < 0.0 || rgb.r > 1.0 ||
|
else if (history->active_image)
|
||||||
rgb.g < 0.0 || rgb.g > 1.0 ||
|
oog = gimp_color_is_out_of_gamut (color, gimp_image_get_layer_space (history->active_image));
|
||||||
rgb.b < 0.0 || rgb.b > 1.0) ||
|
else
|
||||||
/* Indexed images */
|
oog = gimp_color_is_out_of_self_gamut (color);
|
||||||
(colormap_palette && ! gimp_palette_find_entry (colormap_palette, color, NULL)) ||
|
|
||||||
/* Grayscale images */
|
|
||||||
(base_type == GIMP_GRAY &&
|
|
||||||
(ABS (rgb.r - rgb.g) > CHANNEL_EPSILON ||
|
|
||||||
ABS (rgb.r - rgb.b) > CHANNEL_EPSILON ||
|
|
||||||
ABS (rgb.g - rgb.b) > CHANNEL_EPSILON)))
|
|
||||||
oog = TRUE;
|
|
||||||
#endif
|
|
||||||
gimp_color_area_set_out_of_gamut (GIMP_COLOR_AREA (history->color_areas[i]), oog);
|
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],
|
g_signal_handlers_unblock_by_func (history->color_areas[i],
|
||||||
|
|
|
@ -933,50 +933,7 @@ gimp_fg_bg_editor_draw_color_frame (GimpFgBgEditor *editor,
|
||||||
{
|
{
|
||||||
const Babl *target_space = gimp_image_get_layer_space (editor->active_image);
|
const Babl *target_space = gimp_image_get_layer_space (editor->active_image);
|
||||||
|
|
||||||
if (base_type == GIMP_GRAY)
|
is_out_of_gamut = gimp_color_is_out_of_gamut (color, target_space);
|
||||||
{
|
|
||||||
gfloat gray[1];
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
gegl_color_get_pixel (color,
|
|
||||||
babl_format_with_space ("R'G'B' double", 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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,6 +144,184 @@ gimp_color_is_perceptually_identical (GeglColor *color1,
|
||||||
#undef SQR
|
#undef SQR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_color_is_out_of_self_gamut:
|
||||||
|
* @color: a [class@Gegl.Color]
|
||||||
|
*
|
||||||
|
* Determine whether @color is out of its own space gamut. This can only
|
||||||
|
* happen if the color space is unbounded and any of the color component
|
||||||
|
* is out of the `[0; 1]` range.
|
||||||
|
* A small error of margin is accepted, so that for instance a component
|
||||||
|
* at -0.0000001 is not making the whole color to be considered as
|
||||||
|
* out-of-gamut while it may just be computation imprecision.
|
||||||
|
*
|
||||||
|
* Returns: whether the color is out of its own color space gamut.
|
||||||
|
*
|
||||||
|
* Since: 3.0
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gimp_color_is_out_of_self_gamut (GeglColor *color)
|
||||||
|
{
|
||||||
|
const Babl *format;
|
||||||
|
const Babl *space;
|
||||||
|
const Babl *ctype;
|
||||||
|
gboolean oog = FALSE;
|
||||||
|
|
||||||
|
format = gegl_color_get_format (color);
|
||||||
|
space = babl_format_get_space (format);
|
||||||
|
/* XXX assuming that all components have the same type. */
|
||||||
|
ctype = babl_format_get_type (format, 0);
|
||||||
|
|
||||||
|
if (ctype == babl_type ("half") ||
|
||||||
|
ctype == babl_type ("float") ||
|
||||||
|
ctype == babl_type ("double"))
|
||||||
|
{
|
||||||
|
/* Only unbounded colors can be out-of-gamut. */
|
||||||
|
const Babl *model;
|
||||||
|
|
||||||
|
model = babl_format_get_model (format);
|
||||||
|
|
||||||
|
#define CHANNEL_EPSILON 1e-3
|
||||||
|
if (model == babl_model ("R'G'B'") ||
|
||||||
|
model == babl_model ("R~G~B~") ||
|
||||||
|
model == babl_model ("RGB") ||
|
||||||
|
model == babl_model ("R'G'B'A") ||
|
||||||
|
model == babl_model ("R~G~B~A") ||
|
||||||
|
model == babl_model ("RGBA"))
|
||||||
|
{
|
||||||
|
gdouble rgb[3];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color, babl_format_with_space ("RGB double", space), rgb);
|
||||||
|
|
||||||
|
oog = ((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 if (model == babl_model ("Y'") ||
|
||||||
|
model == babl_model ("Y~") ||
|
||||||
|
model == babl_model ("Y") ||
|
||||||
|
model == babl_model ("Y'A") ||
|
||||||
|
model == babl_model ("Y~A") ||
|
||||||
|
model == babl_model ("YA"))
|
||||||
|
{
|
||||||
|
gdouble gray[1];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color, babl_format_with_space ("Y double", space), gray);
|
||||||
|
oog = ((gray[0] < 0.0 && -gray[0] > CHANNEL_EPSILON) ||
|
||||||
|
(gray[0] > 1.0 && gray[0] - 1.0 > CHANNEL_EPSILON));
|
||||||
|
}
|
||||||
|
else if (model == babl_model ("CMYK") ||
|
||||||
|
model == babl_model ("CMYKA") ||
|
||||||
|
model == babl_model ("cmyk") ||
|
||||||
|
model == babl_model ("cmykA"))
|
||||||
|
{
|
||||||
|
gdouble cmyk[4];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color, babl_format_with_space ("CMYK double", space), cmyk);
|
||||||
|
oog = ((cmyk[0] < 0.0 && -cmyk[0] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[0] > 1.0 && cmyk[0] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[1] < 0.0 && -cmyk[1] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[1] > 1.0 && cmyk[1] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[2] < 0.0 && -cmyk[2] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[2] > 1.0 && cmyk[2] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[3] < 0.0 && -cmyk[3] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[3] > 1.0 && cmyk[3] - 1.0 > CHANNEL_EPSILON));
|
||||||
|
}
|
||||||
|
#undef CHANNEL_EPSILON
|
||||||
|
}
|
||||||
|
|
||||||
|
return oog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_color_is_out_of_gamut:
|
||||||
|
* @color: a [class@Gegl.Color]
|
||||||
|
* @space: a color space to convert @color to.
|
||||||
|
*
|
||||||
|
* Determine whether @color is out of its @space gamut.
|
||||||
|
* A small error of margin is accepted, so that for instance a component
|
||||||
|
* at -0.0000001 is not making the whole color to be considered as
|
||||||
|
* out-of-gamut while it may just be computation imprecision.
|
||||||
|
*
|
||||||
|
* Returns: whether the color is out of @space gamut.
|
||||||
|
*
|
||||||
|
* Since: 3.0
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gimp_color_is_out_of_gamut (GeglColor *color,
|
||||||
|
const Babl *space)
|
||||||
|
{
|
||||||
|
gboolean is_out_of_gamut = FALSE;
|
||||||
|
|
||||||
|
#define CHANNEL_EPSILON 1e-3
|
||||||
|
if (babl_space_is_gray (space))
|
||||||
|
{
|
||||||
|
gfloat gray[1];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color,
|
||||||
|
babl_format_with_space ("Y' float", 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", 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 if (babl_space_is_cmyk (space))
|
||||||
|
{
|
||||||
|
gdouble cmyk[4];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color,
|
||||||
|
babl_format_with_space ("CMYK double", space),
|
||||||
|
cmyk);
|
||||||
|
/* 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 = ((cmyk[0] < 0.0 && -cmyk[0] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[0] > 1.0 && cmyk[0] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[1] < 0.0 && -cmyk[1] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[1] > 1.0 && cmyk[1] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[2] < 0.0 && -cmyk[2] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[2] > 1.0 && cmyk[2] - 1.0 > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[3] < 0.0 && -cmyk[3] > CHANNEL_EPSILON) ||
|
||||||
|
(cmyk[3] > 1.0 && cmyk[3] - 1.0 > CHANNEL_EPSILON));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gdouble rgb[3];
|
||||||
|
|
||||||
|
gegl_color_get_pixel (color,
|
||||||
|
babl_format_with_space ("R'G'B' double", space),
|
||||||
|
rgb);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
#undef CHANNEL_EPSILON
|
||||||
|
|
||||||
|
return is_out_of_gamut;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Private functions. */
|
/* Private functions. */
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ EXPORTS
|
||||||
gimp_cmyka_get_uchar
|
gimp_cmyka_get_uchar
|
||||||
gimp_cmyka_set
|
gimp_cmyka_set
|
||||||
gimp_cmyka_set_uchar
|
gimp_cmyka_set_uchar
|
||||||
|
gimp_color_is_out_of_gamut
|
||||||
|
gimp_color_is_out_of_self_gamut
|
||||||
gimp_color_is_perceptually_identical
|
gimp_color_is_perceptually_identical
|
||||||
gimp_color_managed_get_color_profile
|
gimp_color_managed_get_color_profile
|
||||||
gimp_color_managed_get_icc_profile
|
gimp_color_managed_get_icc_profile
|
||||||
|
|
|
@ -56,6 +56,9 @@ gboolean gimp_color_is_perceptually_identical (GeglColor *color1,
|
||||||
GeglColor * gimp_color_parse_css (const gchar *css,
|
GeglColor * gimp_color_parse_css (const gchar *css,
|
||||||
gint len);
|
gint len);
|
||||||
|
|
||||||
|
gboolean gimp_color_is_out_of_self_gamut (GeglColor *color);
|
||||||
|
gboolean gimp_color_is_out_of_gamut (GeglColor *color,
|
||||||
|
const Babl *space);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -461,77 +461,7 @@ gimp_color_area_draw (GtkWidget *widget,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->config && ! oog)
|
if (priv->config && ! oog)
|
||||||
{
|
oog = gimp_color_is_out_of_self_gamut (priv->color);
|
||||||
const Babl *format;
|
|
||||||
const Babl *space;
|
|
||||||
const Babl *ctype;
|
|
||||||
|
|
||||||
format = gegl_color_get_format (priv->color);
|
|
||||||
space = babl_format_get_space (format);
|
|
||||||
/* XXX assuming that all components have the same type. */
|
|
||||||
ctype = babl_format_get_type (format, 0);
|
|
||||||
|
|
||||||
if (ctype == babl_type ("half") ||
|
|
||||||
ctype == babl_type ("float") ||
|
|
||||||
ctype == babl_type ("double"))
|
|
||||||
{
|
|
||||||
/* Only unbounded colors can be out-of-gamut. */
|
|
||||||
const Babl *model;
|
|
||||||
|
|
||||||
model = babl_format_get_model (format);
|
|
||||||
|
|
||||||
#define CHANNEL_EPSILON 1e-3
|
|
||||||
if (model == babl_model ("R'G'B'") ||
|
|
||||||
model == babl_model ("R~G~B~") ||
|
|
||||||
model == babl_model ("RGB") ||
|
|
||||||
model == babl_model ("R'G'B'A") ||
|
|
||||||
model == babl_model ("R~G~B~A") ||
|
|
||||||
model == babl_model ("RGBA"))
|
|
||||||
{
|
|
||||||
gdouble rgb[3];
|
|
||||||
|
|
||||||
gegl_color_get_pixel (priv->color, babl_format_with_space ("RGB double", space), rgb);
|
|
||||||
|
|
||||||
oog = ((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 if (model == babl_model ("Y'") ||
|
|
||||||
model == babl_model ("Y~") ||
|
|
||||||
model == babl_model ("Y") ||
|
|
||||||
model == babl_model ("Y'A") ||
|
|
||||||
model == babl_model ("Y~A") ||
|
|
||||||
model == babl_model ("YA"))
|
|
||||||
{
|
|
||||||
gdouble gray[1];
|
|
||||||
|
|
||||||
gegl_color_get_pixel (priv->color, babl_format_with_space ("Y double", space), gray);
|
|
||||||
oog = ((gray[0] < 0.0 && -gray[0] > CHANNEL_EPSILON) ||
|
|
||||||
(gray[0] > 1.0 && gray[0] - 1.0 > CHANNEL_EPSILON));
|
|
||||||
}
|
|
||||||
else if (model == babl_model ("CMYK") ||
|
|
||||||
model == babl_model ("CMYKA") ||
|
|
||||||
model == babl_model ("cmyk") ||
|
|
||||||
model == babl_model ("cmykA"))
|
|
||||||
{
|
|
||||||
gdouble cmyk[4];
|
|
||||||
|
|
||||||
gegl_color_get_pixel (priv->color, babl_format_with_space ("CMYK double", space), cmyk);
|
|
||||||
oog = ((cmyk[0] < 0.0 && -cmyk[0] > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[0] > 1.0 && cmyk[0] - 1.0 > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[1] < 0.0 && -cmyk[1] > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[1] > 1.0 && cmyk[1] - 1.0 > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[2] < 0.0 && -cmyk[2] > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[2] > 1.0 && cmyk[2] - 1.0 > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[3] < 0.0 && -cmyk[3] > CHANNEL_EPSILON) ||
|
|
||||||
(cmyk[3] > 1.0 && cmyk[3] - 1.0 > CHANNEL_EPSILON));
|
|
||||||
}
|
|
||||||
#undef CHANNEL_EPSILON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->config && oog)
|
if (priv->config && oog)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue