Code

Connector tool: make connectors avoid the convex hull of shapes.
[inkscape.git] / src / color.cpp
1 #define __SP_COLOR_C__
3 /** \file
4  * Colors.
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *   Jon A. Cruz <jon@joncruz.org>
10  *
11  * Copyright (C) 2001-2002 Lauris Kaplinski
12  * Copyright (C) 2001 Ximian, Inc.
13  *
14  * Released under GNU GPL, read the file 'COPYING' for more information
15  */
17 #include <math.h>
18 #include "color.h"
19 #include "svg/svg-icc-color.h"
20 #include "svg/svg-color.h"
22 #include "svg/css-ostringstream.h"
24 using Inkscape::CSSOStringStream;
25 using std::vector;
27 static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second );
29 #define PROFILE_EPSILON 0.00000001
31 SPColor::SPColor() :
32     icc(0)
33 {
34     v.c[0] = 0;
35     v.c[1] = 0;
36     v.c[2] = 0;
37 }
39 SPColor::SPColor( SPColor const& other ) :
40     icc(0)
41 {
42     *this = other;
43 }
45 SPColor::SPColor( float r, float g, float b ) :
46     icc(0)
47 {
48     set( r, g, b );
49 }
51 SPColor::SPColor( guint32 value ) :
52     icc(0)
53 {
54     set( value );
55 }
57 SPColor::~SPColor()
58 {
59     delete icc;
60     icc = 0;
61 }
64 SPColor& SPColor::operator= (SPColor const& other)
65 {
66     SVGICCColor* tmp = other.icc ? new SVGICCColor(*other.icc) : 0;
67     v.c[0] = other.v.c[0];
68     v.c[1] = other.v.c[1];
69     v.c[2] = other.v.c[2];
70     if ( icc ) {
71         delete icc;
72     }
73     icc = tmp;
75     return *this;
76 }
79 /**
80  * Returns true if colors match.
81  */
82 bool SPColor::operator == (SPColor const& other) const
83 {
84     bool match = (v.c[0] != other.v.c[0])
85         && (v.c[1] != other.v.c[1])
86         && (v.c[2] != other.v.c[2]);
88     match &= profileMatches( icc, other.icc );
90     return match;
91 }
93 /**
94  * Returns true if no RGB value differs epsilon or more in both colors,
95  * false otherwise.
96  */
97 bool SPColor::isClose( SPColor const& other, float epsilon ) const
98 {
99     bool match = false;
101     match = (fabs((v.c[0]) - (other.v.c[0])) < epsilon)
102         && (fabs((v.c[1]) - (other.v.c[1])) < epsilon)
103         && (fabs((v.c[2]) - (other.v.c[2])) < epsilon);
105     match &= profileMatches( icc, other.icc );
107     return match;
110 static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second ) {
111     bool match = false;
112     if ( !first && !second ) {
113         match = true;
114     } else {
115         match = first && second
116             && (first->colorProfile == second->colorProfile)
117             && (first->colors.size() == second->colors.size());
118         if ( match ) {
119             for ( guint i = 0; i < first->colors.size(); i++ ) {
120                 match &= (fabs(first->colors[i] - second->colors[i]) < PROFILE_EPSILON);
121             }
122         }
123     }
124     return match;
127 /**
128  * Sets RGB values and colorspace in color.
129  * \pre 0 <={r,g,b}<=1
130  */
131 void SPColor::set( float r, float g, float b )
133     g_return_if_fail(r >= 0.0);
134     g_return_if_fail(r <= 1.0);
135     g_return_if_fail(g >= 0.0);
136     g_return_if_fail(g <= 1.0);
137     g_return_if_fail(b >= 0.0);
138     g_return_if_fail(b <= 1.0);
140     // TODO clear icc if set?
141     v.c[0] = r;
142     v.c[1] = g;
143     v.c[2] = b;
146 /**
147  * Converts 32bit value to RGB floats and sets color.
148  */
149 void SPColor::set( guint32 value )
151     // TODO clear icc if set?
152     v.c[0] = (value >> 24) / 255.0F;
153     v.c[1] = ((value >> 16) & 0xff) / 255.0F;
154     v.c[2] = ((value >> 8) & 0xff) / 255.0F;
157 /**
158  * Convert SPColor with integer alpha value to 32bit RGBA value.
159  * \pre alpha < 256
160  */
161 guint32 SPColor::toRGBA32( gint alpha ) const
163     g_return_val_if_fail (alpha <= 0xff, 0x0);
165     guint32 rgba = SP_RGBA32_U_COMPOSE( SP_COLOR_F_TO_U(v.c[0]),
166                                         SP_COLOR_F_TO_U(v.c[1]),
167                                         SP_COLOR_F_TO_U(v.c[2]),
168                                         alpha );
169     return rgba;
172 /**
173  * Convert SPColor with float alpha value to 32bit RGBA value.
174  * \pre color != NULL && 0 <= alpha <= 1
175  */
176 guint32 SPColor::toRGBA32( gdouble alpha ) const
178     g_return_val_if_fail(alpha >= 0.0, 0x0);
179     g_return_val_if_fail(alpha <= 1.0, 0x0);
181     return toRGBA32( static_cast<gint>(SP_COLOR_F_TO_U(alpha)) );
184 std::string SPColor::toString() const
186     CSSOStringStream css;
188     std::string result;
189     char tmp[64] = {0};
191     sp_svg_write_color(tmp, sizeof(tmp), toRGBA32(0x0ff));
192     css << tmp;
194     if ( icc ) {
195         if ( !css.str().empty() ) {
196             css << " ";
197         }
198         css << "icc-color(" << icc->colorProfile;
199         for (vector<double>::const_iterator i(icc->colors.begin()),
200                  iEnd(icc->colors.end());
201              i != iEnd; ++i) {
202             css << ", " << *i;
203         }
204         css << ')';
205     }
207     return css.str();
211 /**
212  * Fill rgb float array with values from SPColor.
213  * \pre color != NULL && rgb != NULL && rgb[0-2] is meaningful
214  */
215 void
216 sp_color_get_rgb_floatv(SPColor const *color, float *rgb)
218     g_return_if_fail (color != NULL);
219     g_return_if_fail (rgb != NULL);
221     rgb[0] = color->v.c[0];
222     rgb[1] = color->v.c[1];
223     rgb[2] = color->v.c[2];
226 /**
227  * Fill cmyk float array with values from SPColor.
228  * \pre color != NULL && cmyk != NULL && cmyk[0-3] is meaningful
229  */
230 void
231 sp_color_get_cmyk_floatv(SPColor const *color, float *cmyk)
233     g_return_if_fail (color != NULL);
234     g_return_if_fail (cmyk != NULL);
236     sp_color_rgb_to_cmyk_floatv( cmyk,
237                                  color->v.c[0],
238                                  color->v.c[1],
239                                  color->v.c[2] );
242 /* Plain mode helpers */
244 /**
245  * Fill hsv float array from r,g,b float values.
246  */
247 void
248 sp_color_rgb_to_hsv_floatv (float *hsv, float r, float g, float b)
250     float max, min, delta;
252     max = MAX (MAX (r, g), b);
253     min = MIN (MIN (r, g), b);
254     delta = max - min;
256     hsv[2] = max;
258     if (max > 0) {
259         hsv[1] = delta / max;
260     } else {
261         hsv[1] = 0.0;
262     }
264     if (hsv[1] != 0.0) {
265         if (r == max) {
266             hsv[0] = (g - b) / delta;
267         } else if (g == max) {
268             hsv[0] = 2.0 + (b - r) / delta;
269         } else {
270             hsv[0] = 4.0 + (r - g) / delta;
271         }
273         hsv[0] = hsv[0] / 6.0;
275         if (hsv[0] < 0) hsv[0] += 1.0;
276     }
277     else
278         hsv[0] = 0.0;
281 /**
282  * Fill rgb float array from h,s,v float values.
283  */
284 void
285 sp_color_hsv_to_rgb_floatv (float *rgb, float h, float s, float v)
287     gdouble f, w, q, t, d;
289     d = h * 5.99999999;
290     f = d - floor (d);
291     w = v * (1.0 - s);
292     q = v * (1.0 - (s * f));
293     t = v * (1.0 - (s * (1.0 - f)));
295     if (d < 1.0) {
296         *rgb++ = v;
297         *rgb++ = t;
298         *rgb++ = w;
299     } else if (d < 2.0) {
300         *rgb++ = q;
301         *rgb++ = v;
302         *rgb++ = w;
303     } else if (d < 3.0) {
304         *rgb++ = w;
305         *rgb++ = v;
306         *rgb++ = t;
307     } else if (d < 4.0) {
308         *rgb++ = w;
309         *rgb++ = q;
310         *rgb++ = v;
311     } else if (d < 5.0) {
312         *rgb++ = t;
313         *rgb++ = w;
314         *rgb++ = v;
315     } else {
316         *rgb++ = v;
317         *rgb++ = w;
318         *rgb++ = q;
319     }
322 /**
323  * Fill hsl float array from r,g,b float values.
324  */
325 void
326 sp_color_rgb_to_hsl_floatv (float *hsl, float r, float g, float b)
328     float max = MAX (MAX (r, g), b);
329     float min = MIN (MIN (r, g), b);
330     float delta = max - min;
332     hsl[2] = (max + min)/2.0;
334     if (delta == 0) {
335         hsl[0] = 0;
336         hsl[1] = 0;
337     } else {
338         if (hsl[2] <= 0.5)
339             hsl[1] = delta / (max + min);
340         else
341             hsl[1] = delta / (2 - max - min);
343         if (r == max) hsl[0] = (g - b) / delta;
344         else if (g == max) hsl[0] = 2.0 + (b - r) / delta;
345         else if (b == max) hsl[0] = 4.0 + (r - g) / delta;
347         hsl[0] = hsl[0] / 6.0;
349         if (hsl[0] < 0) hsl[0] += 1;
350         if (hsl[0] > 1) hsl[0] -= 1;
351     }
354 float
355 hue_2_rgb (float v1, float v2, float h)
357     if (h < 0) h += 6.0;
358     if (h > 6) h -= 6.0;
360     if (h < 1) return v1 + (v2 - v1) * h;
361     if (h < 3) return v2;
362     if (h < 4) return v1 + (v2 - v1) * (4 - h);
363     return v1;
366 /**
367  * Fill rgb float array from h,s,l float values.
368  */
369 void
370 sp_color_hsl_to_rgb_floatv (float *rgb, float h, float s, float l)
372     if (s == 0) {
373         rgb[0] = l;
374         rgb[1] = l;
375         rgb[2] = l;
376     } else {
377         float v2;
378         if (l < 0.5) {
379             v2 = l * (1 + s);
380         } else {
381             v2 = l + s - l*s;
382         }
383         float v1 = 2*l - v2;
385         rgb[0] = hue_2_rgb (v1, v2, h*6 + 2.0);
386         rgb[1] = hue_2_rgb (v1, v2, h*6);
387         rgb[2] = hue_2_rgb (v1, v2, h*6 - 2.0);
388     }
391 /**
392  * Fill cmyk float array from r,g,b float values.
393  */
394 void
395 sp_color_rgb_to_cmyk_floatv (float *cmyk, float r, float g, float b)
397     float c, m, y, k, kd;
399     c = 1.0 - r;
400     m = 1.0 - g;
401     y = 1.0 - b;
402     k = MIN (MIN (c, m), y);
404     c = c - k;
405     m = m - k;
406     y = y - k;
408     kd = 1.0 - k;
410     if (kd > 1e-9) {
411         c = c / kd;
412         m = m / kd;
413         y = y / kd;
414     }
416     cmyk[0] = c;
417     cmyk[1] = m;
418     cmyk[2] = y;
419     cmyk[3] = k;
422 /**
423  * Fill rgb float array from c,m,y,k float values.
424  */
425 void
426 sp_color_cmyk_to_rgb_floatv (float *rgb, float c, float m, float y, float k)
428     float kd;
430     kd = 1.0 - k;
432     c = c * kd;
433     m = m * kd;
434     y = y * kd;
436     c = c + k;
437     m = m + k;
438     y = y + k;
440     rgb[0] = 1.0 - c;
441     rgb[1] = 1.0 - m;
442     rgb[2] = 1.0 - y;
445 /*
446   Local Variables:
447   mode:c++
448   c-file-style:"stroustrup"
449   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
450   indent-tabs-mode:nil
451   fill-column:99
452   End:
453 */
454 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :