diff options
author | Robin Watts <robin.watts@artifex.com> | 2010-06-22 20:20:12 +0200 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2010-06-22 20:20:12 +0200 |
commit | 685f0177891376b1d0e02de5c95d9ec3175228b3 (patch) | |
tree | bee588d8bbbf22c1ea631092438e8f3445442960 | |
parent | 0edb7f95c50f0012ae173b3fa42cebe2905f1826 (diff) | |
download | mupdf-685f0177891376b1d0e02de5c95d9ec3175228b3.tar.xz |
Add support for greyscale rendering to the mupdf core and pdfdraw.
-rw-r--r-- | apps/pdfdraw.c | 67 | ||||
-rw-r--r-- | draw/imagedraw.c | 123 | ||||
-rw-r--r-- | draw/imageunpack.c | 2 | ||||
-rw-r--r-- | draw/pathscan.c | 54 | ||||
-rw-r--r-- | draw/porterduff.c | 53 | ||||
-rw-r--r-- | fitz/dev_draw.c | 15 | ||||
-rw-r--r-- | fitz/fitz_draw.h | 4 |
7 files changed, 289 insertions, 29 deletions
diff --git a/apps/pdfdraw.c b/apps/pdfdraw.c index 1f93f777..4a4117fe 100644 --- a/apps/pdfdraw.c +++ b/apps/pdfdraw.c @@ -14,7 +14,7 @@ #include <sys/time.h> #endif -enum { DRAWPNM, DRAWTXT, DRAWXML }; +enum { DRAWPNM, DRAWPGM, DRAWTXT, DRAWXML }; struct benchmark { @@ -59,6 +59,7 @@ static void drawusage(void) " -o -\tpattern (%%d for page number) for output file\n" " -r -\tresolution in dpi\n" " -m\tprint benchmark results\n" + " -g\toutput a pgm rather than a pnm\n" " -s\tprint MD5 checksum of page pixel data\n" " -t\ttext extraction mode\n" " -x\txml trace mode\n" @@ -139,7 +140,7 @@ static void drawfreepage(void) } } -static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes) +static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes, int greyscale) { static int fd = -1; fz_error error; @@ -182,11 +183,18 @@ static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark * die(fz_throw("ioerror: could not create raster file '%s'", name)); } - sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h); + if (greyscale) + { + sprintf(pnmhdr, "P5\n%d %d\n255\n", w, h); + } + else + { + sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h); + } write(fd, pnmhdr, strlen(pnmhdr)); } - pix = fz_newpixmap(pdf_devicergb, bbox.x0, bbox.y0, w, bh); + pix = fz_newpixmap((greyscale ? pdf_devicegray : pdf_devicergb), bbox.x0, bbox.y0, w, bh); fz_clearpixmap(pix, 0xFF); memset(pix->samples, 0xff, pix->h * pix->w * pix->n); @@ -204,27 +212,47 @@ static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark * die(fz_rethrow(error, "cannot draw page %d in PDF file '%s'", pagenum, basename)); fz_freedevice(dev); + if (checksum) + fz_md5update(&digest, pix->samples, pix->h * pix->w * pix->n); if (drawpattern) { - for (y = 0; y < pix->h; y++) + unsigned char *src = pix->samples; + if (greyscale) { - unsigned char *src = pix->samples + y * pix->w * 4; - unsigned char *dst = src; + for (y = pix->h; y > 0; y--) + { + unsigned char *dst = src; + + for (x = pix->w; x > 0; x--) + { + src++; + *dst++ = *src++; + } + dst -= pix->w; - for (x = 0; x < pix->w; x++) + write(fd, dst, pix->w); + } + } + else + { + for (y = pix->h; y > 0; y--) { - dst[x * 3 + 0] = src[x * 4 + 1]; - dst[x * 3 + 1] = src[x * 4 + 2]; - dst[x * 3 + 2] = src[x * 4 + 3]; + unsigned char *dst = src; + + for (x = pix->w; x > 0; x--) + { + src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + dst -= pix->w * 3; + + write(fd, dst, pix->w * 3); } - - write(fd, dst, pix->w * 3); } } - if (checksum) - fz_md5update(&digest, pix->samples, pix->h * pix->w * 4); - pix->y += bh; if (pix->y + pix->h > bbox.y1) pix->h = bbox.y1 - pix->y; @@ -374,7 +402,8 @@ static void drawpages(char *pagelist) { switch (drawmode) { - case DRAWPNM: drawpnm(page, &loadtimes, &drawtimes); break; + case DRAWPNM: drawpnm(page, &loadtimes, &drawtimes, 0); break; + case DRAWPGM: drawpnm(page, &loadtimes, &drawtimes, 1); break; case DRAWTXT: drawtxt(page, &loadtimes); break; case DRAWXML: drawxml(page); break; } @@ -411,7 +440,7 @@ int main(int argc, char **argv) fz_cpudetect(); fz_accelerate(); - while ((c = fz_getopt(argc, argv, "b:p:o:r:txms")) != -1) + while ((c = fz_getopt(argc, argv, "b:p:o:r:gtxms")) != -1) { switch (c) { @@ -419,6 +448,7 @@ int main(int argc, char **argv) case 'p': password = fz_optarg; break; case 'o': drawpattern = fz_optarg; break; case 'r': drawzoom = atof(fz_optarg) / 72; break; + case 'g': drawmode = DRAWPGM; break; case 't': drawmode = DRAWTXT; break; case 'x': drawmode = DRAWXML; break; case 'm': benchmark = 1; break; @@ -464,4 +494,3 @@ int main(int argc, char **argv) return 0; } - diff --git a/draw/imagedraw.c b/draw/imagedraw.c index 9f6d93bf..81d2bb05 100644 --- a/draw/imagedraw.c +++ b/draw/imagedraw.c @@ -22,6 +22,16 @@ getargb(byte *s, int w, int h, int u, int v) return s + ((w * v + u) << 2); } +static inline byte * +getag(byte *s, int w, int h, 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) << 1); +} + static inline int getcolor(byte *s, int w, int h, int n, int u, int v, int k) { @@ -39,6 +49,13 @@ lerp(int a, int b, int t) } static inline void +lerpag(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 lerpargb(byte *dst, byte *a, byte *b, int t) { dst[0] = lerp(a[0], b[0], t); @@ -64,6 +81,24 @@ samplemask(byte *s, int w, int h, int u, int v) } static inline void +sampleag(byte *s, int w, int h, int u, int v, byte *out) +{ + byte ab[4]; + byte cd[4]; + int ui = u >> 16; + int vi = v >> 16; + int ud = u & 0xFFFF; + int vd = v & 0xFFFF; + byte *a = getag(s, w, h, ui, vi); + byte *b = getag(s, w, h, ui+1, vi); + byte *c = getag(s, w, h, ui, vi+1); + byte *d = getag(s, w, h, ui+1, vi+1); + lerpag(ab, a, b, ud); + lerpag(cd, c, d, ud); + lerpag(out, ab, cd, vd); +} + +static inline void sampleargb(byte *s, int w, int h, int u, int v, byte *out) { byte ab[4]; @@ -129,6 +164,35 @@ img_1o1(byte * restrict src, byte cov, int len, byte * restrict dst, } static void +img_2o2(byte * restrict src, byte cov, int len, byte * restrict dst, + fz_pixmap *image, int u, int v, int fa, int fb) +{ + byte *samples = image->samples; + int w = image->w; + int h = image->h; + byte ag[2]; + + while (len--) + { + int sa; + cov += *src; *src = 0; src++; + if (cov != 0) + { + sampleag(samples, w, h, u, v, ag); + sa = FZ_COMBINE(FZ_EXPAND(ag[0]), FZ_EXPAND(cov)); + if (sa != 0) + { + dst[0] = FZ_BLEND(255, dst[0], sa); + dst[1] = FZ_BLEND(ag[1], dst[1], sa); + } + } + dst += 2; + u += fa; + v += fb; + } +} + +static void img_4o4(byte * restrict src, byte cov, int len, byte * restrict dst, fz_pixmap *image, int u, int v, int fa, int fb) { @@ -160,6 +224,63 @@ img_4o4(byte * restrict src, byte cov, int len, byte * restrict dst, } static void +img_w2i1o2(byte *ag, byte * restrict src, byte cov, int len, byte * restrict dst, + fz_pixmap *image, int u, int v, int fa, int fb) +{ + byte *samples = image->samples; + int w = image->w; + int h = image->h; + int alpha = FZ_EXPAND(ag[0]); + byte g = ag[1]; + + if (alpha == 0) + return; + if (alpha != 256) + { + while (len--) + { + int ca; + cov += *src; *src = 0; src++; + if (cov != 0) + { + ca = samplemask(samples, w, h, u, v); + ca =FZ_COMBINE(FZ_EXPAND(cov),FZ_EXPAND(ca)); + ca = FZ_COMBINE(ca, alpha); + if (ca != 0) + { + dst[0] = FZ_BLEND(255, dst[0], ca); + dst[1] = FZ_BLEND(g, dst[1], ca); + } + } + dst += 2; + u += fa; + v += fb; + } + } + else + { + while (len--) + { + int ca; + cov += *src; *src = 0; src++; + if (cov != 0) + { + ca = samplemask(samples, w, h, u, v); + ca =FZ_COMBINE(FZ_EXPAND(cov),FZ_EXPAND(ca)); + if (ca != 0) + { + dst[0] = FZ_BLEND(255, dst[0], ca); + dst[1] = FZ_BLEND(g, dst[1], ca); + } + } + dst += 2; + u += fa; + v += fb; + } + } +} + +static void img_w4i1o4(byte *argb, byte * restrict src, byte cov, int len, byte * restrict dst, fz_pixmap *image, int u, int v, int fa, int fb) { @@ -223,5 +344,7 @@ img_w4i1o4(byte *argb, byte * restrict src, byte cov, int len, byte * restrict d } void (*fz_img_1o1)(byte*, byte, int, byte*, fz_pixmap *image, int u, int v, int fa, int fb) = img_1o1; +void (*fz_img_2o2)(byte*, byte, int, byte*, fz_pixmap *image, int u, int v, int fa, int fb) = img_2o2; void (*fz_img_4o4)(byte*, byte, int, byte*, fz_pixmap *image, int u, int v, int fa, int fb) = img_4o4; +void (*fz_img_w2i1o2)(byte*, byte*, byte, int, byte*, fz_pixmap *image, int u, int v, int fa, int fb) = img_w2i1o2; void (*fz_img_w4i1o4)(byte*, byte*, byte, int, byte*, fz_pixmap *image, int u, int v, int fa, int fb) = img_w4i1o4; diff --git a/draw/imageunpack.c b/draw/imageunpack.c index 4c9923fd..4e876092 100644 --- a/draw/imageunpack.c +++ b/draw/imageunpack.c @@ -28,7 +28,7 @@ static void decodetile(fz_pixmap *pix, int skip, float *decode) min[i] = decode[(i - skip) * 2] * 255; max[i] = decode[(i - skip) * 2 + 1] * 255; sub[i] = max[i] - min[i]; - needed |= (min[i] != 0) | (max[i] != 255); + needed |= (min[i] != 0) | (max[i] != 255); justinvert &= min[i] == 255 && max[i] == 0 && sub[i] == -255; } diff --git a/draw/pathscan.c b/draw/pathscan.c index 5a656144..319cfeb1 100644 --- a/draw/pathscan.c +++ b/draw/pathscan.c @@ -422,7 +422,7 @@ static inline void toalpha(unsigned char *list, int n) static inline void blit(fz_pixmap *pix, int x, int y, unsigned char *list, int skipx, int len, - unsigned char *argb, fz_pixmap *image, fz_matrix *invmat) + unsigned char *color, fz_pixmap *image, fz_matrix *invmat) { unsigned char *dst; unsigned char cov; @@ -443,17 +443,61 @@ static inline void blit(fz_pixmap *pix, int x, int y, int v = (invmat->b * (x + 0.5f) + invmat->d * (y + 0.5f) + invmat->f) * 65536; int fa = invmat->a * 65536; int fb = invmat->b * 65536; - if (argb) - fz_img_w4i1o4(argb, list, cov, len, dst, image, u, v, fa, fb); + assert(image->n == pix->n); + if (color) + { + switch (pix->n) + { + case 2: + fz_img_w2i1o2(color, list, cov, len, dst, image, u, v, fa, fb); + break; + case 4: + fz_img_w4i1o4(color, list, cov, len, dst, image, u, v, fa, fb); + break; + default: + assert("Write fz_img_wni1on" != NULL); + //fz_img_wni1on(color, list, cov, len, dst, image, u, v, fa, fb); + break; + } + } else if (image->colorspace) + { + assert(image->colorspace->n == image->n-1); + switch (pix->n) + { + case 2: + fz_img_2o2(list, cov, len, dst, image, u, v, fa, fb); + break; + case 4: fz_img_4o4(list, cov, len, dst, image, u, v, fa, fb); + break; + default: + assert("Write fz_img_non" != NULL); + //fz_img_non(list, cov, len, dst, image, u, v, fa, fb); + break; + } + } else fz_img_1o1(list, cov, len, dst, image, u, v, fa, fb); } else { - if (argb) - fz_path_w4i1o4(argb, list, cov, len, dst); + if (color) + { + switch (pix->n) + { + case 2: + fz_path_w2i1o2(color, list, cov, len, dst); + break; + case 4: + fz_path_w4i1o4(color, list, cov, len, dst); + break; + default: + assert("Write fz_path_wni1on" != NULL); + //fz_path_wni1on(color, list, cov, len, dst); + break; + } + } else fz_path_1o1(list, cov, len, dst); } diff --git a/draw/porterduff.c b/draw/porterduff.c index 34d5cee8..4616e3fa 100644 --- a/draw/porterduff.c +++ b/draw/porterduff.c @@ -20,7 +20,8 @@ duff_non(byte * restrict sp, int sw, int sn, byte * restrict dp, int dw, int w0, { /* RJW: Alpha handling suspicious here; sp[0] counts twice */ int sa = FZ_EXPAND(sp[0]); - for (k = 0; k < sn; k++) + dp[0] = FZ_BLEND(255, dp[k], sa); + for (k = 1; k < sn; k++) { dp[k] = FZ_BLEND(sp[k], dp[k], sa); } @@ -47,7 +48,8 @@ duff_nimon(byte * restrict sp, int sw, int sn, byte * restrict mp, int mw, int m { /* TODO: validate this */ int ma = FZ_COMBINE(FZ_EXPAND(mp[0]), FZ_EXPAND(sp[0])); - for (k = 0; k < sn; k++) + dp[k] = FZ_BLEND(255, dp[k], ma); + for (k = 1; k < sn; k++) { dp[k] = FZ_BLEND(sp[k], dp[k], ma); } @@ -93,7 +95,7 @@ duff_4o4(byte *sp, int sw, byte *dp, int dw, int w0, int h) while (w--) { int alpha = FZ_EXPAND(sp[0]); - dp[0] = FZ_BLEND(sp[0], dp[0], alpha); + dp[0] = FZ_BLEND(255, dp[0], alpha); dp[1] = FZ_BLEND(sp[1], dp[1], alpha); dp[2] = FZ_BLEND(sp[2], dp[2], alpha); dp[3] = FZ_BLEND(sp[3], dp[3], alpha); @@ -174,12 +176,30 @@ path_1o1(byte * restrict src, byte cov, int len, byte * restrict dst) } static void +path_w2i1o2(byte * restrict ag, byte * restrict src, byte cov, int len, byte * restrict dst) +{ + int alpha = FZ_EXPAND(ag[0]); + byte g = ag[1]; + + while (len--) + { + int ca; + cov += *src; *src = 0; src++; + ca = FZ_COMBINE(FZ_EXPAND(cov), alpha); + dst[0] = FZ_BLEND(255, dst[0], ca); + dst[1] = FZ_BLEND(g, dst[1], ca); + dst += 2; + } +} + +static void path_w4i1o4(byte * restrict argb, byte * restrict src, byte cov, int len, byte * restrict dst) { int alpha = FZ_EXPAND(argb[0]); byte r = argb[1]; byte g = argb[2]; byte b = argb[3]; + while (len--) { int ca; @@ -218,12 +238,37 @@ text_1o1(byte * restrict src, int srcw, byte * restrict dst, int dstw, int w0, i } static void +text_w2i1o2(byte * restrict ag, byte * restrict src, int srcw, byte * restrict dst, int dstw, int w0, int h) +{ + int alpha = FZ_EXPAND(ag[0]); + byte g = ag[1]; + + srcw -= w0; + dstw -= w0<<1; + while (h--) + { + int w = w0; + while (w--) + { + int c = FZ_COMBINE(FZ_EXPAND(src[0]), alpha); + dst[0] = FZ_BLEND(255, dst[0], c); + dst[1] = FZ_BLEND(g, dst[1], c); + src ++; + dst += 2; + } + src += srcw; + dst += dstw; + } +} + +static void text_w4i1o4(byte * restrict argb, byte * restrict src, int srcw, byte * restrict dst, int dstw, int w0, int h) { int alpha = FZ_EXPAND(argb[0]); byte r = argb[1]; byte g = argb[2]; byte b = argb[3]; + srcw -= w0; dstw -= w0<<2; while (h--) @@ -256,7 +301,9 @@ void (*fz_duff_1i1o1)(byte*,int,byte*,int,byte*,int,int,int) = duff_1i1o1; void (*fz_duff_4i1o4)(byte*,int,byte*,int,byte*,int,int,int) = duff_4i1o4; void (*fz_path_1o1)(byte*,byte,int,byte*) = path_1o1; +void (*fz_path_w2i1o2)(byte*,byte*,byte,int,byte*) = path_w2i1o2; void (*fz_path_w4i1o4)(byte*,byte*,byte,int,byte*) = path_w4i1o4; void (*fz_text_1o1)(byte*,int,byte*,int,int,int) = text_1o1; +void (*fz_text_w2i1o2)(byte*,byte*,int,byte*,int,int,int) = text_w2i1o2; void (*fz_text_w4i1o4)(byte*,byte*,int,byte*,int,int,int) = text_w4i1o4; diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c index 0b909f85..2698f22d 100644 --- a/fitz/dev_draw.c +++ b/fitz/dev_draw.c @@ -277,7 +277,20 @@ drawglyph(unsigned char *argb, fz_pixmap *dst, fz_pixmap *src, int xorig, int yo h = sy1 - sy0; if (dst->colorspace) - fz_text_w4i1o4(argb, sp, src->w, dp, dst->w * 4, w, h); + { + switch (dst->n) + { + case 2: + fz_text_w2i1o2(argb, sp, src->w, dp, dst->w * 2, w, h); + break; + case 4: + fz_text_w4i1o4(argb, sp, src->w, dp, dst->w * 4, w, h); + break; + default: + assert("Write fz_text_wni1on" != NULL); + break; + } + } else fz_text_1o1(sp, src->w, dp, dst->w, w, h); } diff --git a/fitz/fitz_draw.h b/fitz/fitz_draw.h index 077edd0b..abd94a1e 100644 --- a/fitz/fitz_draw.h +++ b/fitz/fitz_draw.h @@ -487,14 +487,18 @@ extern void (*fz_duff_1i1o1)(unsigned char*,int,unsigned char*,int,unsigned char extern void (*fz_duff_4i1o4)(unsigned char*,int,unsigned char*,int,unsigned char*,int,int,int); extern void (*fz_path_1o1)(unsigned char*,unsigned char,int,unsigned char*); +extern void (*fz_path_w2i1o2)(unsigned char*,unsigned char*,unsigned char,int,unsigned char*); extern void (*fz_path_w4i1o4)(unsigned char*,unsigned char*,unsigned char,int,unsigned char*); extern void (*fz_text_1o1)(unsigned char*,int,unsigned char*,int,int,int); +extern void (*fz_text_w2i1o2)(unsigned char*,unsigned char*,int,unsigned char*,int,int,int); extern void (*fz_text_w4i1o4)(unsigned char*,unsigned char*,int,unsigned char*,int,int,int); extern void (*fz_img_non)(unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,fz_matrix*); extern void (*fz_img_1o1)(unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,int u, int v, int fa, int fb); extern void (*fz_img_4o4)(unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,int u, int v, int fa, int fb); +extern void (*fz_img_2o2)(unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,int u, int v, int fa, int fb); +extern void (*fz_img_w2i1o2)(unsigned char*,unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,int u, int v, int fa, int fb); extern void (*fz_img_w4i1o4)(unsigned char*,unsigned char*,unsigned char,int,unsigned char*,fz_pixmap*,int u, int v, int fa, int fb); extern void (*fz_decodetile)(fz_pixmap *pix, int skip, float *decode); |