1 /* Color utilities
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
6  *          Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
7  *          Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29 
30 #include "config.h"
31 
32 #include <math.h>
33 #include <string.h>
34 
35 #include "gtkcolorutils.h"
36 
37 /* Converts from HSV to RGB */
38 static void
hsv_to_rgb(gdouble * h,gdouble * s,gdouble * v)39 hsv_to_rgb (gdouble *h,
40             gdouble *s,
41             gdouble *v)
42 {
43   gdouble hue, saturation, value;
44   gdouble f, p, q, t;
45 
46   if (*s == 0.0)
47     {
48       *h = *v;
49       *s = *v;
50       *v = *v; /* heh */
51     }
52   else
53     {
54       hue = *h * 6.0;
55       saturation = *s;
56       value = *v;
57 
58       if (hue == 6.0)
59         hue = 0.0;
60 
61       f = hue - (int) hue;
62       p = value * (1.0 - saturation);
63       q = value * (1.0 - saturation * f);
64       t = value * (1.0 - saturation * (1.0 - f));
65 
66       switch ((int) hue)
67         {
68         case 0:
69           *h = value;
70           *s = t;
71           *v = p;
72           break;
73 
74         case 1:
75           *h = q;
76           *s = value;
77           *v = p;
78           break;
79 
80         case 2:
81           *h = p;
82           *s = value;
83           *v = t;
84           break;
85 
86         case 3:
87           *h = p;
88           *s = q;
89           *v = value;
90           break;
91 
92         case 4:
93           *h = t;
94           *s = p;
95           *v = value;
96           break;
97 
98         case 5:
99           *h = value;
100           *s = p;
101           *v = q;
102           break;
103 
104         default:
105           g_assert_not_reached ();
106         }
107     }
108 }
109 
110 /* Converts from RGB to HSV */
111 static void
rgb_to_hsv(gdouble * r,gdouble * g,gdouble * b)112 rgb_to_hsv (gdouble *r,
113             gdouble *g,
114             gdouble *b)
115 {
116   gdouble red, green, blue;
117   gdouble h, s, v;
118   gdouble min, max;
119   gdouble delta;
120 
121   red = *r;
122   green = *g;
123   blue = *b;
124 
125   h = 0.0;
126 
127   if (red > green)
128     {
129       if (red > blue)
130         max = red;
131       else
132         max = blue;
133 
134       if (green < blue)
135         min = green;
136       else
137         min = blue;
138     }
139   else
140     {
141       if (green > blue)
142         max = green;
143       else
144         max = blue;
145 
146       if (red < blue)
147         min = red;
148       else
149         min = blue;
150     }
151 
152   v = max;
153 
154   if (max != 0.0)
155     s = (max - min) / max;
156   else
157     s = 0.0;
158 
159   if (s == 0.0)
160     h = 0.0;
161   else
162     {
163       delta = max - min;
164 
165       if (red == max)
166         h = (green - blue) / delta;
167       else if (green == max)
168         h = 2 + (blue - red) / delta;
169       else if (blue == max)
170         h = 4 + (red - green) / delta;
171 
172       h /= 6.0;
173 
174       if (h < 0.0)
175         h += 1.0;
176       else if (h > 1.0)
177         h -= 1.0;
178     }
179 
180   *r = h;
181   *g = s;
182   *b = v;
183 }
184 
185 /**
186  * gtk_hsv_to_rgb:
187  * @h: Hue
188  * @s: Saturation
189  * @v: Value
190  * @r: (out): Return value for the red component
191  * @g: (out): Return value for the green component
192  * @b: (out): Return value for the blue component
193  *
194  * Converts a color from HSV space to RGB.
195  *
196  * Input values must be in the [0.0, 1.0] range;
197  * output values will be in the same range.
198  *
199  * Since: 2.14
200  */
201 void
gtk_hsv_to_rgb(gdouble h,gdouble s,gdouble v,gdouble * r,gdouble * g,gdouble * b)202 gtk_hsv_to_rgb (gdouble  h, gdouble  s, gdouble  v,
203                 gdouble *r, gdouble *g, gdouble *b)
204 {
205   g_return_if_fail (h >= 0.0 && h <= 1.0);
206   g_return_if_fail (s >= 0.0 && s <= 1.0);
207   g_return_if_fail (v >= 0.0 && v <= 1.0);
208 
209   hsv_to_rgb (&h, &s, &v);
210 
211   if (r)
212     *r = h;
213 
214   if (g)
215     *g = s;
216 
217   if (b)
218     *b = v;
219 }
220 
221 /**
222  * gtk_rgb_to_hsv:
223  * @r: Red
224  * @g: Green
225  * @b: Blue
226  * @h: (out): Return value for the hue component
227  * @s: (out): Return value for the saturation component
228  * @v: (out): Return value for the value component
229  *
230  * Converts a color from RGB space to HSV.
231  *
232  * Input values must be in the [0.0, 1.0] range;
233  * output values will be in the same range.
234  *
235  * Since: 2.14
236  */
237 void
gtk_rgb_to_hsv(gdouble r,gdouble g,gdouble b,gdouble * h,gdouble * s,gdouble * v)238 gtk_rgb_to_hsv (gdouble  r, gdouble  g, gdouble  b,
239                 gdouble *h, gdouble *s, gdouble *v)
240 {
241   g_return_if_fail (r >= 0.0 && r <= 1.0);
242   g_return_if_fail (g >= 0.0 && g <= 1.0);
243   g_return_if_fail (b >= 0.0 && b <= 1.0);
244 
245   rgb_to_hsv (&r, &g, &b);
246 
247   if (h)
248     *h = r;
249 
250   if (s)
251     *s = g;
252 
253   if (v)
254     *v = b;
255 }
256