00001
00021
00022
00023
00024
00025 #ifndef __SYNFIG_COLOR_H
00026 #define __SYNFIG_COLOR_H
00027
00028
00029
00030
00031
00032 #include <math.h>
00033 #include <cassert>
00034 #include "gamma.h"
00035 #include <synfig/string.h>
00036
00037 #ifdef USE_HALF_TYPE
00038 #include <OpenEXR/half.h>
00039 #endif
00040
00041 #ifndef SYNFIG_NO_ANGLE
00042 # include "angle.h"
00043 #endif
00044
00045
00046
00047 #ifdef WIN32
00048 #include <float.h>
00049 #ifndef isnan
00050 extern "C" { int _isnan(double x); }
00051 #define isnan _isnan
00052 #endif
00053 #endif
00054
00055
00056
00057 #if defined(__APPLE__) && !defined(SYNFIG_ISNAN_FIX)
00058 #ifdef isnan
00059 #undef isnan
00060 #endif
00061 inline bool isnan(double x) { return x != x; }
00062 inline bool isnan(float x) { return x != x; }
00063 #define SYNFIG_ISNAN_FIX 1
00064 #endif
00065
00066 namespace synfig {
00067
00068 #ifdef USE_HALF_TYPE
00069 typedef half ColorReal;
00070 #else
00071 typedef float ColorReal;
00072 #endif
00073
00074 static const float EncodeYUV[3][3]=
00075 {
00076 { 0.299f, 0.587f, 0.114f },
00077 { -0.168736f, -0.331264f, 0.5f },
00078 { 0.5f, -0.418688f, -0.081312f }
00079 };
00080
00081 static const float DecodeYUV[3][3]=
00082 {
00083 { 1.0f, 0.0f, 1.402f },
00084 { 1.0f, -0.344136f, -0.714136f },
00085 { 1.0f, 1.772f, 0.0f }
00086 };
00087
00088
00089
00090
00091
00092 #ifdef USE_HALF_TYPE
00093 class ColorAccumulator;
00094 #endif
00095
00096
00097
00098
00103 class Color
00104 {
00105 public:
00106 typedef ColorReal value_type;
00107
00108 private:
00109 value_type a_, r_, g_, b_;
00110 static String hex_;
00111
00112 public:
00113
00114 Color &
00115 operator+=(const Color &rhs)
00116 {
00117 r_+=rhs.r_;
00118 g_+=rhs.g_;
00119 b_+=rhs.b_;
00120 a_+=rhs.a_;
00121 return *this;
00122 }
00123
00124 Color &
00125 operator-=(const Color &rhs)
00126 {
00127 r_-=rhs.r_;
00128 g_-=rhs.g_;
00129 b_-=rhs.b_;
00130 a_-=rhs.a_;
00131 return *this;
00132 }
00133
00134 Color &
00135 operator*=(const float &rhs)
00136 {
00137 r_*=rhs;
00138 g_*=rhs;
00139 b_*=rhs;
00140 a_*=rhs;
00141 return *this;
00142 }
00143
00144 Color &
00145 operator/=(const float &rhs)
00146 {
00147 const float temp(value_type(1)/rhs);
00148 r_*=temp;
00149 g_*=temp;
00150 b_*=temp;
00151 a_*=temp;
00152 return *this;
00153 }
00154
00155 Color
00156 operator+(const Color &rhs)const
00157 { return Color(*this)+=rhs; }
00158
00159 Color
00160 operator-(const Color &rhs)const
00161 { return Color(*this)-=rhs; }
00162
00163 Color
00164 operator*(const float &rhs)const
00165 { return Color(*this)*=rhs; }
00166
00167 Color
00168 operator/(const float &rhs)const
00169 { return Color(*this)/=rhs; }
00170
00171 bool
00172 operator==(const Color &rhs)const
00173 { return r_==rhs.r_ && g_==rhs.g_ && b_==rhs.b_ && a_==rhs.a_; }
00174
00175 bool
00176 operator!=(const Color &rhs)const
00177 { return r_!=rhs.r_ || g_!=rhs.g_ || b_!=rhs.b_ || a_!=rhs.a_; }
00178
00179 Color
00180 operator-()const
00181 { return Color(-r_,-g_,-b_,-a_); }
00182
00184 Color
00185 operator~()const
00186 { return Color(1.0f-r_,1.0f-g_,1.0f-b_,a_); }
00187
00188 bool is_valid()const
00189 { return !isnan(r_) && !isnan(g_) && !isnan(b_) && !isnan(a_); }
00190
00191 Color premult_alpha() const
00192 {
00193 return Color (r_*a_, g_*a_, b_*a_, a_);
00194 }
00195
00196 Color demult_alpha() const
00197 {
00198 if(a_)
00199 {
00200 const value_type inva = 1/a_;
00201 return Color (r_*inva, g_*inva, b_*inva, a_);
00202 }else return alpha();
00203 }
00204
00205 public:
00206 Color() { }
00207 Color(const value_type &f) :a_(f),r_(f), g_(f), b_(f) { }
00208 Color(int f) :a_(f),r_(f), g_(f), b_(f) { }
00209
00214 Color(const value_type& R, const value_type& G, const value_type& B, const value_type& A=1):
00215 a_(A),
00216 r_(R),
00217 g_(G),
00218 b_(B) { }
00219
00222 Color(const Color& c, const value_type& A):
00223 a_(A),
00224 r_(c.r_),
00225 g_(c.g_),
00226 b_(c.b_) { }
00227
00228
00230 Color(const Color& c):
00231 a_(c.a_),
00232 r_(c.r_),
00233 g_(c.g_),
00234 b_(c.b_) { }
00235
00236 #ifdef USE_HALF_TYPE
00237 friend class ColorAccumulator;
00239 Color(const ColorAccumulator& c);
00240 #endif
00241
00243
00244
00245
00246
00247
00248
00249
00250
00251
00253 const value_type& get_r()const { return r_; }
00254
00256 const value_type& get_g()const { return g_; }
00257
00259 const value_type& get_b()const { return b_; }
00260
00262 const value_type& get_a()const { return a_; }
00263
00265 const value_type& get_alpha()const { return get_a(); }
00266
00268 static ColorReal hex2real(String s);
00269
00271 static const String real2hex(ColorReal c);
00272
00274 const String& get_hex()const { return hex_ = real2hex(r_)+real2hex(g_)+real2hex(b_); }
00275
00277 void set_hex(String& hex);
00278
00280 Color& set_r(const value_type& x) { r_ = x; return *this; }
00281
00283 Color& set_g(const value_type& x) { g_ = x; return *this; }
00284
00286 Color& set_b(const value_type& x) { b_ = x; return *this; }
00287
00289 Color& set_a(const value_type& x) { a_ = x; return *this; }
00290
00292 Color& set_alpha(const value_type& x) { return set_a(x); }
00293
00295 float
00296 get_y() const
00297 {
00298 return
00299 (float)get_r()*EncodeYUV[0][0]+
00300 (float)get_g()*EncodeYUV[0][1]+
00301 (float)get_b()*EncodeYUV[0][2];
00302 }
00303
00304
00306 float
00307 get_u() const
00308 {
00309 return
00310 (float)get_r()*EncodeYUV[1][0]+
00311 (float)get_g()*EncodeYUV[1][1]+
00312 (float)get_b()*EncodeYUV[1][2];
00313 }
00314
00315
00317 float
00318 get_v() const
00319 {
00320 return
00321 (float)get_r()*EncodeYUV[2][0]+
00322 (float)get_g()*EncodeYUV[2][1]+
00323 (float)get_b()*EncodeYUV[2][2];
00324 }
00325
00327
00329 float
00330 get_s() const
00331 {
00332 const float u(get_u()), v(get_v());
00333 return sqrt(u*u+v*v);
00334 }
00335
00337 Color&
00338 set_yuv(const float &y, const float &u, const float &v)
00339 {
00340 set_r(y*DecodeYUV[0][0]+u*DecodeYUV[0][1]+v*DecodeYUV[0][2]);
00341 set_g(y*DecodeYUV[1][0]+u*DecodeYUV[1][1]+v*DecodeYUV[1][2]);
00342 set_b(y*DecodeYUV[2][0]+u*DecodeYUV[2][1]+v*DecodeYUV[2][2]);
00343 return *this;
00344 }
00345
00347 Color& set_y(const float &y) { return set_yuv(y,get_u(),get_v()); }
00348
00350 Color& set_u(const float &u) { return set_yuv(get_y(),u,get_v()); }
00351
00353 Color& set_v(const float &v) { return set_yuv(get_y(),get_u(),v); }
00354
00356 Color& set_uv(const float& u, const float& v) { return set_yuv(get_y(),u,v); }
00357
00359
00360 Color&
00361 set_s(const float &x)
00362 {
00363 float u(get_u()), v(get_v());
00364 const float s(sqrt(u*u+v*v));
00365 if(s)
00366 {
00367 u=(u/s)*x;
00368 v=(v/s)*x;
00369 return set_uv(u,v);
00370 }
00371 return *this;
00372 }
00373
00375 static Color YUV(const float& y, const float& u, const float& v, const value_type& a=1)
00376 { return Color().set_yuv(y,u,v).set_a(a); }
00377
00378 #ifndef SYNFIG_NO_ANGLE
00380
00382 Angle
00383 get_hue() const
00384 { return Angle::tan(get_u(),get_v()); }
00385
00387 Angle get_uv_angle() const { return get_hue(); }
00388
00390
00391 Color&
00392 set_hue(const Angle& theta)
00393 {
00394 const float s(get_s());
00395 const float
00396 u(s*(float)Angle::sin(theta).get()),
00397 v(s*(float)Angle::cos(theta).get());
00398 return set_uv(u,v);
00399 }
00400
00402 Color& set_uv_angle(const Angle& theta) { return set_hue(theta); }
00403
00405 Color& rotate_uv(const Angle& theta)
00406 {
00407 const float a(Angle::sin(theta).get()), b(Angle::cos(theta).get());
00408 const float u(get_u()), v(get_v());
00409
00410 return set_uv(b*u-a*v,a*u+b*v);
00411 }
00412
00414
00417 Color& set_yuv(const float& y, const float& s, const Angle& theta)
00418 {
00419 return
00420 set_yuv(
00421 y,
00422 s*(float)Angle::sin(theta).get(),
00423 s*(float)Angle::cos(theta).get()
00424 );
00425 }
00426
00428
00432 static Color YUV(const float& y, const float& s, const Angle& theta, const value_type& a=1)
00433 { return Color().set_yuv(y,s,theta).set_a(a); }
00434
00435 #endif
00436
00438 Color clamped()const;
00439
00441 Color clamped_negative()const;
00442
00443
00444
00446
00447 #ifdef HAS_VIMAGE
00448 static inline Color alpha() { return Color(0,0,0,0.0000001f); }
00449 #else
00450 static inline Color alpha() { return Color(0,0,0,0); }
00451 #endif
00452 static inline Color black() { return Color(0,0,0); }
00453 static inline Color white() { return Color(1,1,1); }
00454 static inline Color gray() { return Color(0.5f,0.5f,0.5f); }
00455 static inline Color magenta() { return Color(1,0,1); }
00456 static inline Color red() { return Color(1,0,0); }
00457 static inline Color green() { return Color(0,1,0); }
00458 static inline Color blue() { return Color(0,0,1); }
00459 static inline Color cyan() { return Color(0,1,1); }
00460 static inline Color yellow() { return Color(1,1,0); }
00462
00464 enum BlendMethod
00465 {
00466 BLEND_COMPOSITE=0,
00467 BLEND_STRAIGHT=1,
00468 BLEND_BRIGHTEN=2,
00469 BLEND_DARKEN=3,
00470 BLEND_ADD=4,
00471 BLEND_SUBTRACT=5,
00472 BLEND_MULTIPLY=6,
00473 BLEND_DIVIDE=7,
00474 BLEND_COLOR=8,
00475 BLEND_HUE=9,
00476 BLEND_SATURATION=10,
00477 BLEND_LUMINANCE=11,
00478 BLEND_BEHIND=12,
00479 BLEND_ONTO=13,
00480 BLEND_SCREEN=16,
00481 BLEND_OVERLAY=20,
00482 BLEND_DIFFERENCE=18,
00483 BLEND_HARD_LIGHT=17,
00484
00486 BLEND_ALPHA_BRIGHTEN=14,
00487 BLEND_ALPHA_DARKEN=15,
00488 BLEND_ALPHA_OVER=19,
00489 BLEND_STRAIGHT_ONTO=21,
00490
00491 BLEND_END=22
00492 };
00493
00494
00495 static Color blend(Color a, Color b,float amount,BlendMethod type=BLEND_COMPOSITE);
00496
00497 static bool is_onto(BlendMethod x)
00498 {
00499 return x==BLEND_BRIGHTEN
00500 || x==BLEND_DARKEN
00501 || x==BLEND_ADD
00502 || x==BLEND_SUBTRACT
00503 || x==BLEND_MULTIPLY
00504 || x==BLEND_DIVIDE
00505 || x==BLEND_COLOR
00506 || x==BLEND_HUE
00507 || x==BLEND_SATURATION
00508 || x==BLEND_LUMINANCE
00509 || x==BLEND_ONTO
00510 || x==BLEND_STRAIGHT_ONTO
00511 || x==BLEND_SCREEN
00512 || x==BLEND_OVERLAY
00513 || x==BLEND_DIFFERENCE
00514 || x==BLEND_HARD_LIGHT
00515 ;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 };
00534
00535 #ifndef USE_HALF_TYPE
00536 typedef Color ColorAccumulator;
00537 #else
00538 class ColorAccumulator
00539 {
00540 friend class Color;
00541 public:
00542 typedef float value_type;
00543
00544 private:
00545 value_type a_, r_, g_, b_;
00546
00547 public:
00548
00549 ColorAccumulator &
00550 operator+=(const ColorAccumulator &rhs)
00551 {
00552 r_+=rhs.r_;
00553 g_+=rhs.g_;
00554 b_+=rhs.b_;
00555 a_+=rhs.a_;
00556 return *this;
00557 }
00558
00559 ColorAccumulator &
00560 operator-=(const ColorAccumulator &rhs)
00561 {
00562 r_-=rhs.r_;
00563 g_-=rhs.g_;
00564 b_-=rhs.b_;
00565 a_-=rhs.a_;
00566 return *this;
00567 }
00568
00569 ColorAccumulator &
00570 operator*=(const float &rhs)
00571 {
00572 r_*=rhs;
00573 g_*=rhs;
00574 b_*=rhs;
00575 a_*=rhs;
00576 return *this;
00577 }
00578
00579 ColorAccumulator &
00580 operator/=(const float &rhs)
00581 {
00582 const float temp(value_type(1)/rhs);
00583 r_*=temp;
00584 g_*=temp;
00585 b_*=temp;
00586 a_*=temp;
00587 return *this;
00588 }
00589
00590 ColorAccumulator
00591 operator+(const ColorAccumulator &rhs)const
00592 { return Color(*this)+=rhs; }
00593
00594 ColorAccumulator
00595 operator-(const ColorAccumulator &rhs)const
00596 { return Color(*this)-=rhs; }
00597
00598 ColorAccumulator
00599 operator*(const float &rhs)const
00600 { return Color(*this)*=rhs; }
00601
00602 ColorAccumulator
00603 operator/(const float &rhs)const
00604 { return Color(*this)/=rhs; }
00605
00606 bool
00607 operator==(const ColorAccumulator &rhs)const
00608 { return r_==rhs.r_ && g_==rhs.g_ && b_==rhs.b_ && a_!=rhs.a_; }
00609
00610 bool
00611 operator!=(const ColorAccumulator &rhs)const
00612 { return r_!=rhs.r_ || g_!=rhs.g_ || b_!=rhs.b_ || a_!=rhs.a_; }
00613
00614 Color
00615 operator-()const
00616 { return ColorAccumulator(-r_,-g_,-b_,-a_); }
00617
00618 bool is_valid()const
00619 { return !isnan(r_) && !isnan(g_) && !isnan(b_) && !isnan(a_); }
00620
00621 public:
00622 ColorAccumulator() { }
00623
00628 ColorAccumulator(const value_type& R, const value_type& G, const value_type& B, const value_type& A=1):
00629 a_(A),
00630 r_(R),
00631 g_(G),
00632 b_(B) { }
00633
00635 ColorAccumulator(const ColorAccumulator& c):
00636 a_(c.a_),
00637 r_(c.r_),
00638 g_(c.g_),
00639 b_(c.b_) { }
00640
00642 ColorAccumulator(const Color& c):
00643 a_(c.a_),
00644 r_(c.r_),
00645 g_(c.g_),
00646 b_(c.b_) { }
00647
00649 ColorAccumulator(int c): a_(c),r_(c), g_(c), b_(c) { }
00650
00652 const value_type& get_r()const { return r_; }
00653
00655 const value_type& get_g()const { return g_; }
00656
00658 const value_type& get_b()const { return b_; }
00659
00661 const value_type& get_a()const { return a_; }
00662
00664 const value_type& get_alpha()const { return get_a(); }
00665
00667 ColorAccumulator& set_r(const value_type& x) { r_ = x; return *this; }
00668
00670 ColorAccumulator& set_g(const value_type& x) { g_ = x; return *this; }
00671
00673 ColorAccumulator& set_b(const value_type& x) { b_ = x; return *this; }
00674
00676 ColorAccumulator& set_a(const value_type& x) { a_ = x; return *this; }
00677
00679 ColorAccumulator& set_alpha(const value_type& x) { return set_a(x); }
00680 };
00681
00682 inline
00683 Color::Color(const ColorAccumulator& c):
00684 a_(c.a_),
00685 r_(c.r_),
00686 g_(c.g_),
00687 b_(c.b_) { }
00688
00689 #endif
00690
00691
00692
00693
00694
00695 enum PixelFormat
00696 {
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 PF_RGB=0,
00710 PF_GRAY=(1<<0),
00711 PF_A=(1<<1),
00712 PF_Z=(1<<2),
00713 PF_BGR=(1<<3),
00714 PF_A_START=(1<<4),
00715 PF_Z_START=(1<<5),
00716 PF_ZA=(1<<6),
00717
00718 PF_A_INV=(1<<7),
00719 PF_Z_INV=(1<<8),
00720 PF_RAW_COLOR=(1<<9)+(1<<1)
00721 };
00722
00723 inline PixelFormat operator|(PixelFormat lhs, PixelFormat rhs)
00724 { return static_cast<PixelFormat>((int)lhs|(int)rhs); }
00725
00726 inline PixelFormat operator&(PixelFormat lhs, PixelFormat rhs)
00727 { return static_cast<PixelFormat>((int)lhs&(int)rhs); }
00728 #define FLAGS(x,y) (((x)&(y))==(y))
00729
00731 inline int
00732 channels(PixelFormat x)
00733 {
00734 int chan=0;
00735 if(FLAGS(x,PF_GRAY))
00736 ++chan;
00737 else
00738 chan+=3;
00739 if(FLAGS(x,PF_A))
00740 ++chan;
00741 if(FLAGS(x,PF_Z))
00742 ++chan;
00743 if(FLAGS(x,PF_RAW_COLOR))
00744 chan=sizeof(Color);
00745
00746 return chan;
00747 }
00748
00749 inline unsigned char *
00750 Color2PixelFormat(const Color &color, const PixelFormat &pf, unsigned char *out, const Gamma &gamma)
00751 {
00752 if(FLAGS(pf,PF_RAW_COLOR))
00753 {
00754 Color *outcol=reinterpret_cast<Color *>(out);
00755 *outcol=color;
00756 out+=sizeof(color);
00757 return out;
00758 }
00759
00760 int alpha=(int)((FLAGS(pf,PF_A_INV)?(-(float)color.get_a()+1):(float)color.get_a())*255);
00761 if(alpha<0)alpha=0;
00762 if(alpha>255)alpha=255;
00763
00764 if(FLAGS(pf,PF_ZA|PF_A_START|PF_Z_START))
00765 {
00766 if(FLAGS(pf,PF_Z_START))
00767 *out++;
00768 if(FLAGS(pf,PF_A_START))
00769 *out++=static_cast<unsigned char>(alpha);
00770 }
00771 else
00772 {
00773 if(FLAGS(pf,PF_A_START))
00774 *out++=static_cast<unsigned char>(alpha);
00775 if(FLAGS(pf,PF_Z_START))
00776 *out++;
00777
00778 }
00779
00780 if(FLAGS(pf,PF_GRAY))
00781 *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_y()));
00782 else
00783 {
00784 if(FLAGS(pf,PF_BGR))
00785 {
00786 *out++=static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_b()));
00787 *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
00788 *out++=static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_r()));
00789 }
00790 else
00791 {
00792 *out++=static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_r()));
00793 *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
00794 *out++=static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_b()));
00795 }
00796 }
00797
00798 if(FLAGS(pf,PF_ZA))
00799 {
00800 if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
00801 out++;
00802 if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
00803 *out++=static_cast<unsigned char>(alpha);
00804 }
00805 else
00806 {
00807 if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
00808 out++;
00809 if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
00810 *out++=static_cast<unsigned char>(alpha);
00811 }
00812 return out;
00813 }
00814
00815 inline void
00816 convert_color_format(unsigned char *dest, const Color *src, int w, PixelFormat pf,const Gamma &gamma)
00817 {
00818 assert(w>=0);
00819 while(w--)
00820 dest=Color2PixelFormat((*(src++)).clamped(),pf,dest,gamma);
00821 }
00822
00823 inline const unsigned char *
00824 PixelFormat2Color(Color &color, const PixelFormat &pf,const unsigned char *out)
00825 {
00826 if(FLAGS(pf,PF_ZA|PF_A_START|PF_Z_START))
00827 {
00828 if(FLAGS(pf,PF_Z_START))
00829 out++;
00830 if(FLAGS(pf,PF_A_START))
00831 color.set_a((float)*out++/255);
00832 }
00833 else
00834 {
00835 if(FLAGS(pf,PF_A_START))
00836 color.set_a((float)*out++/255);
00837 if(FLAGS(pf,PF_Z_START))
00838 out++;
00839 }
00840
00841 if(FLAGS(pf,PF_GRAY))
00842 color.set_yuv((float)*out++/255,0,0);
00843 else
00844 {
00845 if(FLAGS(pf,PF_BGR))
00846 {
00847 color.set_b((float)*out++/255);
00848 color.set_g((float)*out++/255);
00849 color.set_r((float)*out++/255);
00850 }
00851 else
00852 {
00853 color.set_r((float)*out++/255);
00854 color.set_g((float)*out++/255);
00855 color.set_b((float)*out++/255);
00856 }
00857 }
00858
00859 if(FLAGS(pf,PF_ZA))
00860 {
00861 if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
00862 out++;
00863 if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
00864 color.set_a((float)*out++/255);
00865 }
00866 else
00867 {
00868 if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
00869 color.set_a((float)*out++/255);
00870 if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
00871 out++;
00872 }
00873 return out;
00874 }
00875
00876
00877
00878 };
00879
00880
00881
00882 #endif