//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. // //---------------------------------------------------------------------------- // // color types gray8, gray16 // //---------------------------------------------------------------------------- #ifndef AGG_COLOR_GRAY_INCLUDED #define AGG_COLOR_GRAY_INCLUDED #include "agg_basics.h" #include "agg_color_rgba.h" namespace agg { //===================================================================gray8 template struct gray8T { typedef int8u value_type; typedef int32u calc_type; typedef int32 long_type; enum base_scale_e { base_shift = 8, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef gray8T self_type; value_type v; value_type a; static value_type luminance(const rgba& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); } static value_type luminance(const rgba8& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type((55u * c.r + 184u * c.g + 18u * c.b) >> 8); } static void convert(gray8T& dst, const gray8T& src) { dst.v = sRGB_conv::rgb_from_sRGB(src.v); dst.a = src.a; } static void convert(gray8T& dst, const gray8T& src) { dst.v = sRGB_conv::rgb_to_sRGB(src.v); dst.a = src.a; } static void convert(gray8T& dst, const rgba8& src) { dst.v = luminance(src); dst.a = src.a; } static void convert(gray8T& dst, const srgba8& src) { // The RGB weights are only valid for linear values. convert(dst, rgba8(src)); } static void convert(gray8T& dst, const rgba8& src) { dst.v = sRGB_conv::rgb_to_sRGB(luminance(src)); dst.a = src.a; } static void convert(gray8T& dst, const srgba8& src) { // The RGB weights are only valid for linear values. convert(dst, rgba8(src)); } //-------------------------------------------------------------------- gray8T() {} //-------------------------------------------------------------------- explicit gray8T(unsigned v_, unsigned a_ = base_mask) : v(int8u(v_)), a(int8u(a_)) {} //-------------------------------------------------------------------- gray8T(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- gray8T(const rgba& c) : v(luminance(c)), a(value_type(uround(c.a * base_mask))) {} //-------------------------------------------------------------------- template gray8T(const gray8T& c) { convert(*this, c); } //-------------------------------------------------------------------- template gray8T(const rgba8T& c) { convert(*this, c); } //-------------------------------------------------------------------- template T convert_from_sRGB() const { typename T::value_type y = sRGB_conv::rgb_from_sRGB(v); return T(y, y, y, sRGB_conv::alpha_from_sRGB(a)); } template T convert_to_sRGB() const { typename T::value_type y = sRGB_conv::rgb_to_sRGB(v); return T(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- rgba8 make_rgba8(const linear&) const { return rgba8(v, v, v, a); } rgba8 make_rgba8(const sRGB&) const { return convert_from_sRGB(); } operator rgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- srgba8 make_srgba8(const linear&) const { return convert_to_sRGB(); } srgba8 make_srgba8(const sRGB&) const { return srgba8(v, v, v, a); } operator srgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- rgba16 make_rgba16(const linear&) const { rgba16::value_type rgb = (v << 8) | v; return rgba16(rgb, rgb, rgb, (a << 8) | a); } rgba16 make_rgba16(const sRGB&) const { return convert_from_sRGB(); } operator rgba16() const { return make_rgba16(Colorspace()); } //-------------------------------------------------------------------- rgba32 make_rgba32(const linear&) const { rgba32::value_type v32 = v / 255.0f; return rgba32(v32, v32, v32, a / 255.0f); } rgba32 make_rgba32(const sRGB&) const { return convert_from_sRGB(); } operator rgba32() const { return make_rgba32(Colorspace()); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, value_type b) { return multiply(a, b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply(b, a); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- self_type& premultiply() { if (a < base_mask) { if (a == 0) v = 0; else v = multiply(v, a); } return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < base_mask) { if (a == 0) { v = 0; } else { calc_type v_ = (calc_type(v) * base_mask) / a; v = value_type((v_ > base_mask) ? (value_type)base_mask : v_); } } return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { self_type ret; calc_type ik = uround(k * base_scale); ret.v = lerp(v, c.v, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cv = v + c.v; ca = a + c.a; } } else { cv = v + mult_cover(c.v, cover); ca = a + mult_cover(c.a, cover); } v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; typedef gray8T gray8; typedef gray8T sgray8; //==================================================================gray16 struct gray16 { typedef int16u value_type; typedef int32u calc_type; typedef int64 long_type; enum base_scale_e { base_shift = 16, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef gray16 self_type; value_type v; value_type a; static value_type luminance(const rgba& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); } static value_type luminance(const rgba16& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type((13933u * c.r + 46872u * c.g + 4732u * c.b) >> 16); } static value_type luminance(const rgba8& c) { return luminance(rgba16(c)); } static value_type luminance(const srgba8& c) { return luminance(rgba16(c)); } static value_type luminance(const rgba32& c) { return luminance(rgba(c)); } //-------------------------------------------------------------------- gray16() {} //-------------------------------------------------------------------- explicit gray16(unsigned v_, unsigned a_ = base_mask) : v(int16u(v_)), a(int16u(a_)) {} //-------------------------------------------------------------------- gray16(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- gray16(const rgba& c) : v(luminance(c)), a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- gray16(const rgba8& c) : v(luminance(c)), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const srgba8& c) : v(luminance(c)), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const rgba16& c) : v(luminance(c)), a(c.a) {} //-------------------------------------------------------------------- gray16(const gray8& c) : v((value_type(c.v) << 8) | c.v), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const sgray8& c) : v(sRGB_conv::rgb_from_sRGB(c.v)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- operator rgba8() const { return rgba8(v >> 8, v >> 8, v >> 8, a >> 8); } //-------------------------------------------------------------------- operator srgba8() const { value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator rgba16() const { return rgba16(v, v, v, a); } //-------------------------------------------------------------------- operator rgba32() const { rgba32::value_type v32 = v / 65535.0f; return rgba32(v32, v32, v32, a / 65535.0f); } //-------------------------------------------------------------------- operator gray8() const { return gray8(v >> 8, a >> 8); } //-------------------------------------------------------------------- operator sgray8() const { return sgray8( sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int16u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, almost exact over int16u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, b << 8 | b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return mult_cover(b, a) >> 8; } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if(a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- self_type& premultiply() { if (a < base_mask) { if(a == 0) v = 0; else v = multiply(v, a); } return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < base_mask) { if (a == 0) { v = 0; } else { calc_type v_ = (calc_type(v) * base_mask) / a; v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_); } } return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { self_type ret; calc_type ik = uround(k * base_scale); ret.v = lerp(v, c.v, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cv = v + c.v; ca = a + c.a; } } else { cv = v + mult_cover(c.v, cover); ca = a + mult_cover(c.a, cover); } v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; //===================================================================gray32 struct gray32 { typedef float value_type; typedef double calc_type; typedef double long_type; typedef gray32 self_type; value_type v; value_type a; // Calculate grayscale value as per ITU-R BT.709. static value_type luminance(double r, double g, double b) { return value_type(0.2126 * r + 0.7152 * g + 0.0722 * b); } static value_type luminance(const rgba& c) { return luminance(c.r, c.g, c.b); } static value_type luminance(const rgba32& c) { return luminance(c.r, c.g, c.b); } static value_type luminance(const rgba8& c) { return luminance(c.r / 255.0, c.g / 255.0, c.g / 255.0); } static value_type luminance(const rgba16& c) { return luminance(c.r / 65535.0, c.g / 65535.0, c.g / 65535.0); } //-------------------------------------------------------------------- gray32() {} //-------------------------------------------------------------------- explicit gray32(value_type v_, value_type a_ = 1) : v(v_), a(a_) {} //-------------------------------------------------------------------- gray32(const self_type& c, value_type a_) : v(c.v), a(a_) {} //-------------------------------------------------------------------- gray32(const rgba& c) : v(luminance(c)), a(value_type(c.a)) {} //-------------------------------------------------------------------- gray32(const rgba8& c) : v(luminance(c)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const srgba8& c) : v(luminance(rgba32(c))), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const rgba16& c) : v(luminance(c)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- gray32(const rgba32& c) : v(luminance(c)), a(value_type(c.a)) {} //-------------------------------------------------------------------- gray32(const gray8& c) : v(value_type(c.v / 255.0)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const sgray8& c) : v(sRGB_conv::rgb_from_sRGB(c.v)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- gray32(const gray16& c) : v(value_type(c.v / 65535.0)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- operator rgba() const { return rgba(v, v, v, a); } //-------------------------------------------------------------------- operator gray8() const { return gray8(uround(v * 255.0), uround(a * 255.0)); } //-------------------------------------------------------------------- operator sgray8() const { // Return (non-premultiplied) sRGB values. return sgray8( sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator gray16() const { return gray16(uround(v * 65535.0), uround(a * 65535.0)); } //-------------------------------------------------------------------- operator rgba8() const { rgba8::value_type y = uround(v * 255.0); return rgba8(y, y, y, uround(a * 255.0)); } //-------------------------------------------------------------------- operator srgba8() const { srgba8::value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator rgba16() const { rgba16::value_type y = uround(v * 65535.0); return rgba16(y, y, y, uround(a * 65535.0)); } //-------------------------------------------------------------------- operator rgba32() const { return rgba32(v, v, v, a); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return a; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(a); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return 1; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a <= 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a >= 1; } //-------------------------------------------------------------------- static AGG_INLINE value_type invert(value_type x) { return 1 - x; } //-------------------------------------------------------------------- static AGG_INLINE value_type multiply(value_type a, value_type b) { return value_type(a * b); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { return (b == 0) ? 0 : value_type(a / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return n > 0 ? a / (1 << n) : a; } //-------------------------------------------------------------------- static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return value_type(a * b / cover_mask); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return cover_type(uround(a * b)); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return (1 - a) * p + q; // more accurate than "p + q - p * a" } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { // The form "p + a * (q - p)" avoids a multiplication, but may produce an // inaccurate result. For example, "p + (q - p)" may not be exactly equal // to q. Therefore, stick to the basic expression, which at least produces // the correct result at either extreme. return (1 - a) * p + a * q; } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = value_type(a_); return *this; } //-------------------------------------------------------------------- double opacity() const { return a; } //-------------------------------------------------------------------- self_type& premultiply() { if (a < 0) v = 0; else if(a < 1) v *= a; return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < 0) v = 0; else if (a < 1) v /= a; return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { return self_type( value_type(v + (c.v - v) * k), value_type(a + (c.a - a) * k)); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; } #endif