Code

bulk trailing spaces removal. consistency through MD5 of binary
[inkscape.git] / src / color.cpp
1 #define __SP_COLOR_C__
3 /** \file
4  * Colors and colorspaces.
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2001-2002 Lauris Kaplinski
11  * Copyright (C) 2001 Ximian, Inc.
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #include <math.h>
17 #include "color.h"
19 /// A color space is just a name.
20 struct SPColorSpace {
21     gchar const *name;
22 };
24 static SPColorSpace const RGB = {"RGB"};
25 static SPColorSpace const CMYK = {"CMYK"};
27 /**
28  * Returns one of three values depending on if color is valid and if it
29  * has a valid color space. Likely redundant as soon as this is C++.
30  */
31 SPColorSpaceClass
32 sp_color_get_colorspace_class(SPColor const *color)
33 {
34     g_return_val_if_fail (color != NULL, SP_COLORSPACE_CLASS_INVALID);
36     if (color->colorspace == &RGB) return SP_COLORSPACE_CLASS_PROCESS;
37     if (color->colorspace == &CMYK) return SP_COLORSPACE_CLASS_PROCESS;
39     return SP_COLORSPACE_CLASS_UNKNOWN;
40 }
42 /**
43  * Returns the SPColorSpaceType corresponding to color's color space.
44  * \todo color->colorspace should simply be a named enum.
45  */
46 SPColorSpaceType
47 sp_color_get_colorspace_type(SPColor const *color)
48 {
49     g_return_val_if_fail (color != NULL, SP_COLORSPACE_TYPE_INVALID);
51     if (color->colorspace == &RGB) return SP_COLORSPACE_TYPE_RGB;
52     if (color->colorspace == &CMYK) return SP_COLORSPACE_TYPE_CMYK;
54     return SP_COLORSPACE_TYPE_UNKNOWN;
55 }
57 /**
58  * Shallow copy of color struct with NULL check.
59  */
60 void
61 sp_color_copy(SPColor *dst, SPColor const *src)
62 {
63     g_return_if_fail (dst != NULL);
64     g_return_if_fail (src != NULL);
66     *dst = *src;
67 }
69 /**
70  * Returns TRUE if c0 or c1 is NULL, or if colors/opacities differ.
71  */
72 gboolean
73 sp_color_is_equal (SPColor const *c0, SPColor const *c1)
74 {
75     g_return_val_if_fail (c0 != NULL, TRUE);
76     g_return_val_if_fail (c1 != NULL, TRUE);
78     if (c0->colorspace != c1->colorspace) return FALSE;
79     if (c0->v.c[0] != c1->v.c[0]) return FALSE;
80     if (c0->v.c[1] != c1->v.c[1]) return FALSE;
81     if (c0->v.c[2] != c1->v.c[2]) return FALSE;
82     if ((c0->colorspace == &CMYK) && (c0->v.c[3] != c1->v.c[3])) return FALSE;
84     return TRUE;
85 }
87 /**
88  * Returns TRUE if no RGB value differs epsilon or more in both colors,
89  * with CMYK aditionally comparing opacity, or if c0 or c1 is NULL.
90  * \note Do we want the latter?
91  */
92 gboolean
93 sp_color_is_close (SPColor const *c0, SPColor const *c1, float epsilon)
94 {
95     g_return_val_if_fail (c0 != NULL, TRUE);
96     g_return_val_if_fail (c1 != NULL, TRUE);
98     if (c0->colorspace != c1->colorspace) return FALSE;
99     if (fabs ((c0->v.c[0]) - (c1->v.c[0])) >= epsilon) return FALSE;
100     if (fabs ((c0->v.c[1]) - (c1->v.c[1])) >= epsilon) return FALSE;
101     if (fabs ((c0->v.c[2]) - (c1->v.c[2])) >= epsilon) return FALSE;
102     if ((c0->colorspace == &CMYK) && (fabs ((c0->v.c[3]) - (c1->v.c[3])) >= epsilon)) return FALSE;
104     return TRUE;
107 /**
108  * Sets RGB values and colorspace in color.
109  * \pre color != NULL && 0 <={r,g,b}<=1
110  */
111 void
112 sp_color_set_rgb_float(SPColor *color, float r, float g, float b)
114     g_return_if_fail(color != NULL);
115     g_return_if_fail(r >= 0.0);
116     g_return_if_fail(r <= 1.0);
117     g_return_if_fail(g >= 0.0);
118     g_return_if_fail(g <= 1.0);
119     g_return_if_fail(b >= 0.0);
120     g_return_if_fail(b <= 1.0);
122     color->colorspace = &RGB;
123     color->v.c[0] = r;
124     color->v.c[1] = g;
125     color->v.c[2] = b;
126     color->v.c[3] = 0;
129 /**
130  * Converts 32bit value to RGB floats and sets color.
131  * \pre color != NULL
132  */
133 void
134 sp_color_set_rgb_rgba32(SPColor *color, guint32 value)
136     g_return_if_fail (color != NULL);
138     color->colorspace = &RGB;
139     color->v.c[0] = (value >> 24) / 255.0F;
140     color->v.c[1] = ((value >> 16) & 0xff) / 255.0F;
141     color->v.c[2] = ((value >> 8) & 0xff) / 255.0F;
142     color->v.c[3] = 0;
145 /**
146  * Sets CMYK values and colorspace in color.
147  * \pre color != NULL && 0 <={c,m,y,k}<=1
148  */
149 void
150 sp_color_set_cmyk_float(SPColor *color, float c, float m, float y, float k)
152     g_return_if_fail(color != NULL);
153     g_return_if_fail(c >= 0.0);
154     g_return_if_fail(c <= 1.0);
155     g_return_if_fail(m >= 0.0);
156     g_return_if_fail(m <= 1.0);
157     g_return_if_fail(y >= 0.0);
158     g_return_if_fail(y <= 1.0);
159     g_return_if_fail(k >= 0.0);
160     g_return_if_fail(k <= 1.0);
162     color->colorspace = &CMYK;
163     color->v.c[0] = c;
164     color->v.c[1] = m;
165     color->v.c[2] = y;
166     color->v.c[3] = k;
169 /**
170  * Convert SPColor with integer alpha value to 32bit RGBA value.
171  * \pre color != NULL && alpha < 256
172  */
173 guint32
174 sp_color_get_rgba32_ualpha(SPColor const *color, guint32 alpha)
176     guint32 rgba;
178     g_return_val_if_fail (color != NULL, 0x0);
179     g_return_val_if_fail (alpha <= 0xff, 0x0);
181     if (color->colorspace == &RGB) {
182         rgba = SP_RGBA32_U_COMPOSE(SP_COLOR_F_TO_U(color->v.c[0]),
183                                    SP_COLOR_F_TO_U(color->v.c[1]),
184                                    SP_COLOR_F_TO_U(color->v.c[2]),
185                                    alpha);
186     } else {
187         float rgb[3];
188         sp_color_get_rgb_floatv (color, rgb);
189         rgba = SP_RGBA32_U_COMPOSE(SP_COLOR_F_TO_U(rgb[0]),
190                                    SP_COLOR_F_TO_U(rgb[1]),
191                                    SP_COLOR_F_TO_U(rgb[2]),
192                                    alpha);
193     }
195     return rgba;
198 /**
199  * Convert SPColor with float alpha value to 32bit RGBA value.
200  * \pre color != NULL && 0 <= alpha <= 1
201  */
202 guint32
203 sp_color_get_rgba32_falpha(SPColor const *color, float alpha)
205     g_return_val_if_fail(color != NULL, 0x0);
206     g_return_val_if_fail(alpha >= 0.0, 0x0);
207     g_return_val_if_fail(alpha <= 1.0, 0x0);
209     return sp_color_get_rgba32_ualpha(color, SP_COLOR_F_TO_U(alpha));
212 /**
213  * Fill rgb float array with values from SPColor.
214  * \pre color != NULL && rgb != NULL && rgb[0-2] is meaningful
215  */
216 void
217 sp_color_get_rgb_floatv(SPColor const *color, float *rgb)
219     g_return_if_fail (color != NULL);
220     g_return_if_fail (rgb != NULL);
222     if (color->colorspace == &RGB) {
223         rgb[0] = color->v.c[0];
224         rgb[1] = color->v.c[1];
225         rgb[2] = color->v.c[2];
226     } else if (color->colorspace == &CMYK) {
227         sp_color_cmyk_to_rgb_floatv(rgb,
228                                     color->v.c[0],
229                                     color->v.c[1],
230                                     color->v.c[2],
231                                     color->v.c[3]);
232     }
235 /**
236  * Fill cmyk float array with values from SPColor.
237  * \pre color != NULL && cmyk != NULL && cmyk[0-3] is meaningful
238  */
239 void
240 sp_color_get_cmyk_floatv(SPColor const *color, float *cmyk)
242     g_return_if_fail (color != NULL);
243     g_return_if_fail (cmyk != NULL);
245     if (color->colorspace == &CMYK) {
246         cmyk[0] = color->v.c[0];
247         cmyk[1] = color->v.c[1];
248         cmyk[2] = color->v.c[2];
249         cmyk[3] = color->v.c[3];
250     } else if (color->colorspace == &RGB) {
251         sp_color_rgb_to_cmyk_floatv(cmyk,
252                                     color->v.c[0],
253                                     color->v.c[1],
254                                     color->v.c[2]);
255     }
258 /* Plain mode helpers */
260 /**
261  * Fill hsv float array from r,g,b float values.
262  */
263 void
264 sp_color_rgb_to_hsv_floatv (float *hsv, float r, float g, float b)
266     float max, min, delta;
268     max = MAX (MAX (r, g), b);
269     min = MIN (MIN (r, g), b);
270     delta = max - min;
272     hsv[2] = max;
274     if (max > 0) {
275         hsv[1] = delta / max;
276     } else {
277         hsv[1] = 0.0;
278     }
280     if (hsv[1] != 0.0) {
281         if (r == max) {
282             hsv[0] = (g - b) / delta;
283         } else if (g == max) {
284             hsv[0] = 2.0 + (b - r) / delta;
285         } else {
286             hsv[0] = 4.0 + (r - g) / delta;
287         }
289         hsv[0] = hsv[0] / 6.0;
291         if (hsv[0] < 0) hsv[0] += 1.0;
292     }
295 /**
296  * Fill rgb float array from h,s,v float values.
297  */
298 void
299 sp_color_hsv_to_rgb_floatv (float *rgb, float h, float s, float v)
301     gdouble f, w, q, t, d;
303     d = h * 5.99999999;
304     f = d - floor (d);
305     w = v * (1.0 - s);
306     q = v * (1.0 - (s * f));
307     t = v * (1.0 - (s * (1.0 - f)));
309     if (d < 1.0) {
310         *rgb++ = v;
311         *rgb++ = t;
312         *rgb++ = w;
313     } else if (d < 2.0) {
314         *rgb++ = q;
315         *rgb++ = v;
316         *rgb++ = w;
317     } else if (d < 3.0) {
318         *rgb++ = w;
319         *rgb++ = v;
320         *rgb++ = t;
321     } else if (d < 4.0) {
322         *rgb++ = w;
323         *rgb++ = q;
324         *rgb++ = v;
325     } else if (d < 5.0) {
326         *rgb++ = t;
327         *rgb++ = w;
328         *rgb++ = v;
329     } else {
330         *rgb++ = v;
331         *rgb++ = w;
332         *rgb++ = q;
333     }
336 /**
337  * Fill hsl float array from r,g,b float values.
338  */
339 void
340 sp_color_rgb_to_hsl_floatv (float *hsl, float r, float g, float b)
342     float max = MAX (MAX (r, g), b);
343     float min = MIN (MIN (r, g), b);
344     float delta = max - min;
346     hsl[2] = (max + min)/2.0;
348     if (delta == 0) {
349         hsl[0] = 0;
350         hsl[1] = 0;
351     } else {
352         if (hsl[2] <= 0.5)
353             hsl[1] = delta / (max + min);
354         else
355             hsl[1] = delta / (2 - max - min);
357         if (r == max) hsl[0] = (g - b) / delta;
358         else if (g == max) hsl[0] = 2.0 + (b - r) / delta;
359         else if (b == max) hsl[0] = 4.0 + (r - g) / delta;
361         hsl[0] = hsl[0] / 6.0;
363         if (hsl[0] < 0) hsl[0] += 1;
364         if (hsl[0] > 1) hsl[0] -= 1;
365     }
368 float
369 hue_2_rgb (float v1, float v2, float h)
371     if (h < 0) h += 6.0;
372     if (h > 6) h -= 6.0;
374     if (h < 1) return v1 + (v2 - v1) * h;
375     if (h < 3) return v2;
376     if (h < 4) return v1 + (v2 - v1) * (4 - h);
377     return v1;
380 /**
381  * Fill rgb float array from h,s,l float values.
382  */
383 void
384 sp_color_hsl_to_rgb_floatv (float *rgb, float h, float s, float l)
386     if (s == 0) {
387         rgb[0] = l;
388         rgb[1] = l;
389         rgb[2] = l;
390     } else {
391         float v2;
392         if (l < 0.5) {
393             v2 = l * (1 + s);
394         } else {
395             v2 = l + s - l*s;
396         }
397         float v1 = 2*l - v2;
399         rgb[0] = hue_2_rgb (v1, v2, h*6 + 2.0);
400         rgb[1] = hue_2_rgb (v1, v2, h*6);
401         rgb[2] = hue_2_rgb (v1, v2, h*6 - 2.0);
402     }
405 /**
406  * Fill cmyk float array from r,g,b float values.
407  */
408 void
409 sp_color_rgb_to_cmyk_floatv (float *cmyk, float r, float g, float b)
411     float c, m, y, k, kd;
413     c = 1.0 - r;
414     m = 1.0 - g;
415     y = 1.0 - b;
416     k = MIN (MIN (c, m), y);
418     c = c - k;
419     m = m - k;
420     y = y - k;
422     kd = 1.0 - k;
424     if (kd > 1e-9) {
425         c = c / kd;
426         m = m / kd;
427         y = y / kd;
428     }
430     cmyk[0] = c;
431     cmyk[1] = m;
432     cmyk[2] = y;
433     cmyk[3] = k;
436 /**
437  * Fill rgb float array from c,m,y,k float values.
438  */
439 void
440 sp_color_cmyk_to_rgb_floatv (float *rgb, float c, float m, float y, float k)
442     float kd;
444     kd = 1.0 - k;
446     c = c * kd;
447     m = m * kd;
448     y = y * kd;
450     c = c + k;
451     m = m + k;
452     y = y + k;
454     rgb[0] = 1.0 - c;
455     rgb[1] = 1.0 - m;
456     rgb[2] = 1.0 - y;
459 /*
460   Local Variables:
461   mode:c++
462   c-file-style:"stroustrup"
463   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
464   indent-tabs-mode:nil
465   fill-column:99
466   End:
467 */
468 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :