Stable Tag: Copying everything over
[synfig.git] / synfig-core / tags / stable / src / synfig / color.h
diff --git a/synfig-core/tags/stable/src/synfig/color.h b/synfig-core/tags/stable/src/synfig/color.h
new file mode 100644 (file)
index 0000000..d3ae54d
--- /dev/null
@@ -0,0 +1,882 @@
+/* === S Y N F I G ========================================================= */
+/*!    \file color.h
+**     \brief Color Class Implementation
+**
+**     $Id$
+**
+**     \legal
+**     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**
+**     This package is free software; you can redistribute it and/or
+**     modify it under the terms of the GNU General Public License as
+**     published by the Free Software Foundation; either version 2 of
+**     the License, or (at your option) any later version.
+**
+**     This package is distributed in the hope that it will be useful,
+**     but WITHOUT ANY WARRANTY; without even the implied warranty of
+**     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+**     General Public License for more details.
+**     \endlegal
+*/
+/* ========================================================================= */
+
+/* === S T A R T =========================================================== */
+
+#ifndef __SYNFIG_COLOR_H
+#define __SYNFIG_COLOR_H
+
+/* === H E A D E R S ======================================================= */
+
+
+//#include <cmath>
+#include <math.h>
+#include <cassert>
+#include "gamma.h"
+#include <synfig/string.h>
+
+#ifdef USE_HALF_TYPE
+#include <OpenEXR/half.h>
+#endif
+
+#ifndef SYNFIG_NO_ANGLE
+# include "angle.h"
+#endif
+
+/* === M A C R O S ========================================================= */
+
+#ifdef WIN32
+#include <float.h>
+#ifndef isnan
+extern "C" { int _isnan(double x); }
+#define isnan _isnan
+#endif
+#endif
+
+// For some reason isnan() isn't working on macosx any more.
+// This is a quick fix.
+#if defined(__APPLE__) && !defined(SYNFIG_ISNAN_FIX)
+#ifdef isnan
+#undef isnan
+#endif
+inline bool isnan(double x) { return x != x; }
+inline bool isnan(float x) { return x != x; }
+#define SYNFIG_ISNAN_FIX 1
+#endif
+
+namespace synfig {
+
+#ifdef USE_HALF_TYPE
+typedef half ColorReal;
+#else
+typedef float ColorReal;
+#endif
+
+static const float EncodeYUV[3][3]=
+{
+       { 0.299f, 0.587f, 0.114f },
+       { -0.168736f, -0.331264f, 0.5f },
+       { 0.5f, -0.418688f, -0.081312f }
+};
+
+static const float DecodeYUV[3][3]=
+{
+       { 1.0f, 0.0f, 1.402f },
+       { 1.0f, -0.344136f, -0.714136f },
+       { 1.0f, 1.772f, 0.0f }
+};
+
+/* === T Y P E D E F S ===================================================== */
+
+/* === C L A S S E S & S T R U C T S ======================================= */
+
+#ifdef USE_HALF_TYPE
+class ColorAccumulator;
+#endif
+
+
+
+
+/*!    \class Color
+**     \todo Writeme
+**     Future optimizations: lookup table for sqrt()?
+*/
+class Color
+{
+public:
+       typedef ColorReal value_type;
+
+private:
+       value_type a_, r_, g_, b_;
+       static String hex_;
+
+public:
+
+       Color &
+       operator+=(const Color &rhs)
+       {
+               r_+=rhs.r_;
+               g_+=rhs.g_;
+               b_+=rhs.b_;
+               a_+=rhs.a_;
+               return *this;
+       }
+
+       Color &
+       operator-=(const Color &rhs)
+       {
+               r_-=rhs.r_;
+               g_-=rhs.g_;
+               b_-=rhs.b_;
+               a_-=rhs.a_;
+               return *this;
+       }
+
+       Color &
+       operator*=(const float &rhs)
+       {
+               r_*=rhs;
+               g_*=rhs;
+               b_*=rhs;
+               a_*=rhs;
+               return *this;
+       }
+
+       Color &
+       operator/=(const float &rhs)
+       {
+               const float temp(value_type(1)/rhs);
+               r_*=temp;
+               g_*=temp;
+               b_*=temp;
+               a_*=temp;
+               return *this;
+       }
+
+       Color
+       operator+(const Color &rhs)const
+       { return Color(*this)+=rhs; }
+
+       Color
+       operator-(const Color &rhs)const
+       { return Color(*this)-=rhs; }
+
+       Color
+       operator*(const float &rhs)const
+       { return Color(*this)*=rhs; }
+
+       Color
+       operator/(const float &rhs)const
+       { return Color(*this)/=rhs; }
+
+       bool
+       operator==(const Color &rhs)const
+       { return r_==rhs.r_ && g_==rhs.g_ && b_==rhs.b_ && a_==rhs.a_; }
+
+       bool
+       operator!=(const Color &rhs)const
+       { return r_!=rhs.r_ || g_!=rhs.g_ || b_!=rhs.b_ || a_!=rhs.a_; }
+
+       Color
+       operator-()const
+       { return Color(-r_,-g_,-b_,-a_); }
+
+       //! Effectively 1.0-color
+       Color
+       operator~()const
+       { return Color(1.0f-r_,1.0f-g_,1.0f-b_,a_); }
+
+       bool is_valid()const
+       { return !isnan(r_) && !isnan(g_) && !isnan(b_) && !isnan(a_); }
+
+       Color premult_alpha() const
+       {
+               return Color (r_*a_, g_*a_, b_*a_, a_);
+       }
+
+       Color demult_alpha() const
+       {
+               if(a_)
+               {
+                       const value_type inva = 1/a_;
+                       return Color (r_*inva, g_*inva, b_*inva, a_);
+               }else return alpha();
+       }
+
+public:
+       Color() /*:r_(0), g_(0), b_(0), a_(0)*/ { }
+       Color(const value_type &f) :a_(f),r_(f), g_(f), b_(f) { }
+       Color(int f) :a_(f),r_(f), g_(f), b_(f) { }
+
+       /*!     \param R Red
+       **      \param G Green
+       **      \param B Blue
+       **      \param A Opacity(alpha) */
+       Color(const value_type& R, const value_type& G, const value_type& B, const value_type& A=1):
+               a_(A),
+               r_(R),
+               g_(G),
+               b_(B) { }
+
+       /*!     \param c Source for color components
+       **      \param A Opacity(alpha) */
+       Color(const Color& c, const value_type& A):
+               a_(A),
+               r_(c.r_),
+               g_(c.g_),
+               b_(c.b_) { }
+
+
+       //!     Copy constructor
+       Color(const Color& c):
+               a_(c.a_),
+               r_(c.r_),
+               g_(c.g_),
+               b_(c.b_) { }
+
+#ifdef USE_HALF_TYPE
+       friend class ColorAccumulator;
+       //!     Convert constructor
+       Color(const ColorAccumulator& c);
+#endif
+
+       //!     Copy constructor
+       //Color(const Color &c) { memcpy((void*)this, (const void*)&c, sizeof(Color)); }
+
+       /*const Color &operator=(const value_type &i)
+       {
+               r_ = g_ = b_ = a_ = i;
+               return *this;
+       }*/
+       //Color& operator=(const Color &c) { memcpy((void*)this, (const void*)&c, sizeof(Color)); return *this; }
+
+       //! Returns the RED component
+       const value_type& get_r()const { return r_; }
+
+       //! Returns the GREEN component
+       const value_type& get_g()const { return g_; }
+
+       //! Returns the BLUE component
+       const value_type& get_b()const { return b_; }
+
+       //! Returns the amount of opacity (alpha)
+       const value_type& get_a()const { return a_; }
+
+       //! Synonym for get_a(). \see get_a()
+       const value_type& get_alpha()const { return get_a(); }
+
+       //! Converts a 2 character hex string \a s (00-ff) into a ColorReal (0.0-1.0)
+       static ColorReal hex2real(String s);
+
+       //! Converts a ColorReal \a c (0.0-1.0) into a 2 character hex string (00-ff)
+       static const String real2hex(ColorReal c);
+
+       //! Returns the color as a 6 character hex sting
+       const String& get_hex()const { return hex_ = real2hex(r_)+real2hex(g_)+real2hex(b_); }
+
+       //! Sets the color's R, G, and B from a 3 or 6 character hex string
+       void set_hex(String& hex);
+
+       //! Sets the RED component to \a x
+       Color& set_r(const value_type& x) { r_ = x; return *this; }
+
+       //! Sets the GREEN component to \a x
+       Color& set_g(const value_type& x) { g_ = x; return *this; }
+
+       //! Sets the BLUE component to \a x
+       Color& set_b(const value_type& x) { b_ = x; return *this; }
+
+       //! Sets the opacity (alpha) to \a x
+       Color& set_a(const value_type& x) { a_ = x; return *this; }
+
+       //! Synonym for set_a(). \see set_a()
+       Color& set_alpha(const value_type& x) { return set_a(x); }
+
+       //! Returns color's luminance
+       float
+       get_y() const
+       {
+               return
+                       (float)get_r()*EncodeYUV[0][0]+
+                       (float)get_g()*EncodeYUV[0][1]+
+                       (float)get_b()*EncodeYUV[0][2];
+       }
+
+
+       //! Returns U component of chromanance
+       float
+       get_u() const
+       {
+               return
+                       (float)get_r()*EncodeYUV[1][0]+
+                       (float)get_g()*EncodeYUV[1][1]+
+                       (float)get_b()*EncodeYUV[1][2];
+       }
+
+
+       //! Returns V component of chromanance
+       float
+       get_v() const
+       {
+               return
+                       (float)get_r()*EncodeYUV[2][0]+
+                       (float)get_g()*EncodeYUV[2][1]+
+                       (float)get_b()*EncodeYUV[2][2];
+       }
+
+       //! Returns the color's saturation
+       /*!     This is is the magnitude of the U and V components.
+       **      \see set_s() */
+       float
+       get_s() const
+       {
+               const float u(get_u()), v(get_v());
+               return sqrt(u*u+v*v);
+       }
+
+       //! Sets the luminance (\a y) and chromanance (\a u and \a v)
+       Color&
+       set_yuv(const float &y, const float &u, const float &v)
+       {
+               set_r(y*DecodeYUV[0][0]+u*DecodeYUV[0][1]+v*DecodeYUV[0][2]);
+               set_g(y*DecodeYUV[1][0]+u*DecodeYUV[1][1]+v*DecodeYUV[1][2]);
+               set_b(y*DecodeYUV[2][0]+u*DecodeYUV[2][1]+v*DecodeYUV[2][2]);
+               return *this;
+       }
+
+       //! Sets color luminance
+       Color& set_y(const float &y) { return set_yuv(y,get_u(),get_v()); }
+
+       //! Set U component of chromanance
+       Color& set_u(const float &u) { return set_yuv(get_y(),u,get_v()); }
+
+       //! Set V component of chromanance
+       Color& set_v(const float &v) { return set_yuv(get_y(),get_u(),v); }
+
+       //! Set the U and V components of chromanance
+       Color& set_uv(const float& u, const float& v) { return set_yuv(get_y(),u,v); }
+
+       //! Sets the color's saturation
+       /*!     \see get_s() */
+       Color&
+       set_s(const float &x)
+       {
+               float u(get_u()), v(get_v());
+               const float s(sqrt(u*u+v*v));
+               if(s)
+               {
+                       u=(u/s)*x;
+                       v=(v/s)*x;
+                       return set_uv(u,v);
+               }
+               return *this;
+       }
+
+       //! YUV Color constructor
+       static Color YUV(const float& y, const float& u, const float& v, const value_type& a=1)
+               { return Color().set_yuv(y,u,v).set_a(a); }
+
+#ifndef SYNFIG_NO_ANGLE
+       //! Returns the hue of the chromanance
+       /*!     This is the angle of the U and V components.
+       **      \see set_hue() */
+       Angle
+       get_hue() const
+               { return Angle::tan(get_u(),get_v()); }
+
+       //! Synonym for get_hue(). \see get_hue()
+       Angle get_uv_angle() const { return get_hue(); }
+
+       //! Sets the color's hue
+       /*!     \see get_hue() */
+       Color&
+       set_hue(const Angle& theta)
+       {
+               const float s(get_s());
+               const float
+                       u(s*(float)Angle::sin(theta).get()),
+                       v(s*(float)Angle::cos(theta).get());
+               return set_uv(u,v);
+       }
+
+       //! Synonym for set_hue(). \see set_hue()
+       Color& set_uv_angle(const Angle& theta) { return set_hue(theta); }
+
+       //! Rotates the chromanance vector by amount specified by \a theta
+       Color& rotate_uv(const Angle& theta)
+       {
+               const float     a(Angle::sin(theta).get()),     b(Angle::cos(theta).get());
+               const float     u(get_u()),     v(get_v());
+
+               return set_uv(b*u-a*v,a*u+b*v);
+       }
+
+       //! Sets the luminance (\a y) and chromanance (\a s and \a theta).
+       /*!     \param y Luminance
+       **      \param s Saturation
+       **      \param theta Hue */
+       Color& set_yuv(const float& y, const float& s, const Angle& theta)
+       {
+               return
+                       set_yuv(
+                               y,
+                               s*(float)Angle::sin(theta).get(),
+                               s*(float)Angle::cos(theta).get()
+                       );
+       }
+
+       //! YUV color constructor where the chroma is in the saturation/hue form.
+       /*!     \param y Luminance
+       **      \param s Saturation
+       **      \param theta Hue
+       **      \param a Opacity (alpha) */
+       static Color YUV(const float& y, const float& s, const Angle& theta, const value_type& a=1)
+               { return Color().set_yuv(y,s,theta).set_a(a); }
+
+#endif
+
+       //! Clamps a color so that its values are in range. Ignores attempting to visualize negative colors.
+       Color clamped()const;
+
+       //! Clamps a color so that its values are in range.
+       Color clamped_negative()const;
+
+       /* Preset Colors */
+
+       //! Preset Color Constructors
+       //@{
+#ifdef HAS_VIMAGE
+       static inline Color alpha() { return Color(0,0,0,0.0000001f); }
+#else
+       static inline Color alpha() { return Color(0,0,0,0); }
+#endif
+       static inline Color black() { return Color(0,0,0); }
+       static inline Color white() { return Color(1,1,1); }
+       static inline Color gray() { return Color(0.5f,0.5f,0.5f); }
+       static inline Color magenta() { return Color(1,0,1); }
+       static inline Color red() { return Color(1,0,0); }
+       static inline Color green() { return Color(0,1,0); }
+       static inline Color blue() { return Color(0,0,1); }
+       static inline Color cyan() { return Color(0,1,1); }
+       static inline Color yellow() { return Color(1,1,0); }
+       //@}
+
+       //! \writeme
+       enum BlendMethod
+       {
+               BLEND_COMPOSITE=0,      //!< Color A is composited onto B (Taking into about A's alpha)
+               BLEND_STRAIGHT=1,       //!< Straight linear interpolation from A->B (Alpha ignored)
+               BLEND_BRIGHTEN=2,       //!< If composite is brighter than B, use composite. B otherwise.
+               BLEND_DARKEN=3,         //!< If composite is brighter than B, use composite. B otherwise.
+               BLEND_ADD=4,            //!< Simple A+B.
+               BLEND_SUBTRACT=5,       //!< Simple A-B.
+               BLEND_MULTIPLY=6,       //!< Simple A*B.
+               BLEND_DIVIDE=7,         //!< Simple B/A
+               BLEND_COLOR=8,          //!< Preserves the U and V channels of color A
+               BLEND_HUE=9,            //!< Preserves the angle of the UV vector of color A
+               BLEND_SATURATION=10,//!< Preserves the magnitude of the UV Vector of color A
+               BLEND_LUMINANCE=11,     //!< Preserves the Y channel of color A
+               BLEND_BEHIND=12,        //!< Similar to BLEND_COMPOSITE, except that B is composited onto A.
+               BLEND_ONTO=13,          //!< Similar to BLEND_COMPOSITE, except that B's alpha is maintained
+               BLEND_SCREEN=16,                //!< \writeme
+               BLEND_OVERLAY=20,               //!< \writeme
+               BLEND_DIFFERENCE=18,            //!< \writeme
+               BLEND_HARD_LIGHT=17,            //!< \writeme
+
+               //! Deprecated
+               BLEND_ALPHA_BRIGHTEN=14,        //!< If A is less opaque than B, use A
+               BLEND_ALPHA_DARKEN=15,          //!< If A is more opaque than B, use B
+               BLEND_ALPHA_OVER=19,//!< multiply alphas and then straight blends that using the amount
+               BLEND_STRAIGHT_ONTO=21,//!< \writeme
+
+               BLEND_END=22                    //!< \internal
+       };
+
+       /* Other */
+       static Color blend(Color a, Color b,float amount,BlendMethod type=BLEND_COMPOSITE);
+
+       static bool is_onto(BlendMethod x)
+       {
+               return x==BLEND_BRIGHTEN
+                       || x==BLEND_DARKEN
+                       || x==BLEND_ADD
+                       || x==BLEND_SUBTRACT
+                       || x==BLEND_MULTIPLY
+                       || x==BLEND_DIVIDE
+                       || x==BLEND_COLOR
+                       || x==BLEND_HUE
+                       || x==BLEND_SATURATION
+                       || x==BLEND_LUMINANCE
+                       || x==BLEND_ONTO
+                       || x==BLEND_STRAIGHT_ONTO
+                       || x==BLEND_SCREEN
+                       || x==BLEND_OVERLAY
+                       || x==BLEND_DIFFERENCE
+                       || x==BLEND_HARD_LIGHT
+               ;
+       }
+/*protected:
+
+       value_type& operator[](const int i)
+       {
+               assert(i>=0);
+               assert(i<(signed)(sizeof(Color)/sizeof(value_type)));
+               return (&r_)[i];
+       }
+
+       const value_type& operator[](const int i)const
+       {
+               assert(i>=0);
+               assert(i<(signed)(sizeof(Color)/sizeof(value_type)));
+               return (&r_)[i];
+       }
+*/
+}; // END of class Color
+
+#ifndef USE_HALF_TYPE
+typedef Color ColorAccumulator;
+#else
+class ColorAccumulator
+{
+       friend class Color;
+public:
+       typedef float value_type;
+
+private:
+       value_type a_, r_, g_, b_;
+
+public:
+
+       ColorAccumulator &
+       operator+=(const ColorAccumulator &rhs)
+       {
+               r_+=rhs.r_;
+               g_+=rhs.g_;
+               b_+=rhs.b_;
+               a_+=rhs.a_;
+               return *this;
+       }
+
+       ColorAccumulator &
+       operator-=(const ColorAccumulator &rhs)
+       {
+               r_-=rhs.r_;
+               g_-=rhs.g_;
+               b_-=rhs.b_;
+               a_-=rhs.a_;
+               return *this;
+       }
+
+       ColorAccumulator &
+       operator*=(const float &rhs)
+       {
+               r_*=rhs;
+               g_*=rhs;
+               b_*=rhs;
+               a_*=rhs;
+               return *this;
+       }
+
+       ColorAccumulator &
+       operator/=(const float &rhs)
+       {
+               const float temp(value_type(1)/rhs);
+               r_*=temp;
+               g_*=temp;
+               b_*=temp;
+               a_*=temp;
+               return *this;
+       }
+
+       ColorAccumulator
+       operator+(const ColorAccumulator &rhs)const
+       { return Color(*this)+=rhs; }
+
+       ColorAccumulator
+       operator-(const ColorAccumulator &rhs)const
+       { return Color(*this)-=rhs; }
+
+       ColorAccumulator
+       operator*(const float &rhs)const
+       { return Color(*this)*=rhs; }
+
+       ColorAccumulator
+       operator/(const float &rhs)const
+       { return Color(*this)/=rhs; }
+
+       bool
+       operator==(const ColorAccumulator &rhs)const
+       { return r_==rhs.r_ && g_==rhs.g_ && b_==rhs.b_ && a_!=rhs.a_; }
+
+       bool
+       operator!=(const ColorAccumulator &rhs)const
+       { return r_!=rhs.r_ || g_!=rhs.g_ || b_!=rhs.b_ || a_!=rhs.a_; }
+
+       Color
+       operator-()const
+       { return ColorAccumulator(-r_,-g_,-b_,-a_); }
+
+       bool is_valid()const
+       { return !isnan(r_) && !isnan(g_) && !isnan(b_) && !isnan(a_); }
+
+public:
+       ColorAccumulator() { }
+
+       /*!     \param R Red
+       **      \param G Green
+       **      \param B Blue
+       **      \param A Opacity(alpha) */
+       ColorAccumulator(const value_type& R, const value_type& G, const value_type& B, const value_type& A=1):
+               a_(A),
+               r_(R),
+               g_(G),
+               b_(B) { }
+
+       //!     Copy constructor
+       ColorAccumulator(const ColorAccumulator& c):
+               a_(c.a_),
+               r_(c.r_),
+               g_(c.g_),
+               b_(c.b_) { }
+
+       //!     Converter
+       ColorAccumulator(const Color& c):
+               a_(c.a_),
+               r_(c.r_),
+               g_(c.g_),
+               b_(c.b_) { }
+
+       //! Converter
+       ColorAccumulator(int c): a_(c),r_(c), g_(c), b_(c) { }
+
+       //! Returns the RED component
+       const value_type& get_r()const { return r_; }
+
+       //! Returns the GREEN component
+       const value_type& get_g()const { return g_; }
+
+       //! Returns the BLUE component
+       const value_type& get_b()const { return b_; }
+
+       //! Returns the amount of opacity (alpha)
+       const value_type& get_a()const { return a_; }
+
+       //! Synonym for get_a(). \see get_a()
+       const value_type& get_alpha()const { return get_a(); }
+
+       //! Sets the RED component to \a x
+       ColorAccumulator& set_r(const value_type& x) { r_ = x; return *this; }
+
+       //! Sets the GREEN component to \a x
+       ColorAccumulator& set_g(const value_type& x) { g_ = x; return *this; }
+
+       //! Sets the BLUE component to \a x
+       ColorAccumulator& set_b(const value_type& x) { b_ = x; return *this; }
+
+       //! Sets the opacity (alpha) to \a x
+       ColorAccumulator& set_a(const value_type& x) { a_ = x; return *this; }
+
+       //! Synonym for set_a(). \see set_a()
+       ColorAccumulator& set_alpha(const value_type& x) { return set_a(x); }
+};
+
+inline
+Color::Color(const ColorAccumulator& c):
+       a_(c.a_),
+       r_(c.r_),
+       g_(c.g_),
+       b_(c.b_) { }
+
+#endif
+
+
+
+
+
+enum PixelFormat
+{
+/* Bit Descriptions (ON/OFF)
+** ----+-------------
+** 0   Color Channels (Gray/RGB)
+** 1   Alpha Channel (WITH/WITHOUT)
+** 2   ZDepth  (WITH/WITHOUT)
+** 3   Endian (BGR/RGB)
+** 4   Alpha Location (Start/End)
+** 5   ZDepth Location (Start/End)
+** 6   Alpha/ZDepth Arangement (ZA,AZ)
+** 7   Alpha Range (Inverted,Normal)
+** 8   Z Range (Inverted,Normal)
+*/
+       PF_RGB=0,
+       PF_GRAY=(1<<0),                 //!< If set, use one grayscale channel. If clear, use three channels for RGB
+       PF_A=(1<<1),                    //!< If set, include alpha channel
+       PF_Z=(1<<2),                    //!< If set, include ZDepth channel
+       PF_BGR=(1<<3),                  //!< If set, reverse the order of the RGB channels
+       PF_A_START=(1<<4),              //!< If set, alpha channel is before the color data. If clear, it is after.
+       PF_Z_START=(1<<5),              //!< If set, ZDepth channel is before the color data. If clear, it is after.
+       PF_ZA=(1<<6),                   //!< If set, the ZDepth channel will be infront of the alpha channel. If clear, they are reversed.
+
+       PF_A_INV=(1<<7),                //!< If set, the alpha channel is stored as 1.0-a
+       PF_Z_INV=(1<<8),                //!< If set, the ZDepth channel is stored as 1.0-z
+       PF_RAW_COLOR=(1<<9)+(1<<1)      //!< If set, the data represents a raw Color datastructure, and all other bits are ignored.
+};
+
+inline PixelFormat operator|(PixelFormat lhs, PixelFormat rhs)
+       { return static_cast<PixelFormat>((int)lhs|(int)rhs); }
+
+inline PixelFormat operator&(PixelFormat lhs, PixelFormat rhs)
+       { return static_cast<PixelFormat>((int)lhs&(int)rhs); }
+#define FLAGS(x,y)             (((x)&(y))==(y))
+
+//! Returns the number of channels that the given PixelFormat calls for
+inline int
+channels(PixelFormat x)
+{
+       int chan=0;
+       if(FLAGS(x,PF_GRAY))
+               ++chan;
+       else
+               chan+=3;
+       if(FLAGS(x,PF_A))
+               ++chan;
+       if(FLAGS(x,PF_Z))
+               ++chan;
+       if(FLAGS(x,PF_RAW_COLOR))
+               chan=sizeof(Color);
+
+       return chan;
+}
+
+inline unsigned char *
+Color2PixelFormat(const Color &color, const PixelFormat &pf, unsigned char *out, const Gamma &gamma)
+{
+       if(FLAGS(pf,PF_RAW_COLOR))
+       {
+               Color *outcol=reinterpret_cast<Color *>(out);
+               *outcol=color;
+               out+=sizeof(color);
+               return out;
+       }
+
+       int alpha=(int)((FLAGS(pf,PF_A_INV)?(-(float)color.get_a()+1):(float)color.get_a())*255);
+       if(alpha<0)alpha=0;
+       if(alpha>255)alpha=255;
+
+       if(FLAGS(pf,PF_ZA|PF_A_START|PF_Z_START))
+       {
+               if(FLAGS(pf,PF_Z_START))
+                       *out++/*=(unsigned char)(color.GetZ()*255.0f)*/;
+               if(FLAGS(pf,PF_A_START))
+                       *out++=static_cast<unsigned char>(alpha);
+       }
+       else
+       {
+               if(FLAGS(pf,PF_A_START))
+                       *out++=static_cast<unsigned char>(alpha);
+               if(FLAGS(pf,PF_Z_START))
+                       *out++/*=(unsigned char)(color.GetZ()*255.0f)*/;
+
+       }
+
+       if(FLAGS(pf,PF_GRAY))
+               *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_y()));
+       else
+       {
+               if(FLAGS(pf,PF_BGR))
+               {
+                       *out++=static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_b()));
+                       *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
+                       *out++=static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_r()));
+               }
+               else
+               {
+                       *out++=static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_r()));
+                       *out++=static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
+                       *out++=static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_b()));
+               }
+       }
+
+       if(FLAGS(pf,PF_ZA))
+       {
+               if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
+                       out++;//*out++=(unsigned char)(color.GetZ()*255.0f);
+               if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
+                       *out++=static_cast<unsigned char>(alpha);
+       }
+       else
+       {
+               if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
+                       out++;//*out++=(unsigned char)(color.GetZ()*255.0f);
+               if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
+                       *out++=static_cast<unsigned char>(alpha);
+       }
+       return out;
+}
+
+inline void
+convert_color_format(unsigned char *dest, const Color *src, int w, PixelFormat pf,const Gamma &gamma)
+{
+       assert(w>=0);
+       while(w--)
+               dest=Color2PixelFormat((*(src++)).clamped(),pf,dest,gamma);
+}
+
+inline const unsigned char *
+PixelFormat2Color(Color &color, const PixelFormat &pf,const unsigned char *out)
+{
+       if(FLAGS(pf,PF_ZA|PF_A_START|PF_Z_START))
+       {
+               if(FLAGS(pf,PF_Z_START))
+                       out++;//color.SetZ((Color::value_type)*out++/255.0f);
+               if(FLAGS(pf,PF_A_START))
+                       color.set_a((float)*out++/255);
+       }
+       else
+       {
+               if(FLAGS(pf,PF_A_START))
+                       color.set_a((float)*out++/255);
+               if(FLAGS(pf,PF_Z_START))
+                       out++;//color.SetZ((Color::value_type)*out++/255.0f);
+       }
+
+       if(FLAGS(pf,PF_GRAY))
+               color.set_yuv((float)*out++/255,0,0);
+       else
+       {
+               if(FLAGS(pf,PF_BGR))
+               {
+                       color.set_b((float)*out++/255);
+                       color.set_g((float)*out++/255);
+                       color.set_r((float)*out++/255);
+               }
+               else
+               {
+                       color.set_r((float)*out++/255);
+                       color.set_g((float)*out++/255);
+                       color.set_b((float)*out++/255);
+               }
+       }
+
+       if(FLAGS(pf,PF_ZA))
+       {
+               if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
+                       out++;//color.SetZ((Color::value_type)*out++/255.0f);
+               if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
+                       color.set_a((float)*out++/255);
+       }
+       else
+       {
+               if(!FLAGS(pf,PF_A_START) && FLAGS(pf,PF_A))
+                       color.set_a((float)*out++/255);
+               if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
+                       out++;//color.SetZ((Color::value_type)*out++/255.0f);
+       }
+       return out;
+}
+
+
+
+}; // END of namespace synfig
+
+/* === E N D =============================================================== */
+
+#endif