diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
commit | 5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch) | |
tree | cbffb45144febf451e54061db2b21395faf94bfe /libgimpcolor/gimpcolorspace.c | |
parent | Initial commit. (diff) | |
download | gimp-upstream.tar.xz gimp-upstream.zip |
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libgimpcolor/gimpcolorspace.c')
-rw-r--r-- | libgimpcolor/gimpcolorspace.c | 1103 |
1 files changed, 1103 insertions, 0 deletions
diff --git a/libgimpcolor/gimpcolorspace.c b/libgimpcolor/gimpcolorspace.c new file mode 100644 index 0000000..b8885ce --- /dev/null +++ b/libgimpcolor/gimpcolorspace.c @@ -0,0 +1,1103 @@ +/* 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> + +#include "libgimpmath/gimpmath.h" + +#include "gimpcolortypes.h" + +#include "gimpcolorspace.h" +#include "gimprgb.h" +#include "gimphsv.h" + + + +/** + * SECTION: gimpcolorspace + * @title: GimpColorSpace + * @short_description: Utility functions which convert colors between + * different color models. + * + * When programming pixel data manipulation functions you will often + * use algorithms operating on a color model different from the one + * GIMP uses. This file provides utility functions to convert colors + * between different color spaces. + **/ + + +#define GIMP_HSV_UNDEFINED -1.0 +#define GIMP_HSL_UNDEFINED -1.0 + +/********************************* + * color conversion routines * + *********************************/ + + +/* GimpRGB functions */ + + +/** + * gimp_rgb_to_hsv: + * @rgb: A color value in the RGB colorspace + * @hsv: The value converted to the HSV colorspace + * + * Does a conversion from RGB to HSV (Hue, Saturation, + * Value) colorspace. + **/ +void +gimp_rgb_to_hsv (const GimpRGB *rgb, + GimpHSV *hsv) +{ + gdouble max, min, delta; + + g_return_if_fail (rgb != NULL); + g_return_if_fail (hsv != NULL); + + max = gimp_rgb_max (rgb); + min = gimp_rgb_min (rgb); + + hsv->v = max; + delta = max - min; + + if (delta > 0.0001) + { + hsv->s = delta / max; + + if (rgb->r == max) + { + hsv->h = (rgb->g - rgb->b) / delta; + if (hsv->h < 0.0) + hsv->h += 6.0; + } + else if (rgb->g == max) + { + hsv->h = 2.0 + (rgb->b - rgb->r) / delta; + } + else + { + hsv->h = 4.0 + (rgb->r - rgb->g) / delta; + } + + hsv->h /= 6.0; + } + else + { + hsv->s = 0.0; + hsv->h = 0.0; + } + + hsv->a = rgb->a; +} + +/** + * gimp_hsv_to_rgb: + * @hsv: A color value in the HSV colorspace + * @rgb: The returned RGB value. + * + * Converts a color value from HSV to RGB colorspace + **/ +void +gimp_hsv_to_rgb (const GimpHSV *hsv, + GimpRGB *rgb) +{ + gint i; + gdouble f, w, q, t; + + gdouble hue; + + g_return_if_fail (rgb != NULL); + g_return_if_fail (hsv != NULL); + + if (hsv->s == 0.0) + { + rgb->r = hsv->v; + rgb->g = hsv->v; + rgb->b = hsv->v; + } + else + { + hue = hsv->h; + + if (hue == 1.0) + hue = 0.0; + + hue *= 6.0; + + i = (gint) hue; + f = hue - i; + w = hsv->v * (1.0 - hsv->s); + q = hsv->v * (1.0 - (hsv->s * f)); + t = hsv->v * (1.0 - (hsv->s * (1.0 - f))); + + switch (i) + { + case 0: + rgb->r = hsv->v; + rgb->g = t; + rgb->b = w; + break; + case 1: + rgb->r = q; + rgb->g = hsv->v; + rgb->b = w; + break; + case 2: + rgb->r = w; + rgb->g = hsv->v; + rgb->b = t; + break; + case 3: + rgb->r = w; + rgb->g = q; + rgb->b = hsv->v; + break; + case 4: + rgb->r = t; + rgb->g = w; + rgb->b = hsv->v; + break; + case 5: + rgb->r = hsv->v; + rgb->g = w; + rgb->b = q; + break; + } + } + + rgb->a = hsv->a; +} + + +/** + * gimp_rgb_to_hsl: + * @rgb: A color value in the RGB colorspace + * @hsl: The value converted to HSL + * + * Convert an RGB color value to a HSL (Hue, Saturation, Lightness) + * color value. + **/ +void +gimp_rgb_to_hsl (const GimpRGB *rgb, + GimpHSL *hsl) +{ + gdouble max, min, delta; + + g_return_if_fail (rgb != NULL); + g_return_if_fail (hsl != NULL); + + max = gimp_rgb_max (rgb); + min = gimp_rgb_min (rgb); + + hsl->l = (max + min) / 2.0; + + if (max == min) + { + hsl->s = 0.0; + hsl->h = GIMP_HSL_UNDEFINED; + } + else + { + if (hsl->l <= 0.5) + hsl->s = (max - min) / (max + min); + else + hsl->s = (max - min) / (2.0 - max - min); + + delta = max - min; + + if (delta == 0.0) + delta = 1.0; + + if (rgb->r == max) + { + hsl->h = (rgb->g - rgb->b) / delta; + } + else if (rgb->g == max) + { + hsl->h = 2.0 + (rgb->b - rgb->r) / delta; + } + else + { + hsl->h = 4.0 + (rgb->r - rgb->g) / delta; + } + + hsl->h /= 6.0; + + if (hsl->h < 0.0) + hsl->h += 1.0; + } + + hsl->a = rgb->a; +} + +static inline gdouble +gimp_hsl_value (gdouble n1, + gdouble n2, + gdouble hue) +{ + gdouble val; + + if (hue > 6.0) + hue -= 6.0; + else if (hue < 0.0) + hue += 6.0; + + if (hue < 1.0) + val = n1 + (n2 - n1) * hue; + else if (hue < 3.0) + val = n2; + else if (hue < 4.0) + val = n1 + (n2 - n1) * (4.0 - hue); + else + val = n1; + + return val; +} + + +/** + * gimp_hsl_to_rgb: + * @hsl: A color value in the HSL colorspace + * @rgb: The value converted to a value in the RGB colorspace + * + * Convert a HSL color value to an RGB color value. + **/ +void +gimp_hsl_to_rgb (const GimpHSL *hsl, + GimpRGB *rgb) +{ + g_return_if_fail (hsl != NULL); + g_return_if_fail (rgb != NULL); + + if (hsl->s == 0) + { + /* achromatic case */ + rgb->r = hsl->l; + rgb->g = hsl->l; + rgb->b = hsl->l; + } + else + { + gdouble m1, m2; + + if (hsl->l <= 0.5) + m2 = hsl->l * (1.0 + hsl->s); + else + m2 = hsl->l + hsl->s - hsl->l * hsl->s; + + m1 = 2.0 * hsl->l - m2; + + rgb->r = gimp_hsl_value (m1, m2, hsl->h * 6.0 + 2.0); + rgb->g = gimp_hsl_value (m1, m2, hsl->h * 6.0); + rgb->b = gimp_hsl_value (m1, m2, hsl->h * 6.0 - 2.0); + } + + rgb->a = hsl->a; +} + + +/** + * gimp_rgb_to_cmyk: + * @rgb: A value in the RGB colorspace + * @pullout: A scaling value (0-1) indicating how much black should be + * pulled out + * @cmyk: The input value naively converted to the CMYK colorspace + * + * Does a naive conversion from RGB to CMYK colorspace. A simple + * formula that doesn't take any color-profiles into account is used. + * The amount of black pullout how can be controlled via the @pullout + * parameter. A @pullout value of 0 makes this a conversion to CMY. + * A value of 1 causes the maximum amount of black to be pulled out. + **/ +void +gimp_rgb_to_cmyk (const GimpRGB *rgb, + gdouble pullout, + GimpCMYK *cmyk) +{ + gdouble c, m, y, k; + + g_return_if_fail (rgb != NULL); + g_return_if_fail (cmyk != NULL); + + c = 1.0 - rgb->r; + m = 1.0 - rgb->g; + y = 1.0 - rgb->b; + + k = 1.0; + if (c < k) k = c; + if (m < k) k = m; + if (y < k) k = y; + + k *= pullout; + + if (k < 1.0) + { + cmyk->c = (c - k) / (1.0 - k); + cmyk->m = (m - k) / (1.0 - k); + cmyk->y = (y - k) / (1.0 - k); + } + else + { + cmyk->c = 0.0; + cmyk->m = 0.0; + cmyk->y = 0.0; + } + + cmyk->k = k; + cmyk->a = rgb->a; +} + +/** + * gimp_cmyk_to_rgb: + * @cmyk: A color value in the CMYK colorspace + * @rgb: The value converted to the RGB colorspace + * + * Does a simple transformation from the CMYK colorspace to the RGB + * colorspace, without taking color profiles into account. + **/ +void +gimp_cmyk_to_rgb (const GimpCMYK *cmyk, + GimpRGB *rgb) +{ + gdouble c, m, y, k; + + g_return_if_fail (cmyk != NULL); + g_return_if_fail (rgb != NULL); + + k = cmyk->k; + + if (k < 1.0) + { + c = cmyk->c * (1.0 - k) + k; + m = cmyk->m * (1.0 - k) + k; + y = cmyk->y * (1.0 - k) + k; + } + else + { + c = 1.0; + m = 1.0; + y = 1.0; + } + + rgb->r = 1.0 - c; + rgb->g = 1.0 - m; + rgb->b = 1.0 - y; + rgb->a = cmyk->a; +} + + +#define GIMP_RETURN_RGB(x, y, z) { rgb->r = x; rgb->g = y; rgb->b = z; return; } + +/**************************************************************************** + * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. + * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can + * be defined as 0 in situations where only unsigned numbers are desired. + ****************************************************************************/ + +/** + * gimp_rgb_to_hwb: + * @rgb: A color value in the RGB colorspace + * @hue: The hue value of the above color, in the range 0 to 6 + * @whiteness: The whiteness value of the above color, in the range 0 to 1 + * @blackness: The blackness value of the above color, in the range 0 to 1 + * + * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. + * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can + * be defined as 0 in situations where only unsigned numbers are desired. + * + * RGB are each on [0, 1]. Whiteness and Blackness are returned in the + * range [0, 1] and H is returned in the range [0, 6]. If W == 1 - B, H is + * undefined. + **/ +void +gimp_rgb_to_hwb (const GimpRGB *rgb, + gdouble *hue, + gdouble *whiteness, + gdouble *blackness) +{ + /* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is */ + /* returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B. */ + /* ====================================================================== */ + + gdouble R = rgb->r, G = rgb->g, B = rgb->b, w, v, b, f; + gint i; + + w = gimp_rgb_min (rgb); + v = gimp_rgb_max (rgb); + b = 1.0 - v; + + if (v == w) + { + *hue = GIMP_HSV_UNDEFINED; + *whiteness = w; + *blackness = b; + } + else + { + f = (R == w) ? G - B : ((G == w) ? B - R : R - G); + i = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0); + + *hue = (360.0 / 6.0) * (i - f / (v - w)); + *whiteness = w; + *blackness = b; + } +} + +/** + * gimp_hwb_to_rgb: + * @hue: A hue value, in the range 0 to 6 + * @whiteness: A whiteness value, in the range 0 to 1 + * @blackness: A blackness value, in the range 0 to 1 + * @rgb: The above color converted to the RGB colorspace + * + * H is defined in the range [0, 6] or UNDEFINED, B and W are both in the + * range [0, 1]. The returned RGB values are all in the range [0, 1]. + **/ +void +gimp_hwb_to_rgb (gdouble hue, + gdouble whiteness, + gdouble blackness, + GimpRGB *rgb) +{ + /* H is given on [0, 6] or UNDEFINED. whiteness and + * blackness are given on [0, 1]. + * RGB are each returned on [0, 1]. + */ + + gdouble h = hue, w = whiteness, b = blackness, v, n, f; + gint i; + + h = 6.0 * h/ 360.0; + + v = 1.0 - b; + if (h == GIMP_HSV_UNDEFINED) + { + rgb->r = v; + rgb->g = v; + rgb->b = v; + } + else + { + i = floor (h); + f = h - i; + + if (i & 1) + f = 1.0 - f; /* if i is odd */ + + n = w + f * (v - w); /* linear interpolation between w and v */ + + switch (i) + { + case 6: + case 0: GIMP_RETURN_RGB (v, n, w); + break; + case 1: GIMP_RETURN_RGB (n, v, w); + break; + case 2: GIMP_RETURN_RGB (w, v, n); + break; + case 3: GIMP_RETURN_RGB (w, n, v); + break; + case 4: GIMP_RETURN_RGB (n, w, v); + break; + case 5: GIMP_RETURN_RGB (v, w, n); + break; + } + } + +} + + +/* gint functions */ + +/** + * gimp_rgb_to_hsv_int: + * @red: The red channel value, returns the Hue channel + * @green: The green channel value, returns the Saturation channel + * @blue: The blue channel value, returns the Value channel + * + * The arguments are pointers to int representing channel values in + * the RGB colorspace, and the values pointed to are all in the range + * [0, 255]. + * + * The function changes the arguments to point to the HSV value + * corresponding, with the returned values in the following + * ranges: H [0, 359], S [0, 255], V [0, 255]. + **/ +void +gimp_rgb_to_hsv_int (gint *red, + gint *green, + gint *blue) +{ + gdouble r, g, b; + gdouble h, s, v; + gint min; + gdouble delta; + + r = *red; + g = *green; + b = *blue; + + if (r > g) + { + v = MAX (r, b); + min = MIN (g, b); + } + else + { + v = MAX (g, b); + min = MIN (r, b); + } + + delta = v - min; + + if (v == 0.0) + s = 0.0; + else + s = delta / v; + + if (s == 0.0) + { + h = 0.0; + } + else + { + if (r == v) + h = 60.0 * (g - b) / delta; + else if (g == v) + h = 120 + 60.0 * (b - r) / delta; + else + h = 240 + 60.0 * (r - g) / delta; + + if (h < 0.0) + h += 360.0; + + if (h > 360.0) + h -= 360.0; + } + + *red = ROUND (h); + *green = ROUND (s * 255.0); + *blue = ROUND (v); + + /* avoid the ambiguity of returning different values for the same color */ + if (*red == 360) + *red = 0; +} + +/** + * gimp_hsv_to_rgb_int: + * @hue: The hue channel, returns the red channel + * @saturation: The saturation channel, returns the green channel + * @value: The value channel, returns the blue channel + * + * The arguments are pointers to int, with the values pointed to in the + * following ranges: H [0, 360], S [0, 255], V [0, 255]. + * + * The function changes the arguments to point to the RGB value + * corresponding, with the returned values all in the range [0, 255]. + **/ +void +gimp_hsv_to_rgb_int (gint *hue, + gint *saturation, + gint *value) +{ + gdouble h, s, v, h_temp; + gdouble f, p, q, t; + gint i; + + if (*saturation == 0) + { + *hue = *value; + *saturation = *value; + *value = *value; + } + else + { + h = *hue; + s = *saturation / 255.0; + v = *value / 255.0; + + if (h == 360) + h_temp = 0; + else + h_temp = h; + + h_temp = h_temp / 60.0; + i = floor (h_temp); + f = h_temp - i; + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch (i) + { + case 0: + *hue = ROUND (v * 255.0); + *saturation = ROUND (t * 255.0); + *value = ROUND (p * 255.0); + break; + + case 1: + *hue = ROUND (q * 255.0); + *saturation = ROUND (v * 255.0); + *value = ROUND (p * 255.0); + break; + + case 2: + *hue = ROUND (p * 255.0); + *saturation = ROUND (v * 255.0); + *value = ROUND (t * 255.0); + break; + + case 3: + *hue = ROUND (p * 255.0); + *saturation = ROUND (q * 255.0); + *value = ROUND (v * 255.0); + break; + + case 4: + *hue = ROUND (t * 255.0); + *saturation = ROUND (p * 255.0); + *value = ROUND (v * 255.0); + break; + + case 5: + *hue = ROUND (v * 255.0); + *saturation = ROUND (p * 255.0); + *value = ROUND (q * 255.0); + break; + } + } +} + +/** + * gimp_rgb_to_hsl_int: + * @red: Red channel, returns Hue channel + * @green: Green channel, returns Lightness channel + * @blue: Blue channel, returns Saturation channel + * + * The arguments are pointers to int representing channel values in the + * RGB colorspace, and the values pointed to are all in the range [0, 255]. + * + * The function changes the arguments to point to the corresponding HLS + * value with the values pointed to in the following ranges: H [0, 360], + * L [0, 255], S [0, 255]. + **/ +void +gimp_rgb_to_hsl_int (gint *red, + gint *green, + gint *blue) +{ + gint r, g, b; + gdouble h, s, l; + gint min, max; + gint delta; + + r = *red; + g = *green; + b = *blue; + + if (r > g) + { + max = MAX (r, b); + min = MIN (g, b); + } + else + { + max = MAX (g, b); + min = MIN (r, b); + } + + l = (max + min) / 2.0; + + if (max == min) + { + s = 0.0; + h = 0.0; + } + else + { + delta = (max - min); + + if (l < 128) + s = 255 * (gdouble) delta / (gdouble) (max + min); + else + s = 255 * (gdouble) delta / (gdouble) (511 - max - min); + + if (r == max) + h = (g - b) / (gdouble) delta; + else if (g == max) + h = 2 + (b - r) / (gdouble) delta; + else + h = 4 + (r - g) / (gdouble) delta; + + h = h * 42.5; + + if (h < 0) + h += 255; + else if (h > 255) + h -= 255; + } + + *red = ROUND (h); + *green = ROUND (s); + *blue = ROUND (l); +} + +/** + * gimp_rgb_to_l_int: + * @red: Red channel + * @green: Green channel + * @blue: Blue channel + * + * Calculates the lightness value of an RGB triplet with the formula + * L = (max(R, G, B) + min (R, G, B)) / 2 + * + * Return value: Luminance value corresponding to the input RGB value + **/ +gint +gimp_rgb_to_l_int (gint red, + gint green, + gint blue) +{ + gint min, max; + + if (red > green) + { + max = MAX (red, blue); + min = MIN (green, blue); + } + else + { + max = MAX (green, blue); + min = MIN (red, blue); + } + + return ROUND ((max + min) / 2.0); +} + +static inline gint +gimp_hsl_value_int (gdouble n1, + gdouble n2, + gdouble hue) +{ + gdouble value; + + if (hue > 255) + hue -= 255; + else if (hue < 0) + hue += 255; + + if (hue < 42.5) + value = n1 + (n2 - n1) * (hue / 42.5); + else if (hue < 127.5) + value = n2; + else if (hue < 170) + value = n1 + (n2 - n1) * ((170 - hue) / 42.5); + else + value = n1; + + return ROUND (value * 255.0); +} + +/** + * gimp_hsl_to_rgb_int: + * @hue: Hue channel, returns Red channel + * @saturation: Saturation channel, returns Green channel + * @lightness: Lightness channel, returns Blue channel + * + * The arguments are pointers to int, with the values pointed to in the + * following ranges: H [0, 360], L [0, 255], S [0, 255]. + * + * The function changes the arguments to point to the RGB value + * corresponding, with the returned values all in the range [0, 255]. + **/ +void +gimp_hsl_to_rgb_int (gint *hue, + gint *saturation, + gint *lightness) +{ + gdouble h, s, l; + + h = *hue; + s = *saturation; + l = *lightness; + + if (s == 0) + { + /* achromatic case */ + *hue = l; + *lightness = l; + *saturation = l; + } + else + { + gdouble m1, m2; + + if (l < 128) + m2 = (l * (255 + s)) / 65025.0; + else + m2 = (l + s - (l * s) / 255.0) / 255.0; + + m1 = (l / 127.5) - m2; + + /* chromatic case */ + *hue = gimp_hsl_value_int (m1, m2, h + 85); + *saturation = gimp_hsl_value_int (m1, m2, h); + *lightness = gimp_hsl_value_int (m1, m2, h - 85); + } +} + +/** + * gimp_rgb_to_cmyk_int: + * @red: the red channel; returns the cyan value (0-255) + * @green: the green channel; returns the magenta value (0-255) + * @blue: the blue channel; returns the yellow value (0-255) + * @pullout: the percentage of black to pull out (0-100); returns + * the black value (0-255) + * + * Does a naive conversion from RGB to CMYK colorspace. A simple + * formula that doesn't take any color-profiles into account is used. + * The amount of black pullout how can be controlled via the @pullout + * parameter. A @pullout value of 0 makes this a conversion to CMY. + * A value of 100 causes the maximum amount of black to be pulled out. + **/ +void +gimp_rgb_to_cmyk_int (gint *red, + gint *green, + gint *blue, + gint *pullout) +{ + gint c, m, y; + + c = 255 - *red; + m = 255 - *green; + y = 255 - *blue; + + if (*pullout == 0) + { + *red = c; + *green = m; + *blue = y; + } + else + { + gint k = 255; + + if (c < k) k = c; + if (m < k) k = m; + if (y < k) k = y; + + k = (k * CLAMP (*pullout, 0, 100)) / 100; + + *red = ((c - k) << 8) / (256 - k); + *green = ((m - k) << 8) / (256 - k); + *blue = ((y - k) << 8) / (256 - k); + *pullout = k; + } +} + +/** + * gimp_cmyk_to_rgb_int: + * @cyan: the cyan channel; returns the red value (0-255) + * @magenta: the magenta channel; returns the green value (0-255) + * @yellow: the yellow channel; returns the blue value (0-255) + * @black: the black channel (0-255); doesn't change + * + * Does a naive conversion from CMYK to RGB colorspace. A simple + * formula that doesn't take any color-profiles into account is used. + **/ +void +gimp_cmyk_to_rgb_int (gint *cyan, + gint *magenta, + gint *yellow, + gint *black) +{ + gint c, m, y, k; + + c = *cyan; + m = *magenta; + y = *yellow; + k = *black; + + if (k) + { + c = ((c * (256 - k)) >> 8) + k; + m = ((m * (256 - k)) >> 8) + k; + y = ((y * (256 - k)) >> 8) + k; + } + + *cyan = 255 - c; + *magenta = 255 - m; + *yellow = 255 - y; +} + +/** + * gimp_rgb_to_hsv4: + * @rgb: RGB triplet, rgb[0] is red channel, rgb[1] is green, + * rgb[2] is blue (0..255) + * @hue: Pointer to hue channel (0..1) + * @saturation: Pointer to saturation channel (0..1) + * @value: Pointer to value channel (0..1) + **/ +void +gimp_rgb_to_hsv4 (const guchar *rgb, + gdouble *hue, + gdouble *saturation, + gdouble *value) +{ + gdouble red, green, blue; + gdouble h, s, v; + gdouble min, max; + gdouble delta; + + red = rgb[0] / 255.0; + green = rgb[1] / 255.0; + blue = rgb[2] / 255.0; + + if (red > green) + { + max = MAX (red, blue); + min = MIN (green, blue); + } + else + { + max = MAX (green, blue); + min = MIN (red, blue); + } + + v = max; + + if (max != 0.0) + s = (max - min) / max; + else + s = 0.0; + + if (s == 0.0) + h = 0.0; + else + { + delta = max - min; + + if (delta == 0.0) + delta = 1.0; + + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else + h = 4 + (red - green) / delta; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + else if (h > 1.0) + h -= 1.0; + } + + *hue = h; + *saturation = s; + *value = v; +} + +/** + * gimp_hsv_to_rgb4: + * @rgb: RGB triplet, rgb[0] is red channel, rgb[1] is green, + * rgb[2] is blue (0..255) + * @hue: Hue channel (0..1) + * @saturation: Saturation channel (0..1) + * @value: Value channel (0..1) + **/ +void +gimp_hsv_to_rgb4 (guchar *rgb, + gdouble hue, + gdouble saturation, + gdouble value) +{ + gdouble h, s, v; + gdouble f, p, q, t; + + if (saturation == 0.0) + { + hue = value; + saturation = value; + /*value = value;*/ + } + else + { + h = hue * 6.0; + s = saturation; + v = value; + + if (h == 6.0) + h = 0.0; + + f = h - (gint) h; + p = v * (1.0 - s); + q = v * (1.0 - s * f); + t = v * (1.0 - s * (1.0 - f)); + + switch ((int) h) + { + case 0: + hue = v; + saturation = t; + value = p; + break; + + case 1: + hue = q; + saturation = v; + value = p; + break; + + case 2: + hue = p; + saturation = v; + value = t; + break; + + case 3: + hue = p; + saturation = q; + value = v; + break; + + case 4: + hue = t; + saturation = p; + value = v; + break; + + case 5: + hue = v; + saturation = p; + value = q; + break; + } + } + + rgb[0] = ROUND (hue * 255.0); + rgb[1] = ROUND (saturation * 255.0); + rgb[2] = ROUND (value * 255.0); +} |