diff options
-rw-r--r-- | apps/pdfextract.c | 8 | ||||
-rw-r--r-- | draw/imageunpack.c | 27 | ||||
-rw-r--r-- | fitz/fitz.h | 12 | ||||
-rw-r--r-- | fitz/res_colorspace.c | 449 | ||||
-rw-r--r-- | fitz/stm_buffer.c | 18 | ||||
-rw-r--r-- | mupdf/mupdf.h | 35 | ||||
-rw-r--r-- | mupdf/pdf_build.c | 72 | ||||
-rw-r--r-- | mupdf/pdf_colorspace.c | 924 | ||||
-rw-r--r-- | mupdf/pdf_image.c | 539 | ||||
-rw-r--r-- | mupdf/pdf_interpret.c | 14 | ||||
-rw-r--r-- | mupdf/pdf_pattern.c | 2 | ||||
-rw-r--r-- | mupdf/pdf_store.c | 2 | ||||
-rw-r--r-- | mupdf/pdf_xobject.c | 4 |
13 files changed, 742 insertions, 1364 deletions
diff --git a/apps/pdfextract.c b/apps/pdfextract.c index 9da182d7..00bddc11 100644 --- a/apps/pdfextract.c +++ b/apps/pdfextract.c @@ -38,11 +38,11 @@ static void saveimage(int num, int gen) xref->store = pdf_newstore(); - error = pdf_loadimage(&img, xref, ref); + error = pdf_loadimage(&img, xref, nil, ref); if (error) die(error); - pix = fz_newpixmap(img->cs, 0, 0, img->w, img->h); + pix = fz_newpixmap(img->colorspace, 0, 0, img->w, img->h); error = pdf_loadtile(img, pix); if (error) @@ -68,13 +68,13 @@ static void saveimage(int num, int gen) pix = temp; } - if (img->cs && strcmp(img->cs->name, "DeviceRGB")) + if (img->colorspace && strcmp(img->colorspace->name, "DeviceRGB")) { fz_pixmap *temp; temp = fz_newpixmap(pdf_devicergb, pix->x, pix->y, pix->w, pix->h); - fz_convertpixmap(img->cs, pix, pdf_devicergb, temp); + fz_convertpixmap(img->colorspace, pix, pdf_devicergb, temp); fz_droppixmap(pix); pix = temp; } diff --git a/draw/imageunpack.c b/draw/imageunpack.c index 25a21770..6e5467ad 100644 --- a/draw/imageunpack.c +++ b/draw/imageunpack.c @@ -6,7 +6,7 @@ typedef unsigned char byte; * Apply decode parameters */ -static void decodetile(fz_pixmap *pix, int skip, float *decode) +static void decodetile(fz_pixmap *pix, int imagemask, float *decode) { int min[FZ_MAXCOLORS]; int max[FZ_MAXCOLORS]; @@ -17,9 +17,8 @@ static void decodetile(fz_pixmap *pix, int skip, float *decode) int wh = pix->w * pix->h; int i; int justinvert = 1; - unsigned int mask; - for (i = 0; i < n-skip; i++) + for (i = 0; i < n - imagemask; i++) { min[i] = decode[i * 2] * 255; max[i] = decode[i * 2 + 1] * 255; @@ -28,18 +27,13 @@ static void decodetile(fz_pixmap *pix, int skip, float *decode) justinvert &= min[i] == 255 && max[i] == 0 && sub[i] == -255; } - if (skip) + if (imagemask) { min[i] = 0; max[i] = 255; sub[i] = 255; } - if (fz_isbigendian()) - mask = 0x00ff00ff; - else - mask = 0xff00ff00; - if (!needed) return; @@ -52,9 +46,10 @@ static void decodetile(fz_pixmap *pix, int skip, float *decode) } break; case 2: - if (justinvert) { + if (justinvert) + { + unsigned mask = fz_isbigendian() ? 0x00ff00ff : 0xff00ff00; unsigned *wp = (unsigned *)p; - if ((((char *)wp - (char *)0) & 3) == 0) { int hwh = wh / 2; wh = wh - 2 * hwh; @@ -72,11 +67,13 @@ static void decodetile(fz_pixmap *pix, int skip, float *decode) } } else - while (wh--) { - p[0] = min[0] + fz_mul255(sub[0], p[0]); - p[1] = min[1] + fz_mul255(sub[1], p[1]); - p += 2; + while (wh--) + { + p[0] = min[0] + fz_mul255(sub[0], p[0]); + p[1] = min[1] + fz_mul255(sub[1], p[1]); + p += 2; + } } break; default: diff --git a/fitz/fitz.h b/fitz/fitz.h index e74f12cc..8ad72322 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -474,6 +474,7 @@ struct fz_buffer_s fz_buffer * fz_newbuffer(int size); fz_buffer * fz_newbufferwithmemory(unsigned char *data, int size); +void fz_resizebuffer(fz_buffer *buf, int size); void fz_rewindbuffer(fz_buffer *buf); void fz_growbuffer(fz_buffer *buf); @@ -711,30 +712,25 @@ extern fz_colorspace *pdf_devicegray; extern fz_colorspace *pdf_devicergb; extern fz_colorspace *pdf_devicebgr; extern fz_colorspace *pdf_devicecmyk; -extern fz_colorspace *pdf_devicelab; -extern fz_colorspace *pdf_devicepattern; struct fz_colorspace_s { int refs; char name[16]; int n; - void (*convpixmap)(fz_colorspace *ss, fz_pixmap *sp, fz_colorspace *ds, fz_pixmap *dp); - void (*convcolor)(fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv); void (*toxyz)(fz_colorspace *, float *src, float *xyz); void (*fromxyz)(fz_colorspace *, float *xyz, float *dst); - void (*freefunc)(fz_colorspace *); + void (*freedata)(fz_colorspace *); + void *data; }; +fz_colorspace *fz_newcolorspace(char *name, int n); fz_colorspace *fz_keepcolorspace(fz_colorspace *cs); void fz_dropcolorspace(fz_colorspace *cs); void fz_convertcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv); void fz_convertpixmap(fz_colorspace *srcs, fz_pixmap *srcv, fz_colorspace *dsts, fz_pixmap *dstv); -void fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv); -void fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *srcv, fz_colorspace *dsts, fz_pixmap *dstv); - /* * Fonts come in two variants: * Regular fonts are handled by FreeType. diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c index 79ca8ff4..6cad3f16 100644 --- a/fitz/res_colorspace.c +++ b/fitz/res_colorspace.c @@ -1,15 +1,17 @@ #include "fitz.h" -void -fz_convertpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) -{ - srcs->convpixmap(srcs, src, dsts, dst); -} - -void -fz_convertcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) +fz_colorspace * +fz_newcolorspace(char *name, int n) { - srcs->convcolor(srcs, srcv, dsts, dstv); + fz_colorspace *cs = fz_malloc(sizeof(fz_colorspace)); + cs->refs = 1; + fz_strlcpy(cs->name, name, sizeof cs->name); + cs->n = n; + cs->toxyz = NULL; + cs->fromxyz = NULL; + cs->freedata = NULL; + cs->data = NULL; + return cs; } fz_colorspace * @@ -28,33 +30,262 @@ fz_dropcolorspace(fz_colorspace *cs) return; if (cs && --cs->refs == 0) { - if (cs->freefunc) - cs->freefunc(cs); + if (cs->freedata && cs->data) + cs->freedata(cs); fz_free(cs); } } -void -fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) +/* + * Fast Device color spaces + */ + +static void graytoxyz(fz_colorspace *cs, float *gray, float *xyz) { - float xyz[3]; - int i; + xyz[0] = gray[0]; + xyz[1] = gray[0]; + xyz[2] = gray[0]; +} - if (srcs != dsts) +static void xyztogray(fz_colorspace *cs, float *xyz, float *gray) +{ + float r = xyz[0]; + float g = xyz[1]; + float b = xyz[2]; + gray[0] = r * 0.3f + g * 0.59f + b * 0.11f; +} + +static void rgbtoxyz(fz_colorspace *cs, float *rgb, float *xyz) +{ + xyz[0] = rgb[0]; + xyz[1] = rgb[1]; + xyz[2] = rgb[2]; +} + +static void xyztorgb(fz_colorspace *cs, float *xyz, float *rgb) +{ + rgb[0] = xyz[0]; + rgb[1] = xyz[1]; + rgb[2] = xyz[2]; +} + +static void bgrtoxyz(fz_colorspace *cs, float *bgr, float *xyz) +{ + xyz[0] = bgr[2]; + xyz[1] = bgr[1]; + xyz[2] = bgr[0]; +} + +static void xyztobgr(fz_colorspace *cs, float *xyz, float *bgr) +{ + bgr[0] = xyz[2]; + bgr[1] = xyz[1]; + bgr[2] = xyz[0]; +} + +static void cmyktoxyz(fz_colorspace *cs, float *cmyk, float *xyz) +{ + xyz[0] = 1 - MIN(1, cmyk[0] + cmyk[3]); + xyz[1] = 1 - MIN(1, cmyk[1] + cmyk[3]); + xyz[2] = 1 - MIN(1, cmyk[2] + cmyk[3]); +} + +static void xyztocmyk(fz_colorspace *cs, float *xyz, float *cmyk) +{ + float c, m, y, k; + c = 1 - xyz[0]; + m = 1 - xyz[1]; + y = 1 - xyz[2]; + k = MIN(c, MIN(m, y)); + cmyk[0] = c - k; + cmyk[1] = m - k; + cmyk[2] = y - k; + cmyk[3] = k; +} + +static fz_colorspace kdevicegray = { -1, "DeviceGray", 1, graytoxyz, xyztogray }; +static fz_colorspace kdevicergb = { -1, "DeviceRGB", 3, rgbtoxyz, xyztorgb }; +static fz_colorspace kdevicebgr = { -1, "DeviceRGB", 3, bgrtoxyz, xyztobgr }; +static fz_colorspace kdevicecmyk = { -1, "DeviceCMYK", 4, cmyktoxyz, xyztocmyk }; + +fz_colorspace *pdf_devicegray = &kdevicegray; +fz_colorspace *pdf_devicergb = &kdevicergb; +fz_colorspace *pdf_devicebgr = &kdevicebgr; +fz_colorspace *pdf_devicecmyk = &kdevicecmyk; + +/* + * Pixmap color conversions + */ + +static void fastgraytorgb(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) { - srcs->toxyz(srcs, srcv, xyz); - dsts->fromxyz(dsts, xyz, dstv); - for (i = 0; i < dsts->n; i++) - dstv[i] = CLAMP(dstv[i], 0, 1); + d[0] = s[0]; + d[1] = s[0]; + d[2] = s[0]; + d[3] = s[1]; + s += 2; + d += 4; } - else +} + +static void fastgraytocmyk(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) { - for (i = 0; i < srcs->n; i++) - dstv[i] = srcv[i]; + d[0] = 0; + d[1] = 0; + d[2] = 0; + d[3] = s[0]; + d[4] = s[1]; + s += 2; + d += 5; } } -void +static void fastrgbtogray(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; + d[1] = s[3]; + s += 4; + d += 2; + } +} + +static void fastbgrtogray(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; + d[1] = s[3]; + s += 4; + d += 2; + } +} + +static void fastrgbtocmyk(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + unsigned char c = 255 - s[0]; + unsigned char m = 255 - s[1]; + unsigned char y = 255 - s[2]; + unsigned char k = MIN(c, MIN(m, y)); + d[0] = c - k; + d[1] = m - k; + d[2] = y - k; + d[3] = k; + d[4] = s[3]; + s += 4; + d += 5; + } +} + +static void fastbgrtocmyk(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + unsigned char c = 255 - s[2]; + unsigned char m = 255 - s[1]; + unsigned char y = 255 - s[0]; + unsigned char k = MIN(c, MIN(m, y)); + d[0] = c - k; + d[1] = m - k; + d[2] = y - k; + d[3] = k; + d[4] = s[3]; + s += 4; + d += 5; + } +} + +static void fastcmyktogray(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + unsigned char c = fz_mul255(s[0], 77); + unsigned char m = fz_mul255(s[1], 150); + unsigned char y = fz_mul255(s[2], 28); + d[0] = 255 - MIN(c + m + y + s[3], 255); + d[1] = s[4]; + s += 5; + d += 2; + } +} + +static void fastcmyktorgb(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + d[0] = 255 - MIN(s[0] + s[3], 255); + d[1] = 255 - MIN(s[1] + s[3], 255); + d[2] = 255 - MIN(s[2] + s[3], 255); + d[3] = s[4]; + s += 5; + d += 4; + } +} + +static void fastcmyktobgr(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + d[0] = 255 - MIN(s[2] + s[3], 255); + d[1] = 255 - MIN(s[1] + s[3], 255); + d[2] = 255 - MIN(s[0] + s[3], 255); + d[3] = s[4]; + s += 5; + d += 4; + } +} + +static void fastrgbtobgr(fz_pixmap *src, fz_pixmap *dst) +{ + unsigned char *s = src->samples; + unsigned char *d = dst->samples; + int n = src->w * src->h; + while (n--) + { + d[0] = s[2]; + d[1] = s[1]; + d[2] = s[0]; + d[3] = s[3]; + s += 4; + d += 4; + } +} + +static void fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) { float srcv[FZ_MAXCOLORS]; @@ -85,3 +316,173 @@ fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pi } } +void +fz_convertpixmap(fz_colorspace *ss, fz_pixmap *sp, fz_colorspace *ds, fz_pixmap *dp) +{ + if (ss == pdf_devicegray) + { + if (ds == pdf_devicergb) fastgraytorgb(sp, dp); + else if (ds == pdf_devicebgr) fastgraytorgb(sp, dp); /* bgr == rgb here */ + else if (ds == pdf_devicecmyk) fastgraytocmyk(sp, dp); + else fz_stdconvpixmap(ss, sp, ds, dp); + } + + else if (ss == pdf_devicergb) + { + if (ds == pdf_devicegray) fastrgbtogray(sp, dp); + else if (ds == pdf_devicebgr) fastrgbtobgr(sp, dp); + else if (ds == pdf_devicecmyk) fastrgbtocmyk(sp, dp); + else fz_stdconvpixmap(ss, sp, ds, dp); + + } + + else if (ss == pdf_devicebgr) + { + if (ds == pdf_devicegray) fastbgrtogray(sp, dp); + else if (ds == pdf_devicergb) fastrgbtobgr(sp, dp); /* bgr = rgb here */ + else if (ds == pdf_devicecmyk) fastbgrtocmyk(sp, dp); + else fz_stdconvpixmap(ss, sp, ds, dp); + + } + + else if (ss == pdf_devicecmyk) + { + if (ds == pdf_devicegray) fastcmyktogray(sp, dp); + else if (ds == pdf_devicebgr) fastcmyktobgr(sp, dp); + else if (ds == pdf_devicergb) fastcmyktorgb(sp, dp); + else fz_stdconvpixmap(ss, sp, ds, dp); + } + + else fz_stdconvpixmap(ss, sp, ds, dp); +} + +/* + * Convert a single color + */ + +static void +fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) +{ + float xyz[3]; + int i; + + if (srcs != dsts) + { + assert(srcs->toxyz && dsts->fromxyz); + srcs->toxyz(srcs, srcv, xyz); + dsts->fromxyz(dsts, xyz, dstv); + for (i = 0; i < dsts->n; i++) + dstv[i] = CLAMP(dstv[i], 0, 1); + } + else + { + for (i = 0; i < srcs->n; i++) + dstv[i] = srcv[i]; + } +} + +void +fz_convertcolor(fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv) +{ + if (ss == pdf_devicegray) + { + if ((ds == pdf_devicergb) || (ds == pdf_devicebgr)) + { + dv[0] = sv[0]; + dv[1] = sv[0]; + dv[2] = sv[0]; + } + else if (ds == pdf_devicecmyk) + { + dv[0] = 0; + dv[1] = 0; + dv[2] = 0; + dv[3] = sv[0]; + } + else + fz_stdconvcolor(ss, sv, ds, dv); + } + + else if (ss == pdf_devicergb) + { + if (ds == pdf_devicegray) + { + dv[0] = sv[0] * 0.3f + sv[1] * 0.59f + sv[2] * 0.11f; + } + else if (ds == pdf_devicebgr) + { + dv[0] = sv[2]; + dv[1] = sv[1]; + dv[2] = sv[0]; + } + else if (ds == pdf_devicecmyk) + { + float c = 1 - sv[0]; + float m = 1 - sv[1]; + float y = 1 - sv[2]; + float k = MIN(c, MIN(m, y)); + dv[0] = c - k; + dv[1] = m - k; + dv[2] = y - k; + dv[3] = k; + } + else + fz_stdconvcolor(ss, sv, ds, dv); + } + + else if (ss == pdf_devicebgr) + { + if (ds == pdf_devicegray) + { + dv[0] = sv[0] * 0.11f + sv[1] * 0.59f + sv[2] * 0.3f; + } + else if (ds == pdf_devicebgr) + { + dv[0] = sv[2]; + dv[1] = sv[1]; + dv[2] = sv[0]; + } + else if (ds == pdf_devicecmyk) + { + float c = 1 - sv[2]; + float m = 1 - sv[1]; + float y = 1 - sv[0]; + float k = MIN(c, MIN(m, y)); + dv[0] = c - k; + dv[1] = m - k; + dv[2] = y - k; + dv[3] = k; + } + else + fz_stdconvcolor(ss, sv, ds, dv); + } + + else if (ss == pdf_devicecmyk) + { + if (ds == pdf_devicegray) + { + float c = sv[1] * 0.3f; + float m = sv[2] * 0.59f; + float y = sv[2] * 0.11f; + dv[0] = 1 - MIN(c + m + y + sv[3], 1); + } + else if (ds == pdf_devicergb) + { + dv[0] = 1 - MIN(sv[0] + sv[3], 1); + dv[1] = 1 - MIN(sv[1] + sv[3], 1); + dv[2] = 1 - MIN(sv[2] + sv[3], 1); + } + else if (ds == pdf_devicebgr) + { + dv[0] = 1 - MIN(sv[2] + sv[3], 1); + dv[1] = 1 - MIN(sv[1] + sv[3], 1); + dv[2] = 1 - MIN(sv[0] + sv[3], 1); + } + else + fz_stdconvcolor(ss, sv, ds, dv); + } + + else + fz_stdconvcolor(ss, sv, ds, dv); +} + diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c index 3879f871..7886bd49 100644 --- a/fitz/stm_buffer.c +++ b/fitz/stm_buffer.c @@ -53,6 +53,24 @@ fz_dropbuffer(fz_buffer *buf) } void +fz_resizebuffer(fz_buffer *buf, int size) +{ + int rp = MIN(buf->rp - buf->bp, size); + int wp = MIN(buf->wp - buf->bp, size); + + if (!buf->ownsdata) + { + fz_warn("assert: resize borrowed memory"); + return; + } + + buf->bp = fz_realloc(buf->bp, size); + buf->rp = buf->bp + rp; + buf->wp = buf->bp + wp; + buf->ep = buf->bp + size; +} + +void fz_growbuffer(fz_buffer *buf) { int rp = buf->rp - buf->bp; diff --git a/mupdf/mupdf.h b/mupdf/mupdf.h index 387595a2..1c6f964e 100644 --- a/mupdf/mupdf.h +++ b/mupdf/mupdf.h @@ -209,22 +209,9 @@ pdf_function *pdf_keepfunction(pdf_function *func); void pdf_dropfunction(pdf_function *func); /* - * ColorSpace + * Colorspace */ -typedef struct pdf_indexed_s pdf_indexed; - -struct pdf_indexed_s -{ - fz_colorspace super; /* hmmm... */ - fz_colorspace *base; - int high; - unsigned char *lookup; -}; - -void pdf_convcolor(fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv); -void pdf_convpixmap(fz_colorspace *ss, fz_pixmap *sp, fz_colorspace *ds, fz_pixmap *dp); - fz_error pdf_loadcolorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj); /* @@ -286,20 +273,21 @@ typedef struct pdf_image_s pdf_image; struct pdf_image_s { int refs; - int w, h, n, a; - fz_colorspace *cs; - pdf_image *mask; /* explicit mask with subimage */ - int usecolorkey; /* explicit color-keyed masking */ + int w, h, bpc, n; + int imagemask; + int interpolate; + fz_colorspace *colorspace; + int indexed; + pdf_image *mask; /* explicit mask/softmask image */ + int usecolorkey; /* color-keyed masking */ int colorkey[FZ_MAXCOLORS * 2]; - pdf_indexed *indexed; - float decode[32]; - int bpc; + float decode[FZ_MAXCOLORS * 2]; int stride; fz_buffer *samples; }; fz_error pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file); -fz_error pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *obj); +fz_error pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *obj); fz_error pdf_loadtile(pdf_image *image, fz_pixmap *tile); pdf_image *pdf_keepimage(pdf_image *img); void pdf_dropimage(pdf_image *img); @@ -569,8 +557,6 @@ enum { PDF_MNONE, PDF_MCOLOR, - PDF_MLAB, - PDF_MINDEXED, PDF_MPATTERN, PDF_MSHADE, }; @@ -579,7 +565,6 @@ struct pdf_material_s { int kind; fz_colorspace *cs; - pdf_indexed *indexed; pdf_pattern *pattern; fz_shade *shade; float parentalpha; diff --git a/mupdf/pdf_build.c b/mupdf/pdf_build.c index e7012a2a..b64cd986 100644 --- a/mupdf/pdf_build.c +++ b/mupdf/pdf_build.c @@ -18,7 +18,6 @@ pdf_initgstate(pdf_gstate *gs, fz_matrix ctm) gs->stroke.kind = PDF_MCOLOR; gs->stroke.cs = fz_keepcolorspace(pdf_devicegray); gs->stroke.v[0] = 0; - gs->stroke.indexed = nil; gs->stroke.pattern = nil; gs->stroke.shade = nil; gs->stroke.parentalpha = 1; @@ -27,7 +26,6 @@ pdf_initgstate(pdf_gstate *gs, fz_matrix ctm) gs->fill.kind = PDF_MCOLOR; gs->fill.cs = fz_keepcolorspace(pdf_devicegray); gs->fill.v[0] = 0; - gs->fill.indexed = nil; gs->fill.pattern = nil; gs->fill.shade = nil; gs->fill.parentalpha = 1; @@ -60,29 +58,18 @@ pdf_setcolorspace(pdf_csi *csi, int what, fz_colorspace *cs) mat->kind = PDF_MCOLOR; mat->cs = fz_keepcolorspace(cs); - mat->v[0] = 0; /* FIXME: default color */ - mat->v[1] = 0; /* FIXME: default color */ - mat->v[2] = 0; /* FIXME: default color */ - mat->v[3] = 1; /* FIXME: default color */ - - if (!strcmp(cs->name, "Indexed")) - { - mat->kind = PDF_MINDEXED; - mat->indexed = (pdf_indexed*)cs; - mat->cs = mat->indexed->base; - } - - if (!strcmp(cs->name, "Lab")) - mat->kind = PDF_MLAB; + mat->v[0] = 0; + mat->v[1] = 0; + mat->v[2] = 0; + mat->v[3] = 1; } void pdf_setcolor(pdf_csi *csi, int what, float *v) { pdf_gstate *gs = csi->gstate + csi->gtop; - pdf_indexed *ind; pdf_material *mat; - int i, k; + int i; pdf_flushtext(csi); @@ -91,32 +78,16 @@ pdf_setcolor(pdf_csi *csi, int what, float *v) switch (mat->kind) { case PDF_MPATTERN: - if (!strcmp(mat->cs->name, "Lab")) - goto Llab; - if (!strcmp(mat->cs->name, "Indexed")) - goto Lindexed; - /* fall through */ - case PDF_MCOLOR: + if (!strcmp(mat->cs->name, "Lab")) + { + mat->v[0] = v[0] / 100; + mat->v[1] = (v[1] + 100) / 200; + mat->v[2] = (v[2] + 100) / 200; + } for (i = 0; i < mat->cs->n; i++) mat->v[i] = v[i]; break; - - case PDF_MLAB: -Llab: - mat->v[0] = v[0] / 100; - mat->v[1] = (v[1] + 100) / 200; - mat->v[2] = (v[2] + 100) / 200; - break; - - case PDF_MINDEXED: -Lindexed: - ind = mat->indexed; - i = CLAMP(v[0], 0, ind->high); - for (k = 0; k < ind->base->n; k++) - mat->v[k] = ind->lookup[ind->base->n * i + k] / 255.0f; - break; - default: fz_warn("color incompatible with material"); } @@ -133,12 +104,7 @@ pdf_unsetpattern(pdf_csi *csi, int what) if (mat->pattern) pdf_droppattern(mat->pattern); mat->pattern = nil; - if (!strcmp(mat->cs->name, "Lab")) - mat->kind = PDF_MLAB; - else if (!strcmp(mat->cs->name, "Indexed")) - mat->kind = PDF_MINDEXED; - else - mat->kind = PDF_MCOLOR; + mat->kind = PDF_MCOLOR; } } @@ -265,7 +231,7 @@ pdf_showimage(pdf_csi *csi, pdf_image *image) fz_pixmap *tile; fz_error error; - tile = fz_newpixmap(image->cs, 0, 0, image->w, image->h); + tile = fz_newpixmap(image->colorspace, 0, 0, image->w, image->h); error = pdf_loadtile(image, tile); if (error) { @@ -284,7 +250,7 @@ pdf_showimage(pdf_csi *csi, pdf_image *image) fz_droppixmap(mask); } - if (image->n == 0 && image->a == 1) + if (image->imagemask) { fz_rect bbox; @@ -293,8 +259,6 @@ pdf_showimage(pdf_csi *csi, pdf_image *image) case PDF_MNONE: break; case PDF_MCOLOR: - case PDF_MINDEXED: - case PDF_MLAB: csi->dev->fillimagemask(csi->dev->user, tile, gstate->ctm, gstate->fill.cs, gstate->fill.v, gstate->fill.alpha); break; @@ -353,8 +317,6 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd) case PDF_MNONE: break; case PDF_MCOLOR: - case PDF_MINDEXED: - case PDF_MLAB: csi->dev->fillpath(csi->dev->user, path, evenodd, gstate->ctm, gstate->fill.cs, gstate->fill.v, gstate->fill.alpha); break; @@ -379,8 +341,6 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd) case PDF_MNONE: break; case PDF_MCOLOR: - case PDF_MINDEXED: - case PDF_MLAB: csi->dev->strokepath(csi->dev->user, path, &gstate->strokestate, gstate->ctm, gstate->stroke.cs, gstate->stroke.v, gstate->stroke.alpha); break; @@ -471,8 +431,6 @@ pdf_flushtext(pdf_csi *csi) case PDF_MNONE: break; case PDF_MCOLOR: - case PDF_MINDEXED: - case PDF_MLAB: csi->dev->filltext(csi->dev->user, text, gstate->ctm, gstate->fill.cs, gstate->fill.v, gstate->fill.alpha); break; @@ -497,8 +455,6 @@ pdf_flushtext(pdf_csi *csi) case PDF_MNONE: break; case PDF_MCOLOR: - case PDF_MINDEXED: - case PDF_MLAB: csi->dev->stroketext(csi->dev->user, text, &gstate->strokestate, gstate->ctm, gstate->stroke.cs, gstate->stroke.v, gstate->stroke.alpha); break; diff --git a/mupdf/pdf_colorspace.c b/mupdf/pdf_colorspace.c index de18e452..fd20d6b2 100644 --- a/mupdf/pdf_colorspace.c +++ b/mupdf/pdf_colorspace.c @@ -1,468 +1,33 @@ #include "fitz.h" #include "mupdf.h" -#define noUSECAL - -static void initcs(fz_colorspace *cs, char *name, int n, - void(*to)(fz_colorspace*,float*,float*), - void(*from)(fz_colorspace*,float*,float*), - void(*freefunc)(fz_colorspace*)) -{ - fz_strlcpy(cs->name, name, sizeof cs->name); - cs->refs = 1; - cs->convpixmap = pdf_convpixmap; - cs->convcolor = pdf_convcolor; - cs->toxyz = to; - cs->fromxyz = from; - cs->freefunc = freefunc; - cs->n = n; -} - /* - * Optimized color conversions for Device colorspaces + * ICCBased */ -static void fastgraytorgb(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = s[0]; - d[1] = s[0]; - d[2] = s[0]; - d[3] = s[1]; - s += 2; - d += 4; - } -} - -static void fastgraytocmyk(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = 0; - d[1] = 0; - d[2] = 0; - d[3] = s[0]; - d[4] = s[1]; - s += 2; - d += 5; - } -} - -static void fastrgbtogray(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; - d[1] = s[3]; - s += 4; - d += 2; - } -} - -static void fastbgrtogray(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; - d[1] = s[3]; - s += 4; - d += 2; - } -} - -static void fastrgbtocmyk(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = 255 - s[0]; - unsigned char m = 255 - s[1]; - unsigned char y = 255 - s[2]; - unsigned char k = MIN(c, MIN(m, y)); - d[0] = c - k; - d[1] = m - k; - d[2] = y - k; - d[3] = k; - d[4] = s[3]; - s += 4; - d += 5; - } -} - -static void fastbgrtocmyk(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = 255 - s[2]; - unsigned char m = 255 - s[1]; - unsigned char y = 255 - s[0]; - unsigned char k = MIN(c, MIN(m, y)); - d[0] = c - k; - d[1] = m - k; - d[2] = y - k; - d[3] = k; - d[4] = s[3]; - s += 4; - d += 5; - } -} - -static void fastcmyktogray(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - unsigned char c = fz_mul255(s[0], 77); - unsigned char m = fz_mul255(s[1], 150); - unsigned char y = fz_mul255(s[2], 28); - d[0] = 255 - MIN(c + m + y + s[3], 255); - d[1] = s[4]; - s += 5; - d += 2; - } -} - -static void fastcmyktorgb(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = 255 - MIN(s[0] + s[3], 255); - d[1] = 255 - MIN(s[1] + s[3], 255); - d[2] = 255 - MIN(s[2] + s[3], 255); - d[3] = s[4]; - s += 5; - d += 4; - } -} - -static void fastcmyktobgr(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = 255 - MIN(s[2] + s[3], 255); - d[1] = 255 - MIN(s[1] + s[3], 255); - d[2] = 255 - MIN(s[0] + s[3], 255); - d[3] = s[4]; - s += 5; - d += 4; - } -} - -static void fastrgbtobgr(fz_pixmap *src, fz_pixmap *dst) -{ - unsigned char *s = src->samples; - unsigned char *d = dst->samples; - int n = src->w * src->h; - while (n--) - { - d[0] = s[2]; - d[1] = s[1]; - d[2] = s[0]; - d[3] = s[3]; - s += 4; - d += 4; - } -} - -void pdf_convpixmap(fz_colorspace *ss, fz_pixmap *sp, fz_colorspace *ds, fz_pixmap *dp) -{ - pdf_logimage("convert pixmap from %s to %s\n", ss->name, ds->name); - - if (ss == pdf_devicegray) - { - if (ds == pdf_devicergb) fastgraytorgb(sp, dp); - else if (ds == pdf_devicebgr) fastgraytorgb(sp, dp); /* bgr == rgb here */ - else if (ds == pdf_devicecmyk) fastgraytocmyk(sp, dp); - else fz_stdconvpixmap(ss, sp, ds, dp); - } - - else if (ss == pdf_devicergb) - { - if (ds == pdf_devicegray) fastrgbtogray(sp, dp); - else if (ds == pdf_devicebgr) fastrgbtobgr(sp, dp); - else if (ds == pdf_devicecmyk) fastrgbtocmyk(sp, dp); - else fz_stdconvpixmap(ss, sp, ds, dp); - - } - - else if (ss == pdf_devicebgr) - { - if (ds == pdf_devicegray) fastbgrtogray(sp, dp); - else if (ds == pdf_devicergb) fastrgbtobgr(sp, dp); /* bgr = rgb here */ - else if (ds == pdf_devicecmyk) fastbgrtocmyk(sp, dp); - else fz_stdconvpixmap(ss, sp, ds, dp); - - } - - else if (ss == pdf_devicecmyk) - { - if (ds == pdf_devicegray) fastcmyktogray(sp, dp); - else if (ds == pdf_devicebgr) fastcmyktobgr(sp, dp); - else if (ds == pdf_devicergb) fastcmyktorgb(sp, dp); - else fz_stdconvpixmap(ss, sp, ds, dp); - } - - else fz_stdconvpixmap(ss, sp, ds, dp); -} - -void pdf_convcolor(fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv) +static fz_error +loadiccbased(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) { + int n; - if (ss == pdf_devicegray) - { - if ((ds == pdf_devicergb) || (ds == pdf_devicebgr)) - { - dv[0] = sv[0]; - dv[1] = sv[0]; - dv[2] = sv[0]; - } - else if (ds == pdf_devicecmyk) - { - dv[0] = 0; - dv[1] = 0; - dv[2] = 0; - dv[3] = sv[0]; - } - else - fz_stdconvcolor(ss, sv, ds, dv); - } - - else if (ss == pdf_devicergb) - { - if (ds == pdf_devicegray) - { - dv[0] = sv[0] * 0.3f + sv[1] * 0.59f + sv[2] * 0.11f; - } - else if (ds == pdf_devicebgr) - { - dv[0] = sv[2]; - dv[1] = sv[1]; - dv[2] = sv[0]; - } - else if (ds == pdf_devicecmyk) - { - float c = 1 - sv[0]; - float m = 1 - sv[1]; - float y = 1 - sv[2]; - float k = MIN(c, MIN(m, y)); - dv[0] = c - k; - dv[1] = m - k; - dv[2] = y - k; - dv[3] = k; - } - else - fz_stdconvcolor(ss, sv, ds, dv); - } + pdf_logrsrc("load ICCBased\n"); - else if (ss == pdf_devicebgr) - { - if (ds == pdf_devicegray) - { - dv[0] = sv[0] * 0.11f + sv[1] * 0.59f + sv[2] * 0.3f; - } - else if (ds == pdf_devicebgr) - { - dv[0] = sv[2]; - dv[1] = sv[1]; - dv[2] = sv[0]; - } - else if (ds == pdf_devicecmyk) - { - float c = 1 - sv[2]; - float m = 1 - sv[1]; - float y = 1 - sv[0]; - float k = MIN(c, MIN(m, y)); - dv[0] = c - k; - dv[1] = m - k; - dv[2] = y - k; - dv[3] = k; - } - else - fz_stdconvcolor(ss, sv, ds, dv); - } + n = fz_toint(fz_dictgets(dict, "N")); - else if (ss == pdf_devicecmyk) + switch (n) { - if (ds == pdf_devicegray) - { - float c = sv[1] * 0.3f; - float m = sv[2] * 0.59f; - float y = sv[2] * 0.11f; - dv[0] = 1 - MIN(c + m + y + sv[3], 1); - } - else if (ds == pdf_devicergb) - { - dv[0] = 1 - MIN(sv[0] + sv[3], 1); - dv[1] = 1 - MIN(sv[1] + sv[3], 1); - dv[2] = 1 - MIN(sv[2] + sv[3], 1); - } - else if (ds == pdf_devicebgr) - { - dv[0] = 1 - MIN(sv[2] + sv[3], 1); - dv[1] = 1 - MIN(sv[1] + sv[3], 1); - dv[2] = 1 - MIN(sv[0] + sv[3], 1); - } - else - fz_stdconvcolor(ss, sv, ds, dv); + case 1: *csp = pdf_devicegray; return fz_okay; + case 3: *csp = pdf_devicergb; return fz_okay; + case 4: *csp = pdf_devicecmyk; return fz_okay; } - else - fz_stdconvcolor(ss, sv, ds, dv); -} - -/* - * CalGray - */ - -struct calgray -{ - fz_colorspace super; - float white[3]; - float black[3]; - float gamma; -}; - -static void graytoxyz(fz_colorspace *fzcs, float *gray, float *xyz) -{ - struct calgray *cs = (struct calgray *) fzcs; - xyz[0] = powf(gray[0], cs->gamma) * cs->white[0]; - xyz[1] = powf(gray[0], cs->gamma) * cs->white[1]; - xyz[2] = powf(gray[0], cs->gamma) * cs->white[2]; -} - -static void xyztogray(fz_colorspace *fzcs, float *xyz, float *gray) -{ - struct calgray *cs = (struct calgray *) fzcs; - float r = powf(xyz[0], 1 / cs->gamma) / cs->white[0]; - float g = powf(xyz[1], 1 / cs->gamma) / cs->white[1]; - float b = powf(xyz[2], 1 / cs->gamma) / cs->white[2]; - gray[0] = r * 0.3f + g * 0.59f + b * 0.11f; -} - -/* - * CalRGB - */ - -struct calrgb -{ - fz_colorspace super; - float white[3]; - float black[3]; - float gamma[3]; - float matrix[9]; - float invmat[9]; -}; - -static void rgbtoxyz(fz_colorspace *fzcs, float *rgb, float *xyz) -{ - struct calrgb *cs = (struct calrgb *) fzcs; - float a = powf(rgb[0], cs->gamma[0]) * cs->white[0]; - float b = powf(rgb[1], cs->gamma[1]) * cs->white[1]; - float c = powf(rgb[2], cs->gamma[2]) * cs->white[2]; - xyz[0] = a * cs->matrix[0] + b * cs->matrix[1] + c * cs->matrix[2]; - xyz[1] = a * cs->matrix[3] + b * cs->matrix[4] + c * cs->matrix[5]; - xyz[2] = a * cs->matrix[6] + b * cs->matrix[7] + c * cs->matrix[8]; -} - -static void xyztorgb(fz_colorspace *fzcs, float *xyz, float *rgb) -{ - struct calrgb *cs = (struct calrgb *) fzcs; - float a = xyz[0] * cs->invmat[0] + xyz[1] * cs->invmat[1] + xyz[2] * cs->invmat[2]; - float b = xyz[0] * cs->invmat[3] + xyz[1] * cs->invmat[4] + xyz[2] * cs->invmat[5]; - float c = xyz[0] * cs->invmat[6] + xyz[1] * cs->invmat[7] + xyz[2] * cs->invmat[8]; - rgb[0] = powf(a, 1 / cs->gamma[0]) / cs->white[0]; - rgb[1] = powf(b, 1 / cs->gamma[1]) / cs->white[1]; - rgb[2] = powf(c, 1 / cs->gamma[2]) / cs->white[2]; -} - -/* - * DeviceCMYK piggybacks on DeviceRGB - */ - -static void devicecmyktoxyz(fz_colorspace *cs, float *cmyk, float *xyz) -{ - float rgb[3]; - rgb[0] = 1 - MIN(1, cmyk[0] + cmyk[3]); - rgb[1] = 1 - MIN(1, cmyk[1] + cmyk[3]); - rgb[2] = 1 - MIN(1, cmyk[2] + cmyk[3]); - rgbtoxyz(pdf_devicergb, rgb, xyz); -} - -static void xyztodevicecmyk(fz_colorspace *cs, float *xyz, float *cmyk) -{ - float rgb[3]; - float c, m, y, k; - xyztorgb(pdf_devicergb, xyz, rgb); - c = 1 - rgb[0]; - m = 1 - rgb[0]; - y = 1 - rgb[0]; - k = MIN(c, MIN(m, y)); - cmyk[0] = c - k; - cmyk[1] = m - k; - cmyk[2] = y - k; - cmyk[3] = k; -} - -/* - * DeviceBGR piggybacks on DeviceRGB - */ - -static void bgrtoxyz(fz_colorspace *cs, float *bgr, float *xyz) -{ - float rgb[3]; - rgb[0] = bgr[2]; - rgb[1] = bgr[1]; - rgb[2] = bgr[0]; - rgbtoxyz(pdf_devicergb, rgb, xyz); -} - -static void xyztobgr(fz_colorspace *cs, float *xyz, float *bgr) -{ - float rgb[3]; - xyztorgb(pdf_devicergb, xyz, rgb); - bgr[0] = rgb[2]; - bgr[1] = rgb[1]; - bgr[2] = rgb[0]; + return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components"); } /* - * CIE Lab + * Lab */ -struct cielab -{ - fz_colorspace super; - float white[3]; - float black[3]; - float range[4]; -}; - static inline float fung(float x) { if (x >= 6.0f / 29.0f) @@ -477,289 +42,43 @@ static inline float invg(float x) return (7.787f * x) + (16.0f / 116.0f); } -static void labtoxyz(fz_colorspace *fzcs, float *lab, float *xyz) +static void +labtoxyz(fz_colorspace *cs, float *lab, float *xyz) { - struct cielab *cs = (struct cielab *) fzcs; float lstar, astar, bstar, l, m, n; float tmp[3]; tmp[0] = lab[0] * 100; tmp[1] = lab[1] * 200 - 100; tmp[2] = lab[2] * 200 - 100; lstar = tmp[0]; - astar = MAX(MIN(tmp[1], cs->range[1]), cs->range[0]); - bstar = MAX(MIN(tmp[2], cs->range[3]), cs->range[2]); + astar = CLAMP(tmp[1], -100, 100); + bstar = CLAMP(tmp[2], -100, 100); l = (lstar + 16) / 116 + astar / 500; m = (lstar + 16) / 116; n = (lstar + 16) / 116 - bstar / 200; - xyz[0] = fung(l) * cs->white[0]; - xyz[1] = fung(m) * cs->white[1]; - xyz[2] = fung(n) * cs->white[2]; + xyz[0] = fung(l); + xyz[1] = fung(m); + xyz[2] = fung(n); } -static void xyztolab(fz_colorspace *fzcs, float *xyz, float *lab) +static void +xyztolab(fz_colorspace *cs, float *xyz, float *lab) { - struct cielab *cs = (struct cielab *) fzcs; float tmp[3]; - float yyn = xyz[1] / cs->white[1]; + float yyn = xyz[1]; if (yyn < 0.008856f) tmp[0] = 116.0f * yyn * (1.0f / 3.0f) - 16.0f; else tmp[0] = 903.3f * yyn; - tmp[1] = 500 * (invg(xyz[0]/cs->white[0]) - invg(xyz[1]/cs->white[1])); - tmp[2] = 200 * (invg(xyz[1]/cs->white[1]) - invg(xyz[2]/cs->white[2])); + tmp[1] = 500 * (invg(xyz[0]) - invg(xyz[1])); + tmp[2] = 200 * (invg(xyz[1]) - invg(xyz[2])); lab[0] = tmp[0] / 100; lab[1] = (tmp[1] + 100) / 200; lab[2] = (tmp[2] + 100) / 200; } -/* - * Define global Device* colorspaces as Cal* - */ - -static struct calgray kdevicegray = -{ - { -1, "DeviceGray", 1, pdf_convpixmap, pdf_convcolor, graytoxyz, xyztogray, nil }, - { 1, 1, 1 }, - { 0, 0, 0 }, - 1 -}; - -static struct calrgb kdevicergb = -{ - { -1, "DeviceRGB", 3, pdf_convpixmap, pdf_convcolor, rgbtoxyz, xyztorgb, nil }, - { 1, 1, 1 }, - { 0, 0, 0 }, - { 1, 1, 1 }, - { 1,0,0, 0,1,0, 0,0,1 }, - { 1,0,0, 0,1,0, 0,0,1 }, -}; - -static struct calrgb kdevicebgr = -{ - { -1, "DeviceBGR", 3, pdf_convpixmap, pdf_convcolor, bgrtoxyz, xyztobgr, nil }, - { 1, 1, 1 }, - { 0, 0, 0 }, - { 1, 1, 1 }, - { 1,0,0, 0,1,0, 0,0,1 }, - { 1,0,0, 0,1,0, 0,0,1 }, -}; - -static fz_colorspace kdevicecmyk = -{ - -1, "DeviceCMYK", 4, pdf_convpixmap, pdf_convcolor, devicecmyktoxyz, xyztodevicecmyk, nil -}; - -static struct cielab kdevicelab = -{ - { -1, "Lab", 3, pdf_convpixmap, fz_stdconvcolor, labtoxyz, xyztolab, nil }, - { 1, 1, 1 }, - { 0, 0, 0 }, - { -100, 100, -100, 100 }, -}; - -static fz_colorspace kdevicepattern = -{ - -1, "Pattern", 0, nil, nil, nil, nil, nil -}; - -fz_colorspace *pdf_devicegray = &kdevicegray.super; -fz_colorspace *pdf_devicergb = &kdevicergb.super; -fz_colorspace *pdf_devicebgr = &kdevicebgr.super; -fz_colorspace *pdf_devicecmyk = &kdevicecmyk; -fz_colorspace *pdf_devicelab = &kdevicelab.super; -fz_colorspace *pdf_devicepattern = &kdevicepattern; - -/* - * Colorspace parsing - */ - -#ifdef USECAL -static fz_colorspace * -loadcalgray(pdf_xref *xref, fz_obj *dict) -{ - struct calgray *cs; - fz_obj *tmp; - - cs = fz_malloc(sizeof(struct calgray)); - - pdf_logrsrc("load CalGray\n"); - - initcs((fz_colorspace*)cs, "CalGray", 1, graytoxyz, xyztogray, nil); - - cs->white[0] = 1; - cs->white[1] = 1; - cs->white[2] = 1; - - cs->black[0] = 0; - cs->black[1] = 0; - cs->black[2] = 0; - - cs->gamma = 1; - - tmp = fz_dictgets(dict, "WhitePoint"); - if (fz_isarray(tmp)) - { - cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "BlackPoint"); - if (fz_isarray(tmp)) - { - cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "Gamma"); - if (fz_isreal(tmp)) - cs->gamma = fz_toreal(tmp); - - return (fz_colorspace*) cs; -} - -static fz_colorspace * -loadcalrgb(pdf_xref *xref, fz_obj *dict) -{ - struct calrgb *cs; - fz_obj *tmp; - int i; - - cs = fz_malloc(sizeof(struct calrgb)); - - pdf_logrsrc("load CalRGB\n"); - - initcs((fz_colorspace*)cs, "CalRGB", 3, rgbtoxyz, xyztorgb, nil); - - cs->white[0] = 1; - cs->white[1] = 1; - cs->white[2] = 1; - - cs->black[0] = 0; - cs->black[1] = 0; - cs->black[2] = 0; - - cs->gamma[0] = 1; - cs->gamma[1] = 1; - cs->gamma[2] = 1; - - cs->matrix[0] = 1; cs->matrix[1] = 0; cs->matrix[2] = 0; - cs->matrix[3] = 0; cs->matrix[4] = 1; cs->matrix[5] = 0; - cs->matrix[6] = 0; cs->matrix[7] = 0; cs->matrix[8] = 1; - - tmp = fz_dictgets(dict, "WhitePoint"); - if (fz_isarray(tmp)) - { - cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "BlackPoint"); - if (fz_isarray(tmp)) - { - cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "Gamma"); - if (fz_isarray(tmp)) - { - cs->gamma[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->gamma[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->gamma[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "Matrix"); - if (fz_isarray(tmp)) - { - for (i = 0; i < 9; i++) - cs->matrix[i] = fz_toreal(fz_arrayget(tmp, i)); - } - - fz_invert3x3(cs->invmat, cs->matrix); - - return (fz_colorspace*) cs; -} - -static fz_colorspace * -loadlab(pdf_xref *xref, fz_obj *dict) -{ - struct cielab *cs; - fz_obj *tmp; - - cs = fz_malloc(sizeof(struct cielab)); - - pdf_logrsrc("load Lab\n"); - - initcs((fz_colorspace*)cs, "Lab", 3, labtoxyz, xyztolab, nil); - - cs->white[0] = 1; - cs->white[1] = 1; - cs->white[2] = 1; - - cs->black[0] = 0; - cs->black[1] = 0; - cs->black[2] = 0; - - cs->range[0] = -100; - cs->range[1] = 100; - cs->range[2] = -100; - cs->range[3] = 100; - - tmp = fz_dictgets(dict, "WhitePoint"); - if (fz_isarray(tmp)) - { - cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "BlackPoint"); - if (fz_isarray(tmp)) - { - cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); - } - - tmp = fz_dictgets(dict, "Range"); - if (fz_isarray(tmp)) - { - cs->range[0] = fz_toreal(fz_arrayget(tmp, 0)); - cs->range[1] = fz_toreal(fz_arrayget(tmp, 1)); - cs->range[2] = fz_toreal(fz_arrayget(tmp, 2)); - cs->range[3] = fz_toreal(fz_arrayget(tmp, 3)); - } - - return (fz_colorspace*) cs; -} -#endif - -/* - * ICCBased - */ - -static fz_error -loadiccbased(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) -{ - int n; - - pdf_logrsrc("load ICCBased\n"); - - n = fz_toint(fz_dictgets(dict, "N")); - - switch (n) - { - case 1: *csp = pdf_devicegray; return fz_okay; - case 3: *csp = pdf_devicergb; return fz_okay; - case 4: *csp = pdf_devicecmyk; return fz_okay; - } - - return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components"); -} +static fz_colorspace kdevicelab = { -1, "Lab", 3, labtoxyz, xyztolab }; +static fz_colorspace *pdf_devicelab = &kdevicelab; /* * Separation and DeviceN @@ -767,18 +86,18 @@ loadiccbased(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) struct separation { - fz_colorspace super; fz_colorspace *base; pdf_function *tint; }; -static void separationtoxyz(fz_colorspace *fzcs, float *sep, float *xyz) +static void +separationtoxyz(fz_colorspace *cs, float *color, float *xyz) { - struct separation *cs = (struct separation *)fzcs; + struct separation *sep = cs->data; fz_error error; float alt[FZ_MAXCOLORS]; - error = pdf_evalfunction(cs->tint, sep, fzcs->n, alt, cs->base->n); + error = pdf_evalfunction(sep->tint, color, cs->n, alt, sep->base->n); if (error) { fz_catch(error, "cannot evaluate separation function"); @@ -788,22 +107,24 @@ static void separationtoxyz(fz_colorspace *fzcs, float *sep, float *xyz) return; } - cs->base->toxyz(cs->base, alt, xyz); + sep->base->toxyz(sep->base, alt, xyz); } static void -freeseparation(fz_colorspace *fzcs) +freeseparation(fz_colorspace *cs) { - struct separation *cs = (struct separation *)fzcs; - fz_dropcolorspace(cs->base); - pdf_dropfunction(cs->tint); + struct separation *sep = cs->data; + fz_dropcolorspace(sep->base); + pdf_dropfunction(sep->tint); + fz_free(sep); } static fz_error loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; - struct separation *cs; + fz_colorspace *cs; + struct separation *sep; fz_obj *nameobj = fz_arrayget(array, 1); fz_obj *baseobj = fz_arrayget(array, 2); fz_obj *tintobj = fz_arrayget(array, 3); @@ -834,21 +155,18 @@ loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_tonum(tintobj), fz_togen(tintobj)); } - cs = fz_malloc(sizeof(struct separation)); + sep = fz_malloc(sizeof(struct separation)); + sep->base = base; + sep->tint = tint; - initcs((fz_colorspace*)cs, - n == 1 ? "Separation" : "DeviceN", n, - separationtoxyz, nil, freeseparation); - - cs->base = fz_keepcolorspace(base); - cs->tint = pdf_keepfunction(tint); - - fz_dropcolorspace(base); - pdf_dropfunction(tint); + cs = fz_newcolorspace(n == 1 ? "Separation" : "DeviceN", n); + cs->toxyz = separationtoxyz; + cs->freedata = freeseparation; + cs->data = sep; pdf_logrsrc("}\n"); - *csp = (fz_colorspace*)cs; + *csp = cs; return fz_okay; } @@ -856,34 +174,42 @@ loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) * Indexed */ -#if 0 +struct indexed +{ + fz_colorspace *base; + int high; + unsigned char *lookup; +}; + static void -indexedtoxyz(fz_colorspace *fzcs, float *ind, float *xyz) +indexedtoxyz(fz_colorspace *cs, float *color, float *xyz) { - pdf_indexed *cs = (pdf_indexed *)fzcs; + struct indexed *idx = cs->data; float alt[FZ_MAXCOLORS]; int i, k; - i = ind[0] * 255; - i = CLAMP(i, 0, cs->high); - for (k = 0; k < cs->base->n; k++) - alt[k] = cs->lookup[i * cs->base->n + k] / 255.0f; - cs->base->toxyz(cs->base, alt, xyz); + i = color[0] * 255; + i = CLAMP(i, 0, idx->high); + for (k = 0; k < idx->base->n; k++) + alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f; + idx->base->toxyz(idx->base, alt, xyz); } -#endif static void -freeindexed(fz_colorspace *fzcs) +freeindexed(fz_colorspace *cs) { - pdf_indexed *cs = (pdf_indexed *)fzcs; - if (cs->base) fz_dropcolorspace(cs->base); - if (cs->lookup) fz_free(cs->lookup); + struct indexed *idx = cs->data; + if (idx->base) + fz_dropcolorspace(idx->base); + fz_free(idx->lookup); + fz_free(idx); } static fz_error loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; - pdf_indexed *cs; + fz_colorspace *cs; + struct indexed *idx; fz_obj *baseobj = fz_arrayget(array, 1); fz_obj *highobj = fz_arrayget(array, 2); fz_obj *lookup = fz_arrayget(array, 3); @@ -898,17 +224,16 @@ loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) pdf_logrsrc("base %s\n", base->name); - cs = fz_malloc(sizeof(pdf_indexed)); + idx = fz_malloc(sizeof(struct indexed)); + idx->base = base; + idx->high = fz_toint(highobj); + n = base->n * (idx->high + 1); + idx->lookup = fz_malloc(n); - initcs((fz_colorspace*)cs, "Indexed", 1, nil, nil, freeindexed); - - cs->base = fz_keepcolorspace(base); - cs->high = fz_toint(highobj); - - fz_dropcolorspace(base); - - n = base->n * (cs->high + 1); - cs->lookup = fz_malloc(n); + cs = fz_newcolorspace("Indexed", 1); + cs->toxyz = indexedtoxyz; + cs->freedata = freeindexed; + cs->data = idx; if (fz_isstring(lookup) && fz_tostrlen(lookup) == n) { @@ -919,7 +244,7 @@ loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) buf = (unsigned char *) fz_tostrbuf(lookup); for (i = 0; i < n; i++) - cs->lookup[i] = buf[i]; + idx->lookup[i] = buf[i]; } else if (fz_isindirect(lookup)) { @@ -931,24 +256,24 @@ loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) error = pdf_loadstream(&buf, xref, fz_tonum(lookup), fz_togen(lookup)); if (error) { - fz_dropcolorspace((fz_colorspace*)cs); + fz_dropcolorspace(cs); return fz_rethrow(error, "cannot load colorpsace lookup table (%d %d R)", fz_tonum(lookup), fz_togen(lookup)); } for (i = 0; i < n && i < (buf->wp - buf->rp); i++) - cs->lookup[i] = buf->rp[i]; + idx->lookup[i] = buf->rp[i]; fz_dropbuffer(buf); } else { - fz_dropcolorspace((fz_colorspace*)cs); + fz_dropcolorspace(cs); return fz_throw("cannot parse colorspace lookup table"); } pdf_logrsrc("}\n"); - *csp = (fz_colorspace*)cs; + *csp = cs; return fz_okay; } @@ -961,20 +286,23 @@ pdf_loadcolorspaceimp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) { if (fz_isname(obj)) { - if (!strcmp(fz_toname(obj), "DeviceGray")) + if (!strcmp(fz_toname(obj), "Pattern")) + { +fz_warn("uncolored pattern colorspace (name)"); *csp = pdf_devicegray; - else if (!strcmp(fz_toname(obj), "DeviceRGB")) - *csp = pdf_devicergb; - else if (!strcmp(fz_toname(obj), "DeviceCMYK")) - *csp = pdf_devicecmyk; + } else if (!strcmp(fz_toname(obj), "G")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(obj), "RGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(obj), "CMYK")) *csp = pdf_devicecmyk; - else if (!strcmp(fz_toname(obj), "Pattern")) - *csp = pdf_devicepattern; + else if (!strcmp(fz_toname(obj), "DeviceGray")) + *csp = pdf_devicegray; + else if (!strcmp(fz_toname(obj), "DeviceRGB")) + *csp = pdf_devicergb; + else if (!strcmp(fz_toname(obj), "DeviceCMYK")) + *csp = pdf_devicecmyk; else return fz_throw("unknown colorspace: %s", fz_toname(obj)); return fz_okay; @@ -986,49 +314,16 @@ pdf_loadcolorspaceimp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) if (fz_isname(name)) { - if (!strcmp(fz_toname(name), "CalCMYK")) - *csp = pdf_devicecmyk; - -#ifdef USECAL - else if (!strcmp(fz_toname(name), "CalGray")) - *csp = loadcalgray(xref, fz_arrayget(obj, 1)); - else if (!strcmp(fz_toname(name), "CalRGB")) - *csp = loadcalrgb(xref, fz_arrayget(obj, 1)); - else if (!strcmp(fz_toname(name), "Lab")) - *csp = loadlab(xref, fz_arrayget(obj, 1)); -#else - else if (!strcmp(fz_toname(name), "CalGray")) - *csp = pdf_devicegray; - else if (!strcmp(fz_toname(name), "CalRGB")) - *csp = pdf_devicergb; - else if (!strcmp(fz_toname(name), "Lab")) - *csp = pdf_devicelab; -#endif - - else if (!strcmp(fz_toname(name), "ICCBased")) - return loadiccbased(csp, xref, fz_arrayget(obj, 1)); - - else if (!strcmp(fz_toname(name), "Indexed")) - return loadindexed(csp, xref, obj); - - else if (!strcmp(fz_toname(name), "I")) - return loadindexed(csp, xref, obj); - - else if (!strcmp(fz_toname(name), "Separation")) - return loadseparation(csp, xref, obj); - - else if (!strcmp(fz_toname(name), "DeviceN")) - return loadseparation(csp, xref, obj); - /* load base colorspace instead */ - else if (!strcmp(fz_toname(name), "Pattern")) + if (!strcmp(fz_toname(name), "Pattern")) { fz_error error; obj = fz_arrayget(obj, 1); if (!obj) { - *csp = pdf_devicepattern; +fz_warn("uncolored pattern colorspace (array)"); + *csp = pdf_devicegray; return fz_okay; } @@ -1037,18 +332,40 @@ pdf_loadcolorspaceimp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_tonum(obj), fz_togen(obj)); } + else if (!strcmp(fz_toname(name), "G")) + *csp = pdf_devicegray; + else if (!strcmp(fz_toname(name), "RGB")) + *csp = pdf_devicergb; + else if (!strcmp(fz_toname(name), "CMYK")) + *csp = pdf_devicecmyk; else if (!strcmp(fz_toname(name), "DeviceGray")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(name), "DeviceRGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(name), "DeviceCMYK")) *csp = pdf_devicecmyk; - else if (!strcmp(fz_toname(name), "G")) + else if (!strcmp(fz_toname(name), "CalGray")) *csp = pdf_devicegray; - else if (!strcmp(fz_toname(name), "RGB")) + else if (!strcmp(fz_toname(name), "CalRGB")) *csp = pdf_devicergb; - else if (!strcmp(fz_toname(name), "CMYK")) + else if (!strcmp(fz_toname(name), "CalCMYK")) *csp = pdf_devicecmyk; + else if (!strcmp(fz_toname(name), "Lab")) + *csp = pdf_devicelab; + + else if (!strcmp(fz_toname(name), "ICCBased")) + return loadiccbased(csp, xref, fz_arrayget(obj, 1)); + + else if (!strcmp(fz_toname(name), "Indexed")) + return loadindexed(csp, xref, obj); + else if (!strcmp(fz_toname(name), "I")) + return loadindexed(csp, xref, obj); + + else if (!strcmp(fz_toname(name), "Separation")) + return loadseparation(csp, xref, obj); + + else if (!strcmp(fz_toname(name), "DeviceN")) + return loadseparation(csp, xref, obj); else return fz_throw("syntaxerror: unknown colorspace %s", fz_toname(name)); @@ -1079,4 +396,3 @@ pdf_loadcolorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) return fz_okay; } - diff --git a/mupdf/pdf_image.c b/mupdf/pdf_image.c index e4cfabe6..e125545b 100644 --- a/mupdf/pdf_image.c +++ b/mupdf/pdf_image.c @@ -1,10 +1,10 @@ -/* - * TODO: this needs serious cleaning up, and error checking. - */ - #include "fitz.h" #include "mupdf.h" +/* TODO: special case JPXDecode image loading */ +/* TODO: store JPEG compressed samples */ +/* TODO: store flate compressed samples */ + pdf_image * pdf_keepimage(pdf_image *image) { @@ -17,169 +17,146 @@ pdf_dropimage(pdf_image *img) { if (img && --img->refs == 0) { - fz_dropbuffer(img->samples); - if (img->cs) - fz_dropcolorspace(img->cs); - if (img->indexed) - fz_dropcolorspace((fz_colorspace *) img->indexed); + if (img->colorspace) + fz_dropcolorspace(img->colorspace); if (img->mask) pdf_dropimage(img->mask); + if (img->samples) + fz_dropbuffer(img->samples); fz_free(img); } } -fz_error -pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, - fz_obj *rdb, fz_obj *dict, fz_stream *file) +static fz_error +pdf_loadimageheader(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { - fz_error error; pdf_image *img; - fz_filter *filter; - fz_obj *f; - fz_obj *cs; - fz_obj *d; - int ismask; + fz_error error; + fz_obj *obj, *res; int i; img = fz_malloc(sizeof(pdf_image)); - - pdf_logimage("load inline image %p {\n", img); + memset(img, 0, sizeof(pdf_image)); img->refs = 1; - img->cs = nil; - img->n = 0; - img->a = 0; - img->indexed = nil; - img->usecolorkey = 0; - img->mask = nil; - img->w = fz_toint(fz_dictgetsa(dict, "Width", "W")); img->h = fz_toint(fz_dictgetsa(dict, "Height", "H")); img->bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC")); - ismask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); - d = fz_dictgetsa(dict, "Decode", "D"); - cs = fz_dictgetsa(dict, "ColorSpace", "CS"); + img->imagemask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); + img->interpolate = fz_tobool(fz_dictgetsa(dict, "Interpolate", "I")); + + if (img->imagemask) + img->bpc = 1; + if (img->w == 0) - fz_warn("inline image width is zero or undefined"); + fz_warn("image width is zero"); if (img->h == 0) - fz_warn("inline image height is zero or undefined"); + fz_warn("image height is zero"); + if (img->bpc == 0) + fz_warn("image bit depth is zero"); /* okay for JPX */ - pdf_logimage("size %dx%d %d\n", img->w, img->h, img->bpc); - - if (cs) + obj = fz_dictgetsa(dict, "ColorSpace", "CS"); + if (obj) { - fz_obj *csd = nil; - fz_obj *cso = nil; - - /* Attempt to lookup any name in the resource dictionary */ - if (fz_isname(cs)) + if (fz_isname(obj)) { - csd = fz_dictgets(rdb, "ColorSpace"); - cso = fz_dictget(csd, cs); + res = fz_dictget(fz_dictgets(rdb, "ColorSpace"), obj); + if (res) + obj = res; } - /* If no colorspace found in resource dictionary, - * assume that reference is a standard name */ - if (!cso) - cso = cs; - - error = pdf_loadcolorspace(&img->cs, xref, cso); + error = pdf_loadcolorspace(&img->colorspace, xref, obj); if (error) { pdf_dropimage(img); - return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_tonum(cso), fz_togen(cso)); + return fz_rethrow(error, "cannot load image colorspace"); } - if (!img->cs) - return fz_throw("image is missing colorspace"); - - if (!strcmp(img->cs->name, "Indexed")) - { - pdf_logimage("indexed\n"); - img->indexed = (pdf_indexed*)img->cs; - img->cs = img->indexed->base; - fz_keepcolorspace(img->cs); - } + if (!strcmp(img->colorspace->name, "Indexed")) + img->indexed = 1; - pdf_logimage("colorspace %s\n", img->cs->name); - - img->n = img->cs->n; - img->a = 0; + img->n = img->colorspace->n; } - - if (ismask) + else { - pdf_logimage("is mask\n"); - if (img->cs) - { - fz_warn("masks can not have colorspace, proceeding anyway."); - fz_dropcolorspace(img->cs); - img->cs = nil; - } - if (img->bpc != 1) - fz_warn("masks can only have one component, proceeding anyway."); - - img->bpc = 1; - img->n = 0; - img->a = 1; + img->colorspace = pdf_devicegray; + img->n = 1; } - else if (!cs) - return fz_throw("image is missing colorspace"); - if (fz_isarray(d)) + obj = fz_dictgetsa(dict, "Decode", "D"); + if (obj) { - pdf_logimage("decode array\n"); - if (img->indexed) - for (i = 0; i < 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(d, i)); - else - for (i = 0; i < (img->n + img->a) * 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(d, i)); + for (i = 0; i < img->n * 2; i++) + img->decode[i] = fz_toreal(fz_arrayget(obj, i)); } else { - if (img->indexed) - for (i = 0; i < 2; i++) - img->decode[i] = i & 1 ? (1 << img->bpc) - 1 : 0; - else - for (i = 0; i < (img->n + img->a) * 2; i++) - img->decode[i] = i & 1; + for (i = 0; i < img->n * 2; i++) + if (i & 1) + img->decode[i] = 1; + else + img->decode[i] = 0; } - if (img->indexed) - img->stride = (img->w * img->bpc + 7) / 8; - else - img->stride = (img->w * (img->n + img->a) * img->bpc + 7) / 8; - - /* load image data */ - - f = fz_dictgetsa(dict, "Filter", "F"); - if (!f || (fz_isarray(f) && fz_arraylen(f) == 0)) + obj = fz_dictgetsa(dict, "Mask", "SMask"); + if (pdf_isstream(xref, fz_tonum(obj), fz_togen(obj))) { - img->samples = fz_newbuffer(img->h * img->stride); - - error = fz_read(&i, file, img->samples->bp, img->h * img->stride); + error = pdf_loadimage(&img->mask, xref, rdb, obj); if (error) - return error; - - img->samples->wp += img->h * img->stride; + { + pdf_dropimage(img); + return fz_rethrow(error, "cannot load image mask/softmask"); + } + img->mask->imagemask = 1; } - else + else if (fz_isarray(obj)) { - fz_stream *tempfile; + img->usecolorkey = 1; + for (i = 0; i < img->n * 2; i++) + img->colorkey[i] = fz_toint(fz_arrayget(obj, i)); + } - filter = pdf_buildinlinefilter(xref, dict); + img->stride = (img->w * img->n * img->bpc + 7) / 8; - tempfile = fz_openfilter(filter, file); + pdf_logimage("size %dx%d n=%d bpc=%d (imagemask=%d)\n", img->w, img->h, img->n, img->bpc, img->imagemask); - img->samples = fz_readall(tempfile, img->stride * img->h); - fz_dropstream(tempfile); + *imgp = img; + return fz_okay; +} + +fz_error +pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, + fz_obj *rdb, fz_obj *dict, fz_stream *file) +{ + fz_error error; + pdf_image *img; + fz_filter *filter; + fz_stream *subfile; + int n; + + pdf_logimage("load inline image {\n"); + + error = pdf_loadimageheader(&img, xref, rdb, dict); + if (error) + return fz_rethrow(error, "cannot load inline image"); + + filter = pdf_buildinlinefilter(xref, dict); + subfile = fz_openfilter(filter, file); - fz_dropfilter(filter); + img->samples = fz_newbuffer(img->h * img->stride); + error = fz_read(&n, file, img->samples->bp, img->h * img->stride); + if (error) + { + pdf_dropimage(img); + return fz_rethrow(error, "cannot load inline image data"); } + img->samples->wp += n; + + fz_dropstream(subfile); + fz_dropfilter(filter); /* 0 means opaque and 1 means transparent, so we invert to get alpha */ - if (ismask) + if (img->imagemask) { unsigned char *p; for (p = img->samples->bp; p < img->samples->ep; p++) @@ -192,48 +169,11 @@ pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, return fz_okay; } -static void -loadcolorkey(int *colorkey, int bpc, int indexed, fz_obj *obj) -{ - int scale = 1; - int i; - - pdf_logimage("keyed mask\n"); - - if (!indexed) - { - switch (bpc) - { - case 1: scale = 255; break; - case 2: scale = 85; break; - case 4: scale = 17; break; - case 8: scale = 1; break; - } - } - - for (i = 0; i < fz_arraylen(obj); i++) - colorkey[i] = fz_toint(fz_arrayget(obj, i)) * scale; -} - -/* TODO error cleanup */ fz_error -pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict) +pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { fz_error error; pdf_image *img; - pdf_image *mask; - int ismask; - fz_obj *obj; - int i; - - int w, h, bpc; - int n = 0; - int a = 0; - int usecolorkey = 0; - fz_colorspace *cs = nil; - pdf_indexed *indexed = nil; - int stride; - int realsize, expectedsize; if ((*imgp = pdf_finditem(xref->store, PDF_KIMAGE, dict))) { @@ -241,208 +181,36 @@ pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict) return fz_okay; } - img = fz_malloc(sizeof(pdf_image)); - - pdf_logimage("load image (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), img); - - /* - * Dimensions, BPC and ColorSpace - */ - - w = fz_toint(fz_dictgets(dict, "Width")); - if (w == 0) - fz_warn("image width is zero or undefined"); - - h = fz_toint(fz_dictgets(dict, "Height")); - if (h == 0) - fz_warn("image height is zero or undefined"); - - bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent")); - - pdf_logimage("size %dx%d %d\n", w, h, bpc); - - cs = nil; - obj = fz_dictgets(dict, "ColorSpace"); - if (obj) - { - error = pdf_loadcolorspace(&cs, xref, obj); - if (error) - { - pdf_dropimage(img); - return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_tonum(obj), fz_togen(obj)); - } - - if (!strcmp(cs->name, "Indexed")) - { - pdf_logimage("indexed\n"); - indexed = (pdf_indexed*)cs; - cs = indexed->base; - fz_keepcolorspace(cs); - } - n = cs->n; - a = 0; - - pdf_logimage("colorspace %s\n", cs->name); - } - - /* - * ImageMask, Mask and SoftMask - */ - - mask = nil; - - ismask = fz_tobool(fz_dictgets(dict, "ImageMask")); - if (ismask) - { - pdf_logimage("is mask\n"); - if (cs) - { - fz_warn("masks can not have colorspace, proceeding anyway."); - fz_dropcolorspace(cs); - cs = nil; - } - if (bpc != 0 && bpc != 1) - fz_warn("masks can only have one component, proceeding anyway."); - - bpc = 1; - n = 0; - a = 1; - } - else - { - if (!cs) - return fz_throw("colorspace missing for image"); - if (bpc == 0) - return fz_throw("image has no bits per component"); - } - - obj = fz_dictgets(dict, "SMask"); - if (fz_isindirect(obj)) - { - pdf_logimage("has soft mask\n"); - - error = pdf_loadimage(&mask, xref, obj); - if (error) - return error; - - if (mask->cs && mask->cs != pdf_devicegray) - return fz_throw("syntaxerror: SMask must be DeviceGray"); - - mask->cs = nil; - mask->n = 0; - mask->a = 1; - } - - obj = fz_dictgets(dict, "Mask"); - if (fz_isindirect(obj)) - { - if (fz_isarray(obj)) - { - usecolorkey = 1; - loadcolorkey(img->colorkey, bpc, indexed != nil, obj); - } - else - { - pdf_logimage("has mask\n"); - if (mask) - { - fz_warn("image has both a mask and a soft mask. ignoring the soft mask."); - pdf_dropimage(mask); - mask = nil; - } - error = pdf_loadimage(&mask, xref, obj); - if (error) - return error; - } - } - else if (fz_isarray(obj)) - { - usecolorkey = 1; - loadcolorkey(img->colorkey, bpc, indexed != nil, obj); - } - - /* - * Decode - */ - - obj = fz_dictgets(dict, "Decode"); - if (fz_isarray(obj)) - { - pdf_logimage("decode array\n"); - if (indexed) - for (i = 0; i < 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(obj, i)); - else - for (i = 0; i < (n + a) * 2; i++) - img->decode[i] = fz_toreal(fz_arrayget(obj, i)); - } - else - { - if (indexed) - for (i = 0; i < 2; i++) - img->decode[i] = i & 1 ? (1 << bpc) - 1 : 0; - else - for (i = 0; i < (n + a) * 2; i++) - img->decode[i] = i & 1; - } - - /* - * Load samples - */ + pdf_logimage("load image (%d %d R) {\n", fz_tonum(dict), fz_togen(dict)); - if (indexed) - stride = (w * bpc + 7) / 8; - else - stride = (w * (n + a) * bpc + 7) / 8; + error = pdf_loadimageheader(&img, xref, rdb, dict); + if (error) + return fz_rethrow(error, "cannot load image (%d %d R)", fz_tonum(dict), fz_togen(dict)); error = pdf_loadstream(&img->samples, xref, fz_tonum(dict), fz_togen(dict)); if (error) { - /* TODO: colorspace? */ - fz_free(img); - return error; + pdf_dropimage(img); + return fz_rethrow(error, "cannot load image data (%d %d R)", fz_tonum(dict), fz_togen(dict)); } - expectedsize = stride *h; - realsize = img->samples->wp - img->samples->bp; - if (realsize < expectedsize) + /* Pad truncated images */ + if (img->samples->wp - img->samples->bp < img->stride * img->h) { - /* don't treat truncated image as fatal - get as much as possible and - fill the rest with 0 */ - fz_buffer *buf; - buf = fz_newbuffer(expectedsize); - memset(buf->bp, 0, expectedsize); - memmove(buf->bp, img->samples->bp, realsize); - buf->wp = buf->bp + expectedsize; - fz_dropbuffer(img->samples); - img->samples = buf; - fz_warn("truncated image; proceeding anyway"); + fz_warn("padding truncated image"); + fz_resizebuffer(img->samples, img->stride * img->h); + memset(img->samples->wp, 0, img->samples->ep - img->samples->wp); + img->samples->wp = img->samples->bp + img->stride * img->h; } /* 0 means opaque and 1 means transparent, so we invert to get alpha */ - if (ismask) + if (img->imagemask) { unsigned char *p; for (p = img->samples->bp; p < img->samples->ep; p++) *p = ~*p; } - /* - * Create image object - */ - - img->refs = 1; - img->cs = cs; - img->w = w; - img->h = h; - img->n = n; - img->a = a; - img->indexed = indexed; - img->stride = stride; - img->bpc = bpc; - img->mask = mask; - img->usecolorkey = usecolorkey; - pdf_logimage("}\n"); pdf_storeitem(xref->store, PDF_KIMAGE, dict, img); @@ -452,15 +220,15 @@ pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict) } static void -maskcolorkey(fz_pixmap *pix, int *colorkey) +pdf_maskcolorkey(fz_pixmap *pix, int n, int *colorkey, int scale) { unsigned char *p = pix->samples; int i, k, t; for (i = 0; i < pix->w * pix->h; i++) { t = 1; - for (k = 1; k < pix->n; k++) - if (p[k] < colorkey[k * 2 - 2] || p[k] > colorkey[k * 2 - 1]) + for (k = 0; k < n; k++) + if (p[k] < colorkey[k * 2] * scale || p[k] > colorkey[k * 2 + 1] * scale) t = 0; if (t) for (k = 0; k < pix->n; k++) @@ -469,23 +237,6 @@ maskcolorkey(fz_pixmap *pix, int *colorkey) } } -static void -maskcolorkeyindexed(fz_pixmap *ind, fz_pixmap *pix, int *colorkey) -{ - unsigned char *s = ind->samples; - unsigned char *d = pix->samples; - int i, k; - - for (i = 0; i < pix->w * pix->h; i++) - { - if (s[0] >= colorkey[0] && s[0] <= colorkey[1]) - for (k = 0; k < pix->n; k++) - d[k] = 0; - s += ind->n; - d += pix->n; - } -} - fz_error pdf_loadtile(pdf_image *src, fz_pixmap *tile) { @@ -493,7 +244,7 @@ pdf_loadtile(pdf_image *src, fz_pixmap *tile) assert(tile->x == 0); /* can't handle general tile yet, only y-banding */ - assert(tile->n == src->n + 1); + assert(tile->n == src->n + 1 - src->imagemask); assert(tile->x >= 0); assert(tile->y >= 0); assert(tile->x + tile->w <= src->w); @@ -510,62 +261,30 @@ pdf_loadtile(pdf_image *src, fz_pixmap *tile) return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc); } - if (src->indexed) - { - fz_pixmap *tmp; - int x, y, k, i; - int bpcfact = 1; - - tmp = fz_newpixmap(nil, tile->x, tile->y, tile->w, tile->h); + tilefunc(src->samples->rp + (tile->y * src->stride), src->stride, + tile->samples, tile->w * tile->n, + tile->w * src->n, tile->h, src->imagemask ? 0 : src->n); - switch (src->bpc) - { - case 1: bpcfact = 255; break; - case 2: bpcfact = 85; break; - case 4: bpcfact = 17; break; - case 8: bpcfact = 1; break; - } - - tilefunc(src->samples->rp + (tile->y * src->stride), src->stride, - tmp->samples, tmp->w, - tmp->w, tmp->h, 0); - - for (y = 0; y < tile->h; y++) + if (src->usecolorkey) + { + int scale = 1; /* tilefunc scaled image samples to 0..255 */ + if (!src->indexed) { - int dn = tile->n; - unsigned char *dst = tile->samples + y * tile->w * dn; - unsigned char *st = tmp->samples + y * tmp->w; - unsigned char *index = src->indexed->lookup; - int high = src->indexed->high; - int sn = src->indexed->base->n; - for (x = 0; x < tile->w; x++) + switch (src->bpc) { - i = st[x] / bpcfact; - i = CLAMP(i, 0, high); - for (k = 0; k < sn; k++) - { - dst[x * dn + k] = index[i * sn + k]; - } - dst[x * dn + sn] = 255; /* alpha */ + case 1: scale = 255; break; + case 2: scale = 85; break; + case 4: scale = 17; break; + case 8: scale = 1; break; + case 16: + fz_warn("color-key masked 16-bpc images are not supported"); + break; } } - - if (src->usecolorkey) - maskcolorkeyindexed(tmp, tile, src->colorkey); - - fz_droppixmap(tmp); + pdf_maskcolorkey(tile, src->n, src->colorkey, scale); } - else - { - tilefunc(src->samples->rp + (tile->y * src->stride), src->stride, - tile->samples, tile->w * tile->n, - tile->w * (src->n + src->a), tile->h, src->a ? 0 : src->n); - if (src->usecolorkey) - maskcolorkey(tile, src->colorkey); - fz_decodetile(tile, !src->a, src->decode); - } + fz_decodetile(tile, !src->imagemask, src->decode); return fz_okay; } - diff --git a/mupdf/pdf_interpret.c b/mupdf/pdf_interpret.c index bda4a601..f45b9299 100644 --- a/mupdf/pdf_interpret.c +++ b/mupdf/pdf_interpret.c @@ -45,8 +45,6 @@ pdf_keepmaterial(pdf_material *mat) { if (mat->cs) fz_keepcolorspace(mat->cs); - if (mat->indexed) - fz_keepcolorspace(&mat->indexed->super); if (mat->pattern) pdf_keeppattern(mat->pattern); if (mat->shade) @@ -59,8 +57,6 @@ pdf_dropmaterial(pdf_material *mat) { if (mat->cs) fz_dropcolorspace(mat->cs); - if (mat->indexed) - fz_dropcolorspace(&mat->indexed->super); if (mat->pattern) pdf_droppattern(mat->pattern); if (mat->shade) @@ -573,7 +569,7 @@ Lsetcolorspace: if ((csi->dev->hints & FZ_IGNOREIMAGE) == 0) { pdf_image *img; - error = pdf_loadimage(&img, csi->xref, obj); + error = pdf_loadimage(&img, csi->xref, rdb, obj); if (error) return fz_rethrow(error, "cannot load image (%d %d R)", fz_tonum(obj), fz_togen(obj)); pdf_showimage(csi, img); @@ -743,15 +739,7 @@ Lsetcolor: case PDF_MNONE: return fz_throw("cannot set color in mask objects"); - case PDF_MINDEXED: - if (csi->top < 1) - goto syntaxerror; - v[0] = fz_toreal(csi->stack[0]); - pdf_setcolor(csi, what, v); - break; - case PDF_MCOLOR: - case PDF_MLAB: if (csi->top < mat->cs->n) goto syntaxerror; for (i = 0; i < csi->top; i++) diff --git a/mupdf/pdf_pattern.c b/mupdf/pdf_pattern.c index 678698ef..d083c855 100644 --- a/mupdf/pdf_pattern.c +++ b/mupdf/pdf_pattern.c @@ -62,6 +62,8 @@ pdf_loadpattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict) return fz_rethrow(error, "cannot load pattern stream (%d %d R)", fz_tonum(dict), fz_togen(dict)); } + pdf_logrsrc("}\n"); + *patp = pat; return fz_okay; } diff --git a/mupdf/pdf_store.c b/mupdf/pdf_store.c index a5fc3cfe..519ec9e8 100644 --- a/mupdf/pdf_store.c +++ b/mupdf/pdf_store.c @@ -228,7 +228,7 @@ pdf_storeitem(pdf_store *store, pdf_itemkind kind, fz_obj *key, void *val) } else { - pdf_logrsrc("store item %s: ... = %p\n", kindstr(kind), val); + pdf_logrsrc("store item %s (...) = %p\n", kindstr(kind), val); item->next = store->root; store->root = item; diff --git a/mupdf/pdf_xobject.c b/mupdf/pdf_xobject.c index a083a38d..38310163 100644 --- a/mupdf/pdf_xobject.c +++ b/mupdf/pdf_xobject.c @@ -19,11 +19,11 @@ pdf_loadxobject(pdf_xobject **formp, pdf_xref *xref, fz_obj *dict) form->resources = nil; form->contents = nil; + pdf_logrsrc("load xobject (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), form); + /* Store item immediately, to avoid possible recursion if objects refer back to this one */ pdf_storeitem(xref->store, PDF_KXOBJECT, dict, form); - pdf_logrsrc("load xobject (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), form); - obj = fz_dictgets(dict, "BBox"); form->bbox = pdf_torect(obj); |