diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:13:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:13:10 +0000 |
commit | 3c57dd931145d43f2b0aef96c4d178135956bf91 (patch) | |
tree | 3de698981e9f0cc2c4f9569b19a5f3595e741f6b /libgimpcolor/gimprgb.c | |
parent | Initial commit. (diff) | |
download | gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip |
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libgimpcolor/gimprgb.c')
-rw-r--r-- | libgimpcolor/gimprgb.c | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/libgimpcolor/gimprgb.c b/libgimpcolor/gimprgb.c new file mode 100644 index 0000000..b9ab4be --- /dev/null +++ b/libgimpcolor/gimprgb.c @@ -0,0 +1,846 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * 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 + * Library 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 + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <babl/babl.h> +#include <glib-object.h> + +#define GIMP_DISABLE_DEPRECATION_WARNINGS /* for GIMP_RGB_INTENSITY() */ +#include "libgimpmath/gimpmath.h" + +#include "gimpcolortypes.h" + +#undef GIMP_DISABLE_DEPRECATED /* for GIMP_RGB_INTENSITY() */ +#include "gimprgb.h" + + +/** + * SECTION: gimprgb + * @title: GimpRGB + * @short_description: Definitions and Functions relating to RGB colors. + * + * Definitions and Functions relating to RGB colors. + **/ + + +/* + * GIMP_TYPE_RGB + */ + +static GimpRGB * gimp_rgb_copy (const GimpRGB *rgb); + + +GType +gimp_rgb_get_type (void) +{ + static GType rgb_type = 0; + + if (!rgb_type) + rgb_type = g_boxed_type_register_static ("GimpRGB", + (GBoxedCopyFunc) gimp_rgb_copy, + (GBoxedFreeFunc) g_free); + + return rgb_type; +} + +void +gimp_value_get_rgb (const GValue *value, + GimpRGB *rgb) +{ + g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value)); + g_return_if_fail (rgb != NULL); + + if (value->data[0].v_pointer) + *rgb = *((GimpRGB *) value->data[0].v_pointer); + else + gimp_rgba_set (rgb, 0.0, 0.0, 0.0, 1.0); +} + +void +gimp_value_set_rgb (GValue *value, + const GimpRGB *rgb) +{ + g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value)); + g_return_if_fail (rgb != NULL); + + g_value_set_boxed (value, rgb); +} + +static GimpRGB * +gimp_rgb_copy (const GimpRGB *rgb) +{ + return g_memdup (rgb, sizeof (GimpRGB)); +} + + +/* RGB functions */ + +/** + * gimp_rgb_set: + * @rgb: a #GimpRGB struct + * @red: the red component + * @green: the green component + * @blue: the blue component + * + * Sets the red, green and blue components of @rgb and leaves the + * alpha component unchanged. The color values should be between 0.0 + * and 1.0 but there is no check to enforce this and the values are + * set exactly as they are passed in. + **/ +void +gimp_rgb_set (GimpRGB *rgb, + gdouble r, + gdouble g, + gdouble b) +{ + g_return_if_fail (rgb != NULL); + + rgb->r = r; + rgb->g = g; + rgb->b = b; +} + +/** + * gimp_rgb_set_alpha: + * @rgb: a #GimpRGB struct + * @alpha: the alpha component + * + * Sets the alpha component of @rgb and leaves the RGB components unchanged. + **/ +void +gimp_rgb_set_alpha (GimpRGB *rgb, + gdouble a) +{ + g_return_if_fail (rgb != NULL); + + rgb->a = a; +} + +/** + * gimp_rgb_set_pixel: + * @rgb: a #GimpRGB struct + * @format: a Babl format + * @pixel: pointer to the source pixel + * + * Sets the red, green and blue components of @rgb from the color + * stored in @pixel. The pixel format of @pixel is determined by + * @format. + * + * Since: 2.10 + **/ +void +gimp_rgb_set_pixel (GimpRGB *rgb, + const Babl *format, + gconstpointer pixel) +{ + g_return_if_fail (rgb != NULL); + g_return_if_fail (format != NULL); + g_return_if_fail (pixel != NULL); + + babl_process (babl_fish (format, + babl_format ("R'G'B' double")), + pixel, rgb, 1); +} + +/** + * gimp_rgb_get_pixel: + * @rgb: a #GimpRGB struct + * @format: a Babl format + * @pixel: pointer to the destination pixel + * + * Writes the red, green, blue and alpha components of @rgb to the + * color stored in @pixel. The pixel format of @pixel is determined by + * @format. + * + * Since: 2.10 + **/ +void +gimp_rgb_get_pixel (const GimpRGB *rgb, + const Babl *format, + gpointer pixel) +{ + g_return_if_fail (rgb != NULL); + g_return_if_fail (format != NULL); + g_return_if_fail (pixel != NULL); + + babl_process (babl_fish (babl_format ("R'G'B' double"), + format), + rgb, pixel, 1); +} + +/** + * gimp_rgb_set_uchar: + * @rgb: a #GimpRGB struct + * @red: the red component + * @green: the green component + * @blue: the blue component + * + * Sets the red, green and blue components of @rgb from 8bit values + * (0 to 255) and leaves the alpha component unchanged. + **/ +void +gimp_rgb_set_uchar (GimpRGB *rgb, + guchar r, + guchar g, + guchar b) +{ + g_return_if_fail (rgb != NULL); + + rgb->r = (gdouble) r / 255.0; + rgb->g = (gdouble) g / 255.0; + rgb->b = (gdouble) b / 255.0; +} + +void +gimp_rgb_get_uchar (const GimpRGB *rgb, + guchar *r, + guchar *g, + guchar *b) +{ + g_return_if_fail (rgb != NULL); + + if (r) *r = ROUND (CLAMP (rgb->r, 0.0, 1.0) * 255.0); + if (g) *g = ROUND (CLAMP (rgb->g, 0.0, 1.0) * 255.0); + if (b) *b = ROUND (CLAMP (rgb->b, 0.0, 1.0) * 255.0); +} + +void +gimp_rgb_add (GimpRGB *rgb1, + const GimpRGB *rgb2) +{ + g_return_if_fail (rgb1 != NULL); + g_return_if_fail (rgb2 != NULL); + + rgb1->r += rgb2->r; + rgb1->g += rgb2->g; + rgb1->b += rgb2->b; +} + +void +gimp_rgb_subtract (GimpRGB *rgb1, + const GimpRGB *rgb2) +{ + g_return_if_fail (rgb1 != NULL); + g_return_if_fail (rgb2 != NULL); + + rgb1->r -= rgb2->r; + rgb1->g -= rgb2->g; + rgb1->b -= rgb2->b; +} + +void +gimp_rgb_multiply (GimpRGB *rgb, + gdouble factor) +{ + g_return_if_fail (rgb != NULL); + + rgb->r *= factor; + rgb->g *= factor; + rgb->b *= factor; +} + +gdouble +gimp_rgb_distance (const GimpRGB *rgb1, + const GimpRGB *rgb2) +{ + g_return_val_if_fail (rgb1 != NULL, 0.0); + g_return_val_if_fail (rgb2 != NULL, 0.0); + + return (fabs (rgb1->r - rgb2->r) + + fabs (rgb1->g - rgb2->g) + + fabs (rgb1->b - rgb2->b)); +} + +gdouble +gimp_rgb_max (const GimpRGB *rgb) +{ + g_return_val_if_fail (rgb != NULL, 0.0); + + if (rgb->r > rgb->g) + return (rgb->r > rgb->b) ? rgb->r : rgb->b; + else + return (rgb->g > rgb->b) ? rgb->g : rgb->b; +} + +gdouble +gimp_rgb_min (const GimpRGB *rgb) +{ + g_return_val_if_fail (rgb != NULL, 0.0); + + if (rgb->r < rgb->g) + return (rgb->r < rgb->b) ? rgb->r : rgb->b; + else + return (rgb->g < rgb->b) ? rgb->g : rgb->b; +} + +void +gimp_rgb_clamp (GimpRGB *rgb) +{ + g_return_if_fail (rgb != NULL); + + rgb->r = CLAMP (rgb->r, 0.0, 1.0); + rgb->g = CLAMP (rgb->g, 0.0, 1.0); + rgb->b = CLAMP (rgb->b, 0.0, 1.0); + rgb->a = CLAMP (rgb->a, 0.0, 1.0); +} + +void +gimp_rgb_gamma (GimpRGB *rgb, + gdouble gamma) +{ + gdouble ig; + + g_return_if_fail (rgb != NULL); + + if (gamma != 0.0) + ig = 1.0 / gamma; + else + ig = 0.0; + + rgb->r = pow (rgb->r, ig); + rgb->g = pow (rgb->g, ig); + rgb->b = pow (rgb->b, ig); +} + +/** + * gimp_rgb_luminance: + * @rgb: a #GimpRGB struct + * + * Return value: the luminous intensity of the range from 0.0 to 1.0. + * + * Since: 2.4 + **/ +gdouble +gimp_rgb_luminance (const GimpRGB *rgb) +{ + gdouble luminance; + + g_return_val_if_fail (rgb != NULL, 0.0); + + luminance = GIMP_RGB_LUMINANCE (rgb->r, rgb->g, rgb->b); + + return CLAMP (luminance, 0.0, 1.0); +} + +/** + * gimp_rgb_luminance_uchar: + * @rgb: a #GimpRGB struct + * + * Return value: the luminous intensity in the range from 0 to 255. + * + * Since: 2.4 + **/ +guchar +gimp_rgb_luminance_uchar (const GimpRGB *rgb) +{ + g_return_val_if_fail (rgb != NULL, 0); + + return ROUND (gimp_rgb_luminance (rgb) * 255.0); +} + +/** + * gimp_rgb_intensity: + * @rgb: a #GimpRGB struct + * + * This function is deprecated! Use gimp_rgb_luminance() instead. + * + * Return value: the intensity in the range from 0.0 to 1.0. + **/ +gdouble +gimp_rgb_intensity (const GimpRGB *rgb) +{ + gdouble intensity; + + g_return_val_if_fail (rgb != NULL, 0.0); + + intensity = GIMP_RGB_INTENSITY (rgb->r, rgb->g, rgb->b); + + return CLAMP (intensity, 0.0, 1.0); +} + +/** + * gimp_rgb_intensity_uchar: + * @rgb: a #GimpRGB struct + * + * This function is deprecated! Use gimp_rgb_luminance_uchar() instead. + * + * Return value: the intensity in the range from 0 to 255. + **/ +guchar +gimp_rgb_intensity_uchar (const GimpRGB *rgb) +{ + g_return_val_if_fail (rgb != NULL, 0); + + return ROUND (gimp_rgb_intensity (rgb) * 255.0); +} + +void +gimp_rgb_composite (GimpRGB *color1, + const GimpRGB *color2, + GimpRGBCompositeMode mode) +{ + g_return_if_fail (color1 != NULL); + g_return_if_fail (color2 != NULL); + + switch (mode) + { + case GIMP_RGB_COMPOSITE_NONE: + break; + + case GIMP_RGB_COMPOSITE_NORMAL: + /* put color2 on top of color1 */ + if (color2->a == 1.0) + { + *color1 = *color2; + } + else + { + gdouble factor = color1->a * (1.0 - color2->a); + + color1->r = color1->r * factor + color2->r * color2->a; + color1->g = color1->g * factor + color2->g * color2->a; + color1->b = color1->b * factor + color2->b * color2->a; + color1->a = factor + color2->a; + } + break; + + case GIMP_RGB_COMPOSITE_BEHIND: + /* put color2 below color1 */ + if (color1->a < 1.0) + { + gdouble factor = color2->a * (1.0 - color1->a); + + color1->r = color2->r * factor + color1->r * color1->a; + color1->g = color2->g * factor + color1->g * color1->a; + color1->b = color2->b * factor + color1->b * color1->a; + color1->a = factor + color1->a; + } + break; + } +} + +/* RGBA functions */ + +/** + * gimp_rgba_set_pixel: + * @rgba: a #GimpRGB struct + * @format: a Babl format + * @pixel: pointer to the source pixel + * + * Sets the red, green, blue and alpha components of @rgba from the + * color stored in @pixel. The pixel format of @pixel is determined + * by @format. + * + * Since: 2.10 + **/ +void +gimp_rgba_set_pixel (GimpRGB *rgba, + const Babl *format, + gconstpointer pixel) +{ + g_return_if_fail (rgba != NULL); + g_return_if_fail (format != NULL); + g_return_if_fail (pixel != NULL); + + babl_process (babl_fish (format, + babl_format ("R'G'B'A double")), + pixel, rgba, 1); +} + +/** + * gimp_rgba_get_pixel: + * @rgba: a #GimpRGB struct + * @format: a Babl format + * @pixel: pointer to the destination pixel + * + * Writes the red, green, blue and alpha components of @rgba to the + * color stored in @pixel. The pixel format of @pixel is determined by + * @format. + * + * Since: 2.10 + **/ +void +gimp_rgba_get_pixel (const GimpRGB *rgba, + const Babl *format, + gpointer pixel) +{ + g_return_if_fail (rgba != NULL); + g_return_if_fail (format != NULL); + g_return_if_fail (pixel != NULL); + + babl_process (babl_fish (babl_format ("R'G'B'A double"), + format), + rgba, pixel, 1); +} + +/** + * gimp_rgba_set: + * @rgba: a #GimpRGB struct + * @red: the red component + * @green: the green component + * @blue: the blue component + * @alpha: the alpha component + * + * Sets the red, green, blue and alpha components of @rgb. The values + * should be between 0.0 and 1.0 but there is no check to enforce this + * and the values are set exactly as they are passed in. + **/ +void +gimp_rgba_set (GimpRGB *rgba, + gdouble r, + gdouble g, + gdouble b, + gdouble a) +{ + g_return_if_fail (rgba != NULL); + + rgba->r = r; + rgba->g = g; + rgba->b = b; + rgba->a = a; +} + +/** + * gimp_rgba_set_uchar: + * @rgba: a #GimpRGB struct + * @red: the red component + * @green: the green component + * @blue: the blue component + * @alpha: the alpha component + * + * Sets the red, green, blue and alpha components of @rgb from 8bit + * values (0 to 255). + **/ +void +gimp_rgba_set_uchar (GimpRGB *rgba, + guchar r, + guchar g, + guchar b, + guchar a) +{ + g_return_if_fail (rgba != NULL); + + rgba->r = (gdouble) r / 255.0; + rgba->g = (gdouble) g / 255.0; + rgba->b = (gdouble) b / 255.0; + rgba->a = (gdouble) a / 255.0; +} + +void +gimp_rgba_get_uchar (const GimpRGB *rgba, + guchar *r, + guchar *g, + guchar *b, + guchar *a) +{ + g_return_if_fail (rgba != NULL); + + if (r) *r = ROUND (CLAMP (rgba->r, 0.0, 1.0) * 255.0); + if (g) *g = ROUND (CLAMP (rgba->g, 0.0, 1.0) * 255.0); + if (b) *b = ROUND (CLAMP (rgba->b, 0.0, 1.0) * 255.0); + if (a) *a = ROUND (CLAMP (rgba->a, 0.0, 1.0) * 255.0); +} + +void +gimp_rgba_add (GimpRGB *rgba1, + const GimpRGB *rgba2) +{ + g_return_if_fail (rgba1 != NULL); + g_return_if_fail (rgba2 != NULL); + + rgba1->r += rgba2->r; + rgba1->g += rgba2->g; + rgba1->b += rgba2->b; + rgba1->a += rgba2->a; +} + +void +gimp_rgba_subtract (GimpRGB *rgba1, + const GimpRGB *rgba2) +{ + g_return_if_fail (rgba1 != NULL); + g_return_if_fail (rgba2 != NULL); + + rgba1->r -= rgba2->r; + rgba1->g -= rgba2->g; + rgba1->b -= rgba2->b; + rgba1->a -= rgba2->a; +} + +void +gimp_rgba_multiply (GimpRGB *rgba, + gdouble factor) +{ + g_return_if_fail (rgba != NULL); + + rgba->r *= factor; + rgba->g *= factor; + rgba->b *= factor; + rgba->a *= factor; +} + +gdouble +gimp_rgba_distance (const GimpRGB *rgba1, + const GimpRGB *rgba2) +{ + g_return_val_if_fail (rgba1 != NULL, 0.0); + g_return_val_if_fail (rgba2 != NULL, 0.0); + + return (fabs (rgba1->r - rgba2->r) + + fabs (rgba1->g - rgba2->g) + + fabs (rgba1->b - rgba2->b) + + fabs (rgba1->a - rgba2->a)); +} + + +/* + * GIMP_TYPE_PARAM_RGB + */ + +#define GIMP_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_RGB, GimpParamSpecRGB)) + +typedef struct _GimpParamSpecRGB GimpParamSpecRGB; + +struct _GimpParamSpecRGB +{ + GParamSpecBoxed parent_instance; + + gboolean has_alpha; + gboolean validate; /* change this to enable [0.0...1.0] */ + GimpRGB default_value; +}; + +static void gimp_param_rgb_class_init (GParamSpecClass *class); +static void gimp_param_rgb_init (GParamSpec *pspec); +static void gimp_param_rgb_set_default (GParamSpec *pspec, + GValue *value); +static gboolean gimp_param_rgb_validate (GParamSpec *pspec, + GValue *value); +static gint gimp_param_rgb_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2); + +/** + * gimp_param_rgb_get_type: + * + * Reveals the object type + * + * Returns: the #GType for a GimpParamRGB object + * + * Since: 2.4 + **/ +GType +gimp_param_rgb_get_type (void) +{ + static GType spec_type = 0; + + if (! spec_type) + { + const GTypeInfo type_info = + { + sizeof (GParamSpecClass), + NULL, NULL, + (GClassInitFunc) gimp_param_rgb_class_init, + NULL, NULL, + sizeof (GimpParamSpecRGB), + 0, + (GInstanceInitFunc) gimp_param_rgb_init + }; + + spec_type = g_type_register_static (G_TYPE_PARAM_BOXED, + "GimpParamRGB", + &type_info, 0); + } + + return spec_type; +} + +static void +gimp_param_rgb_class_init (GParamSpecClass *class) +{ + class->value_type = GIMP_TYPE_RGB; + class->value_set_default = gimp_param_rgb_set_default; + class->value_validate = gimp_param_rgb_validate; + class->values_cmp = gimp_param_rgb_values_cmp; +} + +static void +gimp_param_rgb_init (GParamSpec *pspec) +{ + GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec); + + gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0); +} + +static void +gimp_param_rgb_set_default (GParamSpec *pspec, + GValue *value) +{ + GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec); + + g_value_set_static_boxed (value, &cspec->default_value); +} + +static gboolean +gimp_param_rgb_validate (GParamSpec *pspec, + GValue *value) +{ + GimpParamSpecRGB *rgb_spec = GIMP_PARAM_SPEC_RGB (pspec); + GimpRGB *rgb = value->data[0].v_pointer; + + if (rgb_spec->validate && rgb) + { + GimpRGB oval = *rgb; + + gimp_rgb_clamp (rgb); + + return (oval.r != rgb->r || + oval.g != rgb->g || + oval.b != rgb->b || + (rgb_spec->has_alpha && oval.a != rgb->a)); + } + + return FALSE; +} + +static gint +gimp_param_rgb_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) +{ + GimpRGB *rgb1 = value1->data[0].v_pointer; + GimpRGB *rgb2 = value2->data[0].v_pointer; + + /* try to return at least *something*, it's useless anyway... */ + + if (! rgb1) + { + return rgb2 != NULL ? -1 : 0; + } + else if (! rgb2) + { + return rgb1 != NULL; + } + else + { + guint32 int1 = 0; + guint32 int2 = 0; + + if (GIMP_PARAM_SPEC_RGB (pspec)->has_alpha) + { + gimp_rgba_get_uchar (rgb1, + ((guchar *) &int1) + 0, + ((guchar *) &int1) + 1, + ((guchar *) &int1) + 2, + ((guchar *) &int1) + 3); + gimp_rgba_get_uchar (rgb2, + ((guchar *) &int2) + 0, + ((guchar *) &int2) + 1, + ((guchar *) &int2) + 2, + ((guchar *) &int2) + 3); + } + else + { + gimp_rgb_get_uchar (rgb1, + ((guchar *) &int1) + 0, + ((guchar *) &int1) + 1, + ((guchar *) &int1) + 2); + gimp_rgb_get_uchar (rgb2, + ((guchar *) &int2) + 0, + ((guchar *) &int2) + 1, + ((guchar *) &int2) + 2); + } + + return int1 - int2; + } +} + +/** + * gimp_param_spec_rgb: + * @name: Canonical name of the param + * @nick: Nickname of the param + * @blurb: Brief description of param. + * @has_alpha: %TRUE if the alpha channel has relevance. + * @default_value: Value to use if none is assigned. + * @flags: a combination of #GParamFlags + * + * Creates a param spec to hold an #GimpRGB value. + * See g_param_spec_internal() for more information. + * + * Returns: a newly allocated #GParamSpec instance + * + * Since: 2.4 + **/ +GParamSpec * +gimp_param_spec_rgb (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean has_alpha, + const GimpRGB *default_value, + GParamFlags flags) +{ + GimpParamSpecRGB *cspec; + + cspec = g_param_spec_internal (GIMP_TYPE_PARAM_RGB, + name, nick, blurb, flags); + + cspec->has_alpha = has_alpha; + + if (default_value) + cspec->default_value = *default_value; + else + gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0); + + return G_PARAM_SPEC (cspec); +} + +/** + * gimp_param_spec_rgb_get_default: + * @pspec: a #GimpParamSpecRGB. + * @default_value: return location for @pspec's default value + * + * Returns the @pspec's default color value. + * + * Since: 2.10.14 + **/ +void +gimp_param_spec_rgb_get_default (GParamSpec *pspec, + GimpRGB *default_value) +{ + g_return_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec)); + g_return_if_fail (default_value != NULL); + + *default_value = GIMP_PARAM_SPEC_RGB (pspec)->default_value; +} + +/** + * gimp_param_spec_rgb_has_alpha: + * @pspec: a #GParamSpec to hold an #GimpRGB value. + * + * Returns: %TRUE if the alpha channel is relevant. + * + * Since: 2.4 + **/ +gboolean +gimp_param_spec_rgb_has_alpha (GParamSpec *pspec) +{ + g_return_val_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec), FALSE); + + return GIMP_PARAM_SPEC_RGB (pspec)->has_alpha; +} |