8dc4c865762af724607a92ef5149ffabed55e004
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"
21 static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second );
23 #define PROFILE_EPSILON 0.00000001
25 SPColor::SPColor() :
26 icc(0)
27 {
28 v.c[0] = 0;
29 v.c[1] = 0;
30 v.c[2] = 0;
31 }
33 SPColor::SPColor( SPColor const& other ) :
34 icc(0)
35 {
36 *this = other;
37 }
39 SPColor::SPColor( float r, float g, float b ) :
40 icc(0)
41 {
42 set( r, g, b );
43 }
45 SPColor::SPColor( guint32 value ) :
46 icc(0)
47 {
48 set( value );
49 }
51 SPColor::~SPColor()
52 {
53 delete icc;
54 icc = 0;
55 }
58 SPColor& SPColor::operator= (SPColor const& other)
59 {
60 SVGICCColor* tmp = other.icc ? new SVGICCColor(*other.icc) : 0;
61 v.c[0] = other.v.c[0];
62 v.c[1] = other.v.c[1];
63 v.c[2] = other.v.c[2];
64 if ( icc ) {
65 delete icc;
66 }
67 icc = tmp;
69 return *this;
70 }
73 /**
74 * Returns true if colors match.
75 */
76 bool SPColor::operator == (SPColor const& other) const
77 {
78 bool match = (v.c[0] != other.v.c[0])
79 && (v.c[1] != other.v.c[1])
80 && (v.c[2] != other.v.c[2]);
82 match &= profileMatches( icc, other.icc );
84 return match;
85 }
87 /**
88 * Returns true if no RGB value differs epsilon or more in both colors,
89 * false otherwise.
90 */
91 bool SPColor::isClose( SPColor const& other, float epsilon ) const
92 {
93 bool match = false;
95 match = (fabs((v.c[0]) - (other.v.c[0])) < epsilon)
96 && (fabs((v.c[1]) - (other.v.c[1])) < epsilon)
97 && (fabs((v.c[2]) - (other.v.c[2])) < epsilon);
99 // TODO uncomment once we start using that profile. Will be RSN
100 //match &= profileMatches( icc, other.icc );
102 return match;
103 }
105 static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second ) {
106 bool match = false;
107 if ( !first && !second ) {
108 match = true;
109 } else {
110 match = first && second
111 && (first->colorProfile == second->colorProfile)
112 && (first->colors.size() == second->colors.size());
113 if ( match ) {
114 for ( guint i = 0; i < first->colors.size(); i++ ) {
115 match &= (fabs(first->colors[i] - second->colors[i]) < PROFILE_EPSILON);
116 }
117 }
118 }
119 return match;
120 }
122 /**
123 * Sets RGB values and colorspace in color.
124 * \pre 0 <={r,g,b}<=1
125 */
126 void SPColor::set( float r, float g, float b )
127 {
128 g_return_if_fail(r >= 0.0);
129 g_return_if_fail(r <= 1.0);
130 g_return_if_fail(g >= 0.0);
131 g_return_if_fail(g <= 1.0);
132 g_return_if_fail(b >= 0.0);
133 g_return_if_fail(b <= 1.0);
135 // TODO clear icc if set?
136 v.c[0] = r;
137 v.c[1] = g;
138 v.c[2] = b;
139 }
141 /**
142 * Converts 32bit value to RGB floats and sets color.
143 */
144 void SPColor::set( guint32 value )
145 {
146 // TODO clear icc if set?
147 v.c[0] = (value >> 24) / 255.0F;
148 v.c[1] = ((value >> 16) & 0xff) / 255.0F;
149 v.c[2] = ((value >> 8) & 0xff) / 255.0F;
150 }
152 /**
153 * Convert SPColor with integer alpha value to 32bit RGBA value.
154 * \pre alpha < 256
155 */
156 guint32 SPColor::toRGBA32( gint alpha ) const
157 {
158 g_return_val_if_fail (alpha <= 0xff, 0x0);
160 guint32 rgba = SP_RGBA32_U_COMPOSE( SP_COLOR_F_TO_U(v.c[0]),
161 SP_COLOR_F_TO_U(v.c[1]),
162 SP_COLOR_F_TO_U(v.c[2]),
163 alpha );
164 return rgba;
165 }
167 /**
168 * Convert SPColor with float alpha value to 32bit RGBA value.
169 * \pre color != NULL && 0 <= alpha <= 1
170 */
171 guint32 SPColor::toRGBA32( gdouble alpha ) const
172 {
173 g_return_val_if_fail(alpha >= 0.0, 0x0);
174 g_return_val_if_fail(alpha <= 1.0, 0x0);
176 return toRGBA32( static_cast<gint>(SP_COLOR_F_TO_U(alpha)) );
177 }
179 /**
180 * Fill rgb float array with values from SPColor.
181 * \pre color != NULL && rgb != NULL && rgb[0-2] is meaningful
182 */
183 void
184 sp_color_get_rgb_floatv(SPColor const *color, float *rgb)
185 {
186 g_return_if_fail (color != NULL);
187 g_return_if_fail (rgb != NULL);
189 rgb[0] = color->v.c[0];
190 rgb[1] = color->v.c[1];
191 rgb[2] = color->v.c[2];
192 }
194 /**
195 * Fill cmyk float array with values from SPColor.
196 * \pre color != NULL && cmyk != NULL && cmyk[0-3] is meaningful
197 */
198 void
199 sp_color_get_cmyk_floatv(SPColor const *color, float *cmyk)
200 {
201 g_return_if_fail (color != NULL);
202 g_return_if_fail (cmyk != NULL);
204 sp_color_rgb_to_cmyk_floatv( cmyk,
205 color->v.c[0],
206 color->v.c[1],
207 color->v.c[2] );
208 }
210 /* Plain mode helpers */
212 /**
213 * Fill hsv float array from r,g,b float values.
214 */
215 void
216 sp_color_rgb_to_hsv_floatv (float *hsv, float r, float g, float b)
217 {
218 float max, min, delta;
220 max = MAX (MAX (r, g), b);
221 min = MIN (MIN (r, g), b);
222 delta = max - min;
224 hsv[2] = max;
226 if (max > 0) {
227 hsv[1] = delta / max;
228 } else {
229 hsv[1] = 0.0;
230 }
232 if (hsv[1] != 0.0) {
233 if (r == max) {
234 hsv[0] = (g - b) / delta;
235 } else if (g == max) {
236 hsv[0] = 2.0 + (b - r) / delta;
237 } else {
238 hsv[0] = 4.0 + (r - g) / delta;
239 }
241 hsv[0] = hsv[0] / 6.0;
243 if (hsv[0] < 0) hsv[0] += 1.0;
244 }
245 else
246 hsv[0] = 0.0;
247 }
249 /**
250 * Fill rgb float array from h,s,v float values.
251 */
252 void
253 sp_color_hsv_to_rgb_floatv (float *rgb, float h, float s, float v)
254 {
255 gdouble f, w, q, t, d;
257 d = h * 5.99999999;
258 f = d - floor (d);
259 w = v * (1.0 - s);
260 q = v * (1.0 - (s * f));
261 t = v * (1.0 - (s * (1.0 - f)));
263 if (d < 1.0) {
264 *rgb++ = v;
265 *rgb++ = t;
266 *rgb++ = w;
267 } else if (d < 2.0) {
268 *rgb++ = q;
269 *rgb++ = v;
270 *rgb++ = w;
271 } else if (d < 3.0) {
272 *rgb++ = w;
273 *rgb++ = v;
274 *rgb++ = t;
275 } else if (d < 4.0) {
276 *rgb++ = w;
277 *rgb++ = q;
278 *rgb++ = v;
279 } else if (d < 5.0) {
280 *rgb++ = t;
281 *rgb++ = w;
282 *rgb++ = v;
283 } else {
284 *rgb++ = v;
285 *rgb++ = w;
286 *rgb++ = q;
287 }
288 }
290 /**
291 * Fill hsl float array from r,g,b float values.
292 */
293 void
294 sp_color_rgb_to_hsl_floatv (float *hsl, float r, float g, float b)
295 {
296 float max = MAX (MAX (r, g), b);
297 float min = MIN (MIN (r, g), b);
298 float delta = max - min;
300 hsl[2] = (max + min)/2.0;
302 if (delta == 0) {
303 hsl[0] = 0;
304 hsl[1] = 0;
305 } else {
306 if (hsl[2] <= 0.5)
307 hsl[1] = delta / (max + min);
308 else
309 hsl[1] = delta / (2 - max - min);
311 if (r == max) hsl[0] = (g - b) / delta;
312 else if (g == max) hsl[0] = 2.0 + (b - r) / delta;
313 else if (b == max) hsl[0] = 4.0 + (r - g) / delta;
315 hsl[0] = hsl[0] / 6.0;
317 if (hsl[0] < 0) hsl[0] += 1;
318 if (hsl[0] > 1) hsl[0] -= 1;
319 }
320 }
322 float
323 hue_2_rgb (float v1, float v2, float h)
324 {
325 if (h < 0) h += 6.0;
326 if (h > 6) h -= 6.0;
328 if (h < 1) return v1 + (v2 - v1) * h;
329 if (h < 3) return v2;
330 if (h < 4) return v1 + (v2 - v1) * (4 - h);
331 return v1;
332 }
334 /**
335 * Fill rgb float array from h,s,l float values.
336 */
337 void
338 sp_color_hsl_to_rgb_floatv (float *rgb, float h, float s, float l)
339 {
340 if (s == 0) {
341 rgb[0] = l;
342 rgb[1] = l;
343 rgb[2] = l;
344 } else {
345 float v2;
346 if (l < 0.5) {
347 v2 = l * (1 + s);
348 } else {
349 v2 = l + s - l*s;
350 }
351 float v1 = 2*l - v2;
353 rgb[0] = hue_2_rgb (v1, v2, h*6 + 2.0);
354 rgb[1] = hue_2_rgb (v1, v2, h*6);
355 rgb[2] = hue_2_rgb (v1, v2, h*6 - 2.0);
356 }
357 }
359 /**
360 * Fill cmyk float array from r,g,b float values.
361 */
362 void
363 sp_color_rgb_to_cmyk_floatv (float *cmyk, float r, float g, float b)
364 {
365 float c, m, y, k, kd;
367 c = 1.0 - r;
368 m = 1.0 - g;
369 y = 1.0 - b;
370 k = MIN (MIN (c, m), y);
372 c = c - k;
373 m = m - k;
374 y = y - k;
376 kd = 1.0 - k;
378 if (kd > 1e-9) {
379 c = c / kd;
380 m = m / kd;
381 y = y / kd;
382 }
384 cmyk[0] = c;
385 cmyk[1] = m;
386 cmyk[2] = y;
387 cmyk[3] = k;
388 }
390 /**
391 * Fill rgb float array from c,m,y,k float values.
392 */
393 void
394 sp_color_cmyk_to_rgb_floatv (float *rgb, float c, float m, float y, float k)
395 {
396 float kd;
398 kd = 1.0 - k;
400 c = c * kd;
401 m = m * kd;
402 y = y * kd;
404 c = c + k;
405 m = m + k;
406 y = y + k;
408 rgb[0] = 1.0 - c;
409 rgb[1] = 1.0 - m;
410 rgb[2] = 1.0 - y;
411 }
413 /*
414 Local Variables:
415 mode:c++
416 c-file-style:"stroustrup"
417 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
418 indent-tabs-mode:nil
419 fill-column:99
420 End:
421 */
422 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :