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