#pragma once #ifndef TCG_PIXEL_OPS_H #define TCG_PIXEL_OPS_H // tcg includes #include "base.h" namespace tcg { //************************************************************************** // Pixel Categories //************************************************************************** struct grayscale_pixel_tag { }; struct rgb_pixel_tag { }; struct rgbm_pixel_tag : public rgb_pixel_tag { }; struct indexed_pixel_tag { }; //************************************************************************** // Pixel Traits Types //************************************************************************** template struct pixel_traits_types; template struct pixel_traits_types { typedef Pix pixel_type; typedef grayscale_pixel_tag pixel_category; typedef typename Pix::channel_type channel_type; enum { channels_count = 1 }; }; template struct pixel_traits_types { typedef Pix pixel_type; typedef rgb_pixel_tag pixel_category; typedef typename Pix::channel_type channel_type; enum { channels_count = 3 }; }; template struct pixel_traits_types : public pixel_traits_types { typedef Pix pixel_type; typedef rgbm_pixel_tag pixel_category; typedef typename Pix::channel_type channel_type; enum { channels_count = 4 }; }; template struct pixel_traits_types { typedef Pix pixel_type; typedef indexed_pixel_tag pixel_category; typedef typename Pix::index_type index_type; }; //************************************************************************** // Pixel Traits //************************************************************************** template struct pixel_traits; template struct pixel_traits : public pixel_traits_types { typedef pixel_traits_types tr; public: static typename tr::channel_type max_channel_value(); static typename tr::channel_type l(const typename tr::pixel_type &pix); static typename tr::channel_type &l(typename tr::pixel_type &pix); }; template struct pixel_traits { typedef pixel_traits_types tr; public: static typename tr::channel_type max_channel_value(); static typename tr::channel_type r(const typename tr::pixel_type &pix); static typename tr::channel_type &r(typename tr::pixel_type &pix); static typename tr::channel_type g(const typename tr::pixel_type &pix); static typename tr::channel_type &g(typename tr::pixel_type &pix); static typename tr::channel_type b(const typename tr::pixel_type &pix); static typename tr::channel_type &b(typename tr::pixel_type &pix); }; template struct pixel_traits : public pixel_traits { typedef pixel_traits_types tr; public: static typename tr::channel_type m(const typename tr::pixel_type &pix); static typename tr::channel_type &m(typename tr::pixel_type &pix); }; template struct pixel_traits { typedef pixel_traits_types tr; typedef typename tr::pixel_type pixel_type; typedef typename tr::index_type index_type; public: static typename tr::index_type index(const typename tr::pixel_type &pix); static typename tr::index_type &index(typename tr::pixel_type &pix); }; namespace pixel_ops { //************************************************************************** // Pixel Functions //************************************************************************** template inline PixOut _cast(const PixIn &pix, grayscale_pixel_tag) { return PixOut(pixel_traits::l(pix)); } template inline PixOut _cast(const PixIn &pix, rgb_pixel_tag) { return PixOut(pixel_traits::r(pix), pixel_traits::g(pix), pixel_traits::b(pix)); } template inline PixOut _cast(const PixIn &pix, rgbm_pixel_tag) { return PixOut(pixel_traits::r(pix), pixel_traits::g(pix), pixel_traits::b(pix), pixel_traits::m(pix)); } template inline PixOut cast(const PixIn &pix) { return _cast(pix, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline void _assign(PixOut &pixout, const PixIn &pixin, grayscale_pixel_tag) { pixel_traits::l(pixout) = pixel_traits::l(pixin); } template inline void _assign(PixOut &pixout, const PixIn &pixin, rgb_pixel_tag) { pixel_traits::r(pixout) = pixel_traits::r(pixin); pixel_traits::g(pixout) = pixel_traits::g(pixin); pixel_traits::b(pixout) = pixel_traits::b(pixin); } template inline void _assign(PixOut &pixout, const PixIn &pixin, rgbm_pixel_tag) { pixel_traits::r(pixout) = pixel_traits::r(pixin); pixel_traits::g(pixout) = pixel_traits::g(pixin); pixel_traits::b(pixout) = pixel_traits::b(pixin); pixel_traits::m(pixout) = pixel_traits::m(pixin); } template inline void assign(PixOut &pixout, const PixIn &pixin) { _assign(pixout, pixin, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline Pix1 _sum(const Pix1 &a, const Pix2 &b, grayscale_pixel_tag) { return Pix1(pixel_traits::l(a) + pixel_traits::l(b)); } template inline Pix1 _sum(const Pix1 &a, const Pix2 &b, rgb_pixel_tag) { return Pix1(pixel_traits::r(a) + pixel_traits::r(b), pixel_traits::g(a) + pixel_traits::g(b), pixel_traits::b(a) + pixel_traits::b(b)); } template inline Pix1 _sum(const Pix1 &a, const Pix2 &b, rgbm_pixel_tag) { return Pix1(pixel_traits::r(a) + pixel_traits::r(b), pixel_traits::g(a) + pixel_traits::g(b), pixel_traits::b(a) + pixel_traits::b(b), pixel_traits::m(a) + pixel_traits::m(b)); } template inline Pix1 operator+(const Pix1 &a, const Pix2 &b) { return _sum(a, b, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline Pix1 _sub(const Pix1 &a, const Pix2 &b, grayscale_pixel_tag) { return Pix1(pixel_traits::l(a) - pixel_traits::l(b)); } template inline Pix1 _sub(const Pix1 &a, const Pix2 &b, rgb_pixel_tag) { return Pix1(pixel_traits::r(a) - pixel_traits::r(b), pixel_traits::g(a) - pixel_traits::g(b), pixel_traits::b(a) - pixel_traits::b(b)); } template inline Pix1 _sub(const Pix1 &a, const Pix2 &b, rgbm_pixel_tag) { return Pix1(pixel_traits::r(a) - pixel_traits::r(b), pixel_traits::g(a) - pixel_traits::g(b), pixel_traits::b(a) - pixel_traits::b(b), pixel_traits::m(a) - pixel_traits::m(b)); } template inline Pix1 operator-(const Pix1 &a, const Pix2 &b) { return _sub(a, b, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline Pix _mult(const Pix &a, Scalar k, grayscale_pixel_tag) { return Pix(pixel_traits::l(a) * k); } template inline Pix _mult(const Pix &a, Scalar k, rgb_pixel_tag) { return Pix(pixel_traits::r(a) * k, pixel_traits::g(a) * k, pixel_traits::b(a) * k); } template inline Pix _mult(const Pix &a, Scalar k, rgbm_pixel_tag) { return Pix(pixel_traits::r(a) * k, pixel_traits::g(a) * k, pixel_traits::b(a) * k, pixel_traits::m(a) * k); } template inline Pix operator*(Scalar k, const Pix &pix) { return _mult(pix, k, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline Pix _div(const Pix &a, Scalar k, grayscale_pixel_tag) { return Pix(pixel_traits::l(a) / k); } template inline Pix _div(const Pix &a, Scalar k, rgb_pixel_tag) { return Pix(pixel_traits::r(a) / k, pixel_traits::g(a) / k, pixel_traits::b(a) / k); } template inline Pix _div(const Pix &a, Scalar k, rgbm_pixel_tag) { return Pix(pixel_traits::r(a) / k, pixel_traits::g(a) / k, pixel_traits::b(a) / k, pixel_traits::m(a) / k); } template inline Pix operator/(const Pix &pix, Scalar k) { return _div(pix, k, typename pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline void premultiply(Pix &pix, Scalar = 0) { Scalar factor = pixel_traits::m(pix) / Scalar(pixel_traits::max_channel_value); pixel_traits::r(pix) = pixel_traits::r(pix) * factor; pixel_traits::g(pix) = pixel_traits::g(pix) * factor; pixel_traits::b(pix) = pixel_traits::b(pix) * factor; } //------------------------------------------------------------------ template inline void depremultiply(Pix &pix, Scalar = 0) { if (pixel_traits::channel_type m = pixel_traits::m(pix)) { Scalar factor = pixel_traits::max_channel_value / Scalar(m); pixel_traits::r(pix) = pixel_traits::r(pix) * factor; pixel_traits::g(pix) = pixel_traits::g(pix) * factor; pixel_traits::b(pix) = pixel_traits::b(pix) * factor; } } //------------------------------------------------------------------ template inline Pix _blend(const Pix &p0, const Pix &p1, Scalar t, grayscale_pixel_tag) { return Pix((1 - t) * pixel_traits::l(p0) + t * pixel_traits::l(p1)); } //------------------------------------------------------------------ template inline Pix _blend(const Pix &p0, const Pix &p1, Scalar t, rgb_pixel_tag) { Scalar one_t = 1 - t; return Pix( one_t * pixel_traits::r(p0) + t * pixel_traits::r(p1), one_t * pixel_traits::g(p0) + t * pixel_traits::g(p1), one_t * pixel_traits::m(p0) + t * pixel_traits::b(p1)); } //------------------------------------------------------------------ template inline Pix _blend(const Pix &p0, const Pix &p1, Scalar t, rgbm_pixel_tag) { Scalar one_t = 1 - t; return Pix( one_t * pixel_traits::r(p0) + t * pixel_traits::r(p1), one_t * pixel_traits::g(p0) + t * pixel_traits::g(p1), one_t * pixel_traits::b(p0) + t * pixel_traits::b(p1), one_t * pixel_traits::m(p0) + t * pixel_traits::m(p1)); } //------------------------------------------------------------------ template inline Pix blend(const Pix &p0, const Pix &p1, Scalar t) { return _blend(p0, p1, t, pixel_traits::pixel_category()); } //------------------------------------------------------------------ template inline void over_premult(Pix &down, const Pix &up, Scalar = 0) { Scalar t = (1 - pixel_traits::m(up) / Scalar(pixel_traits::max_channel_value)); pixel_traits::r(down) = pixel_traits::r(up) + t * pixel_traits::r(down); pixel_traits::g(down) = pixel_traits::g(up) + t * pixel_traits::g(down); pixel_traits::b(down) = pixel_traits::b(up) + t * pixel_traits::b(down); pixel_traits::m(down) = pixel_traits::m(up) + t * pixel_traits::m(down); } //------------------------------------------------------------------ template inline void over(Pix &down, const Pix &up, Scalar = 0) { Scalar t = (1 - pixel_traits::m(up) / Scalar(pixel_traits::max_channel_value)) * pixel_traits::m(down); Scalar m = pixel_traits::m(up) + t; Scalar up_fac = pixel_traits::m(up) / m; Scalar dn_fac = t / m; pixel_traits::r(down) = up_fac * pixel_traits::r(up) + dn_fac * pixel_traits::r(down); pixel_traits::g(down) = up_fac * pixel_traits::g(up) + dn_fac * pixel_traits::g(down); pixel_traits::b(down) = up_fac * pixel_traits::b(up) + dn_fac * pixel_traits::b(down); pixel_traits::m(down) = m; } } } // namespace tcg::pixel_ops #endif // TCG_PIXEL_OPS_H