diff --git a/libgimpcolor/gimpcolor.c b/libgimpcolor/gimpcolor.c new file mode 100644 index 0000000000..9fc6013d1e --- /dev/null +++ b/libgimpcolor/gimpcolor.c @@ -0,0 +1,125 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpcolor.c + * Copyright (C) 2023 Jehan + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "gimpcolor.h" + + +/** + * SECTION: gimpcolor + * @title: GimpColor + * @short_description: API to manipulate [class@Gegl.Color] objects. + * + * #GimpColor contains a few helper functions to manipulate [class@Gegl.Color] + * objects more easily. + **/ + +/** + * gimp_color_set_alpha: + * @color: a [class@Gegl.Color] + * @alpha: new value for the alpha channel. + * + * Update the @alpha channel, and any other component if necessary (e.g. in case + * of premultiplied channels), without changing the format of @color. + * + * If @color has no alpha component, this function is a no-op. + * + * Since: 3.0 + **/ +void +gimp_color_set_alpha (GeglColor *color, + gdouble alpha) +{ + const Babl *format; + gdouble red; + gdouble green; + gdouble blue; + guint8 pixel[40]; + + format = gegl_color_get_format (color); + + gegl_color_get_rgba (color, &red, &green, &blue, NULL); + gegl_color_set_rgba (color, red, green, blue, alpha); + + /* I could stop at this point, but we want to keep the initial format as much + * as possible. Since we made a round-trip through linear RGBA float, we need + * to reset the right format. + * + * Also why we do this round trip is because we know we can just change the + * alpha channel and babl fishes will do the appropriate conversion. I first + * thought of updating the alpha channel directly by editing the raw data + * depending on the format, but doing so would break e.g. with premultiplied + * channels. Babl already has all the internal knowledge so let it do its + * thing. The only risk is the possible precision loss during conversion. + * Let's assume that since we use an unbounded 32-bit intermediate value + * (float), the loss would be acceptable. + */ + gegl_color_get_pixel (color, format, pixel); + gegl_color_set_pixel (color, format, pixel); +} + +/** + * gimp_color_is_perceptually_identical: + * @color1: a [class@Gegl.Color] + * @color2: a [class@Gegl.Color] + * + * Determine whether @color1 and @color2 can be considered identical to the + * human eyes, by computing the distance in a color space as perceptually + * uniform as possible. + * + * Returns: whether the 2 colors can be considered the same for the human eyes. + * + * Since: 3.0 + **/ +gboolean +gimp_color_is_perceptually_identical (GeglColor *color1, + GeglColor *color2) +{ + gfloat pixel1[3]; + gfloat pixel2[3]; + + g_return_val_if_fail (GEGL_IS_COLOR (color1), FALSE); + g_return_val_if_fail (GEGL_IS_COLOR (color2), FALSE); + + /* CIE LCh space is considered quite perceptually uniform, a bit better than + * Lab on this aspect, AFAIU. + */ + gegl_color_get_pixel (color1, babl_format ("CIE LCH(ab) float"), pixel1); + gegl_color_get_pixel (color2, babl_format ("CIE LCH(ab) float"), pixel2); + + /* This is not a proper distance computation, but is acceptable for our use + * case while being simpler. While we used to use 1e-6 as threshold with float + * RGB, LCh is not in [0, 1] range, and some channels can reach over 300 with + * wide gamut spaces. This is why use the threshold is 1e-4 right now. + */ +#define SQR(x) ((x) * (x)) + return (SQR (pixel1[0] - pixel2[0]) + + SQR (pixel1[1] - pixel2[1]) + + SQR (pixel1[2] - pixel2[2]) <= 1e-4); +#undef SQR +} diff --git a/libgimpcolor/gimpcolor.def b/libgimpcolor/gimpcolor.def index a016f042d4..7390e740f3 100644 --- a/libgimpcolor/gimpcolor.def +++ b/libgimpcolor/gimpcolor.def @@ -19,6 +19,7 @@ EXPORTS gimp_cmyka_get_uchar gimp_cmyka_set gimp_cmyka_set_uchar + gimp_color_is_perceptually_identical gimp_color_managed_get_color_profile gimp_color_managed_get_icc_profile gimp_color_managed_get_simulation_bpc @@ -58,6 +59,7 @@ EXPORTS gimp_color_profile_new_rgb_srgb_linear gimp_color_profile_new_srgb_trc_from_color_profile gimp_color_profile_save_to_file + gimp_color_set_alpha gimp_color_transform_can_gegl_copy gimp_color_transform_get_type gimp_color_transform_new diff --git a/libgimpcolor/gimpcolor.h b/libgimpcolor/gimpcolor.h index 7e960a14ea..d4aa629790 100644 --- a/libgimpcolor/gimpcolor.h +++ b/libgimpcolor/gimpcolor.h @@ -38,4 +38,22 @@ #undef __GIMP_COLOR_H_INSIDE__ +G_BEGIN_DECLS + +/* + * GEGL_TYPE_COLOR + */ + +#define GIMP_VALUE_HOLDS_COLOR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GEGL_TYPE_COLOR)) + + +void gimp_color_set_alpha (GeglColor *color, + gdouble alpha); + +gboolean gimp_color_is_perceptually_identical (GeglColor *color1, + GeglColor *color2); + + +G_END_DECLS + #endif /* __GIMP_COLOR_H__ */ diff --git a/libgimpcolor/gimprgb.h b/libgimpcolor/gimprgb.h index 6215a397e3..144880f3dd 100644 --- a/libgimpcolor/gimprgb.h +++ b/libgimpcolor/gimprgb.h @@ -28,12 +28,6 @@ G_BEGIN_DECLS /* For information look into the C source or the html documentation */ -/* - * GIMP_TYPE_COLOR - */ - -#define GIMP_VALUE_HOLDS_COLOR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GEGL_TYPE_COLOR)) - /* * GIMP_TYPE_RGB */ diff --git a/libgimpcolor/meson.build b/libgimpcolor/meson.build index 99e7a1ff1f..a4aefe051e 100644 --- a/libgimpcolor/meson.build +++ b/libgimpcolor/meson.build @@ -4,6 +4,7 @@ libgimpcolor_sources = files( 'gimpbilinear.c', 'gimpcairo.c', 'gimpcmyk.c', + 'gimpcolor.c', 'gimpcolormanaged.c', 'gimpcolorprofile.c', 'gimpcolorspace.c',