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 #define GIMP_DISABLE_DEPRECATION_WARNINGS /* for GIMP_RGB_INTENSITY() */
25 #include "libgimpmath/gimpmath.h"
26
27 #include "gimpcolortypes.h"
28
29 #undef GIMP_DISABLE_DEPRECATED /* for GIMP_RGB_INTENSITY() */
30 #include "gimprgb.h"
31
32
33 /**
34 * SECTION: gimprgb
35 * @title: GimpRGB
36 * @short_description: Definitions and Functions relating to RGB colors.
37 *
38 * Definitions and Functions relating to RGB colors.
39 **/
40
41
42 /*
43 * GIMP_TYPE_RGB
44 */
45
46 static GimpRGB * gimp_rgb_copy (const GimpRGB *rgb);
47
48
49 GType
gimp_rgb_get_type(void)50 gimp_rgb_get_type (void)
51 {
52 static GType rgb_type = 0;
53
54 if (!rgb_type)
55 rgb_type = g_boxed_type_register_static ("GimpRGB",
56 (GBoxedCopyFunc) gimp_rgb_copy,
57 (GBoxedFreeFunc) g_free);
58
59 return rgb_type;
60 }
61
62 void
gimp_value_get_rgb(const GValue * value,GimpRGB * rgb)63 gimp_value_get_rgb (const GValue *value,
64 GimpRGB *rgb)
65 {
66 g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value));
67 g_return_if_fail (rgb != NULL);
68
69 if (value->data[0].v_pointer)
70 *rgb = *((GimpRGB *) value->data[0].v_pointer);
71 else
72 gimp_rgba_set (rgb, 0.0, 0.0, 0.0, 1.0);
73 }
74
75 void
gimp_value_set_rgb(GValue * value,const GimpRGB * rgb)76 gimp_value_set_rgb (GValue *value,
77 const GimpRGB *rgb)
78 {
79 g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value));
80 g_return_if_fail (rgb != NULL);
81
82 g_value_set_boxed (value, rgb);
83 }
84
85 static GimpRGB *
gimp_rgb_copy(const GimpRGB * rgb)86 gimp_rgb_copy (const GimpRGB *rgb)
87 {
88 return g_memdup (rgb, sizeof (GimpRGB));
89 }
90
91
92 /* RGB functions */
93
94 /**
95 * gimp_rgb_set:
96 * @rgb: a #GimpRGB struct
97 * @red: the red component
98 * @green: the green component
99 * @blue: the blue component
100 *
101 * Sets the red, green and blue components of @rgb and leaves the
102 * alpha component unchanged. The color values should be between 0.0
103 * and 1.0 but there is no check to enforce this and the values are
104 * set exactly as they are passed in.
105 **/
106 void
gimp_rgb_set(GimpRGB * rgb,gdouble r,gdouble g,gdouble b)107 gimp_rgb_set (GimpRGB *rgb,
108 gdouble r,
109 gdouble g,
110 gdouble b)
111 {
112 g_return_if_fail (rgb != NULL);
113
114 rgb->r = r;
115 rgb->g = g;
116 rgb->b = b;
117 }
118
119 /**
120 * gimp_rgb_set_alpha:
121 * @rgb: a #GimpRGB struct
122 * @alpha: the alpha component
123 *
124 * Sets the alpha component of @rgb and leaves the RGB components unchanged.
125 **/
126 void
gimp_rgb_set_alpha(GimpRGB * rgb,gdouble a)127 gimp_rgb_set_alpha (GimpRGB *rgb,
128 gdouble a)
129 {
130 g_return_if_fail (rgb != NULL);
131
132 rgb->a = a;
133 }
134
135 /**
136 * gimp_rgb_set_pixel:
137 * @rgb: a #GimpRGB struct
138 * @format: a Babl format
139 * @pixel: pointer to the source pixel
140 *
141 * Sets the red, green and blue components of @rgb from the color
142 * stored in @pixel. The pixel format of @pixel is determined by
143 * @format.
144 *
145 * Since: 2.10
146 **/
147 void
gimp_rgb_set_pixel(GimpRGB * rgb,const Babl * format,gconstpointer pixel)148 gimp_rgb_set_pixel (GimpRGB *rgb,
149 const Babl *format,
150 gconstpointer pixel)
151 {
152 g_return_if_fail (rgb != NULL);
153 g_return_if_fail (format != NULL);
154 g_return_if_fail (pixel != NULL);
155
156 babl_process (babl_fish (format,
157 babl_format ("R'G'B' double")),
158 pixel, rgb, 1);
159 }
160
161 /**
162 * gimp_rgb_get_pixel:
163 * @rgb: a #GimpRGB struct
164 * @format: a Babl format
165 * @pixel: pointer to the destination pixel
166 *
167 * Writes the red, green, blue and alpha components of @rgb to the
168 * color stored in @pixel. The pixel format of @pixel is determined by
169 * @format.
170 *
171 * Since: 2.10
172 **/
173 void
gimp_rgb_get_pixel(const GimpRGB * rgb,const Babl * format,gpointer pixel)174 gimp_rgb_get_pixel (const GimpRGB *rgb,
175 const Babl *format,
176 gpointer pixel)
177 {
178 g_return_if_fail (rgb != NULL);
179 g_return_if_fail (format != NULL);
180 g_return_if_fail (pixel != NULL);
181
182 babl_process (babl_fish (babl_format ("R'G'B' double"),
183 format),
184 rgb, pixel, 1);
185 }
186
187 /**
188 * gimp_rgb_set_uchar:
189 * @rgb: a #GimpRGB struct
190 * @red: the red component
191 * @green: the green component
192 * @blue: the blue component
193 *
194 * Sets the red, green and blue components of @rgb from 8bit values
195 * (0 to 255) and leaves the alpha component unchanged.
196 **/
197 void
gimp_rgb_set_uchar(GimpRGB * rgb,guchar r,guchar g,guchar b)198 gimp_rgb_set_uchar (GimpRGB *rgb,
199 guchar r,
200 guchar g,
201 guchar b)
202 {
203 g_return_if_fail (rgb != NULL);
204
205 rgb->r = (gdouble) r / 255.0;
206 rgb->g = (gdouble) g / 255.0;
207 rgb->b = (gdouble) b / 255.0;
208 }
209
210 void
gimp_rgb_get_uchar(const GimpRGB * rgb,guchar * r,guchar * g,guchar * b)211 gimp_rgb_get_uchar (const GimpRGB *rgb,
212 guchar *r,
213 guchar *g,
214 guchar *b)
215 {
216 g_return_if_fail (rgb != NULL);
217
218 if (r) *r = ROUND (CLAMP (rgb->r, 0.0, 1.0) * 255.0);
219 if (g) *g = ROUND (CLAMP (rgb->g, 0.0, 1.0) * 255.0);
220 if (b) *b = ROUND (CLAMP (rgb->b, 0.0, 1.0) * 255.0);
221 }
222
223 void
gimp_rgb_add(GimpRGB * rgb1,const GimpRGB * rgb2)224 gimp_rgb_add (GimpRGB *rgb1,
225 const GimpRGB *rgb2)
226 {
227 g_return_if_fail (rgb1 != NULL);
228 g_return_if_fail (rgb2 != NULL);
229
230 rgb1->r += rgb2->r;
231 rgb1->g += rgb2->g;
232 rgb1->b += rgb2->b;
233 }
234
235 void
gimp_rgb_subtract(GimpRGB * rgb1,const GimpRGB * rgb2)236 gimp_rgb_subtract (GimpRGB *rgb1,
237 const GimpRGB *rgb2)
238 {
239 g_return_if_fail (rgb1 != NULL);
240 g_return_if_fail (rgb2 != NULL);
241
242 rgb1->r -= rgb2->r;
243 rgb1->g -= rgb2->g;
244 rgb1->b -= rgb2->b;
245 }
246
247 void
gimp_rgb_multiply(GimpRGB * rgb,gdouble factor)248 gimp_rgb_multiply (GimpRGB *rgb,
249 gdouble factor)
250 {
251 g_return_if_fail (rgb != NULL);
252
253 rgb->r *= factor;
254 rgb->g *= factor;
255 rgb->b *= factor;
256 }
257
258 gdouble
gimp_rgb_distance(const GimpRGB * rgb1,const GimpRGB * rgb2)259 gimp_rgb_distance (const GimpRGB *rgb1,
260 const GimpRGB *rgb2)
261 {
262 g_return_val_if_fail (rgb1 != NULL, 0.0);
263 g_return_val_if_fail (rgb2 != NULL, 0.0);
264
265 return (fabs (rgb1->r - rgb2->r) +
266 fabs (rgb1->g - rgb2->g) +
267 fabs (rgb1->b - rgb2->b));
268 }
269
270 gdouble
gimp_rgb_max(const GimpRGB * rgb)271 gimp_rgb_max (const GimpRGB *rgb)
272 {
273 g_return_val_if_fail (rgb != NULL, 0.0);
274
275 if (rgb->r > rgb->g)
276 return (rgb->r > rgb->b) ? rgb->r : rgb->b;
277 else
278 return (rgb->g > rgb->b) ? rgb->g : rgb->b;
279 }
280
281 gdouble
gimp_rgb_min(const GimpRGB * rgb)282 gimp_rgb_min (const GimpRGB *rgb)
283 {
284 g_return_val_if_fail (rgb != NULL, 0.0);
285
286 if (rgb->r < rgb->g)
287 return (rgb->r < rgb->b) ? rgb->r : rgb->b;
288 else
289 return (rgb->g < rgb->b) ? rgb->g : rgb->b;
290 }
291
292 void
gimp_rgb_clamp(GimpRGB * rgb)293 gimp_rgb_clamp (GimpRGB *rgb)
294 {
295 g_return_if_fail (rgb != NULL);
296
297 rgb->r = CLAMP (rgb->r, 0.0, 1.0);
298 rgb->g = CLAMP (rgb->g, 0.0, 1.0);
299 rgb->b = CLAMP (rgb->b, 0.0, 1.0);
300 rgb->a = CLAMP (rgb->a, 0.0, 1.0);
301 }
302
303 void
gimp_rgb_gamma(GimpRGB * rgb,gdouble gamma)304 gimp_rgb_gamma (GimpRGB *rgb,
305 gdouble gamma)
306 {
307 gdouble ig;
308
309 g_return_if_fail (rgb != NULL);
310
311 if (gamma != 0.0)
312 ig = 1.0 / gamma;
313 else
314 ig = 0.0;
315
316 rgb->r = pow (rgb->r, ig);
317 rgb->g = pow (rgb->g, ig);
318 rgb->b = pow (rgb->b, ig);
319 }
320
321 /**
322 * gimp_rgb_luminance:
323 * @rgb: a #GimpRGB struct
324 *
325 * Return value: the luminous intensity of the range from 0.0 to 1.0.
326 *
327 * Since: 2.4
328 **/
329 gdouble
gimp_rgb_luminance(const GimpRGB * rgb)330 gimp_rgb_luminance (const GimpRGB *rgb)
331 {
332 gdouble luminance;
333
334 g_return_val_if_fail (rgb != NULL, 0.0);
335
336 luminance = GIMP_RGB_LUMINANCE (rgb->r, rgb->g, rgb->b);
337
338 return CLAMP (luminance, 0.0, 1.0);
339 }
340
341 /**
342 * gimp_rgb_luminance_uchar:
343 * @rgb: a #GimpRGB struct
344 *
345 * Return value: the luminous intensity in the range from 0 to 255.
346 *
347 * Since: 2.4
348 **/
349 guchar
gimp_rgb_luminance_uchar(const GimpRGB * rgb)350 gimp_rgb_luminance_uchar (const GimpRGB *rgb)
351 {
352 g_return_val_if_fail (rgb != NULL, 0);
353
354 return ROUND (gimp_rgb_luminance (rgb) * 255.0);
355 }
356
357 /**
358 * gimp_rgb_intensity:
359 * @rgb: a #GimpRGB struct
360 *
361 * This function is deprecated! Use gimp_rgb_luminance() instead.
362 *
363 * Return value: the intensity in the range from 0.0 to 1.0.
364 **/
365 gdouble
gimp_rgb_intensity(const GimpRGB * rgb)366 gimp_rgb_intensity (const GimpRGB *rgb)
367 {
368 gdouble intensity;
369
370 g_return_val_if_fail (rgb != NULL, 0.0);
371
372 intensity = GIMP_RGB_INTENSITY (rgb->r, rgb->g, rgb->b);
373
374 return CLAMP (intensity, 0.0, 1.0);
375 }
376
377 /**
378 * gimp_rgb_intensity_uchar:
379 * @rgb: a #GimpRGB struct
380 *
381 * This function is deprecated! Use gimp_rgb_luminance_uchar() instead.
382 *
383 * Return value: the intensity in the range from 0 to 255.
384 **/
385 guchar
gimp_rgb_intensity_uchar(const GimpRGB * rgb)386 gimp_rgb_intensity_uchar (const GimpRGB *rgb)
387 {
388 g_return_val_if_fail (rgb != NULL, 0);
389
390 return ROUND (gimp_rgb_intensity (rgb) * 255.0);
391 }
392
393 void
gimp_rgb_composite(GimpRGB * color1,const GimpRGB * color2,GimpRGBCompositeMode mode)394 gimp_rgb_composite (GimpRGB *color1,
395 const GimpRGB *color2,
396 GimpRGBCompositeMode mode)
397 {
398 g_return_if_fail (color1 != NULL);
399 g_return_if_fail (color2 != NULL);
400
401 switch (mode)
402 {
403 case GIMP_RGB_COMPOSITE_NONE:
404 break;
405
406 case GIMP_RGB_COMPOSITE_NORMAL:
407 /* put color2 on top of color1 */
408 if (color2->a == 1.0)
409 {
410 *color1 = *color2;
411 }
412 else
413 {
414 gdouble factor = color1->a * (1.0 - color2->a);
415
416 color1->r = color1->r * factor + color2->r * color2->a;
417 color1->g = color1->g * factor + color2->g * color2->a;
418 color1->b = color1->b * factor + color2->b * color2->a;
419 color1->a = factor + color2->a;
420 }
421 break;
422
423 case GIMP_RGB_COMPOSITE_BEHIND:
424 /* put color2 below color1 */
425 if (color1->a < 1.0)
426 {
427 gdouble factor = color2->a * (1.0 - color1->a);
428
429 color1->r = color2->r * factor + color1->r * color1->a;
430 color1->g = color2->g * factor + color1->g * color1->a;
431 color1->b = color2->b * factor + color1->b * color1->a;
432 color1->a = factor + color1->a;
433 }
434 break;
435 }
436 }
437
438 /* RGBA functions */
439
440 /**
441 * gimp_rgba_set_pixel:
442 * @rgba: a #GimpRGB struct
443 * @format: a Babl format
444 * @pixel: pointer to the source pixel
445 *
446 * Sets the red, green, blue and alpha components of @rgba from the
447 * color stored in @pixel. The pixel format of @pixel is determined
448 * by @format.
449 *
450 * Since: 2.10
451 **/
452 void
gimp_rgba_set_pixel(GimpRGB * rgba,const Babl * format,gconstpointer pixel)453 gimp_rgba_set_pixel (GimpRGB *rgba,
454 const Babl *format,
455 gconstpointer pixel)
456 {
457 g_return_if_fail (rgba != NULL);
458 g_return_if_fail (format != NULL);
459 g_return_if_fail (pixel != NULL);
460
461 babl_process (babl_fish (format,
462 babl_format ("R'G'B'A double")),
463 pixel, rgba, 1);
464 }
465
466 /**
467 * gimp_rgba_get_pixel:
468 * @rgba: a #GimpRGB struct
469 * @format: a Babl format
470 * @pixel: pointer to the destination pixel
471 *
472 * Writes the red, green, blue and alpha components of @rgba to the
473 * color stored in @pixel. The pixel format of @pixel is determined by
474 * @format.
475 *
476 * Since: 2.10
477 **/
478 void
gimp_rgba_get_pixel(const GimpRGB * rgba,const Babl * format,gpointer pixel)479 gimp_rgba_get_pixel (const GimpRGB *rgba,
480 const Babl *format,
481 gpointer pixel)
482 {
483 g_return_if_fail (rgba != NULL);
484 g_return_if_fail (format != NULL);
485 g_return_if_fail (pixel != NULL);
486
487 babl_process (babl_fish (babl_format ("R'G'B'A double"),
488 format),
489 rgba, pixel, 1);
490 }
491
492 /**
493 * gimp_rgba_set:
494 * @rgba: a #GimpRGB struct
495 * @red: the red component
496 * @green: the green component
497 * @blue: the blue component
498 * @alpha: the alpha component
499 *
500 * Sets the red, green, blue and alpha components of @rgb. The values
501 * should be between 0.0 and 1.0 but there is no check to enforce this
502 * and the values are set exactly as they are passed in.
503 **/
504 void
gimp_rgba_set(GimpRGB * rgba,gdouble r,gdouble g,gdouble b,gdouble a)505 gimp_rgba_set (GimpRGB *rgba,
506 gdouble r,
507 gdouble g,
508 gdouble b,
509 gdouble a)
510 {
511 g_return_if_fail (rgba != NULL);
512
513 rgba->r = r;
514 rgba->g = g;
515 rgba->b = b;
516 rgba->a = a;
517 }
518
519 /**
520 * gimp_rgba_set_uchar:
521 * @rgba: a #GimpRGB struct
522 * @red: the red component
523 * @green: the green component
524 * @blue: the blue component
525 * @alpha: the alpha component
526 *
527 * Sets the red, green, blue and alpha components of @rgb from 8bit
528 * values (0 to 255).
529 **/
530 void
gimp_rgba_set_uchar(GimpRGB * rgba,guchar r,guchar g,guchar b,guchar a)531 gimp_rgba_set_uchar (GimpRGB *rgba,
532 guchar r,
533 guchar g,
534 guchar b,
535 guchar a)
536 {
537 g_return_if_fail (rgba != NULL);
538
539 rgba->r = (gdouble) r / 255.0;
540 rgba->g = (gdouble) g / 255.0;
541 rgba->b = (gdouble) b / 255.0;
542 rgba->a = (gdouble) a / 255.0;
543 }
544
545 void
gimp_rgba_get_uchar(const GimpRGB * rgba,guchar * r,guchar * g,guchar * b,guchar * a)546 gimp_rgba_get_uchar (const GimpRGB *rgba,
547 guchar *r,
548 guchar *g,
549 guchar *b,
550 guchar *a)
551 {
552 g_return_if_fail (rgba != NULL);
553
554 if (r) *r = ROUND (CLAMP (rgba->r, 0.0, 1.0) * 255.0);
555 if (g) *g = ROUND (CLAMP (rgba->g, 0.0, 1.0) * 255.0);
556 if (b) *b = ROUND (CLAMP (rgba->b, 0.0, 1.0) * 255.0);
557 if (a) *a = ROUND (CLAMP (rgba->a, 0.0, 1.0) * 255.0);
558 }
559
560 void
gimp_rgba_add(GimpRGB * rgba1,const GimpRGB * rgba2)561 gimp_rgba_add (GimpRGB *rgba1,
562 const GimpRGB *rgba2)
563 {
564 g_return_if_fail (rgba1 != NULL);
565 g_return_if_fail (rgba2 != NULL);
566
567 rgba1->r += rgba2->r;
568 rgba1->g += rgba2->g;
569 rgba1->b += rgba2->b;
570 rgba1->a += rgba2->a;
571 }
572
573 void
gimp_rgba_subtract(GimpRGB * rgba1,const GimpRGB * rgba2)574 gimp_rgba_subtract (GimpRGB *rgba1,
575 const GimpRGB *rgba2)
576 {
577 g_return_if_fail (rgba1 != NULL);
578 g_return_if_fail (rgba2 != NULL);
579
580 rgba1->r -= rgba2->r;
581 rgba1->g -= rgba2->g;
582 rgba1->b -= rgba2->b;
583 rgba1->a -= rgba2->a;
584 }
585
586 void
gimp_rgba_multiply(GimpRGB * rgba,gdouble factor)587 gimp_rgba_multiply (GimpRGB *rgba,
588 gdouble factor)
589 {
590 g_return_if_fail (rgba != NULL);
591
592 rgba->r *= factor;
593 rgba->g *= factor;
594 rgba->b *= factor;
595 rgba->a *= factor;
596 }
597
598 gdouble
gimp_rgba_distance(const GimpRGB * rgba1,const GimpRGB * rgba2)599 gimp_rgba_distance (const GimpRGB *rgba1,
600 const GimpRGB *rgba2)
601 {
602 g_return_val_if_fail (rgba1 != NULL, 0.0);
603 g_return_val_if_fail (rgba2 != NULL, 0.0);
604
605 return (fabs (rgba1->r - rgba2->r) +
606 fabs (rgba1->g - rgba2->g) +
607 fabs (rgba1->b - rgba2->b) +
608 fabs (rgba1->a - rgba2->a));
609 }
610
611
612 /*
613 * GIMP_TYPE_PARAM_RGB
614 */
615
616 #define GIMP_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_RGB, GimpParamSpecRGB))
617
618 typedef struct _GimpParamSpecRGB GimpParamSpecRGB;
619
620 struct _GimpParamSpecRGB
621 {
622 GParamSpecBoxed parent_instance;
623
624 gboolean has_alpha;
625 gboolean validate; /* change this to enable [0.0...1.0] */
626 GimpRGB default_value;
627 };
628
629 static void gimp_param_rgb_class_init (GParamSpecClass *class);
630 static void gimp_param_rgb_init (GParamSpec *pspec);
631 static void gimp_param_rgb_set_default (GParamSpec *pspec,
632 GValue *value);
633 static gboolean gimp_param_rgb_validate (GParamSpec *pspec,
634 GValue *value);
635 static gint gimp_param_rgb_values_cmp (GParamSpec *pspec,
636 const GValue *value1,
637 const GValue *value2);
638
639 /**
640 * gimp_param_rgb_get_type:
641 *
642 * Reveals the object type
643 *
644 * Returns: the #GType for a GimpParamRGB object
645 *
646 * Since: 2.4
647 **/
648 GType
gimp_param_rgb_get_type(void)649 gimp_param_rgb_get_type (void)
650 {
651 static GType spec_type = 0;
652
653 if (! spec_type)
654 {
655 const GTypeInfo type_info =
656 {
657 sizeof (GParamSpecClass),
658 NULL, NULL,
659 (GClassInitFunc) gimp_param_rgb_class_init,
660 NULL, NULL,
661 sizeof (GimpParamSpecRGB),
662 0,
663 (GInstanceInitFunc) gimp_param_rgb_init
664 };
665
666 spec_type = g_type_register_static (G_TYPE_PARAM_BOXED,
667 "GimpParamRGB",
668 &type_info, 0);
669 }
670
671 return spec_type;
672 }
673
674 static void
gimp_param_rgb_class_init(GParamSpecClass * class)675 gimp_param_rgb_class_init (GParamSpecClass *class)
676 {
677 class->value_type = GIMP_TYPE_RGB;
678 class->value_set_default = gimp_param_rgb_set_default;
679 class->value_validate = gimp_param_rgb_validate;
680 class->values_cmp = gimp_param_rgb_values_cmp;
681 }
682
683 static void
gimp_param_rgb_init(GParamSpec * pspec)684 gimp_param_rgb_init (GParamSpec *pspec)
685 {
686 GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec);
687
688 gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
689 }
690
691 static void
gimp_param_rgb_set_default(GParamSpec * pspec,GValue * value)692 gimp_param_rgb_set_default (GParamSpec *pspec,
693 GValue *value)
694 {
695 GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec);
696
697 g_value_set_static_boxed (value, &cspec->default_value);
698 }
699
700 static gboolean
gimp_param_rgb_validate(GParamSpec * pspec,GValue * value)701 gimp_param_rgb_validate (GParamSpec *pspec,
702 GValue *value)
703 {
704 GimpParamSpecRGB *rgb_spec = GIMP_PARAM_SPEC_RGB (pspec);
705 GimpRGB *rgb = value->data[0].v_pointer;
706
707 if (rgb_spec->validate && rgb)
708 {
709 GimpRGB oval = *rgb;
710
711 gimp_rgb_clamp (rgb);
712
713 return (oval.r != rgb->r ||
714 oval.g != rgb->g ||
715 oval.b != rgb->b ||
716 (rgb_spec->has_alpha && oval.a != rgb->a));
717 }
718
719 return FALSE;
720 }
721
722 static gint
gimp_param_rgb_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)723 gimp_param_rgb_values_cmp (GParamSpec *pspec,
724 const GValue *value1,
725 const GValue *value2)
726 {
727 GimpRGB *rgb1 = value1->data[0].v_pointer;
728 GimpRGB *rgb2 = value2->data[0].v_pointer;
729
730 /* try to return at least *something*, it's useless anyway... */
731
732 if (! rgb1)
733 {
734 return rgb2 != NULL ? -1 : 0;
735 }
736 else if (! rgb2)
737 {
738 return rgb1 != NULL;
739 }
740 else
741 {
742 guint32 int1 = 0;
743 guint32 int2 = 0;
744
745 if (GIMP_PARAM_SPEC_RGB (pspec)->has_alpha)
746 {
747 gimp_rgba_get_uchar (rgb1,
748 ((guchar *) &int1) + 0,
749 ((guchar *) &int1) + 1,
750 ((guchar *) &int1) + 2,
751 ((guchar *) &int1) + 3);
752 gimp_rgba_get_uchar (rgb2,
753 ((guchar *) &int2) + 0,
754 ((guchar *) &int2) + 1,
755 ((guchar *) &int2) + 2,
756 ((guchar *) &int2) + 3);
757 }
758 else
759 {
760 gimp_rgb_get_uchar (rgb1,
761 ((guchar *) &int1) + 0,
762 ((guchar *) &int1) + 1,
763 ((guchar *) &int1) + 2);
764 gimp_rgb_get_uchar (rgb2,
765 ((guchar *) &int2) + 0,
766 ((guchar *) &int2) + 1,
767 ((guchar *) &int2) + 2);
768 }
769
770 return int1 - int2;
771 }
772 }
773
774 /**
775 * gimp_param_spec_rgb:
776 * @name: Canonical name of the param
777 * @nick: Nickname of the param
778 * @blurb: Brief description of param.
779 * @has_alpha: %TRUE if the alpha channel has relevance.
780 * @default_value: Value to use if none is assigned.
781 * @flags: a combination of #GParamFlags
782 *
783 * Creates a param spec to hold an #GimpRGB value.
784 * See g_param_spec_internal() for more information.
785 *
786 * Returns: a newly allocated #GParamSpec instance
787 *
788 * Since: 2.4
789 **/
790 GParamSpec *
gimp_param_spec_rgb(const gchar * name,const gchar * nick,const gchar * blurb,gboolean has_alpha,const GimpRGB * default_value,GParamFlags flags)791 gimp_param_spec_rgb (const gchar *name,
792 const gchar *nick,
793 const gchar *blurb,
794 gboolean has_alpha,
795 const GimpRGB *default_value,
796 GParamFlags flags)
797 {
798 GimpParamSpecRGB *cspec;
799
800 cspec = g_param_spec_internal (GIMP_TYPE_PARAM_RGB,
801 name, nick, blurb, flags);
802
803 cspec->has_alpha = has_alpha;
804
805 if (default_value)
806 cspec->default_value = *default_value;
807 else
808 gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
809
810 return G_PARAM_SPEC (cspec);
811 }
812
813 /**
814 * gimp_param_spec_rgb_get_default:
815 * @pspec: a #GimpParamSpecRGB.
816 * @default_value: return location for @pspec's default value
817 *
818 * Returns the @pspec's default color value.
819 *
820 * Since: 2.10.14
821 **/
822 void
gimp_param_spec_rgb_get_default(GParamSpec * pspec,GimpRGB * default_value)823 gimp_param_spec_rgb_get_default (GParamSpec *pspec,
824 GimpRGB *default_value)
825 {
826 g_return_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec));
827 g_return_if_fail (default_value != NULL);
828
829 *default_value = GIMP_PARAM_SPEC_RGB (pspec)->default_value;
830 }
831
832 /**
833 * gimp_param_spec_rgb_has_alpha:
834 * @pspec: a #GParamSpec to hold an #GimpRGB value.
835 *
836 * Returns: %TRUE if the alpha channel is relevant.
837 *
838 * Since: 2.4
839 **/
840 gboolean
gimp_param_spec_rgb_has_alpha(GParamSpec * pspec)841 gimp_param_spec_rgb_has_alpha (GParamSpec *pspec)
842 {
843 g_return_val_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec), FALSE);
844
845 return GIMP_PARAM_SPEC_RGB (pspec)->has_alpha;
846 }
847