1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * This library is free software: you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 3 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <https://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 
21 #include <babl/babl.h>
22 #include <glib-object.h>
23 
24 #include "libgimpmath/gimpmath.h"
25 
26 #include "gimpcolortypes.h"
27 
28 #include "gimpcolorspace.h"
29 #include "gimprgb.h"
30 #include "gimphsv.h"
31 
32 
33 
34 /**
35  * SECTION: gimpcolorspace
36  * @title: GimpColorSpace
37  * @short_description: Utility functions which convert colors between
38  *                     different color models.
39  *
40  * When programming pixel data manipulation functions you will often
41  * use algorithms operating on a color model different from the one
42  * GIMP uses.  This file provides utility functions to convert colors
43  * between different color spaces.
44  **/
45 
46 
47 #define GIMP_HSV_UNDEFINED -1.0
48 #define GIMP_HSL_UNDEFINED -1.0
49 
50 /*********************************
51  *   color conversion routines   *
52  *********************************/
53 
54 
55 /*  GimpRGB functions  */
56 
57 
58 /**
59  * gimp_rgb_to_hsv:
60  * @rgb: A color value in the RGB colorspace
61  * @hsv: The value converted to the HSV colorspace
62  *
63  * Does a conversion from RGB to HSV (Hue, Saturation,
64  * Value) colorspace.
65  **/
66 void
gimp_rgb_to_hsv(const GimpRGB * rgb,GimpHSV * hsv)67 gimp_rgb_to_hsv (const GimpRGB *rgb,
68                  GimpHSV       *hsv)
69 {
70   gdouble max, min, delta;
71 
72   g_return_if_fail (rgb != NULL);
73   g_return_if_fail (hsv != NULL);
74 
75   max = gimp_rgb_max (rgb);
76   min = gimp_rgb_min (rgb);
77 
78   hsv->v = max;
79   delta = max - min;
80 
81   if (delta > 0.0001)
82     {
83       hsv->s = delta / max;
84 
85       if (rgb->r == max)
86         {
87           hsv->h = (rgb->g - rgb->b) / delta;
88           if (hsv->h < 0.0)
89             hsv->h += 6.0;
90         }
91       else if (rgb->g == max)
92         {
93           hsv->h = 2.0 + (rgb->b - rgb->r) / delta;
94         }
95       else
96         {
97           hsv->h = 4.0 + (rgb->r - rgb->g) / delta;
98         }
99 
100       hsv->h /= 6.0;
101     }
102   else
103     {
104       hsv->s = 0.0;
105       hsv->h = 0.0;
106     }
107 
108   hsv->a = rgb->a;
109 }
110 
111 /**
112  * gimp_hsv_to_rgb:
113  * @hsv: A color value in the HSV colorspace
114  * @rgb: The returned RGB value.
115  *
116  * Converts a color value from HSV to RGB colorspace
117  **/
118 void
gimp_hsv_to_rgb(const GimpHSV * hsv,GimpRGB * rgb)119 gimp_hsv_to_rgb (const GimpHSV *hsv,
120                  GimpRGB       *rgb)
121 {
122   gint    i;
123   gdouble f, w, q, t;
124 
125   gdouble hue;
126 
127   g_return_if_fail (rgb != NULL);
128   g_return_if_fail (hsv != NULL);
129 
130   if (hsv->s == 0.0)
131     {
132       rgb->r = hsv->v;
133       rgb->g = hsv->v;
134       rgb->b = hsv->v;
135     }
136   else
137     {
138       hue = hsv->h;
139 
140       if (hue == 1.0)
141         hue = 0.0;
142 
143       hue *= 6.0;
144 
145       i = (gint) hue;
146       f = hue - i;
147       w = hsv->v * (1.0 - hsv->s);
148       q = hsv->v * (1.0 - (hsv->s * f));
149       t = hsv->v * (1.0 - (hsv->s * (1.0 - f)));
150 
151       switch (i)
152         {
153         case 0:
154           rgb->r = hsv->v;
155           rgb->g = t;
156           rgb->b = w;
157           break;
158         case 1:
159           rgb->r = q;
160           rgb->g = hsv->v;
161           rgb->b = w;
162           break;
163         case 2:
164           rgb->r = w;
165           rgb->g = hsv->v;
166           rgb->b = t;
167           break;
168         case 3:
169           rgb->r = w;
170           rgb->g = q;
171           rgb->b = hsv->v;
172           break;
173         case 4:
174           rgb->r = t;
175           rgb->g = w;
176           rgb->b = hsv->v;
177           break;
178         case 5:
179           rgb->r = hsv->v;
180           rgb->g = w;
181           rgb->b = q;
182           break;
183         }
184     }
185 
186   rgb->a = hsv->a;
187 }
188 
189 
190 /**
191  * gimp_rgb_to_hsl:
192  * @rgb: A color value in the RGB colorspace
193  * @hsl: The value converted to HSL
194  *
195  * Convert an RGB color value to a HSL (Hue, Saturation, Lightness)
196  * color value.
197  **/
198 void
gimp_rgb_to_hsl(const GimpRGB * rgb,GimpHSL * hsl)199 gimp_rgb_to_hsl (const GimpRGB *rgb,
200                  GimpHSL       *hsl)
201 {
202   gdouble max, min, delta;
203 
204   g_return_if_fail (rgb != NULL);
205   g_return_if_fail (hsl != NULL);
206 
207   max = gimp_rgb_max (rgb);
208   min = gimp_rgb_min (rgb);
209 
210   hsl->l = (max + min) / 2.0;
211 
212   if (max == min)
213     {
214       hsl->s = 0.0;
215       hsl->h = GIMP_HSL_UNDEFINED;
216     }
217   else
218     {
219       if (hsl->l <= 0.5)
220         hsl->s = (max - min) / (max + min);
221       else
222         hsl->s = (max - min) / (2.0 - max - min);
223 
224       delta = max - min;
225 
226       if (delta == 0.0)
227         delta = 1.0;
228 
229       if (rgb->r == max)
230         {
231           hsl->h = (rgb->g - rgb->b) / delta;
232         }
233       else if (rgb->g == max)
234         {
235           hsl->h = 2.0 + (rgb->b - rgb->r) / delta;
236         }
237       else
238         {
239           hsl->h = 4.0 + (rgb->r - rgb->g) / delta;
240         }
241 
242       hsl->h /= 6.0;
243 
244       if (hsl->h < 0.0)
245         hsl->h += 1.0;
246     }
247 
248   hsl->a = rgb->a;
249 }
250 
251 static inline gdouble
gimp_hsl_value(gdouble n1,gdouble n2,gdouble hue)252 gimp_hsl_value (gdouble n1,
253                 gdouble n2,
254                 gdouble hue)
255 {
256   gdouble val;
257 
258   if (hue > 6.0)
259     hue -= 6.0;
260   else if (hue < 0.0)
261     hue += 6.0;
262 
263   if (hue < 1.0)
264     val = n1 + (n2 - n1) * hue;
265   else if (hue < 3.0)
266     val = n2;
267   else if (hue < 4.0)
268     val = n1 + (n2 - n1) * (4.0 - hue);
269   else
270     val = n1;
271 
272   return val;
273 }
274 
275 
276 /**
277  * gimp_hsl_to_rgb:
278  * @hsl: A color value in the HSL colorspace
279  * @rgb: The value converted to a value in the RGB colorspace
280  *
281  * Convert a HSL color value to an RGB color value.
282  **/
283 void
gimp_hsl_to_rgb(const GimpHSL * hsl,GimpRGB * rgb)284 gimp_hsl_to_rgb (const GimpHSL *hsl,
285                  GimpRGB       *rgb)
286 {
287   g_return_if_fail (hsl != NULL);
288   g_return_if_fail (rgb != NULL);
289 
290   if (hsl->s == 0)
291     {
292       /*  achromatic case  */
293       rgb->r = hsl->l;
294       rgb->g = hsl->l;
295       rgb->b = hsl->l;
296     }
297   else
298     {
299       gdouble m1, m2;
300 
301       if (hsl->l <= 0.5)
302         m2 = hsl->l * (1.0 + hsl->s);
303       else
304         m2 = hsl->l + hsl->s - hsl->l * hsl->s;
305 
306       m1 = 2.0 * hsl->l - m2;
307 
308       rgb->r = gimp_hsl_value (m1, m2, hsl->h * 6.0 + 2.0);
309       rgb->g = gimp_hsl_value (m1, m2, hsl->h * 6.0);
310       rgb->b = gimp_hsl_value (m1, m2, hsl->h * 6.0 - 2.0);
311     }
312 
313   rgb->a = hsl->a;
314 }
315 
316 
317 /**
318  * gimp_rgb_to_cmyk:
319  * @rgb: A value in the RGB colorspace
320  * @pullout: A scaling value (0-1) indicating how much black should be
321  *           pulled out
322  * @cmyk: The input value naively converted to the CMYK colorspace
323  *
324  * Does a naive conversion from RGB to CMYK colorspace. A simple
325  * formula that doesn't take any color-profiles into account is used.
326  * The amount of black pullout how can be controlled via the @pullout
327  * parameter. A @pullout value of 0 makes this a conversion to CMY.
328  * A value of 1 causes the maximum amount of black to be pulled out.
329  **/
330 void
gimp_rgb_to_cmyk(const GimpRGB * rgb,gdouble pullout,GimpCMYK * cmyk)331 gimp_rgb_to_cmyk (const GimpRGB  *rgb,
332                   gdouble         pullout,
333                   GimpCMYK       *cmyk)
334 {
335   gdouble c, m, y, k;
336 
337   g_return_if_fail (rgb != NULL);
338   g_return_if_fail (cmyk != NULL);
339 
340   c = 1.0 - rgb->r;
341   m = 1.0 - rgb->g;
342   y = 1.0 - rgb->b;
343 
344   k = 1.0;
345   if (c < k)  k = c;
346   if (m < k)  k = m;
347   if (y < k)  k = y;
348 
349   k *= pullout;
350 
351   if (k < 1.0)
352     {
353       cmyk->c = (c - k) / (1.0 - k);
354       cmyk->m = (m - k) / (1.0 - k);
355       cmyk->y = (y - k) / (1.0 - k);
356     }
357   else
358     {
359       cmyk->c = 0.0;
360       cmyk->m = 0.0;
361       cmyk->y = 0.0;
362     }
363 
364   cmyk->k = k;
365   cmyk->a = rgb->a;
366 }
367 
368 /**
369  * gimp_cmyk_to_rgb:
370  * @cmyk: A color value in the CMYK colorspace
371  * @rgb: The value converted to the RGB colorspace
372  *
373  * Does a simple transformation from the CMYK colorspace to the RGB
374  * colorspace, without taking color profiles into account.
375  **/
376 void
gimp_cmyk_to_rgb(const GimpCMYK * cmyk,GimpRGB * rgb)377 gimp_cmyk_to_rgb (const GimpCMYK *cmyk,
378                   GimpRGB        *rgb)
379 {
380   gdouble c, m, y, k;
381 
382   g_return_if_fail (cmyk != NULL);
383   g_return_if_fail (rgb != NULL);
384 
385   k = cmyk->k;
386 
387   if (k < 1.0)
388     {
389       c = cmyk->c * (1.0 - k) + k;
390       m = cmyk->m * (1.0 - k) + k;
391       y = cmyk->y * (1.0 - k) + k;
392     }
393   else
394     {
395       c = 1.0;
396       m = 1.0;
397       y = 1.0;
398     }
399 
400   rgb->r = 1.0 - c;
401   rgb->g = 1.0 - m;
402   rgb->b = 1.0 - y;
403   rgb->a = cmyk->a;
404 }
405 
406 
407 #define GIMP_RETURN_RGB(x, y, z) { rgb->r = x; rgb->g = y; rgb->b = z; return; }
408 
409 /****************************************************************************
410  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms.
411  * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can
412  * be defined as 0 in situations where only unsigned numbers are desired.
413  ****************************************************************************/
414 
415 /**
416  * gimp_rgb_to_hwb:
417  * @rgb: A color value in the RGB colorspace
418  * @hue: The hue value of the above color, in the range 0 to 6
419  * @whiteness: The whiteness value of the above color, in the range 0 to 1
420  * @blackness: The blackness value of the above color, in the range 0 to 1
421  *
422  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms.
423  * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can
424  * be defined as 0 in situations where only unsigned numbers are desired.
425  *
426  * RGB are each on [0, 1]. Whiteness and Blackness are returned in the
427  * range [0, 1] and H is returned in the range [0, 6]. If W == 1 - B, H is
428  * undefined.
429  **/
430 void
gimp_rgb_to_hwb(const GimpRGB * rgb,gdouble * hue,gdouble * whiteness,gdouble * blackness)431 gimp_rgb_to_hwb (const GimpRGB *rgb,
432                  gdouble       *hue,
433                  gdouble       *whiteness,
434                  gdouble       *blackness)
435 {
436   /* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is        */
437   /* returned on [0, 6]. Exception: H is returned UNDEFINED if W ==  1 - B. */
438   /* ====================================================================== */
439 
440   gdouble R = rgb->r, G = rgb->g, B = rgb->b, w, v, b, f;
441   gint i;
442 
443   w = gimp_rgb_min (rgb);
444   v = gimp_rgb_max (rgb);
445   b = 1.0 - v;
446 
447   if (v == w)
448     {
449       *hue = GIMP_HSV_UNDEFINED;
450       *whiteness = w;
451       *blackness = b;
452     }
453   else
454     {
455       f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
456       i = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0);
457 
458       *hue = (360.0 / 6.0) * (i - f / (v - w));
459       *whiteness = w;
460       *blackness = b;
461     }
462 }
463 
464 /**
465  * gimp_hwb_to_rgb:
466  * @hue: A hue value, in the range 0 to 6
467  * @whiteness: A whiteness value, in the range 0 to 1
468  * @blackness: A blackness value, in the range 0 to 1
469  * @rgb: The above color converted to the RGB colorspace
470  *
471  * H is defined in the range [0, 6] or UNDEFINED, B and W are both in the
472  * range [0, 1]. The returned RGB values are all in the range [0, 1].
473  **/
474 void
gimp_hwb_to_rgb(gdouble hue,gdouble whiteness,gdouble blackness,GimpRGB * rgb)475 gimp_hwb_to_rgb (gdouble  hue,
476                  gdouble  whiteness,
477                  gdouble  blackness,
478                  GimpRGB *rgb)
479 {
480   /* H is given on [0, 6] or UNDEFINED. whiteness and
481    * blackness are given on [0, 1].
482    * RGB are each returned on [0, 1].
483    */
484 
485   gdouble h = hue, w = whiteness, b = blackness, v, n, f;
486   gint    i;
487 
488   h = 6.0 * h/ 360.0;
489 
490   v = 1.0 - b;
491   if (h == GIMP_HSV_UNDEFINED)
492     {
493       rgb->r = v;
494       rgb->g = v;
495       rgb->b = v;
496     }
497   else
498     {
499       i = floor (h);
500       f = h - i;
501 
502       if (i & 1)
503         f = 1.0 - f;  /* if i is odd */
504 
505       n = w + f * (v - w);     /* linear interpolation between w and v */
506 
507       switch (i)
508         {
509           case 6:
510           case 0: GIMP_RETURN_RGB (v, n, w);
511             break;
512           case 1: GIMP_RETURN_RGB (n, v, w);
513             break;
514           case 2: GIMP_RETURN_RGB (w, v, n);
515             break;
516           case 3: GIMP_RETURN_RGB (w, n, v);
517             break;
518           case 4: GIMP_RETURN_RGB (n, w, v);
519             break;
520           case 5: GIMP_RETURN_RGB (v, w, n);
521             break;
522         }
523     }
524 
525 }
526 
527 
528 /*  gint functions  */
529 
530 /**
531  * gimp_rgb_to_hsv_int:
532  * @red: The red channel value, returns the Hue channel
533  * @green: The green channel value, returns the Saturation channel
534  * @blue: The blue channel value, returns the Value channel
535  *
536  * The arguments are pointers to int representing channel values in
537  * the RGB colorspace, and the values pointed to are all in the range
538  * [0, 255].
539  *
540  * The function changes the arguments to point to the HSV value
541  * corresponding, with the returned values in the following
542  * ranges: H [0, 359], S [0, 255], V [0, 255].
543  **/
544 void
gimp_rgb_to_hsv_int(gint * red,gint * green,gint * blue)545 gimp_rgb_to_hsv_int (gint *red,
546                      gint *green,
547                      gint *blue)
548 {
549   gdouble  r, g, b;
550   gdouble  h, s, v;
551   gint     min;
552   gdouble  delta;
553 
554   r = *red;
555   g = *green;
556   b = *blue;
557 
558   if (r > g)
559     {
560       v = MAX (r, b);
561       min = MIN (g, b);
562     }
563   else
564     {
565       v = MAX (g, b);
566       min = MIN (r, b);
567     }
568 
569   delta = v - min;
570 
571   if (v == 0.0)
572     s = 0.0;
573   else
574     s = delta / v;
575 
576   if (s == 0.0)
577     {
578       h = 0.0;
579     }
580   else
581     {
582       if (r == v)
583         h = 60.0 * (g - b) / delta;
584       else if (g == v)
585         h = 120 + 60.0 * (b - r) / delta;
586       else
587         h = 240 + 60.0 * (r - g) / delta;
588 
589       if (h < 0.0)
590         h += 360.0;
591 
592       if (h > 360.0)
593         h -= 360.0;
594     }
595 
596   *red   = ROUND (h);
597   *green = ROUND (s * 255.0);
598   *blue  = ROUND (v);
599 
600   /* avoid the ambiguity of returning different values for the same color */
601   if (*red == 360)
602     *red = 0;
603 }
604 
605 /**
606  * gimp_hsv_to_rgb_int:
607  * @hue: The hue channel, returns the red channel
608  * @saturation: The saturation channel, returns the green channel
609  * @value: The value channel, returns the blue channel
610  *
611  * The arguments are pointers to int, with the values pointed to in the
612  * following ranges:  H [0, 360], S [0, 255], V [0, 255].
613  *
614  * The function changes the arguments to point to the RGB value
615  * corresponding, with the returned values all in the range [0, 255].
616  **/
617 void
gimp_hsv_to_rgb_int(gint * hue,gint * saturation,gint * value)618 gimp_hsv_to_rgb_int (gint *hue,
619                      gint *saturation,
620                      gint *value)
621 {
622   gdouble h, s, v, h_temp;
623   gdouble f, p, q, t;
624   gint i;
625 
626   if (*saturation == 0)
627     {
628       *hue        = *value;
629       *saturation = *value;
630       *value      = *value;
631     }
632   else
633     {
634       h = *hue;
635       s = *saturation / 255.0;
636       v = *value      / 255.0;
637 
638       if (h == 360)
639         h_temp = 0;
640       else
641         h_temp = h;
642 
643       h_temp = h_temp / 60.0;
644       i = floor (h_temp);
645       f = h_temp - i;
646       p = v * (1.0 - s);
647       q = v * (1.0 - (s * f));
648       t = v * (1.0 - (s * (1.0 - f)));
649 
650       switch (i)
651         {
652         case 0:
653           *hue        = ROUND (v * 255.0);
654           *saturation = ROUND (t * 255.0);
655           *value      = ROUND (p * 255.0);
656           break;
657 
658         case 1:
659           *hue        = ROUND (q * 255.0);
660           *saturation = ROUND (v * 255.0);
661           *value      = ROUND (p * 255.0);
662           break;
663 
664         case 2:
665           *hue        = ROUND (p * 255.0);
666           *saturation = ROUND (v * 255.0);
667           *value      = ROUND (t * 255.0);
668           break;
669 
670         case 3:
671           *hue        = ROUND (p * 255.0);
672           *saturation = ROUND (q * 255.0);
673           *value      = ROUND (v * 255.0);
674           break;
675 
676         case 4:
677           *hue        = ROUND (t * 255.0);
678           *saturation = ROUND (p * 255.0);
679           *value      = ROUND (v * 255.0);
680           break;
681 
682         case 5:
683           *hue        = ROUND (v * 255.0);
684           *saturation = ROUND (p * 255.0);
685           *value      = ROUND (q * 255.0);
686           break;
687         }
688     }
689 }
690 
691 /**
692  * gimp_rgb_to_hsl_int:
693  * @red: Red channel, returns Hue channel
694  * @green: Green channel, returns Lightness channel
695  * @blue: Blue channel, returns Saturation channel
696  *
697  * The arguments are pointers to int representing channel values in the
698  * RGB colorspace, and the values pointed to are all in the range [0, 255].
699  *
700  * The function changes the arguments to point to the corresponding HLS
701  * value with the values pointed to in the following ranges:  H [0, 360],
702  * L [0, 255], S [0, 255].
703  **/
704 void
gimp_rgb_to_hsl_int(gint * red,gint * green,gint * blue)705 gimp_rgb_to_hsl_int (gint *red,
706                      gint *green,
707                      gint *blue)
708 {
709   gint    r, g, b;
710   gdouble h, s, l;
711   gint    min, max;
712   gint    delta;
713 
714   r = *red;
715   g = *green;
716   b = *blue;
717 
718   if (r > g)
719     {
720       max = MAX (r, b);
721       min = MIN (g, b);
722     }
723   else
724     {
725       max = MAX (g, b);
726       min = MIN (r, b);
727     }
728 
729   l = (max + min) / 2.0;
730 
731   if (max == min)
732     {
733       s = 0.0;
734       h = 0.0;
735     }
736   else
737     {
738       delta = (max - min);
739 
740       if (l < 128)
741         s = 255 * (gdouble) delta / (gdouble) (max + min);
742       else
743         s = 255 * (gdouble) delta / (gdouble) (511 - max - min);
744 
745       if (r == max)
746         h = (g - b) / (gdouble) delta;
747       else if (g == max)
748         h = 2 + (b - r) / (gdouble) delta;
749       else
750         h = 4 + (r - g) / (gdouble) delta;
751 
752       h = h * 42.5;
753 
754       if (h < 0)
755         h += 255;
756       else if (h > 255)
757         h -= 255;
758     }
759 
760   *red   = ROUND (h);
761   *green = ROUND (s);
762   *blue  = ROUND (l);
763 }
764 
765 /**
766  * gimp_rgb_to_l_int:
767  * @red: Red channel
768  * @green: Green channel
769  * @blue: Blue channel
770  *
771  * Calculates the lightness value of an RGB triplet with the formula
772  * L = (max(R, G, B) + min (R, G, B)) / 2
773  *
774  * Return value: Luminance value corresponding to the input RGB value
775  **/
776 gint
gimp_rgb_to_l_int(gint red,gint green,gint blue)777 gimp_rgb_to_l_int (gint red,
778                    gint green,
779                    gint blue)
780 {
781   gint min, max;
782 
783   if (red > green)
784     {
785       max = MAX (red,   blue);
786       min = MIN (green, blue);
787     }
788   else
789     {
790       max = MAX (green, blue);
791       min = MIN (red,   blue);
792     }
793 
794   return ROUND ((max + min) / 2.0);
795 }
796 
797 static inline gint
gimp_hsl_value_int(gdouble n1,gdouble n2,gdouble hue)798 gimp_hsl_value_int (gdouble n1,
799                     gdouble n2,
800                     gdouble hue)
801 {
802   gdouble value;
803 
804   if (hue > 255)
805     hue -= 255;
806   else if (hue < 0)
807     hue += 255;
808 
809   if (hue < 42.5)
810     value = n1 + (n2 - n1) * (hue / 42.5);
811   else if (hue < 127.5)
812     value = n2;
813   else if (hue < 170)
814     value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
815   else
816     value = n1;
817 
818   return ROUND (value * 255.0);
819 }
820 
821 /**
822  * gimp_hsl_to_rgb_int:
823  * @hue: Hue channel, returns Red channel
824  * @saturation: Saturation channel, returns Green channel
825  * @lightness: Lightness channel, returns Blue channel
826  *
827  * The arguments are pointers to int, with the values pointed to in the
828  * following ranges:  H [0, 360], L [0, 255], S [0, 255].
829  *
830  * The function changes the arguments to point to the RGB value
831  * corresponding, with the returned values all in the range [0, 255].
832  **/
833 void
gimp_hsl_to_rgb_int(gint * hue,gint * saturation,gint * lightness)834 gimp_hsl_to_rgb_int (gint *hue,
835                      gint *saturation,
836                      gint *lightness)
837 {
838   gdouble h, s, l;
839 
840   h = *hue;
841   s = *saturation;
842   l = *lightness;
843 
844   if (s == 0)
845     {
846       /*  achromatic case  */
847       *hue        = l;
848       *lightness  = l;
849       *saturation = l;
850     }
851   else
852     {
853       gdouble m1, m2;
854 
855       if (l < 128)
856         m2 = (l * (255 + s)) / 65025.0;
857       else
858         m2 = (l + s - (l * s) / 255.0) / 255.0;
859 
860       m1 = (l / 127.5) - m2;
861 
862       /*  chromatic case  */
863       *hue        = gimp_hsl_value_int (m1, m2, h + 85);
864       *saturation = gimp_hsl_value_int (m1, m2, h);
865       *lightness  = gimp_hsl_value_int (m1, m2, h - 85);
866     }
867 }
868 
869 /**
870  * gimp_rgb_to_cmyk_int:
871  * @red:     the red channel; returns the cyan value (0-255)
872  * @green:   the green channel; returns the magenta value (0-255)
873  * @blue:    the blue channel; returns the yellow value (0-255)
874  * @pullout: the percentage of black to pull out (0-100); returns
875  *           the black value (0-255)
876  *
877  * Does a naive conversion from RGB to CMYK colorspace. A simple
878  * formula that doesn't take any color-profiles into account is used.
879  * The amount of black pullout how can be controlled via the @pullout
880  * parameter. A @pullout value of 0 makes this a conversion to CMY.
881  * A value of 100 causes the maximum amount of black to be pulled out.
882  **/
883 void
gimp_rgb_to_cmyk_int(gint * red,gint * green,gint * blue,gint * pullout)884 gimp_rgb_to_cmyk_int (gint *red,
885                       gint *green,
886                       gint *blue,
887                       gint *pullout)
888 {
889   gint c, m, y;
890 
891   c = 255 - *red;
892   m = 255 - *green;
893   y = 255 - *blue;
894 
895   if (*pullout == 0)
896     {
897       *red   = c;
898       *green = m;
899       *blue  = y;
900     }
901   else
902     {
903       gint k = 255;
904 
905       if (c < k)  k = c;
906       if (m < k)  k = m;
907       if (y < k)  k = y;
908 
909       k = (k * CLAMP (*pullout, 0, 100)) / 100;
910 
911       *red   = ((c - k) << 8) / (256 - k);
912       *green = ((m - k) << 8) / (256 - k);
913       *blue  = ((y - k) << 8) / (256 - k);
914       *pullout = k;
915     }
916 }
917 
918 /**
919  * gimp_cmyk_to_rgb_int:
920  * @cyan:    the cyan channel; returns the red value (0-255)
921  * @magenta: the magenta channel; returns the green value (0-255)
922  * @yellow:  the yellow channel; returns the blue value (0-255)
923  * @black:   the black channel (0-255); doesn't change
924  *
925  * Does a naive conversion from CMYK to RGB colorspace. A simple
926  * formula that doesn't take any color-profiles into account is used.
927  **/
928 void
gimp_cmyk_to_rgb_int(gint * cyan,gint * magenta,gint * yellow,gint * black)929 gimp_cmyk_to_rgb_int (gint *cyan,
930                       gint *magenta,
931                       gint *yellow,
932                       gint *black)
933 {
934   gint c, m, y, k;
935 
936   c = *cyan;
937   m = *magenta;
938   y = *yellow;
939   k = *black;
940 
941   if (k)
942     {
943       c = ((c * (256 - k)) >> 8) + k;
944       m = ((m * (256 - k)) >> 8) + k;
945       y = ((y * (256 - k)) >> 8) + k;
946     }
947 
948   *cyan    = 255 - c;
949   *magenta = 255 - m;
950   *yellow  = 255 - y;
951 }
952 
953 /**
954  * gimp_rgb_to_hsv4:
955  * @rgb:        RGB triplet, rgb[0] is red channel, rgb[1] is green,
956  *              rgb[2] is blue (0..255)
957  * @hue:        Pointer to hue channel (0..1)
958  * @saturation: Pointer to saturation channel (0..1)
959  * @value:      Pointer to value channel (0..1)
960  **/
961 void
gimp_rgb_to_hsv4(const guchar * rgb,gdouble * hue,gdouble * saturation,gdouble * value)962 gimp_rgb_to_hsv4 (const guchar *rgb,
963                   gdouble      *hue,
964                   gdouble      *saturation,
965                   gdouble      *value)
966 {
967   gdouble red, green, blue;
968   gdouble h, s, v;
969   gdouble min, max;
970   gdouble delta;
971 
972   red   = rgb[0] / 255.0;
973   green = rgb[1] / 255.0;
974   blue  = rgb[2] / 255.0;
975 
976   if (red > green)
977     {
978       max = MAX (red,   blue);
979       min = MIN (green, blue);
980     }
981   else
982     {
983       max = MAX (green, blue);
984       min = MIN (red,   blue);
985     }
986 
987   v = max;
988 
989   if (max != 0.0)
990     s = (max - min) / max;
991   else
992     s = 0.0;
993 
994   if (s == 0.0)
995     h = 0.0;
996   else
997     {
998       delta = max - min;
999 
1000       if (delta == 0.0)
1001         delta = 1.0;
1002 
1003       if (red == max)
1004         h = (green - blue) / delta;
1005       else if (green == max)
1006         h = 2 + (blue - red) / delta;
1007       else
1008         h = 4 + (red - green) / delta;
1009 
1010       h /= 6.0;
1011 
1012       if (h < 0.0)
1013         h += 1.0;
1014       else if (h > 1.0)
1015         h -= 1.0;
1016     }
1017 
1018   *hue        = h;
1019   *saturation = s;
1020   *value      = v;
1021 }
1022 
1023 /**
1024  * gimp_hsv_to_rgb4:
1025  * @rgb:        RGB triplet, rgb[0] is red channel, rgb[1] is green,
1026  *              rgb[2] is blue (0..255)
1027  * @hue:        Hue channel (0..1)
1028  * @saturation: Saturation channel (0..1)
1029  * @value:      Value channel (0..1)
1030  **/
1031 void
gimp_hsv_to_rgb4(guchar * rgb,gdouble hue,gdouble saturation,gdouble value)1032 gimp_hsv_to_rgb4 (guchar  *rgb,
1033                   gdouble  hue,
1034                   gdouble  saturation,
1035                   gdouble  value)
1036 {
1037   gdouble h, s, v;
1038   gdouble f, p, q, t;
1039 
1040   if (saturation == 0.0)
1041     {
1042       hue        = value;
1043       saturation = value;
1044       /*value      = value;*/
1045     }
1046   else
1047     {
1048       h = hue * 6.0;
1049       s = saturation;
1050       v = value;
1051 
1052       if (h == 6.0)
1053         h = 0.0;
1054 
1055       f = h - (gint) h;
1056       p = v * (1.0 - s);
1057       q = v * (1.0 - s * f);
1058       t = v * (1.0 - s * (1.0 - f));
1059 
1060       switch ((int) h)
1061         {
1062         case 0:
1063           hue        = v;
1064           saturation = t;
1065           value      = p;
1066           break;
1067 
1068         case 1:
1069           hue        = q;
1070           saturation = v;
1071           value      = p;
1072           break;
1073 
1074         case 2:
1075           hue        = p;
1076           saturation = v;
1077           value      = t;
1078           break;
1079 
1080         case 3:
1081           hue        = p;
1082           saturation = q;
1083           value      = v;
1084           break;
1085 
1086         case 4:
1087           hue        = t;
1088           saturation = p;
1089           value      = v;
1090           break;
1091 
1092         case 5:
1093           hue        = v;
1094           saturation = p;
1095           value      = q;
1096           break;
1097         }
1098     }
1099 
1100   rgb[0] = ROUND (hue        * 255.0);
1101   rgb[1] = ROUND (saturation * 255.0);
1102   rgb[2] = ROUND (value      * 255.0);
1103 }
1104