diff options
author | Tor Andersson <tor@ghostscript.com> | 2010-07-14 02:51:01 +0200 |
---|---|---|
committer | Tor Andersson <tor@ghostscript.com> | 2010-07-14 02:51:01 +0200 |
commit | b8fa3eabea0fc29a1937d661565cda0caf79ce50 (patch) | |
tree | 2a6d14905ea660155a8d0d5b5de294375f0f006f | |
parent | 48f6f0e2cd05182613b78322c2b924635caf3f55 (diff) | |
download | mupdf-b8fa3eabea0fc29a1937d661565cda0caf79ce50.tar.xz |
Add transparency group/mask device calls and implement basic blend modes when drawing primitive objects.
-rw-r--r-- | draw/blendmodes.c | 133 | ||||
-rw-r--r-- | fitz/dev_draw.c | 87 | ||||
-rw-r--r-- | fitz/dev_list.c | 88 | ||||
-rw-r--r-- | fitz/dev_null.c | 9 | ||||
-rw-r--r-- | fitz/dev_trace.c | 2 | ||||
-rw-r--r-- | fitz/fitz.h | 26 | ||||
-rw-r--r-- | mupdf/mupdf.h | 2 | ||||
-rw-r--r-- | mupdf/pdf_build.c | 41 | ||||
-rw-r--r-- | mupdf/pdf_image.c | 2 | ||||
-rw-r--r-- | mupdf/pdf_interpret.c | 16 |
10 files changed, 339 insertions, 67 deletions
diff --git a/draw/blendmodes.c b/draw/blendmodes.c index f86fa1ef..9dde35d1 100644 --- a/draw/blendmodes.c +++ b/draw/blendmodes.c @@ -8,49 +8,43 @@ Only the actual blend routines are here, not the node rendering logic which live These are slow. */ - /* These functions apply to a single component, 0-255 range typically */ -static int +static inline int fz_screen_byte(int bd, int s) { return bd + s - fz_mul255(bd, s); } - -static int +static inline int fz_hardlight_byte(int bd, int s) { int s2 = s << 1; if (s <= 127) return fz_mul255(bd, s2); else - return fz_screen_byte(bd, s2); + return fz_screen_byte(bd, s2 - 1); } - -static int +static inline int fz_overlay_byte(int bd, int s) { return fz_hardlight_byte(s, bd); // note swapped order } - -static int +static inline int fz_darken_byte(int bd, int s) { return MIN(bd, s); } - -static int +static inline int fz_lighten_byte(int bd, int s) { return MAX(bd, s); } - -static int +static inline int fz_colordodge_byte(int bd, int s) { if (s < 255) @@ -59,8 +53,7 @@ fz_colordodge_byte(int bd, int s) return 255; } - -static int +static inline int fz_colorburn_byte(int bd, int s) { if (s > 0) @@ -69,8 +62,7 @@ fz_colorburn_byte(int bd, int s) return 0; } - -static int +static inline int fz_softlight_byte(int bd, int s) { /* review this */ @@ -87,32 +79,27 @@ fz_softlight_byte(int bd, int s) } } - -static int +static inline int fz_difference_byte(int bd, int s) { return ABS(bd - s); } - -static int +static inline int fz_exclusion_byte(int bd, int s) { return bd + s - (fz_mul255(bd, s)<<1); } - /* Non-separable blend modes */ - -static int +static inline int lum(int r, int g, int b) { /* 0.3, 0.59, 0.11 in 16.16 fixed point */ return (19662 * r + 38666 * g + 7208 * b) >> 16; } - static void clipcolor(int r, int g, int b, int *dr, int *dg, int *db) { @@ -131,7 +118,6 @@ clipcolor(int r, int g, int b, int *dr, int *dg, int *db) } } - static void setlum(int r, int g, int b, int l, int *dr, int *dg, int *db) { @@ -139,14 +125,12 @@ setlum(int r, int g, int b, int l, int *dr, int *dg, int *db) clipcolor(r + d, g + d, b + d, dr, dg, db); } - -static int +static inline int sat(int r, int g, int b) { return MAX(MAX(r, g), b) - MIN(MIN(r, g), b); } - static void setsat(int r, int g, int b, int s, int *dr, int *dg, int *db) { @@ -176,7 +160,6 @@ setsat(int r, int g, int b, int s, int *dr, int *dg, int *db) *db = b; } - static void fz_hue_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) { @@ -185,7 +168,6 @@ fz_hue_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); } - static void fz_saturation_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) { @@ -194,21 +176,100 @@ fz_saturation_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); } - static void fz_color_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) { setlum(sr, sg, sb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb); } - static void fz_luminosity_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb) { setlum(*bdr, *bdg, *bdb, lum(sr, sg, sb), bdr, bdg, bdb); } +/* + * + */ + +void +fz_blend_nxn(byte * restrict sp, int sw, int sn, + byte * restrict dp, int dw, + int w0, int h, fz_blendmode blendmode) +{ + int k; + + sw -= w0*sn; + dw -= w0*sn; + while (h--) + { + int w = w0; + while (w--) + { + int sa = sp[sn-1]; + int da = dp[sn-1]; + int ta = 255 - sa; + int tb = 255 - da; + int tc = fz_mul255(sa, da); + for (k = 0; k < sn; k++) + { + int r, bd, s; + if (da) + bd = dp[k] * 255 / da; + if (sa) + s = sp[k] * 255 / sa; + switch (blendmode) + { + default: + case FZ_BMULTIPLY: r = fz_mul255(bd, s); break; + case FZ_BSCREEN: r = fz_screen_byte(bd, s); break; + case FZ_BOVERLAY: r = fz_overlay_byte(bd, s); break; + case FZ_BDARKEN: r = fz_darken_byte(bd, s); break; + case FZ_BLIGHTEN: r = fz_lighten_byte(bd, s); break; + case FZ_BCOLORDODGE: r = fz_colordodge_byte(bd, s); break; + case FZ_BCOLORBURN: r = fz_colorburn_byte(bd, s); break; + case FZ_BHARDLIGHT: r = fz_hardlight_byte(bd, s); break; + case FZ_BSOFTLIGHT: r = fz_softlight_byte(bd, s); break; + case FZ_BDIFFERENCE: r = fz_difference_byte(bd, s); break; + case FZ_BEXCLUSION: r = fz_exclusion_byte(bd, s); break; + } + dp[k] = fz_mul255(ta, dp[k]) + fz_mul255(tb, sp[k]) + fz_mul255(tc, r); + } + sp += sn; + dp += sn; + } + sp += sw; + dp += dw; + } +} + +void +fz_blendpixmaps(fz_pixmap *src, fz_pixmap *dst, fz_blendmode blendmode) +{ + unsigned char *sp, *dp; + fz_bbox sr, dr; + int x, y, w, h; + + assert(src->n == dst->n); + + sr.x0 = src->x; + sr.y0 = src->y; + sr.x1 = src->x + src->w; + sr.y1 = src->y + src->h; -//fz_separable_blend(, fz_blendkind mode) -//{ - //} + dr.x0 = dst->x; + dr.y0 = dst->y; + dr.x1 = dst->x + dst->w; + dr.y1 = dst->y + dst->h; + + dr = fz_intersectbbox(sr, dr); + x = dr.x0; + y = dr.y0; + w = dr.x1 - dr.x0; + h = dr.y1 - dr.y0; + + sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; + dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; + + fz_blend_nxn(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h, blendmode); +} diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c index 369cdf06..86ef1846 100644 --- a/fitz/dev_draw.c +++ b/fitz/dev_draw.c @@ -15,6 +15,7 @@ struct fz_drawdevice_s fz_gel *gel; fz_ael *ael; fz_pixmap *dest; + fz_bbox scissor; struct { fz_pixmap *dest; @@ -22,6 +23,10 @@ struct fz_drawdevice_s fz_bbox scissor; } clipstack[MAXCLIP]; int cliptop; + + fz_blendmode blendmode; + fz_pixmap *groupstack[MAXCLIP]; + int grouptop; }; static void @@ -185,8 +190,8 @@ fz_drawclippath(void *user, fz_path *path, int evenodd, fz_matrix ctm) mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(dev->model, bbox); - memset(mask->samples, 0, mask->w * mask->h * mask->n); - memset(dest->samples, 0, dest->w * dest->h * dest->n); + fz_clearpixmap(mask, 0); + fz_clearpixmap(dest, 0); fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, mask, nil, nil, nil); @@ -230,8 +235,8 @@ fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matr mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(dev->model, bbox); - memset(mask->samples, 0, mask->w * mask->h * mask->n); - memset(dest->samples, 0, dest->w * dest->h * dest->n); + fz_clearpixmap(mask, 0); + fz_clearpixmap(dest, 0); if (!fz_isemptyrect(bbox)) fz_scanconvert(dev->gel, dev->ael, 0, bbox, mask, nil, nil, nil); @@ -429,8 +434,8 @@ fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(dev->model, bbox); - memset(mask->samples, 0, mask->w * mask->h * mask->n); - memset(dest->samples, 0, dest->w * dest->h * dest->n); + fz_clearpixmap(mask, 0); + fz_clearpixmap(dest, 0); dev->clipstack[dev->cliptop].scissor = dev->scissor; dev->clipstack[dev->cliptop].mask = mask; @@ -495,8 +500,8 @@ fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matr mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(dev->model, bbox); - memset(mask->samples, 0, mask->w * mask->h * mask->n); - memset(dest->samples, 0, dest->w * dest->h * dest->n); + fz_clearpixmap(mask, 0); + fz_clearpixmap(dest, 0); dev->clipstack[dev->cliptop].scissor = dev->scissor; dev->clipstack[dev->cliptop].mask = mask; @@ -763,8 +768,8 @@ fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(dev->model, bbox); - memset(mask->samples, 0, mask->w * mask->h * mask->n); - memset(dest->samples, 0, dest->w * dest->h * dest->n); + fz_clearpixmap(mask, 0); + fz_clearpixmap(dest, 0); fz_scanconvert(dev->gel, dev->ael, 0, bbox, mask, nil, image, &invmat); @@ -802,6 +807,62 @@ fz_drawpopclip(void *user) } static void +fz_drawbeginmask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) +{ + fz_warn("fz_drawbeginmask"); +} + +static void +fz_drawendmask(void *user) +{ + fz_warn("fz_drawendmask"); +} + +static void +fz_drawbegingroup(void *user, fz_rect rect, fz_colorspace *colorspace, int isolated, int knockout, fz_blendmode blendmode) +{ + fz_drawdevice *dev = user; + fz_bbox bbox; + fz_pixmap *dest; + + fz_warn("fz_drawbegingroup"); + + if (dev->cliptop == MAXCLIP) + { + fz_warn("assert: too many clip masks on stack"); + return; + } + + bbox = fz_roundrect(rect); + bbox = fz_intersectbbox(bbox, dev->scissor); + dest = fz_newpixmapwithrect(dev->model, bbox); + + fz_clearpixmap(dest, 0); + + dev->blendmode = blendmode; + dev->groupstack[dev->grouptop++] = dev->dest; + dev->dest = dest; +} + +static void +fz_drawendgroup(void *user) +{ + fz_drawdevice *dev = user; + fz_pixmap *group = dev->dest; + + fz_warn("fz_drawendgroup"); + + if (dev->grouptop > 0) + { + dev->grouptop--; + dev->dest = dev->groupstack[dev->grouptop]; + fz_blendpixmaps(group, dev->dest, dev->blendmode); + } + + fz_droppixmap(group); +} + +static void fz_drawfreeuser(void *user) { fz_drawdevice *dev = user; @@ -826,6 +887,7 @@ fz_newdrawdevice(fz_glyphcache *cache, fz_pixmap *dest) ddev->ael = fz_newael(); ddev->dest = dest; ddev->cliptop = 0; + ddev->grouptop = 0; ddev->scissor.x0 = dest->x; ddev->scissor.y0 = dest->y; @@ -853,5 +915,10 @@ fz_newdrawdevice(fz_glyphcache *cache, fz_pixmap *dest) dev->popclip = fz_drawpopclip; + dev->beginmask = fz_drawbeginmask; + dev->endmask = fz_drawendmask; + dev->begingroup = fz_drawbegingroup; + dev->endgroup = fz_drawendgroup; + return dev; } diff --git a/fitz/dev_list.c b/fitz/dev_list.c index 3ca6fca6..f3e7c750 100644 --- a/fitz/dev_list.c +++ b/fitz/dev_list.c @@ -1,5 +1,8 @@ #include "fitz.h" +#define ISOLATED 1 +#define KNOCKOUT 2 + static fz_displaynode * fz_newdisplaynode(fz_displaycommand cmd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) @@ -10,6 +13,7 @@ fz_newdisplaynode(fz_displaycommand cmd, fz_matrix ctm, node = fz_malloc(sizeof(fz_displaynode)); node->cmd = cmd; node->next = nil; + node->rect = fz_emptyrect; node->item.path = nil; node->stroke = nil; node->flag = 0; @@ -17,8 +21,11 @@ fz_newdisplaynode(fz_displaycommand cmd, fz_matrix ctm, if (colorspace) { node->colorspace = fz_keepcolorspace(colorspace); - for (i = 0; i < node->colorspace->n; i++) - node->color[i] = color[i]; + if (color) + { + for (i = 0; i < node->colorspace->n; i++) + node->color[i] = color[i]; + } } else { @@ -79,6 +86,10 @@ fz_freedisplaynode(fz_displaynode *node) fz_droppixmap(node->item.image); break; case FZ_CMDPOPCLIP: + case FZ_CMDBEGINMASK: + case FZ_CMDENDMASK: + case FZ_CMDBEGINGROUP: + case FZ_CMDENDGROUP: break; } if (node->stroke) @@ -94,6 +105,7 @@ fz_listfillpath(void *user, fz_path *path, int evenodd, fz_matrix ctm, { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDFILLPATH, ctm, colorspace, color, alpha); + node->rect = fz_boundpath(path, nil, ctm); node->item.path = fz_clonepath(path); node->flag = evenodd; fz_appenddisplaynode(user, node); @@ -105,6 +117,7 @@ fz_liststrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix c { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDSTROKEPATH, ctm, colorspace, color, alpha); + node->rect = fz_boundpath(path, stroke, ctm); node->item.path = fz_clonepath(path); node->stroke = fz_clonestrokestate(stroke); fz_appenddisplaynode(user, node); @@ -115,6 +128,7 @@ fz_listclippath(void *user, fz_path *path, int evenodd, fz_matrix ctm) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDCLIPPATH, ctm, nil, nil, 0); + node->rect = fz_boundpath(path, nil, ctm); node->item.path = fz_clonepath(path); node->flag = evenodd; fz_appenddisplaynode(user, node); @@ -125,6 +139,7 @@ fz_listclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matr { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDCLIPSTROKEPATH, ctm, nil, nil, 0); + node->rect = fz_boundpath(path, stroke, ctm); node->item.path = fz_clonepath(path); node->stroke = fz_clonestrokestate(stroke); fz_appenddisplaynode(user, node); @@ -136,6 +151,7 @@ fz_listfilltext(void *user, fz_text *text, fz_matrix ctm, { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDFILLTEXT, ctm, colorspace, color, alpha); + node->rect = fz_boundtext(text, ctm); node->item.text = fz_clonetext(text); fz_appenddisplaynode(user, node); } @@ -146,6 +162,7 @@ fz_liststroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix c { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDSTROKETEXT, ctm, colorspace, color, alpha); + node->rect = fz_boundtext(text, ctm); node->item.text = fz_clonetext(text); node->stroke = fz_clonestrokestate(stroke); fz_appenddisplaynode(user, node); @@ -156,6 +173,7 @@ fz_listcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDCLIPTEXT, ctm, nil, nil, 0); + node->rect = fz_boundtext(text, ctm); node->item.text = fz_clonetext(text); node->flag = accumulate; fz_appenddisplaynode(user, node); @@ -166,6 +184,7 @@ fz_listclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matr { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDCLIPSTROKETEXT, ctm, nil, nil, 0); + node->rect = fz_boundtext(text, ctm); node->item.text = fz_clonetext(text); node->stroke = fz_clonestrokestate(stroke); fz_appenddisplaynode(user, node); @@ -176,6 +195,7 @@ fz_listignoretext(void *user, fz_text *text, fz_matrix ctm) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDIGNORETEXT, ctm, nil, nil, 0); + node->rect = fz_boundtext(text, ctm); node->item.text = fz_clonetext(text); fz_appenddisplaynode(user, node); } @@ -185,6 +205,7 @@ fz_listpopclip(void *user) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDPOPCLIP, fz_identity, nil, nil, 0); + /* TODO: scan back for matching pushclip and calculate bbox of contents */ fz_appenddisplaynode(user, node); } @@ -193,6 +214,7 @@ fz_listfillshade(void *user, fz_shade *shade, fz_matrix ctm) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDFILLSHADE, ctm, nil, nil, 0); + node->rect = fz_boundshade(shade, ctm); node->item.shade = fz_keepshade(shade); fz_appenddisplaynode(user, node); } @@ -202,6 +224,7 @@ fz_listfillimage(void *user, fz_pixmap *image, fz_matrix ctm) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDFILLIMAGE, ctm, nil, nil, 0); + node->rect = fz_transformrect(ctm, fz_unitrect); node->item.image = fz_keeppixmap(image); fz_appenddisplaynode(user, node); } @@ -212,6 +235,7 @@ fz_listfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm, { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDFILLIMAGEMASK, ctm, colorspace, color, alpha); + node->rect = fz_transformrect(ctm, fz_unitrect); node->item.image = fz_keeppixmap(image); fz_appenddisplaynode(user, node); } @@ -221,10 +245,49 @@ fz_listclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) { fz_displaynode *node; node = fz_newdisplaynode(FZ_CMDCLIPIMAGEMASK, ctm, nil, nil, 0); + node->rect = fz_transformrect(ctm, fz_unitrect); node->item.image = fz_keeppixmap(image); fz_appenddisplaynode(user, node); } +static void +fz_listbeginmask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *color) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDBEGINMASK, fz_identity, colorspace, color, 0); + node->rect = rect; + node->flag = luminosity; + fz_appenddisplaynode(user, node); +} + +static void +fz_listendmask(void *user) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDENDMASK, fz_identity, nil, nil, 0); + fz_appenddisplaynode(user, node); +} + +static void +fz_listbegingroup(void *user, fz_rect rect, fz_colorspace *colorspace, int isolated, int knockout, fz_blendmode blendmode) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDBEGINGROUP, fz_identity, colorspace, nil, 0); + node->rect = rect; + node->item.blendmode = blendmode; + node->flag |= isolated ? ISOLATED : 0; + node->flag |= knockout ? KNOCKOUT : 0; + fz_appenddisplaynode(user, node); +} + +static void +fz_listendgroup(void *user) +{ + fz_displaynode *node; + node = fz_newdisplaynode(FZ_CMDENDGROUP, fz_identity, nil, nil, 0); + fz_appenddisplaynode(user, node); +} + fz_device * fz_newlistdevice(fz_displaylist *list) { @@ -248,6 +311,11 @@ fz_newlistdevice(fz_displaylist *list) dev->popclip = fz_listpopclip; + dev->beginmask = fz_listbeginmask; + dev->endmask = fz_listendmask; + dev->begingroup = fz_listbegingroup; + dev->endgroup = fz_listendgroup; + return dev; } @@ -276,6 +344,7 @@ void fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm) { fz_displaynode *node; + fz_rect bbox; for (node = list->first; node; node = node->next) { fz_matrix ctm = fz_concat(node->ctm, topctm); @@ -328,6 +397,21 @@ fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix topctm) case FZ_CMDPOPCLIP: dev->popclip(dev->user); break; + case FZ_CMDBEGINMASK: + bbox = fz_transformrect(topctm, node->rect); + dev->beginmask(dev->user, bbox, node->flag, node->colorspace, node->color); + break; + case FZ_CMDENDMASK: + dev->endmask(dev->user); + break; + case FZ_CMDBEGINGROUP: + bbox = fz_transformrect(topctm, node->rect); + dev->begingroup(dev->user, bbox, node->colorspace, + node->flag & ISOLATED, node->flag & KNOCKOUT, node->item.blendmode); + break; + case FZ_CMDENDGROUP: + dev->endgroup(dev->user); + break; } } } diff --git a/fitz/dev_null.c b/fitz/dev_null.c index 1c3788a5..223275aa 100644 --- a/fitz/dev_null.c +++ b/fitz/dev_null.c @@ -15,6 +15,10 @@ static void fz_nullfillshade(void *user, fz_shade *shade, fz_matrix ctm) {} static void fz_nullfillimage(void *user, fz_pixmap *image, fz_matrix ctm) {} static void fz_nullfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) {} static void fz_nullclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) {} +static void fz_nullbeginmask(void *user, fz_rect r, int luminosity, fz_colorspace *cs, float *bc) {} +static void fz_nullendmask(void *user) {} +static void fz_nullbegingroup(void *user, fz_rect r, fz_colorspace *cs, int isolated, int knockout, fz_blendmode blendmode) {} +static void fz_nullendgroup(void *user) {} fz_device * fz_newdevice(void *user) @@ -45,6 +49,11 @@ fz_newdevice(void *user) dev->popclip = fz_nullpopclip; + dev->beginmask = fz_nullbeginmask; + dev->endmask = fz_nullendmask; + dev->begingroup = fz_nullbegingroup; + dev->endgroup = fz_nullendgroup; + return dev; } diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c index 0edbb5c9..ebf28535 100644 --- a/fitz/dev_trace.c +++ b/fitz/dev_trace.c @@ -227,6 +227,8 @@ fz_tracepopclip(void *user) printf("</gsave>\n"); } +/* TODO: transparency group functions */ + fz_device *fz_newtracedevice(void) { fz_device *dev = fz_newdevice(nil); diff --git a/fitz/fitz.h b/fitz/fitz.h index 5adf331a..2d2aa003 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -653,7 +653,7 @@ static inline void fz_unreadbyte(fz_stream *stm) enum { FZ_MAXCOLORS = 32 }; -typedef enum fz_blendkind_e +typedef enum fz_blendmode_e { /* PDF 1.4 -- standard separable */ FZ_BNORMAL, @@ -674,7 +674,7 @@ typedef enum fz_blendkind_e FZ_BSATURATION, FZ_BCOLOR, FZ_BLUMINOSITY, -} fz_blendkind; +} fz_blendmode; /* * Pixmaps have n components per pixel. the last is always alpha. @@ -1010,6 +1010,11 @@ struct fz_device_s void (*clipimagemask)(void *, fz_pixmap *img, fz_matrix ctm); void (*popclip)(void *); + + void (*beginmask)(void *, fz_rect, int luminosity, fz_colorspace *cs, float *bc); + void (*endmask)(void *); + void (*begingroup)(void *, fz_rect, fz_colorspace *, int isolated, int knockout, fz_blendmode blendmode); + void (*endgroup)(void *); }; fz_device *fz_newdevice(void *user); @@ -1075,6 +1080,10 @@ typedef enum fz_displaycommand_e FZ_CMDFILLIMAGEMASK, FZ_CMDCLIPIMAGEMASK, FZ_CMDPOPCLIP, + FZ_CMDBEGINMASK, + FZ_CMDENDMASK, + FZ_CMDBEGINGROUP, + FZ_CMDENDGROUP, } fz_displaycommand; struct fz_displaylist_s @@ -1087,14 +1096,16 @@ struct fz_displaynode_s { fz_displaycommand cmd; fz_displaynode *next; + fz_rect rect; union { fz_path *path; fz_text *text; fz_shade *shade; fz_pixmap *image; + fz_blendmode blendmode; } item; fz_strokestate *stroke; - int flag; /* evenodd, accumulate, ... */ + int flag; /* evenodd, accumulate, isolated/knockout... */ fz_matrix ctm; fz_colorspace *colorspace; float alpha; @@ -1111,11 +1122,12 @@ void fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix ctm); * They can be replaced by cpu-optimized versions. */ -extern void fz_accelerate(void); -extern void fz_acceleratearch(void); +void fz_accelerate(void); +void fz_acceleratearch(void); -extern void fz_decodetile(fz_pixmap *pix, float *decode); -extern void fz_unpacktile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale); +void fz_decodetile(fz_pixmap *pix, float *decode); +void fz_unpacktile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale); +void fz_blendpixmaps(fz_pixmap *src, fz_pixmap *dst, fz_blendmode blendmode); extern void (*fz_duff_ni1on)(unsigned char*restrict,int,int,unsigned char*restrict,int,unsigned char*restrict,int,int,int); extern void (*fz_duff_1i1o1)(unsigned char*restrict,int,unsigned char*restrict,int,unsigned char*restrict,int,int,int); diff --git a/mupdf/mupdf.h b/mupdf/mupdf.h index 35117790..90b6fc6c 100644 --- a/mupdf/mupdf.h +++ b/mupdf/mupdf.h @@ -584,7 +584,7 @@ struct pdf_gstate_s /* materials */ pdf_material stroke; pdf_material fill; - fz_blendkind blendmode; + fz_blendmode blendmode; /* text state */ float charspace; diff --git a/mupdf/pdf_build.c b/mupdf/pdf_build.c index ec3e8baf..ae408bf3 100644 --- a/mupdf/pdf_build.c +++ b/mupdf/pdf_build.c @@ -221,7 +221,17 @@ void pdf_showshade(pdf_csi *csi, fz_shade *shd) { pdf_gstate *gstate = csi->gstate + csi->gtop; + + if (gstate->blendmode != FZ_BNORMAL) + { + fz_rect bbox = fz_boundshade(shd, gstate->ctm); + csi->dev->begingroup(csi->dev->user, bbox, nil, 0, 0, gstate->blendmode); + } + csi->dev->fillshade(csi->dev->user, shd, gstate->ctm); + + if (gstate->blendmode != FZ_BNORMAL) + csi->dev->endgroup(csi->dev->user); } void @@ -237,6 +247,12 @@ pdf_showimage(pdf_csi *csi, pdf_image *image) fz_droppixmap(mask); } + if (gstate->blendmode != FZ_BNORMAL) + { + fz_rect bbox = fz_transformrect(gstate->ctm, fz_unitrect); + csi->dev->begingroup(csi->dev->user, bbox, nil, 0, 0, gstate->blendmode); + } + tile = pdf_loadtile(image); if (image->imagemask) @@ -275,6 +291,9 @@ pdf_showimage(pdf_csi *csi, pdf_image *image) csi->dev->fillimage(csi->dev->user, tile, gstate->ctm); } + if (gstate->blendmode != FZ_BNORMAL) + csi->dev->endgroup(csi->dev->user); + if (image->mask) csi->dev->popclip(csi->dev->user); @@ -301,6 +320,16 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd) csi->clip = 0; } + if (gstate->blendmode != FZ_BNORMAL) + { + fz_rect bbox; + if (dostroke) + bbox = fz_boundpath(path, &gstate->strokestate, gstate->ctm); + else + bbox = fz_boundpath(path, nil, gstate->ctm); + csi->dev->begingroup(csi->dev->user, bbox, nil, 0, 0, gstate->blendmode); + } + if (dofill) { switch (gstate->fill.kind) @@ -361,6 +390,9 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd) } } + if (gstate->blendmode != FZ_BNORMAL) + csi->dev->endgroup(csi->dev->user); + fz_freepath(path); } @@ -427,6 +459,12 @@ pdf_flushtext(pdf_csi *csi) csi->accumulate = 2; } + if (gstate->blendmode != FZ_BNORMAL) + { + fz_rect bbox = fz_boundtext(text, gstate->ctm); + csi->dev->begingroup(csi->dev->user, bbox, nil, 0, 0, gstate->blendmode); + } + if (dofill) { switch (gstate->fill.kind) @@ -487,6 +525,9 @@ pdf_flushtext(pdf_csi *csi) } } + if (gstate->blendmode != FZ_BNORMAL) + csi->dev->endgroup(csi->dev->user); + fz_freetext(text); } diff --git a/mupdf/pdf_image.c b/mupdf/pdf_image.c index 9724b1ef..20df8b46 100644 --- a/mupdf/pdf_image.c +++ b/mupdf/pdf_image.c @@ -107,7 +107,7 @@ pdf_loadimageheader(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) } /* Not allowed for inline images */ - obj = fz_dictgetsa(dict, "Mask", "SMask"); + obj = fz_dictgetsa(dict, "SMask", "Mask"); if (pdf_isstream(xref, fz_tonum(obj), fz_togen(obj))) { error = pdf_loadimage(&img->mask, xref, rdb, obj); diff --git a/mupdf/pdf_interpret.c b/mupdf/pdf_interpret.c index ad82ebc3..acf4d2bf 100644 --- a/mupdf/pdf_interpret.c +++ b/mupdf/pdf_interpret.c @@ -311,7 +311,7 @@ pdf_runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *rdb, fz_obj *extgst else if (!strcmp(s, "BM")) { - static const struct { const char *name; fz_blendkind mode; } bm[] = { + static const struct { const char *name; fz_blendmode mode; } bm[] = { { "Normal", FZ_BNORMAL }, { "Multiply", FZ_BMULTIPLY }, { "Screen", FZ_BSCREEN }, @@ -334,6 +334,7 @@ pdf_runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *rdb, fz_obj *extgst return fz_throw("malformed BM"); gstate->blendmode = FZ_BNORMAL; +#if 1 for (k = 0; k < nelem(bm); k++) { if (!strcmp(bm[k].name, n)) { gstate->blendmode = bm[k].mode; @@ -342,26 +343,21 @@ pdf_runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *rdb, fz_obj *extgst break; } } - - /* The content stream ought to be blended properly, - but for now, just do over and hope for something - */ - // TODO: push, pop and blend buffers +#endif } else if (!strcmp(s, "SMask")) { if (fz_isdict(val)) { - /* TODO: we should do something here, like inserting a mask node for the S key in val */ - /* TODO: how to deal with the non-recursive nature of pdf soft masks? */ - /* fz_error error; fz_obj *g; fz_obj *subtype; pdf_xobject *xobj; pdf_image *img; + fz_warn("ignoring soft mask"); +#if 0 g = fz_dictgets(val, "G"); subtype = fz_dictgets(g, "Subtype"); @@ -378,7 +374,7 @@ pdf_runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *rdb, fz_obj *extgst if (error) return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_tonum(val), fz_togen(val)); } - */ +#endif } } |