agg/include/agg_color_gray.h

1048 lines
33 KiB
C++

//----------------------------------------------------------------------------
// 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<class Colorspace>
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<linear>& dst, const gray8T<sRGB>& src)
{
dst.v = sRGB_conv<value_type>::rgb_from_sRGB(src.v);
dst.a = src.a;
}
static void convert(gray8T<sRGB>& dst, const gray8T<linear>& src)
{
dst.v = sRGB_conv<value_type>::rgb_to_sRGB(src.v);
dst.a = src.a;
}
static void convert(gray8T<linear>& dst, const rgba8& src)
{
dst.v = luminance(src);
dst.a = src.a;
}
static void convert(gray8T<linear>& dst, const srgba8& src)
{
// The RGB weights are only valid for linear values.
convert(dst, rgba8(src));
}
static void convert(gray8T<sRGB>& dst, const rgba8& src)
{
dst.v = sRGB_conv<value_type>::rgb_to_sRGB(luminance(src));
dst.a = src.a;
}
static void convert(gray8T<sRGB>& 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<class T>
gray8T(const gray8T<T>& c)
{
convert(*this, c);
}
//--------------------------------------------------------------------
template<class T>
gray8T(const rgba8T<T>& c)
{
convert(*this, c);
}
//--------------------------------------------------------------------
template<class T>
T convert_from_sRGB() const
{
typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_from_sRGB(v);
return T(y, y, y, sRGB_conv<typename T::value_type>::alpha_from_sRGB(a));
}
template<class T>
T convert_to_sRGB() const
{
typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_to_sRGB(v);
return T(y, y, y, sRGB_conv<typename T::value_type>::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<srgba8>();
}
operator rgba8() const
{
return make_rgba8(Colorspace());
}
//--------------------------------------------------------------------
srgba8 make_srgba8(const linear&) const
{
return convert_to_sRGB<rgba8>();
}
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<rgba16>();
}
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<rgba32>();
}
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<typename T>
static AGG_INLINE T downscale(T a)
{
return a >> base_shift;
}
//--------------------------------------------------------------------
template<typename T>
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<linear> gray8;
typedef gray8T<sRGB> 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<value_type>::rgb_from_sRGB(c.v)),
a(sRGB_conv<value_type>::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<value_type>::rgb_to_sRGB(v);
return srgba8(y, y, y, sRGB_conv<value_type>::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<value_type>::rgb_to_sRGB(v),
sRGB_conv<value_type>::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<typename T>
static AGG_INLINE T downscale(T a)
{
return a >> base_shift;
}
//--------------------------------------------------------------------
template<typename T>
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<value_type>::rgb_from_sRGB(c.v)),
a(sRGB_conv<value_type>::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<value_type>::rgb_to_sRGB(v),
sRGB_conv<value_type>::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<value_type>::rgb_to_sRGB(v);
return srgba8(y, y, y, sRGB_conv<value_type>::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<typename T>
static AGG_INLINE T downscale(T a)
{
return a;
}
//--------------------------------------------------------------------
template<typename T>
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