From bb4dcc4a138882dd0a51792a0e9ad3b778063247 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 28 Oct 2010 16:34:43 +0000 Subject: Use bilinear sampling for non-rectilinear and upscaled images. --- draw/imagedraw.c | 168 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 34 deletions(-) (limited to 'draw') diff --git a/draw/imagedraw.c b/draw/imagedraw.c index 017eaf39..668bfd22 100644 --- a/draw/imagedraw.c +++ b/draw/imagedraw.c @@ -1,7 +1,5 @@ #include "fitz.h" -#define noLINEAR - typedef unsigned char byte; static inline float roundup(float x) @@ -9,8 +7,6 @@ static inline float roundup(float x) return (x < 0) ? floorf(x) : ceilf(x); } -#ifdef LINEAR - static inline int lerp(int a, int b, int t) { return a + (((b - a) * t) >> 16); @@ -30,12 +26,10 @@ static inline byte *samplenearest(byte *s, int w, int h, int n, int u, int v) return s + (v * w + u) * n; } -#endif - /* Blend premultiplied source image in constant alpha over destination */ static inline void -fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) +fz_paintaffinealphaNlerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { int k; @@ -45,7 +39,6 @@ fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i int vi = v >> 16; if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { -#ifdef LINEAR int uf = u & 0xffff; int vf = v & 0xffff; byte *a = samplenearest(sp, sw, sh, n, ui, vi); @@ -59,12 +52,28 @@ fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i x = bilerp(a[k], b[k], c[k], d[k], uf, vf); dp[k] = fz_mul255(x, alpha) + fz_mul255(dp[k], t); } -#else + } + dp += n; + u += fa; + v += fb; + } +} + +static inline void +fz_paintaffinealphaNnear(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) +{ + int k; + + while (w--) + { + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) + { byte *sample = sp + ((vi * sw + ui) * n); int t = 255 - fz_mul255(sample[n-1], alpha); for (k = 0; k < n; k++) dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t); -#endif } dp += n; u += fa; @@ -75,7 +84,7 @@ fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i /* Blend premultiplied source image over destination */ static inline void -fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) +fz_paintaffineNlerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) { int k; @@ -85,7 +94,6 @@ fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb int vi = v >> 16; if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { -#ifdef LINEAR int uf = u & 0xffff; int vf = v & 0xffff; byte *a = samplenearest(sp, sw, sh, n, ui, vi); @@ -98,12 +106,28 @@ fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb int x = bilerp(a[k], b[k], c[k], d[k], uf, vf); dp[k] = x + fz_mul255(dp[k], t); } -#else + } + dp += n; + u += fa; + v += fb; + } +} + +static inline void +fz_paintaffineNnear(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) +{ + int k; + + while (w--) + { + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) + { 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 += n; u += fa; @@ -114,7 +138,7 @@ fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb /* Blend non-premultiplied color in source image mask over destination */ static inline void -fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) +fz_paintaffinecolorNlerp(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; @@ -125,7 +149,6 @@ fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i int vi = v >> 16; if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { -#ifdef LINEAR int uf = u & 0xffff; int vf = v & 0xffff; byte *a = samplenearest(sp, sw, sh, 1, ui, vi); @@ -133,9 +156,30 @@ fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i 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 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 += n; + u += fa; + v += fb; + } +} + +static inline void +fz_paintaffinecolorNnear(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--) + { + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) + { 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); @@ -148,38 +192,74 @@ fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, i } 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) +fz_paintaffinelerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { if (alpha == 255) { switch (n) { - 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; + case 1: fz_paintaffineNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; + case 2: fz_paintaffineNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; + case 4: fz_paintaffineNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; + default: fz_paintaffineNlerp(dp, sp, sw, sh, u, v, fa, fb, w, n); break; } } else if (alpha > 0) { switch (n) { - 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; + case 1: fz_paintaffinealphaNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; + case 2: fz_paintaffinealphaNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; + case 4: fz_paintaffinealphaNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; + default: fz_paintaffinealphaNlerp(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; } } } 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) +fz_paintaffinenear(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) +{ + if (alpha == 255) + { + switch (n) + { + case 1: fz_paintaffineNnear(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; + case 2: fz_paintaffineNnear(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; + case 4: fz_paintaffineNnear(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; + default: fz_paintaffineNnear(dp, sp, sw, sh, u, v, fa, fb, w, n); break; + } + } + else if (alpha > 0) + { + switch (n) + { + case 1: fz_paintaffinealphaNnear(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; + case 2: fz_paintaffinealphaNnear(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; + case 4: fz_paintaffinealphaNnear(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; + default: fz_paintaffinealphaNnear(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; + } + } +} + +void +fz_paintaffinecolorlerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) { 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; + case 2: fz_paintaffinecolorNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; + case 4: fz_paintaffinecolorNlerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; + default: fz_paintaffinecolorNlerp(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; + } +} + +void +fz_paintaffinecolornear(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) +{ + switch (n) + { + case 2: fz_paintaffinecolorNnear(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; + case 4: fz_paintaffinecolorNnear(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; + default: fz_paintaffinecolorNnear(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; } } @@ -194,6 +274,7 @@ fz_paintimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, int sw, sh, n; fz_matrix inv; fz_bbox bbox; + int dolerp; /* grid fit the image */ if (fz_isrectilinear(ctm)) @@ -206,6 +287,15 @@ fz_paintimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, ctm.f = floorf(ctm.f); } + /* turn on interpolation for upscaled and non-rectilinear transforms */ + dolerp = 0; + if (!fz_isrectilinear(ctm)) + dolerp = 1; + if (sqrtf(ctm.a * ctm.a + ctm.b * ctm.b) > img->w) + dolerp = 1; + if (sqrtf(ctm.c * ctm.c + ctm.d * ctm.d) > img->h) + dolerp = 1; + bbox = fz_roundrect(fz_transformrect(ctm, fz_unitrect)); bbox = fz_intersectbbox(bbox, scissor); x = bbox.x0; @@ -238,10 +328,20 @@ fz_paintimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, while (h--) { - if (color) - fz_paintaffinecolor(dp, sp, sw, sh, u, v, fa, fb, w, n, color); + if (dolerp) + { + if (color) + fz_paintaffinecolorlerp(dp, sp, sw, sh, u, v, fa, fb, w, n, color); + else + fz_paintaffinelerp(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); + } else - fz_paintaffine(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); + { + if (color) + fz_paintaffinecolornear(dp, sp, sw, sh, u, v, fa, fb, w, n, color); + else + fz_paintaffinenear(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); + } dp += dst->w * n; u += fc; v += fd; -- cgit v1.2.3