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