1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
10 //----------------------------------------------------------------------------
12 // Adaptation for high precision colors has been sponsored by
13 // Liberty Technology Systems, Inc., visit http://lib-sys.com
15 // Liberty Technology Systems, Inc. is the provider of
16 // PostScript and PDF technology for software developers.
18 //----------------------------------------------------------------------------
19 // Contact: mcseem@antigrain.com
20 // mcseemagg@yahoo.com
21 // http://www.antigrain.com
22 //----------------------------------------------------------------------------
24 #ifndef AGG_COLOR_RGBA_INCLUDED
25 #define AGG_COLOR_RGBA_INCLUDED
28 #include "agg_basics.h"
32 // Supported byte orders for RGB and RGBA pixel formats
33 //=======================================================================
34 struct order_rgb
{ enum rgb_e
{ R
=0, G
=1, B
=2, rgb_tag
}; }; //----order_rgb
35 struct order_bgr
{ enum bgr_e
{ B
=0, G
=1, R
=2, rgb_tag
}; }; //----order_bgr
36 struct order_rgba
{ enum rgba_e
{ R
=0, G
=1, B
=2, A
=3, rgba_tag
}; }; //----order_rgba
37 struct order_argb
{ enum argb_e
{ A
=0, R
=1, G
=2, B
=3, rgba_tag
}; }; //----order_argb
38 struct order_abgr
{ enum abgr_e
{ A
=0, B
=1, G
=2, R
=3, rgba_tag
}; }; //----order_abgr
39 struct order_bgra
{ enum bgra_e
{ B
=0, G
=1, R
=2, A
=3, rgba_tag
}; }; //----order_bgra
41 //====================================================================rgba
44 typedef double value_type
;
51 //--------------------------------------------------------------------
54 //--------------------------------------------------------------------
55 rgba(double r_
, double g_
, double b_
, double a_
=1.0) :
56 r(r_
), g(g_
), b(b_
), a(a_
) {}
58 //--------------------------------------------------------------------
59 rgba(const rgba
& c
, double a_
) : r(c
.r
), g(c
.g
), b(c
.b
), a(a_
) {}
61 //--------------------------------------------------------------------
67 //--------------------------------------------------------------------
68 const rgba
& transparent()
74 //--------------------------------------------------------------------
75 const rgba
& opacity(double a_
)
77 if(a_
< 0.0) a_
= 0.0;
78 if(a_
> 1.0) a_
= 1.0;
83 //--------------------------------------------------------------------
84 double opacity() const
89 //--------------------------------------------------------------------
90 const rgba
& premultiply()
98 //--------------------------------------------------------------------
99 const rgba
& premultiply(double a_
)
101 if(a
<= 0.0 || a_
<= 0.0)
114 //--------------------------------------------------------------------
115 const rgba
& demultiply()
130 //--------------------------------------------------------------------
131 rgba
gradient(rgba c
, double k
) const
134 ret
.r
= r
+ (c
.r
- r
) * k
;
135 ret
.g
= g
+ (c
.g
- g
) * k
;
136 ret
.b
= b
+ (c
.b
- b
) * k
;
137 ret
.a
= a
+ (c
.a
- a
) * k
;
141 //--------------------------------------------------------------------
142 static rgba
no_color() { return rgba(0,0,0,0); }
144 //--------------------------------------------------------------------
145 static rgba
from_wavelength(double wl
, double gamma
= 1.0);
147 //--------------------------------------------------------------------
148 explicit rgba(double wavelen
, double gamma
=1.0)
150 *this = from_wavelength(wavelen
, gamma
);
155 //----------------------------------------------------------------rgba_pre
156 inline rgba
rgba_pre(double r
, double g
, double b
, double a
=1.0)
158 return rgba(r
, g
, b
, a
).premultiply();
160 inline rgba
rgba_pre(const rgba
& c
)
162 return rgba(c
).premultiply();
164 inline rgba
rgba_pre(const rgba
& c
, double a
)
166 return rgba(c
, a
).premultiply();
169 //------------------------------------------------------------------------
170 inline rgba
rgba::from_wavelength(double wl
, double gamma
)
172 rgba
t(0.0, 0.0, 0.0);
174 if(wl
>= 380.0 && wl
<= 440.0)
176 t
.r
= -1.0 * (wl
- 440.0) / (440.0 - 380.0);
180 if(wl
>= 440.0 && wl
<= 490.0)
182 t
.g
= (wl
- 440.0) / (490.0 - 440.0);
186 if(wl
>= 490.0 && wl
<= 510.0)
189 t
.b
= -1.0 * (wl
- 510.0) / (510.0 - 490.0);
192 if(wl
>= 510.0 && wl
<= 580.0)
194 t
.r
= (wl
- 510.0) / (580.0 - 510.0);
198 if(wl
>= 580.0 && wl
<= 645.0)
201 t
.g
= -1.0 * (wl
- 645.0) / (645.0 - 580.0);
204 if(wl
>= 645.0 && wl
<= 780.0)
210 if(wl
> 700.0) s
= 0.3 + 0.7 * (780.0 - wl
) / (780.0 - 700.0);
211 else if(wl
< 420.0) s
= 0.3 + 0.7 * (wl
- 380.0) / (420.0 - 380.0);
213 t
.r
= pow(t
.r
* s
, gamma
);
214 t
.g
= pow(t
.g
* s
, gamma
);
215 t
.b
= pow(t
.b
* s
, gamma
);
222 //===================================================================rgba8
225 typedef int8u value_type
;
226 typedef int32u calc_type
;
227 typedef int32 long_type
;
231 base_scale
= 1 << base_shift
,
232 base_mask
= base_scale
- 1
234 typedef rgba8 self_type
;
242 //--------------------------------------------------------------------
245 //--------------------------------------------------------------------
246 rgba8(unsigned r_
, unsigned g_
, unsigned b_
, unsigned a_
=base_mask
) :
252 //--------------------------------------------------------------------
253 rgba8(const rgba
& c
, double a_
) :
254 r((value_type
)uround(c
.r
* double(base_mask
))),
255 g((value_type
)uround(c
.g
* double(base_mask
))),
256 b((value_type
)uround(c
.b
* double(base_mask
))),
257 a((value_type
)uround(a_
* double(base_mask
))) {}
259 //--------------------------------------------------------------------
260 rgba8(const self_type
& c
, unsigned a_
) :
261 r(c
.r
), g(c
.g
), b(c
.b
), a(value_type(a_
)) {}
263 //--------------------------------------------------------------------
264 rgba8(const rgba
& c
) :
265 r((value_type
)uround(c
.r
* double(base_mask
))),
266 g((value_type
)uround(c
.g
* double(base_mask
))),
267 b((value_type
)uround(c
.b
* double(base_mask
))),
268 a((value_type
)uround(c
.a
* double(base_mask
))) {}
270 //--------------------------------------------------------------------
276 //--------------------------------------------------------------------
277 const self_type
& transparent()
283 //--------------------------------------------------------------------
284 const self_type
& opacity(double a_
)
286 if(a_
< 0.0) a_
= 0.0;
287 if(a_
> 1.0) a_
= 1.0;
288 a
= (value_type
)uround(a_
* double(base_mask
));
292 //--------------------------------------------------------------------
293 double opacity() const
295 return double(a
) / double(base_mask
);
298 //--------------------------------------------------------------------
299 AGG_INLINE
const self_type
& premultiply()
301 if(a
== base_mask
) return *this;
307 r
= value_type((calc_type(r
) * a
) >> base_shift
);
308 g
= value_type((calc_type(g
) * a
) >> base_shift
);
309 b
= value_type((calc_type(b
) * a
) >> base_shift
);
313 //--------------------------------------------------------------------
314 AGG_INLINE
const self_type
& premultiply(unsigned a_
)
316 if(a
== base_mask
&& a_
>= base_mask
) return *this;
317 if(a
== 0 || a_
== 0)
322 calc_type r_
= (calc_type(r
) * a_
) / a
;
323 calc_type g_
= (calc_type(g
) * a_
) / a
;
324 calc_type b_
= (calc_type(b
) * a_
) / a
;
325 r
= value_type((r_
> a_
) ? a_
: r_
);
326 g
= value_type((g_
> a_
) ? a_
: g_
);
327 b
= value_type((b_
> a_
) ? a_
: b_
);
332 //--------------------------------------------------------------------
333 AGG_INLINE
const self_type
& demultiply()
335 if(a
== base_mask
) return *this;
341 calc_type r_
= (calc_type(r
) * base_mask
) / a
;
342 calc_type g_
= (calc_type(g
) * base_mask
) / a
;
343 calc_type b_
= (calc_type(b
) * base_mask
) / a
;
344 r
= value_type((r_
> calc_type(base_mask
)) ? calc_type(base_mask
) : r_
);
345 g
= value_type((g_
> calc_type(base_mask
)) ? calc_type(base_mask
) : g_
);
346 b
= value_type((b_
> calc_type(base_mask
)) ? calc_type(base_mask
) : b_
);
350 //--------------------------------------------------------------------
351 AGG_INLINE self_type
gradient(const self_type
& c
, double k
) const
354 calc_type ik
= uround(k
* base_scale
);
355 ret
.r
= value_type(calc_type(r
) + (((calc_type(c
.r
) - r
) * ik
) >> base_shift
));
356 ret
.g
= value_type(calc_type(g
) + (((calc_type(c
.g
) - g
) * ik
) >> base_shift
));
357 ret
.b
= value_type(calc_type(b
) + (((calc_type(c
.b
) - b
) * ik
) >> base_shift
));
358 ret
.a
= value_type(calc_type(a
) + (((calc_type(c
.a
) - a
) * ik
) >> base_shift
));
362 //--------------------------------------------------------------------
363 AGG_INLINE
void add(const self_type
& c
, unsigned cover
)
365 calc_type cr
, cg
, cb
, ca
;
366 if(cover
== cover_mask
)
374 cr
= r
+ c
.r
; r
= (cr
> calc_type(base_mask
)) ? calc_type(base_mask
) : cr
;
375 cg
= g
+ c
.g
; g
= (cg
> calc_type(base_mask
)) ? calc_type(base_mask
) : cg
;
376 cb
= b
+ c
.b
; b
= (cb
> calc_type(base_mask
)) ? calc_type(base_mask
) : cb
;
377 ca
= a
+ c
.a
; a
= (ca
> calc_type(base_mask
)) ? calc_type(base_mask
) : ca
;
382 cr
= r
+ ((c
.r
* cover
+ cover_mask
/2) >> cover_shift
);
383 cg
= g
+ ((c
.g
* cover
+ cover_mask
/2) >> cover_shift
);
384 cb
= b
+ ((c
.b
* cover
+ cover_mask
/2) >> cover_shift
);
385 ca
= a
+ ((c
.a
* cover
+ cover_mask
/2) >> cover_shift
);
386 r
= (cr
> calc_type(base_mask
)) ? calc_type(base_mask
) : cr
;
387 g
= (cg
> calc_type(base_mask
)) ? calc_type(base_mask
) : cg
;
388 b
= (cb
> calc_type(base_mask
)) ? calc_type(base_mask
) : cb
;
389 a
= (ca
> calc_type(base_mask
)) ? calc_type(base_mask
) : ca
;
393 //--------------------------------------------------------------------
394 template<class GammaLUT
>
395 AGG_INLINE
void apply_gamma_dir(const GammaLUT
& gamma
)
402 //--------------------------------------------------------------------
403 template<class GammaLUT
>
404 AGG_INLINE
void apply_gamma_inv(const GammaLUT
& gamma
)
411 //--------------------------------------------------------------------
412 static self_type
no_color() { return self_type(0,0,0,0); }
414 //--------------------------------------------------------------------
415 static self_type
from_wavelength(double wl
, double gamma
= 1.0)
417 return self_type(rgba::from_wavelength(wl
, gamma
));
422 //-------------------------------------------------------------rgba8_pre
423 inline rgba8
rgba8_pre(unsigned r
, unsigned g
, unsigned b
,
424 unsigned a
= rgba8::base_mask
)
426 return rgba8(r
,g
,b
,a
).premultiply();
428 inline rgba8
rgba8_pre(const rgba8
& c
)
430 return rgba8(c
).premultiply();
432 inline rgba8
rgba8_pre(const rgba8
& c
, unsigned a
)
434 return rgba8(c
,a
).premultiply();
436 inline rgba8
rgba8_pre(const rgba
& c
)
438 return rgba8(c
).premultiply();
440 inline rgba8
rgba8_pre(const rgba
& c
, double a
)
442 return rgba8(c
,a
).premultiply();
446 //-----------------------------------------------------------rgb8_packed
447 inline rgba8
rgb8_packed(unsigned v
)
449 return rgba8((v
>> 16) & 0xFF, (v
>> 8) & 0xFF, v
& 0xFF);
452 //-----------------------------------------------------------bgr8_packed
453 inline rgba8
bgr8_packed(unsigned v
)
455 return rgba8(v
& 0xFF, (v
>> 8) & 0xFF, (v
>> 16) & 0xFF);
458 //----------------------------------------------------------argb8_packed
459 inline rgba8
argb8_packed(unsigned v
)
461 return rgba8((v
>> 16) & 0xFF, (v
>> 8) & 0xFF, v
& 0xFF, v
>> 24);
471 //=================================================================rgba16
474 typedef int16u value_type
;
475 typedef int32u calc_type
;
476 typedef int64 long_type
;
480 base_scale
= 1 << base_shift
,
481 base_mask
= base_scale
- 1
483 typedef rgba16 self_type
;
490 //--------------------------------------------------------------------
493 //--------------------------------------------------------------------
494 rgba16(unsigned r_
, unsigned g_
, unsigned b_
, unsigned a_
=base_mask
) :
500 //--------------------------------------------------------------------
501 rgba16(const self_type
& c
, unsigned a_
) :
502 r(c
.r
), g(c
.g
), b(c
.b
), a(value_type(a_
)) {}
504 //--------------------------------------------------------------------
505 rgba16(const rgba
& c
) :
506 r((value_type
)uround(c
.r
* double(base_mask
))),
507 g((value_type
)uround(c
.g
* double(base_mask
))),
508 b((value_type
)uround(c
.b
* double(base_mask
))),
509 a((value_type
)uround(c
.a
* double(base_mask
))) {}
511 //--------------------------------------------------------------------
512 rgba16(const rgba
& c
, double a_
) :
513 r((value_type
)uround(c
.r
* double(base_mask
))),
514 g((value_type
)uround(c
.g
* double(base_mask
))),
515 b((value_type
)uround(c
.b
* double(base_mask
))),
516 a((value_type
)uround(a_
* double(base_mask
))) {}
518 //--------------------------------------------------------------------
519 rgba16(const rgba8
& c
) :
520 r(value_type((value_type(c
.r
) << 8) | c
.r
)),
521 g(value_type((value_type(c
.g
) << 8) | c
.g
)),
522 b(value_type((value_type(c
.b
) << 8) | c
.b
)),
523 a(value_type((value_type(c
.a
) << 8) | c
.a
)) {}
525 //--------------------------------------------------------------------
526 rgba16(const rgba8
& c
, unsigned a_
) :
527 r(value_type((value_type(c
.r
) << 8) | c
.r
)),
528 g(value_type((value_type(c
.g
) << 8) | c
.g
)),
529 b(value_type((value_type(c
.b
) << 8) | c
.b
)),
530 a(value_type(( a_
<< 8) | c
.a
)) {}
532 //--------------------------------------------------------------------
538 //--------------------------------------------------------------------
539 const self_type
& transparent()
545 //--------------------------------------------------------------------
546 AGG_INLINE
const self_type
& opacity(double a_
)
548 if(a_
< 0.0) a_
= 0.0;
549 if(a_
> 1.0) a_
= 1.0;
550 a
= (value_type
)uround(a_
* double(base_mask
));
554 //--------------------------------------------------------------------
555 double opacity() const
557 return double(a
) / double(base_mask
);
560 //--------------------------------------------------------------------
561 AGG_INLINE
const self_type
& premultiply()
563 if(a
== base_mask
) return *this;
569 r
= value_type((calc_type(r
) * a
) >> base_shift
);
570 g
= value_type((calc_type(g
) * a
) >> base_shift
);
571 b
= value_type((calc_type(b
) * a
) >> base_shift
);
575 //--------------------------------------------------------------------
576 AGG_INLINE
const self_type
& premultiply(unsigned a_
)
578 if(a
== base_mask
&& a_
>= base_mask
) return *this;
579 if(a
== 0 || a_
== 0)
584 calc_type r_
= (calc_type(r
) * a_
) / a
;
585 calc_type g_
= (calc_type(g
) * a_
) / a
;
586 calc_type b_
= (calc_type(b
) * a_
) / a
;
587 r
= value_type((r_
> a_
) ? a_
: r_
);
588 g
= value_type((g_
> a_
) ? a_
: g_
);
589 b
= value_type((b_
> a_
) ? a_
: b_
);
594 //--------------------------------------------------------------------
595 AGG_INLINE
const self_type
& demultiply()
597 if(a
== base_mask
) return *this;
603 calc_type r_
= (calc_type(r
) * base_mask
) / a
;
604 calc_type g_
= (calc_type(g
) * base_mask
) / a
;
605 calc_type b_
= (calc_type(b
) * base_mask
) / a
;
606 r
= value_type((r_
> calc_type(base_mask
)) ? calc_type(base_mask
) : r_
);
607 g
= value_type((g_
> calc_type(base_mask
)) ? calc_type(base_mask
) : g_
);
608 b
= value_type((b_
> calc_type(base_mask
)) ? calc_type(base_mask
) : b_
);
612 //--------------------------------------------------------------------
613 AGG_INLINE self_type
gradient(const self_type
& c
, double k
) const
616 calc_type ik
= uround(k
* base_scale
);
617 ret
.r
= value_type(calc_type(r
) + (((calc_type(c
.r
) - r
) * ik
) >> base_shift
));
618 ret
.g
= value_type(calc_type(g
) + (((calc_type(c
.g
) - g
) * ik
) >> base_shift
));
619 ret
.b
= value_type(calc_type(b
) + (((calc_type(c
.b
) - b
) * ik
) >> base_shift
));
620 ret
.a
= value_type(calc_type(a
) + (((calc_type(c
.a
) - a
) * ik
) >> base_shift
));
624 //--------------------------------------------------------------------
625 AGG_INLINE
void add(const self_type
& c
, unsigned cover
)
627 calc_type cr
, cg
, cb
, ca
;
628 if(cover
== cover_mask
)
636 cr
= r
+ c
.r
; r
= (cr
> calc_type(base_mask
)) ? calc_type(base_mask
) : cr
;
637 cg
= g
+ c
.g
; g
= (cg
> calc_type(base_mask
)) ? calc_type(base_mask
) : cg
;
638 cb
= b
+ c
.b
; b
= (cb
> calc_type(base_mask
)) ? calc_type(base_mask
) : cb
;
639 ca
= a
+ c
.a
; a
= (ca
> calc_type(base_mask
)) ? calc_type(base_mask
) : ca
;
644 cr
= r
+ ((c
.r
* cover
+ cover_mask
) >> cover_shift
);
645 cg
= g
+ ((c
.g
* cover
+ cover_mask
) >> cover_shift
);
646 cb
= b
+ ((c
.b
* cover
+ cover_mask
) >> cover_shift
);
647 ca
= a
+ ((c
.a
* cover
+ cover_mask
) >> cover_shift
);
648 r
= (cr
> calc_type(base_mask
)) ? calc_type(base_mask
) : cr
;
649 g
= (cg
> calc_type(base_mask
)) ? calc_type(base_mask
) : cg
;
650 b
= (cb
> calc_type(base_mask
)) ? calc_type(base_mask
) : cb
;
651 a
= (ca
> calc_type(base_mask
)) ? calc_type(base_mask
) : ca
;
655 //--------------------------------------------------------------------
656 template<class GammaLUT
>
657 AGG_INLINE
void apply_gamma_dir(const GammaLUT
& gamma
)
664 //--------------------------------------------------------------------
665 template<class GammaLUT
>
666 AGG_INLINE
void apply_gamma_inv(const GammaLUT
& gamma
)
673 //--------------------------------------------------------------------
674 static self_type
no_color() { return self_type(0,0,0,0); }
676 //--------------------------------------------------------------------
677 static self_type
from_wavelength(double wl
, double gamma
= 1.0)
679 return self_type(rgba::from_wavelength(wl
, gamma
));
685 //--------------------------------------------------------------rgba16_pre
686 inline rgba16
rgba16_pre(unsigned r
, unsigned g
, unsigned b
,
687 unsigned a
= rgba16::base_mask
)
689 return rgba16(r
,g
,b
,a
).premultiply();
691 inline rgba16
rgba16_pre(const rgba16
& c
, unsigned a
)
693 return rgba16(c
,a
).premultiply();
695 inline rgba16
rgba16_pre(const rgba
& c
)
697 return rgba16(c
).premultiply();
699 inline rgba16
rgba16_pre(const rgba
& c
, double a
)
701 return rgba16(c
,a
).premultiply();
703 inline rgba16
rgba16_pre(const rgba8
& c
)
705 return rgba16(c
).premultiply();
707 inline rgba16
rgba16_pre(const rgba8
& c
, unsigned a
)
709 return rgba16(c
,a
).premultiply();