summaryrefslogtreecommitdiff
path: root/draw/imagedraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'draw/imagedraw.c')
-rw-r--r--draw/imagedraw.c364
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);
}