summaryrefslogtreecommitdiff
path: root/draw
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2010-10-28 16:34:43 +0000
committerTor Andersson <tor@ghostscript.com>2010-10-28 16:34:43 +0000
commitbb4dcc4a138882dd0a51792a0e9ad3b778063247 (patch)
tree4dfc74dbeb83040dc2ceaa219fb27f4e48a1e12d /draw
parent80ff420366dd1086c434a003b2f5b7bdfa2468cd (diff)
downloadmupdf-bb4dcc4a138882dd0a51792a0e9ad3b778063247.tar.xz
Use bilinear sampling for non-rectilinear and upscaled images.
Diffstat (limited to 'draw')
-rw-r--r--draw/imagedraw.c168
1 files changed, 134 insertions, 34 deletions
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;