diff options
Diffstat (limited to 'draw/imagedraw.c')
-rw-r--r-- | draw/imagedraw.c | 364 |
1 files changed, 124 insertions, 240 deletions
diff --git a/draw/imagedraw.c b/draw/imagedraw.c index a626deb7..b9bb2702 100644 --- a/draw/imagedraw.c +++ b/draw/imagedraw.c @@ -1,301 +1,194 @@ #include "fitz.h" -#define noNEAREST +#define LINEAR typedef unsigned char byte; -/* Sample image and clamp to edge */ - -static inline byte -getmask(byte *s, int w, int h, int u, int v) +static inline float roundup(float x) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s[w * v + u]; + return (x < 0) ? floorf(x) : ceilf(x); } -static inline byte * -getga(byte *s, int w, int h, int u, int v) +#ifdef LINEAR + +static inline int lerp(int a, int b, int t) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s + ((w * v + u) << 1); + return a + (((b - a) * t) >> 16); } -static inline byte * -getrgba(byte *s, int w, int h, int u, int v) +static inline int bilerp(int a, int b, int c, int d, int u, int v) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s + ((w * v + u) << 2); + return lerp(lerp(a, b, u), lerp(c, d, u), v); } -static inline int -getcolor(byte *s, int w, int h, int n, int u, int v, int k) +static inline byte *samplenearest(byte *s, int w, int h, int n, int u, int v) { if (u < 0) u = 0; if (v < 0) v = 0; if (u >= w) u = w - 1; if (v >= h) v = h - 1; - return s[w * v * n + u + k]; -} - -/* Bi-linear interpolation of sample */ - -static inline int -lerp(int a, int b, int t) -{ - return a + (((b - a) * t) >> 16); -} - -static inline void -lerpga(byte *dst, byte *a, byte *b, int t) -{ - dst[0] = lerp(a[0], b[0], t); - dst[1] = lerp(a[1], b[1], t); -} - -static inline void -lerprgba(byte *dst, byte *a, byte *b, int t) -{ - dst[0] = lerp(a[0], b[0], t); - dst[1] = lerp(a[1], b[1], t); - dst[2] = lerp(a[2], b[2], t); - dst[3] = lerp(a[3], b[3], t); -} - -static inline int -samplemask(byte *s, int w, int h, int u, int v) -{ -#ifdef NEAREST - return getmask(s, w, h, u >> 16, v >> 16); -#else - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - int a = getmask(s, w, h, ui, vi); - int b = getmask(s, w, h, ui+1, vi); - int c = getmask(s, w, h, ui, vi+1); - int d = getmask(s, w, h, ui+1, vi+1); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - return lerp(ab, cd, vd); -#endif + return s + (v * w + u) * n; } -static inline void -samplega(byte *s, int w, int h, int u, int v, int *gout, int *aout) -{ -#ifdef NEAREST - byte *ga = getga(s, w, h, u >> 16, v >> 16); - *gout = ga[0]; - *aout = ga[1]; -#else - byte ab[2]; - byte cd[2]; - byte abcd[2]; - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - byte *a = getga(s, w, h, ui, vi); - byte *b = getga(s, w, h, ui+1, vi); - byte *c = getga(s, w, h, ui, vi+1); - byte *d = getga(s, w, h, ui+1, vi+1); - lerpga(ab, a, b, ud); - lerpga(cd, c, d, ud); - lerpga(abcd, ab, cd, vd); - *gout = abcd[0]; - *aout = abcd[1]; #endif -} -static inline void -samplergba(byte *s, int w, int h, int u, int v, int *rout, int *gout, int *bout, int *aout) -{ -#ifdef NEAREST - byte *rgba = getrgba(s, w, h, u >> 16, v >> 16); - *rout = rgba[0]; - *gout = rgba[1]; - *bout = rgba[2]; - *aout = rgba[3]; -#else - byte ab[4]; - byte cd[4]; - byte abcd[4]; - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - byte *a = getrgba(s, w, h, ui, vi); - byte *b = getrgba(s, w, h, ui+1, vi); - byte *c = getrgba(s, w, h, ui, vi+1); - byte *d = getrgba(s, w, h, ui+1, vi+1); - lerprgba(ab, a, b, ud); - lerprgba(cd, c, d, ud); - lerprgba(abcd, ab, cd, vd); - *rout = abcd[0]; - *gout = abcd[1]; - *bout = abcd[2]; - *aout = abcd[3]; -#endif -} +/* Blend premultiplied source image in constant alpha over destination */ static inline void -samplecolor(byte *s, int w, int h, int n, int u, int v, byte *out) +fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { -#ifdef NEAREST - int k; - for (k = 0; k < n; k++) - out[k] = getcolor(s, w, h, n, u >> 16, v >> 16, k); -#else - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; int k; - for (k = 0; k < n; k++) - { - int a = getcolor(s, w, h, n, ui, vi, k); - int b = getcolor(s, w, h, n, ui+1, vi, k); - int c = getcolor(s, w, h, n, ui, vi+1, k); - int d = getcolor(s, w, h, n, ui+1, vi+1, k); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - out[k] = lerp(ab, cd, vd); - } -#endif -} - -/* Blend source image scanline over destination */ -#define INSIDEU u >= 0 && u <= (sw << 16) -#define INSIDEV v >= 0 && v <= (sh << 16) -#define INSIDE INSIDEU && INSIDEV - -static inline void -fz_blendscan1(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) -{ while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int a = samplemask(sp, sw, sh, u, v); - dp[0] = a + fz_mul255(dp[0], 255 - a); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, n, ui, vi); + byte *b = samplenearest(sp, sw, sh, n, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, n, ui, vi+1); + byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1); + int x = bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf); + int t = 255 - fz_mul255(x, alpha); + for (k = 0; k < n; k++) + { + x = bilerp(a[k], b[k], c[k], d[k], uf, vf); + dp[k] = x + fz_mul255(dp[k], t); + } +#else + byte *sample = sp + ((vi * sw + ui) * n); + int t = 255 - fz_mul255(sample[n-1], alpha); + for (k = 0; k < n; k++) + dp[k] = sample[k] + fz_mul255(dp[k], t); +#endif } - dp ++; + dp += n; u += fa; v += fb; } } +/* Blend premultiplied source image over destination */ + static inline void -fz_blendscan2(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) +fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) { + int k; + while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int g, a, t; - samplega(sp, sw, sh, u, v, &g, &a); - t = 255 - a; - dp[0] = g + fz_mul255(dp[0], t); - dp[1] = a + fz_mul255(dp[1], t); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, n, ui, vi); + byte *b = samplenearest(sp, sw, sh, n, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, n, ui, vi+1); + byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1); + int t = 255 - bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf); + for (k = 0; k < n; k++) + { + int x = bilerp(a[k], b[k], c[k], d[k], uf, vf); + dp[k] = x + fz_mul255(dp[k], t); + } +#else + byte *sample = sp + ((vi * sw + ui) * n); + int t = 255 - sample[n-1]; + for (k = 0; k < n; k++) + dp[k] = sample[k] + fz_mul255(dp[k], t); +#endif } - dp += 2; + dp += n; u += fa; v += fb; } } +/* Blend non-premultiplied color in source image mask over destination */ + static inline void -fz_blendscan4(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) +fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) { + int sa = color[n-1]; + int k; + while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int r, g, b, a, t; - samplergba(sp, sw, sh, u, v, &r, &g, &b, &a); - t = 255 - a; - dp[0] = r + fz_mul255(dp[0], t); - dp[1] = g + fz_mul255(dp[1], t); - dp[2] = b + fz_mul255(dp[2], t); - dp[3] = a + fz_mul255(dp[3], t); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, 1, ui, vi); + byte *b = samplenearest(sp, sw, sh, 1, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, 1, ui, vi+1); + byte *d = samplenearest(sp, sw, sh, 1, ui+1, vi+1); + int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf); +#else + int ma = sp[vi * sw + ui]; +#endif + int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); + for (k = 0; k < n - 1; k++) + dp[k] = FZ_BLEND(color[k], dp[k], masa); + dp[k] = FZ_BLEND(255, dp[k], masa); } - dp += 4; + dp += n; u += fa; v += fb; } } -static inline void -fz_blendscan(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w, int n) +void +fz_paintaffine(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { - while (w--) + if (alpha == 255) { - if (INSIDE) + switch (n) { - unsigned char color[FZ_MAXCOLORS+1]; - int k, t; - samplecolor(sp, sw, sh, n, u, v, color); - t = 255 - color[n-1]; - for (k = 0; k < n; k++) - dp[k] = color[k] + fz_mul255(dp[k], t); + case 1: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; + case 2: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; + case 4: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; + default: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, n); break; } - dp += n; - u += fa; - v += fb; } -} - -/* Blend non-premultiplied color in image mask over destination */ - -static inline void -fz_blendscanwithcolor(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w, int n, unsigned char *color) -{ - int sa = color[n-1]; - while (w--) + else if (alpha > 0) { - if (INSIDE) + switch (n) { - int ma = samplemask(sp, sw, sh, u, v); - int masa = fz_mul255(sa, ma); - int t = 255 - masa; - int k; - for (k = 0; k < n; k++) - dp[k] = fz_mul255(color[k], ma) + fz_mul255(dp[k], t); + case 1: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; + case 2: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; + case 4: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; + default: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; } - dp += n; - u += fa; - v += fb; } } -/* Draw an image with an affine transform on destination */ - -static inline float roundup(float x) +void +fz_paintaffinecolor(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) { - return (x < 0) ? floorf(x) : ceilf(x); + switch (n) + { + case 2: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; + case 4: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; + default: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; + } } +/* Draw an image with an affine transform on destination */ + static void -fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, - unsigned char *color) +fz_paintimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color, int alpha) { - unsigned char *dp, *sp; + byte *dp, *sp; int u, v, fa, fb, fc, fd; int x, y, w, h; int sw, sh, n; @@ -339,22 +232,14 @@ fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, sw = img->w; sh = img->h; + /* TODO: if (fb == 0 && fa == 1) call fz_paintspan */ + while (h--) { if (color) - { - fz_blendscanwithcolor(dp, sp, sw, sh, u, v, fa, fb, w, n, color); - } + fz_paintaffinecolor(dp, sp, sw, sh, u, v, fa, fb, w, n, color); else - { - switch (n) - { - case 1: fz_blendscan1(dp, sp, sw, sh, u, v, fa, fb, w); break; - case 2: fz_blendscan2(dp, sp, sw, sh, u, v, fa, fb, w); break; - case 4: fz_blendscan4(dp, sp, sw, sh, u, v, fa, fb, w); break; - default: fz_blendscan(dp, sp, sw, sh, u, v, fa, fb, w, n); break; - } - } + fz_paintaffine(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); dp += dst->w * n; u += fc; v += fd; @@ -362,16 +247,15 @@ fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, } void -fz_blendimagewithcolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, - unsigned char *color) +fz_paintimagecolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color) { assert(img->n == 1); - fz_blendimageimp(dst, scissor, img, ctm, color); + fz_paintimageimp(dst, scissor, img, ctm, color, 255); } void -fz_blendimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm) +fz_paintimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, int alpha) { assert(dst->n == img->n); - fz_blendimageimp(dst, scissor, img, ctm, nil); + fz_paintimageimp(dst, scissor, img, ctm, nil, alpha); } |