summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--draw/blendmodes.c133
-rw-r--r--fitz/dev_draw.c87
-rw-r--r--fitz/dev_list.c88
-rw-r--r--fitz/dev_null.c9
-rw-r--r--fitz/dev_trace.c2
-rw-r--r--fitz/fitz.h26
-rw-r--r--mupdf/mupdf.h2
-rw-r--r--mupdf/pdf_build.c41
-rw-r--r--mupdf/pdf_image.c2
-rw-r--r--mupdf/pdf_interpret.c16
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
}
}