| |
| |
| #ifndef T_PIXELUTILS_INCLUDED |
| #define T_PIXELUTILS_INCLUDED |
| |
| #include "tpixel.h" |
| #include "tpixelgr.h" |
| |
| #undef DVAPI |
| #undef DVVAR |
| #ifdef TCOLOR_EXPORTS |
| #define DVAPI DV_EXPORT_API |
| #define DVVAR DV_EXPORT_VAR |
| #else |
| #define DVAPI DV_IMPORT_API |
| #define DVVAR DV_IMPORT_VAR |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| |
| template <class T> |
| inline T blend(const T &a, const T &b, double t) |
| { |
| return T( |
| troundp((1 - t) * a.r + t * b.r), |
| troundp((1 - t) * a.g + t * b.g), |
| troundp((1 - t) * a.b + t * b.b), |
| troundp((1 - t) * a.m + t * b.m)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <class T> |
| inline T blend( |
| const T &a, |
| const T &b, |
| int num, int den) |
| { |
| return T( |
| (int)(((den - num) * a.r + num * b.r) / den), |
| (int)(((den - num) * a.g + num * b.g) / den), |
| (int)(((den - num) * a.b + num * b.b) / den), |
| (int)(((den - num) * a.m + num * b.m) / den)); |
| } |
| |
| template <class T> |
| inline T antialias( |
| const T &a, |
| int num) |
| { |
| return T( |
| (int)((num * a.r) / 255), |
| (int)((num * a.g) / 255), |
| (int)((num * a.b) / 255), |
| (int)((num * a.m) / 255)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <class T, class Q> |
| DVAPI inline T overPixT(const T &bot, const T &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| if (top.m == max) |
| return top; |
| |
| if (top.m == 0) |
| return bot; |
| |
| TUINT32 r = top.r + bot.r * (max - top.m) / max; |
| TUINT32 g = top.g + bot.g * (max - top.m) / max; |
| TUINT32 b = top.b + bot.b * (max - top.m) / max; |
| return T( |
| (r < max) ? (Q)r : (Q)max, |
| (g < max) ? (Q)g : (Q)max, |
| (b < max) ? (Q)b : (Q)max, |
| (bot.m == max) ? max : max - (max - bot.m) * (max - top.m) / max); |
| } |
| |
| |
| template <class T, class S, class Q> |
| DVAPI inline T overPixGRT(const T &bot, const S &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| if (top.value == max) |
| return T(top.value, top.value, top.value, top.value); |
| |
| if (top.value == 0) |
| return bot; |
| |
| double aux = (max - top.value) / max; |
| TUINT32 r = (TUINT32)(top.value + bot.r * aux); |
| TUINT32 g = (TUINT32)(top.value + bot.g * aux); |
| TUINT32 b = (TUINT32)(top.value + bot.b * aux); |
| return T( |
| (r < max) ? (Q)r : (Q)max, |
| (g < max) ? (Q)g : (Q)max, |
| (b < max) ? (Q)b : (Q)max, |
| (bot.m == max) ? max : (TUINT32)(max - (max - bot.m) * aux)); |
| } |
| |
| |
| |
| template <class T, class Q> |
| |
| DVAPI inline T quickOverPixT(const T &bot, const T &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| TUINT32 r = top.r + bot.r * (max - top.m) / max; |
| TUINT32 g = top.g + bot.g * (max - top.m) / max; |
| TUINT32 b = top.b + bot.b * (max - top.m) / max; |
| return T( |
| (r < max) ? (Q)r : (Q)max, |
| (g < max) ? (Q)g : (Q)max, |
| (b < max) ? (Q)b : (Q)max, |
| (bot.m == max) ? max : max - (max - bot.m) * (max - top.m) / max); |
| } |
| |
| |
| |
| template <class T, class Q> |
| |
| DVAPI inline T quickOverPixPremultT(const T &bot, const T &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| TUINT32 r = (top.r * top.m + bot.r * (max - top.m)) / max; |
| TUINT32 g = (top.g * top.m + bot.g * (max - top.m)) / max; |
| TUINT32 b = (top.b * top.m + bot.b * (max - top.m)) / max; |
| return T( |
| (r < max) ? (Q)r : (Q)max, |
| (g < max) ? (Q)g : (Q)max, |
| (b < max) ? (Q)b : (Q)max, |
| (bot.m == max) ? max : max - (max - bot.m) * (max - top.m) / max); |
| } |
| |
| |
| template <class T, class Q> |
| DVAPI inline T quickOverPixDarkenBlendedT(const T &bot, const T &top) |
| { |
| UINT max = T::maxChannelValue; |
| TUINT32 r = (top.r < bot.r) ? top.r : bot.r; |
| TUINT32 g = (top.g < bot.g) ? top.g : bot.g; |
| TUINT32 b = (top.b < bot.b) ? top.b : bot.b; |
| return T( |
| (Q)r, |
| (Q)g, |
| (Q)b, |
| max); |
| } |
| |
| |
| template <class T, class S, class Q> |
| DVAPI inline T quickOverPixGRT(const T &bot, const S &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| double aux = (max - top.value) / max; |
| TUINT32 r = (TUINT32)(top.value + bot.r * aux); |
| TUINT32 g = (TUINT32)(top.value + bot.g * aux); |
| TUINT32 b = (TUINT32)(top.value + bot.b * aux); |
| return T( |
| (r < max) ? (Q)r : (Q)max, |
| (g < max) ? (Q)g : (Q)max, |
| (b < max) ? (Q)b : (Q)max, |
| (bot.m == max) ? max : (TUINT32)(max - (max - bot.m) * aux)); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 overPix(const TPixel32 &bot, const TPixelGR8 &top) |
| { |
| return overPixGRT<TPixel32, TPixelGR8, UCHAR>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel64 overPix(const TPixel64 &bot, const TPixelGR16 &top) |
| { |
| return overPixGRT<TPixel64, TPixelGR16, USHORT>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 overPix(const TPixel32 &bot, const TPixel32 &top) |
| { |
| return overPixT<TPixel32, UCHAR>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel64 overPix(const TPixel64 &bot, const TPixel64 &top) |
| { |
| return overPixT<TPixel64, USHORT>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 quickOverPix(const TPixel32 &bot, const TPixelGR8 &top) |
| { |
| return quickOverPixGRT<TPixel32, TPixelGR8, UCHAR>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel64 quickOverPix(const TPixel64 &bot, const TPixelGR16 &top) |
| { |
| return quickOverPixGRT<TPixel64, TPixelGR16, USHORT>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 quickOverPix(const TPixel32 &bot, const TPixel32 &top) |
| { |
| return quickOverPixT<TPixel32, UCHAR>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 quickOverPixPremult(const TPixel32 &bot, const TPixel32 &top) |
| { |
| return quickOverPixPremultT<TPixel32, UCHAR>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel64 quickOverPix(const TPixel64 &bot, const TPixel64 &top) |
| { |
| return quickOverPixT<TPixel64, USHORT>(bot, top); |
| } |
| |
| |
| |
| DVAPI inline TPixel32 quickOverPixDarkenBlended(const TPixel32 &bot, const TPixel32 &top) |
| { |
| return quickOverPixDarkenBlendedT<TPixel32, UCHAR>(bot, top); |
| } |
| |
| |
| |
| template <class T, class Q> |
| DVAPI inline void overPix(T &outPix, const T &bot, const T &top) |
| { |
| UINT max = T::maxChannelValue; |
| |
| if (top.m == max) |
| outPix = top; |
| else if (top.m == 0) |
| outPix = bot; |
| else { |
| TUINT32 r = top.r + bot.r * (max - top.m) / max; |
| TUINT32 g = top.g + bot.g * (max - top.m) / max; |
| TUINT32 b = top.b + bot.b * (max - top.m) / max; |
| outPix.r = (r < max) ? (Q)r : (Q)max, |
| outPix.g = (g < max) ? (Q)g : (Q)max, |
| outPix.b = (b < max) ? (Q)b : (Q)max, |
| outPix.m = (bot.m == max) ? max : max - (max - bot.m) * (max - top.m) / max; |
| } |
| } |
| |
| |
| |
| DVAPI inline TPixel32 overPixOnWhite(const TPixel32 &top) |
| { |
| UINT max = TPixel32::maxChannelValue; |
| |
| if (top.m == max) |
| return top; |
| else if (top.m == 0) |
| return TPixel32::White; |
| else |
| return TPixel32(top.r + max - top.m, |
| top.g + max - top.m, |
| top.b + max - top.m, |
| max); |
| } |
| |
| DVAPI inline TPixel32 overPixOnBlack(const TPixel32 &top) |
| { |
| UINT max = TPixel32::maxChannelValue; |
| |
| if (top.m == max) |
| return top; |
| |
| if (top.m == 0) |
| return TPixel32::Black; |
| |
| return TPixel32(top.r, top.g, top.b, max); |
| } |
| |
| |
| |
| |
| |
| |
| DVAPI inline TPixelGR8 over(const TPixelGR8 &bot, const TPixelGR8 &top) |
| { |
| return TPixelGR8(tmin(bot.value, top.value)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| DVAPI inline void premult(TPixel32 &pix) |
| { |
| const int MAGICFAC = (257U * 256U + 1U); |
| UINT fac = MAGICFAC * pix.m; |
| |
| pix.r = (UINT)(pix.r * fac + (1U << 23)) >> 24; |
| pix.g = (UINT)(pix.g * fac + (1U << 23)) >> 24; |
| pix.b = (UINT)(pix.b * fac + (1U << 23)) >> 24; |
| } |
| |
| DVAPI inline void premult(TPixel64 &pix) |
| { |
| pix.r = pix.r * pix.m / 65535.0; |
| pix.g = pix.g * pix.m / 65535.0; |
| pix.b = pix.b * pix.m / 65535.0; |
| } |
| |
| DVAPI inline void depremult(TPixel32 &pix) |
| { |
| float fac = 255.0f / pix.m; |
| pix.r = tmin(pix.r * fac, 255.0f); |
| pix.g = tmin(pix.g * fac, 255.0f); |
| pix.b = tmin(pix.b * fac, 255.0f); |
| } |
| |
| DVAPI inline void depremult(TPixel64 &pix) |
| { |
| double fac = 65535.0 / pix.m; |
| pix.r = tmin(pix.r * fac, 65535.0); |
| pix.g = tmin(pix.g * fac, 65535.0); |
| pix.b = tmin(pix.b * fac, 65535.0); |
| } |
| |
| |
| |
| template <typename Chan> |
| const double *premultiplyTable(); |
| |
| template <typename Chan> |
| const double *depremultiplyTable(); |
| |
| |
| |
| DVAPI inline TPixel32 premultiply(const TPixel32 &pix) |
| { |
| const int MAGICFAC = (257U * 256U + 1U); |
| UINT fac = MAGICFAC * pix.m; |
| |
| return TPixel32( |
| ((UINT)(pix.r * fac + (1U << 23)) >> 24), |
| ((UINT)(pix.g * fac + (1U << 23)) >> 24), |
| ((UINT)(pix.b * fac + (1U << 23)) >> 24), |
| pix.m); |
| } |
| |
| DVAPI inline TPixel64 premultiply(const TPixel64 &pix) |
| { |
| return TPixel64( |
| pix.r * pix.m / 65535.0, |
| pix.g * pix.m / 65535.0, |
| pix.b * pix.m / 65535.0, |
| pix.m); |
| } |
| |
| DVAPI inline TPixel32 depremultiply(const TPixel32 &pix) |
| { |
| return TPixel32( |
| pix.r * 255.0 / pix.m, |
| pix.g * 255.0 / pix.m, |
| pix.b * 255.0 / pix.m, |
| pix.m); |
| } |
| |
| DVAPI inline TPixel64 depremultiply(const TPixel64 &pix) |
| { |
| return TPixel64( |
| pix.r * 65535.0 / pix.m, |
| pix.g * 65535.0 / pix.m, |
| pix.b * 65535.0 / pix.m, |
| pix.m); |
| } |
| |
| |
| |
| |
| DVAPI void hsv2rgb(TPixel32 &dstRgb, int srcHsv[3], int maxHsv = 255); |
| |
| |
| |
| |
| |
| |
| |
| DVAPI void HSV2RGB(double hue, double sat, double value, |
| double *red, double *green, double *blue); |
| |
| |
| |
| DVAPI void rgb2hsv(int dstHsv[3], const TPixel32 &srcRgb, int maxHsv = 255); |
| |
| DVAPI void RGB2HSV(double r, double g, double b, |
| double *h, double *s, double *v); |
| |
| |
| |
| |
| |
| |
| |
| |
| DVAPI void HLS2RGB(double h, double l, double s, |
| double *r, double *g, double *b); |
| |
| |
| |
| |
| |
| |
| |
| |
| DVAPI void rgb2hls(double r, double g, double b, |
| double *h, double *l, double *s); |
| |
| DVAPI TPixel32 toPixel32(const TPixel64 &); |
| DVAPI TPixel32 toPixel32(const TPixelD &); |
| DVAPI TPixel32 toPixel32(const TPixelGR8 &); |
| |
| DVAPI TPixel64 toPixel64(const TPixel32 &); |
| DVAPI TPixel64 toPixel64(const TPixelD &); |
| DVAPI TPixel64 toPixel64(const TPixelGR8 &); |
| |
| DVAPI TPixelD toPixelD(const TPixel32 &); |
| DVAPI TPixelD toPixelD(const TPixel64 &); |
| DVAPI TPixelD toPixelD(const TPixelGR8 &); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <class T> |
| class PixelConverter |
| { |
| public: |
| inline static T from(const TPixel32 &pix); |
| inline static T from(const TPixel64 &pix); |
| inline static T from(const TPixelD &pix); |
| inline static T from(const TPixelGR8 &pix); |
| }; |
| |
| template <> |
| class PixelConverter<TPixel32> |
| { |
| public: |
| inline static TPixel32 from(const TPixel32 &pix) { return pix; } |
| inline static TPixel32 from(const TPixel64 &pix) { return toPixel32(pix); } |
| inline static TPixel32 from(const TPixelD &pix) { return toPixel32(pix); } |
| inline static TPixel32 from(const TPixelGR8 &pix) { return toPixel32(pix); } |
| }; |
| |
| template <> |
| class PixelConverter<TPixel64> |
| { |
| public: |
| inline static TPixel64 from(const TPixel32 &pix) { return toPixel64(pix); } |
| inline static TPixel64 from(const TPixel64 &pix) { return pix; } |
| inline static TPixel64 from(const TPixelD &pix) { return toPixel64(pix); } |
| inline static TPixel64 from(const TPixelGR8 &pix) { return toPixel64(pix); } |
| }; |
| |
| template <> |
| class PixelConverter<TPixelD> |
| { |
| public: |
| inline static TPixelD from(const TPixel32 &pix) { return toPixelD(pix); } |
| inline static TPixelD from(const TPixel64 &pix) { return toPixelD(pix); } |
| inline static TPixelD from(const TPixelD &pix) { return pix; } |
| inline static TPixelD from(const TPixelGR8 &pix) { return toPixelD(pix); } |
| }; |
| |
| |
| |
| template <class T> |
| void add(T &pixout, const T &pixin, double v) |
| { |
| TINT32 r, g, b, m; |
| r = pixout.r + tround(pixin.r * v); |
| g = pixout.g + tround(pixin.g * v); |
| b = pixout.b + tround(pixin.b * v); |
| m = pixout.m + tround(pixin.m * v); |
| pixout.r = tcrop<TINT32>(r, 0, T::maxChannelValue); |
| pixout.g = tcrop<TINT32>(g, 0, T::maxChannelValue); |
| pixout.b = tcrop<TINT32>(b, 0, T::maxChannelValue); |
| pixout.m = tcrop<TINT32>(m, 0, T::maxChannelValue); |
| } |
| |
| |
| |
| template <class T> |
| void sub(T &pixout, const T &pixin, double v) |
| { |
| TINT32 r, g, b, m; |
| r = pixout.r - (pixin.r * v); |
| g = pixout.g - (pixin.g * v); |
| b = pixout.b - (pixin.b * v); |
| m = pixout.m - (pixin.m * v); |
| pixout.r = tcrop<TINT32>(r, 0, T::maxChannelValue); |
| pixout.g = tcrop<TINT32>(g, 0, T::maxChannelValue); |
| pixout.b = tcrop<TINT32>(b, 0, T::maxChannelValue); |
| pixout.m = tcrop<TINT32>(m, 0, T::maxChannelValue); |
| } |
| |
| |
| |
| |
| |
| template <class T> |
| void mult(T &pixout, const T &pixin, double v) |
| { |
| double r, g, b, m; |
| r = pixin.r + v; |
| g = pixin.g + v; |
| b = pixin.b + v; |
| m = pixin.m + v; |
| pixout.r = (r < 0) ? 0 : ((r < T::maxChannelValue) ? troundp(r * (pixout.r / (double)T::maxChannelValue)) : pixout.r); |
| pixout.g = (g < 0) ? 0 : ((g < T::maxChannelValue) ? troundp(g * (pixout.g / (double)T::maxChannelValue)) : pixout.g); |
| pixout.b = (b < 0) ? 0 : ((b < T::maxChannelValue) ? troundp(b * (pixout.b / (double)T::maxChannelValue)) : pixout.b); |
| pixout.m = (m < 0) ? 0 : ((m < T::maxChannelValue) ? troundp(m * (pixout.m / (double)T::maxChannelValue)) : pixout.m); |
| } |
| |
| |
| |
| |
| template <class T> |
| void lighten(T &pixout, const T &pixin, double v) |
| { |
| pixout.r = pixin.r > pixout.r ? pixin.r : pixout.r; |
| pixout.g = pixin.g > pixout.g ? pixin.g : pixout.g; |
| pixout.b = pixin.b > pixout.b ? pixin.b : pixout.b; |
| pixout.m = pixin.m > pixout.m ? pixin.m : pixout.m; |
| } |
| |
| |
| |
| |
| template <class T> |
| void darken(T &pixout, const T &pixin, double v) |
| { |
| pixout.r = pixin.r < pixout.r ? pixin.r : pixout.r; |
| pixout.g = pixin.g < pixout.g ? pixin.g : pixout.g; |
| pixout.b = pixin.b < pixout.b ? pixin.b : pixout.b; |
| pixout.m = pixin.m < pixout.m ? pixin.m : pixout.m; |
| } |
| |
| #endif |
| |