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