[gs-commits] mupdf/master - 0_6-189-g81fedd6 - Support SMasks for general graphics (incomplete).
Tor Andersson
tor at ghostscript.com
Sat Jul 17 01:47:52 UTC 2010
commit 81fedd67062acfe802c0e5541d31e294df9607c9
Author: Tor Andersson <tor at ghostscript.com>
Date: Sat Jul 17 01:41:20 2010 +0000
Support SMasks for general graphics (incomplete).
Ignore-this: 67f56d1a8b654ba609ddb7b168f29a42
darcs-hash:20100717014120-f546f-2af4690a72960c5eba62f01fc5b43c96279e9648.gz
9 files changed, 333 insertions(+), 223 deletions(-)
diff --git a/draw/blendmodes.c b/draw/blendmodes.c
index 11cb627..713b6cf 100644
--- a/draw/blendmodes.c
+++ b/draw/blendmodes.c
@@ -2,6 +2,27 @@
typedef unsigned char byte;
+const char *fz_blendnames[] =
+{
+ "Normal",
+ "Multiply",
+ "Screen",
+ "Overlay",
+ "Darken",
+ "Lighten",
+ "ColorDodge",
+ "ColorBurn",
+ "HardLight",
+ "SoftLight",
+ "Difference",
+ "Exclusion",
+ "Hue",
+ "Saturation",
+ "Color",
+ "Luminosity",
+ nil
+};
+
/*
PDF 1.4 blend modes.
Only the actual blend routines are here, not the rendering logic.
diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c
index 3148360..5c2445a 100644
--- a/fitz/dev_draw.c
+++ b/fitz/dev_draw.c
@@ -4,32 +4,27 @@
#define HSUBPIX 5.0
#define VSUBPIX 5.0
-#define MAXCLIP 64
+#define STACKSIZE 96
typedef struct fz_drawdevice_s fz_drawdevice;
struct fz_drawdevice_s
{
- fz_colorspace *model;
fz_glyphcache *cache;
fz_gel *gel;
fz_ael *ael;
- fz_pixmap *dest;
+ fz_pixmap *dest;
fz_bbox scissor;
- struct {
- fz_pixmap *dest;
- fz_pixmap *mask;
- fz_bbox scissor;
- } clipstack[MAXCLIP];
- int cliptop;
struct {
+ fz_bbox scissor;
fz_pixmap *dest;
+ fz_pixmap *mask;
fz_blendmode blendmode;
- fz_bbox scissor;
- } groupstack[MAXCLIP];
- int grouptop;
+ int luminosity;
+ } stack[STACKSIZE];
+ int top;
};
static void
@@ -84,6 +79,7 @@ fz_drawfillpath(void *user, fz_path *path, int evenodd, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
float expansion = fz_matrixexpansion(ctm);
float flatness = 0.3f / expansion;
unsigned char colorbv[FZ_MAXCOLORS + 1];
@@ -101,10 +97,10 @@ fz_drawfillpath(void *user, fz_path *path, int evenodd, fz_matrix ctm,
if (fz_isemptyrect(bbox))
return;
- if (dev->model)
+ if (model)
{
- fz_convertcolor(colorspace, color, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = alpha * 255;
fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, dev->dest, colorbv, nil, nil);
@@ -120,6 +116,7 @@ fz_drawstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix c
fz_colorspace *colorspace, float *color, float alpha)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
float expansion = fz_matrixexpansion(ctm);
float flatness = 0.3f / expansion;
float linewidth = stroke->linewidth;
@@ -144,10 +141,10 @@ fz_drawstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix c
if (fz_isemptyrect(bbox))
return;
- if (dev->model)
+ if (model)
{
- fz_convertcolor(colorspace, color, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = alpha * 255;
fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv, nil, nil);
@@ -162,14 +159,15 @@ static void
fz_drawclippath(void *user, fz_path *path, int evenodd, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
float expansion = fz_matrixexpansion(ctm);
float flatness = 0.3f / expansion;
fz_pixmap *mask, *dest;
fz_bbox bbox;
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
@@ -182,43 +180,44 @@ fz_drawclippath(void *user, fz_path *path, int evenodd, fz_matrix ctm)
if (fz_isemptyrect(bbox) || fz_isrectgel(dev->gel))
{
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = nil;
- dev->clipstack[dev->cliptop].dest = nil;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = nil;
+ dev->stack[dev->top].dest = nil;
dev->scissor = bbox;
- dev->cliptop++;
+ dev->top++;
return;
}
mask = fz_newpixmapwithrect(nil, bbox);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(mask, 0);
fz_clearpixmap(dest, 0);
fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, mask, nil, nil, nil);
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = mask;
- dev->clipstack[dev->cliptop].dest = dev->dest;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = mask;
+ dev->stack[dev->top].dest = dev->dest;
dev->scissor = bbox;
dev->dest = dest;
- dev->cliptop++;
+ dev->top++;
}
static void
fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
float expansion = fz_matrixexpansion(ctm);
float flatness = 0.3f / expansion;
float linewidth = stroke->linewidth;
fz_pixmap *mask, *dest;
fz_bbox bbox;
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
@@ -236,7 +235,7 @@ fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matr
bbox = fz_intersectbbox(bbox, dev->scissor);
mask = fz_newpixmapwithrect(nil, bbox);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(mask, 0);
fz_clearpixmap(dest, 0);
@@ -244,12 +243,12 @@ fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matr
if (!fz_isemptyrect(bbox))
fz_scanconvert(dev->gel, dev->ael, 0, bbox, mask, nil, nil, nil);
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = mask;
- dev->clipstack[dev->cliptop].dest = dev->dest;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = mask;
+ dev->stack[dev->top].dest = dev->dest;
dev->scissor = bbox;
dev->dest = dest;
- dev->cliptop++;
+ dev->top++;
}
static void
@@ -311,16 +310,17 @@ fz_drawfilltext(void *user, fz_text *text, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
unsigned char colorbv[FZ_MAXCOLORS + 1];
float colorfv[FZ_MAXCOLORS];
fz_matrix tm, trm;
fz_pixmap *glyph;
int i, x, y, gid;
- if (dev->model)
+ if (model)
{
- fz_convertcolor(colorspace, color, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = alpha * 255;
}
@@ -344,7 +344,7 @@ fz_drawfilltext(void *user, fz_text *text, fz_matrix ctm,
glyph = fz_renderglyph(dev->cache, text->font, gid, trm);
if (glyph)
{
- if (dev->model)
+ if (model)
drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor);
else
drawglyph(nil, dev->dest, glyph, x, y, dev->scissor);
@@ -358,16 +358,17 @@ fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix c
fz_colorspace *colorspace, float *color, float alpha)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
unsigned char colorbv[FZ_MAXCOLORS + 1];
float colorfv[FZ_MAXCOLORS];
fz_matrix tm, trm;
fz_pixmap *glyph;
int i, x, y, gid;
- if (dev->model)
+ if (model)
{
- fz_convertcolor(colorspace, color, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = alpha * 255;
}
@@ -391,7 +392,7 @@ fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix c
glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke);
if (glyph)
{
- if (dev->model)
+ if (model)
drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor);
else
drawglyph(nil, dev->dest, glyph, x, y, dev->scissor);
@@ -404,6 +405,7 @@ static void
fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_bbox bbox;
fz_pixmap *mask, *dest;
fz_matrix tm, trm;
@@ -414,9 +416,9 @@ fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate)
/* If accumulate == 1 then this text object is the first (or only) in a sequence */
/* If accumulate == 2 then this text object is a continuation */
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
@@ -435,21 +437,21 @@ fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate)
if (accumulate == 0 || accumulate == 1)
{
mask = fz_newpixmapwithrect(nil, bbox);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(mask, 0);
fz_clearpixmap(dest, 0);
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = mask;
- dev->clipstack[dev->cliptop].dest = dev->dest;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = mask;
+ dev->stack[dev->top].dest = dev->dest;
dev->scissor = bbox;
dev->dest = dest;
- dev->cliptop++;
+ dev->top++;
}
else
{
- mask = dev->clipstack[dev->cliptop-1].mask;
+ mask = dev->stack[dev->top-1].mask;
}
if (!fz_isemptyrect(bbox))
@@ -484,15 +486,16 @@ static void
fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_bbox bbox;
fz_pixmap *mask, *dest;
fz_matrix tm, trm;
fz_pixmap *glyph;
int i, x, y, gid;
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
@@ -501,17 +504,17 @@ fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matr
bbox = fz_intersectbbox(bbox, dev->scissor);
mask = fz_newpixmapwithrect(nil, bbox);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(mask, 0);
fz_clearpixmap(dest, 0);
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = mask;
- dev->clipstack[dev->cliptop].dest = dev->dest;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = mask;
+ dev->stack[dev->top].dest = dev->dest;
dev->scissor = bbox;
dev->dest = dest;
- dev->cliptop++;
+ dev->top++;
if (!fz_isemptyrect(bbox))
{
@@ -550,6 +553,7 @@ static void
fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_pixmap *dest = dev->dest;
fz_rect bounds;
fz_bbox bbox;
@@ -569,7 +573,7 @@ fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm)
if (fz_isemptyrect(bbox))
return;
- if (!dev->model)
+ if (!model)
{
fz_warn("cannot render shading directly to an alpha mask");
return;
@@ -579,8 +583,8 @@ fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm)
{
unsigned char *s;
int x, y, n, i;
- fz_convertcolor(shade->cs, shade->background, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(shade->cs, shade->background, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = 255;
@@ -655,13 +659,14 @@ static void
fz_drawfillimage(void *user, fz_pixmap *image, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_bbox bbox;
int dx, dy;
fz_pixmap *scaled = nil;
fz_pixmap *converted = nil;
fz_matrix invmat;
- if (!dev->model)
+ if (!model)
{
fz_warn("cannot render image directly to an alpha mask");
return;
@@ -678,9 +683,9 @@ fz_drawfillimage(void *user, fz_pixmap *image, fz_matrix ctm)
image = scaled;
}
- if (image->colorspace != dev->model)
+ if (image->colorspace != model)
{
- converted = fz_newpixmap(dev->model, image->x, image->y, image->w, image->h);
+ converted = fz_newpixmap(model, image->x, image->y, image->w, image->h);
fz_convertpixmap(image, converted);
image = converted;
}
@@ -698,6 +703,7 @@ fz_drawfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
unsigned char colorbv[FZ_MAXCOLORS + 1];
float colorfv[FZ_MAXCOLORS];
fz_bbox bbox;
@@ -719,8 +725,8 @@ fz_drawfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm,
if (dev->dest->colorspace)
{
- fz_convertcolor(colorspace, color, dev->model, colorfv);
- for (i = 0; i < dev->model->n; i++)
+ fz_convertcolor(colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
colorbv[i] = colorfv[i] * 255;
colorbv[i] = alpha * 255;
fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv, image, &invmat);
@@ -738,15 +744,16 @@ static void
fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_bbox bbox;
fz_pixmap *mask, *dest;
int dx, dy;
fz_pixmap *scaled = nil;
fz_matrix invmat;
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
@@ -754,11 +761,11 @@ fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm)
if (fz_isemptyrect(bbox) || image->w == 0 || image->h == 0)
{
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = nil;
- dev->clipstack[dev->cliptop].dest = nil;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = nil;
+ dev->stack[dev->top].dest = nil;
dev->scissor = bbox;
- dev->cliptop++;
+ dev->top++;
return;
}
@@ -769,19 +776,19 @@ fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm)
}
mask = fz_newpixmapwithrect(nil, bbox);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(mask, 0);
fz_clearpixmap(dest, 0);
fz_scanconvert(dev->gel, dev->ael, 0, bbox, mask, nil, image, &invmat);
- dev->clipstack[dev->cliptop].scissor = dev->scissor;
- dev->clipstack[dev->cliptop].mask = mask;
- dev->clipstack[dev->cliptop].dest = dev->dest;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = mask;
+ dev->stack[dev->top].dest = dev->dest;
dev->scissor = bbox;
dev->dest = dest;
- dev->cliptop++;
+ dev->top++;
if (scaled)
fz_droppixmap(scaled);
@@ -792,12 +799,12 @@ fz_drawpopclip(void *user)
{
fz_drawdevice *dev = user;
fz_pixmap *mask, *dest;
- if (dev->cliptop > 0)
+ if (dev->top > 0)
{
- dev->cliptop--;
- dev->scissor = dev->clipstack[dev->cliptop].scissor;
- mask = dev->clipstack[dev->cliptop].mask;
- dest = dev->clipstack[dev->cliptop].dest;
+ dev->top--;
+ dev->scissor = dev->stack[dev->top].scissor;
+ mask = dev->stack[dev->top].mask;
+ dest = dev->stack[dev->top].dest;
if (mask && dest)
{
fz_pixmap *scratch = dev->dest;
@@ -812,38 +819,106 @@ fz_drawpopclip(void *user)
static void
fz_drawbeginmask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv)
{
+ fz_drawdevice *dev = user;
+ fz_pixmap *dest;
+ fz_bbox bbox;
+
fz_warn("fz_drawbeginmask");
+
+ if (dev->top == STACKSIZE)
+ {
+ fz_warn("assert: too many buffers on stack");
+ return;
+ }
+
+ bbox = fz_roundrect(rect);
+ bbox = fz_intersectbbox(bbox, dev->scissor);
+ dest = fz_newpixmapwithrect(pdf_devicegray, bbox);
+
+ if (luminosity)
+ fz_clearpixmap(dest, 255);
+ else
+ fz_clearpixmap(dest, 0);
+
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].dest = dev->dest;
+ dev->stack[dev->top].luminosity = luminosity;
+ dev->top++;
+
+ dev->scissor = bbox;
+ dev->dest = dest;
}
static void
fz_drawendmask(void *user)
{
+ fz_drawdevice *dev = user;
+ fz_pixmap *mask = dev->dest;
+ fz_pixmap *temp, *dest;
+ fz_bbox bbox;
+ int luminosity;
+
fz_warn("fz_drawendmask");
+
+ if (dev->top == STACKSIZE)
+ {
+ fz_warn("assert: too many buffers on stack");
+ return;
+ }
+
+ if (dev->top > 0)
+ {
+ /* pop soft mask buffer */
+ dev->top--;
+ luminosity = dev->stack[dev->top].luminosity;
+ dev->scissor = dev->stack[dev->top].scissor;
+ dev->dest = dev->stack[dev->top].dest;
+
+ /* convert to alpha mask */
+ temp = fz_alphafromgray(mask, luminosity);
+fz_writepng(mask, "softmask-1.png", 1);
+fz_writepng(temp, "softmask-2.png", 1);
+ fz_droppixmap(mask);
+
+ /* create new dest scratch buffer */
+ bbox = fz_boundpixmap(temp);
+ dest = fz_newpixmapwithrect(dev->dest->colorspace, bbox);
+ fz_clearpixmap(dest, 0);
+
+ /* push soft mask as clip mask */
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].mask = temp;
+ dev->stack[dev->top].dest = dev->dest;
+ dev->scissor = bbox;
+ dev->dest = dest;
+ dev->top++;
+ }
}
static void
fz_drawbegingroup(void *user, fz_rect rect, int isolated, int knockout, fz_blendmode blendmode)
{
fz_drawdevice *dev = user;
+ fz_colorspace *model = dev->dest->colorspace;
fz_bbox bbox;
fz_pixmap *dest;
- if (dev->cliptop == MAXCLIP)
+ if (dev->top == STACKSIZE)
{
- fz_warn("assert: too many clip masks on stack");
+ fz_warn("assert: too many buffers on stack");
return;
}
bbox = fz_roundrect(rect);
bbox = fz_intersectbbox(bbox, dev->scissor);
- dest = fz_newpixmapwithrect(dev->model, bbox);
+ dest = fz_newpixmapwithrect(model, bbox);
fz_clearpixmap(dest, 0);
- dev->groupstack[dev->grouptop].blendmode = blendmode;
- dev->groupstack[dev->grouptop].scissor = dev->scissor;
- dev->groupstack[dev->grouptop].dest = dev->dest;
- dev->grouptop++;
+ dev->stack[dev->top].blendmode = blendmode;
+ dev->stack[dev->top].scissor = dev->scissor;
+ dev->stack[dev->top].dest = dev->dest;
+ dev->top++;
dev->scissor = bbox;
dev->dest = dest;
@@ -856,24 +931,22 @@ fz_drawendgroup(void *user)
fz_pixmap *group = dev->dest;
fz_blendmode blendmode;
- if (dev->grouptop > 0)
+ if (dev->top > 0)
{
- dev->grouptop--;
- blendmode = dev->groupstack[dev->grouptop].blendmode;
- dev->dest = dev->groupstack[dev->grouptop].dest;
- dev->scissor = dev->groupstack[dev->grouptop].scissor;
+ dev->top--;
+ blendmode = dev->stack[dev->top].blendmode;
+ dev->dest = dev->stack[dev->top].dest;
+ dev->scissor = dev->stack[dev->top].scissor;
fz_blendpixmaps(group, dev->dest, blendmode);
+ fz_droppixmap(group);
}
-
- fz_droppixmap(group);
}
static void
fz_drawfreeuser(void *user)
{
fz_drawdevice *dev = user;
- if (dev->model)
- fz_dropcolorspace(dev->model);
+ /* TODO: pop and free the stacks */
fz_freegel(dev->gel);
fz_freeael(dev->ael);
fz_free(dev);
@@ -884,16 +957,11 @@ fz_newdrawdevice(fz_glyphcache *cache, fz_pixmap *dest)
{
fz_device *dev;
fz_drawdevice *ddev = fz_malloc(sizeof(fz_drawdevice));
- if (dest->colorspace)
- ddev->model = fz_keepcolorspace(dest->colorspace);
- else
- ddev->model = nil;
ddev->cache = cache;
ddev->gel = fz_newgel();
ddev->ael = fz_newael();
ddev->dest = dest;
- ddev->cliptop = 0;
- ddev->grouptop = 0;
+ ddev->top = 0;
ddev->scissor.x0 = dest->x;
ddev->scissor.y0 = dest->y;
diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c
index 6941ec4..84aaff5 100644
--- a/fitz/dev_trace.c
+++ b/fitz/dev_trace.c
@@ -230,10 +230,11 @@ fz_tracepopclip(void *user)
static void
fz_tracebeginmask(void *user, fz_rect bbox, int luminosity, fz_colorspace *colorspace, float *color)
{
+ printf("<gsave>\n");
printf("<mask bbox=\"%g %g %g %g\" s=\"%s\" ",
bbox.x0, bbox.y0, bbox.x1, bbox.y1,
luminosity ? "luminosity" : "alpha");
- fz_tracecolor(colorspace, color, 1);
+// fz_tracecolor(colorspace, color, 1);
printf(">\n");
}
@@ -246,9 +247,9 @@ fz_traceendmask(void *user)
static void
fz_tracebegingroup(void *user, fz_rect bbox, int isolated, int knockout, fz_blendmode blendmode)
{
- printf("<group bbox=\"%g %g %g %g\" isolated=\"%d\" knockout=\"%d\" blendmode=\"%d\">\n",
+ printf("<group bbox=\"%g %g %g %g\" isolated=\"%d\" knockout=\"%d\" blendmode=\"%s\">\n",
bbox.x0, bbox.y0, bbox.x1, bbox.y1,
- isolated, knockout, blendmode);
+ isolated, knockout, fz_blendnames[blendmode]);
}
static void
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 3d7c5cb..215b943 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -676,6 +676,8 @@ typedef enum fz_blendmode_e
FZ_BLUMINOSITY,
} fz_blendmode;
+extern const char *fz_blendnames[];
+
/*
* Pixmaps have n components per pixel. the last is always alpha.
* premultiplied alpha when rendering, but non-premultiplied for colorspace
@@ -695,10 +697,12 @@ struct fz_pixmap_s
fz_pixmap * fz_newpixmapwithrect(fz_colorspace *, fz_bbox bbox);
fz_pixmap * fz_newpixmap(fz_colorspace *, int x, int y, int w, int h);
-fz_pixmap *fz_keeppixmap(fz_pixmap *map);
-void fz_droppixmap(fz_pixmap *map);
-void fz_clearpixmap(fz_pixmap *map, unsigned char value);
+fz_pixmap *fz_keeppixmap(fz_pixmap *pix);
+void fz_droppixmap(fz_pixmap *pix);
+void fz_clearpixmap(fz_pixmap *pix, int value);
void fz_gammapixmap(fz_pixmap *pix, float gamma);
+fz_pixmap *fz_alphafromgray(fz_pixmap *gray, int luminosity);
+fz_bbox fz_boundpixmap(fz_pixmap *pix);
fz_pixmap * fz_scalepixmap(fz_pixmap *src, int xdenom, int ydenom);
diff --git a/fitz/res_font.c b/fitz/res_font.c
index 368c491..8dc0690 100644
--- a/fitz/res_font.c
+++ b/fitz/res_font.c
@@ -472,7 +472,7 @@ fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm)
fz_freedevice(dev);
glyph = fz_newpixmap(nil, bbox.x0-1, bbox.y0-1, bbox.x1 - bbox.x0 + 1, bbox.y1 - bbox.y0 + 1);
- fz_clearpixmap(glyph, 0x00);
+ fz_clearpixmap(glyph, 0);
cache = fz_newglyphcache();
dev = fz_newdrawdevice(cache, glyph);
diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c
index e1184ff..4599fb0 100644
--- a/fitz/res_pixmap.c
+++ b/fitz/res_pixmap.c
@@ -51,11 +51,22 @@ fz_droppixmap(fz_pixmap *pix)
}
void
-fz_clearpixmap(fz_pixmap *pix, unsigned char value)
+fz_clearpixmap(fz_pixmap *pix, int value)
{
memset(pix->samples, value, pix->w * pix->h * pix->n);
}
+fz_bbox
+fz_boundpixmap(fz_pixmap *pix)
+{
+ fz_bbox bbox;
+ bbox.x0 = pix->x;
+ bbox.y0 = pix->y;
+ bbox.x1 = pix->x + pix->w;
+ bbox.y1 = pix->y + pix->h;
+ return bbox;
+}
+
void
fz_gammapixmap(fz_pixmap *pix, float gamma)
{
@@ -72,6 +83,31 @@ fz_gammapixmap(fz_pixmap *pix, float gamma)
}
}
+fz_pixmap *
+fz_alphafromgray(fz_pixmap *gray, int luminosity)
+{
+ fz_pixmap *alpha;
+ unsigned char *sp, *dp;
+ int len;
+
+ assert(gray->n == 2);
+
+ alpha = fz_newpixmap(nil, gray->x, gray->y, gray->w, gray->h);
+ dp = alpha->samples;
+ sp = gray->samples;
+ if (!luminosity)
+ sp ++;
+
+ len = gray->w * gray->h;
+ while (len--)
+ {
+ *dp++ = sp[0];
+ sp += 2;
+ }
+
+ return alpha;
+}
+
/*
* Write pixmap to PNM file (without alpha channel)
*/
diff --git a/mupdf/mupdf.h b/mupdf/mupdf.h
index faf7740..8c9acdd 100644
--- a/mupdf/mupdf.h
+++ b/mupdf/mupdf.h
@@ -570,7 +570,6 @@ struct pdf_gstate_s
/* materials */
pdf_material stroke;
pdf_material fill;
- fz_blendmode blendmode;
/* text state */
float charspace;
@@ -581,6 +580,12 @@ struct pdf_gstate_s
float size;
int render;
float rise;
+
+ /* transparency */
+ fz_blendmode blendmode;
+ pdf_xobject *softmask;
+ fz_matrix softmaskctm;
+ int luminosity;
};
struct pdf_csi_s
@@ -627,6 +632,7 @@ void pdf_showshade(pdf_csi*, fz_shade *shd);
void pdf_gsave(pdf_csi *csi);
void pdf_grestore(pdf_csi *csi);
fz_error pdf_runcsibuffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents);
+fz_error pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj);
fz_error pdf_runcontents(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm);
fz_error pdf_runpage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm);
diff --git a/mupdf/pdf_build.c b/mupdf/pdf_build.c
index fe6cc30..ff57d0f 100644
--- a/mupdf/pdf_build.c
+++ b/mupdf/pdf_build.c
@@ -31,8 +31,6 @@ pdf_initgstate(pdf_gstate *gs, fz_matrix ctm)
gs->fill.parentalpha = 1;
gs->fill.alpha = 1;
- gs->blendmode = FZ_BNORMAL;
-
gs->charspace = 0;
gs->wordspace = 0;
gs->scale = 1;
@@ -41,6 +39,11 @@ pdf_initgstate(pdf_gstate *gs, fz_matrix ctm)
gs->size = -1;
gs->render = 0;
gs->rise = 0;
+
+ gs->blendmode = FZ_BNORMAL;
+ gs->softmask = nil;
+ gs->softmaskctm = fz_identity;
+ gs->luminosity = 0;
}
void
@@ -221,12 +224,12 @@ void
pdf_showshade(pdf_csi *csi, fz_shade *shd)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_rect bbox;
+
+ bbox = fz_boundshade(shd, gstate->ctm);
if (gstate->blendmode != FZ_BNORMAL)
- {
- fz_rect bbox = fz_boundshade(shd, gstate->ctm);
csi->dev->begingroup(csi->dev->user, bbox, 0, 0, gstate->blendmode);
- }
csi->dev->fillshade(csi->dev->user, shd, gstate->ctm);
@@ -239,6 +242,12 @@ pdf_showimage(pdf_csi *csi, pdf_image *image)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
fz_pixmap *tile, *mask;
+ fz_rect bbox;
+
+ bbox = fz_transformrect(gstate->ctm, fz_unitrect);
+
+ if (gstate->blendmode != FZ_BNORMAL)
+ csi->dev->begingroup(csi->dev->user, bbox, 0, 0, gstate->blendmode);
if (image->mask)
{
@@ -247,17 +256,10 @@ 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, 0, 0, gstate->blendmode);
- }
-
tile = pdf_loadtile(image);
if (image->imagemask)
{
- fz_rect bbox;
switch (gstate->fill.kind)
{
@@ -270,7 +272,6 @@ pdf_showimage(pdf_csi *csi, pdf_image *image)
case PDF_MPATTERN:
if (gstate->fill.pattern)
{
- bbox = fz_transformrect(gstate->ctm, fz_unitrect);
csi->dev->clipimagemask(csi->dev->user, tile, gstate->ctm);
pdf_showpattern(csi, gstate->fill.pattern, bbox, PDF_MFILL);
csi->dev->popclip(csi->dev->user);
@@ -291,12 +292,12 @@ 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);
+ if (gstate->blendmode != FZ_BNORMAL)
+ csi->dev->endgroup(csi->dev->user);
+
fz_droppixmap(tile);
}
@@ -304,8 +305,8 @@ void
pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_rect bbox;
fz_path *path;
+ fz_rect bbox;
path = csi->path;
csi->path = fz_newpath();
@@ -320,15 +321,13 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd)
csi->clip = 0;
}
+ if (dostroke)
+ bbox = fz_boundpath(path, &gstate->strokestate, gstate->ctm);
+ else
+ bbox = fz_boundpath(path, nil, gstate->ctm);
+
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, 0, 0, gstate->blendmode);
- }
if (dofill)
{
@@ -343,7 +342,6 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd)
case PDF_MPATTERN:
if (gstate->fill.pattern)
{
- bbox = fz_boundpath(path, nil, gstate->ctm);
csi->dev->clippath(csi->dev->user, path, evenodd, gstate->ctm);
pdf_showpattern(csi, gstate->fill.pattern, bbox, PDF_MFILL);
csi->dev->popclip(csi->dev->user);
@@ -373,7 +371,6 @@ pdf_showpath(pdf_csi *csi, int doclose, int dofill, int dostroke, int evenodd)
case PDF_MPATTERN:
if (gstate->stroke.pattern)
{
- bbox = fz_boundpath(path, &gstate->strokestate, gstate->ctm);
csi->dev->clipstrokepath(csi->dev->user, path, &gstate->strokestate, gstate->ctm);
pdf_showpattern(csi, gstate->stroke.pattern, bbox, PDF_MFILL);
csi->dev->popclip(csi->dev->user);
@@ -416,39 +413,24 @@ pdf_flushtext(pdf_csi *csi)
text = csi->text;
csi->text = nil;
+ dofill = dostroke = doclip = doinvisible = 0;
switch (csi->textmode)
{
- case 0:
- dofill = 1;
- break;
- case 1:
- dostroke = 1;
- break;
- case 2:
- dofill = 1;
- dostroke = 1;
- break;
- case 3:
- doinvisible = 1;
- break;
- case 4:
- dofill = 1;
- doclip = 1;
- break;
- case 5:
- dostroke = 1;
- doclip = 1;
- break;
- case 6:
- dofill = 1;
- dostroke = 1;
- doclip = 1;
- break;
- case 7:
- doclip = 1;
- break;
+ case 0: dofill = 1; break;
+ case 1: dostroke = 1; break;
+ case 2: dofill = dostroke = 1; break;
+ case 3: doinvisible = 1; break;
+ case 4: dofill = doclip = 1; break;
+ case 5: dostroke = doclip = 1; break;
+ case 6: dofill = dostroke = doclip = 1; break;
+ case 7: doclip = 1; break;
}
+ bbox = fz_boundtext(text, gstate->ctm);
+
+ if (gstate->blendmode != FZ_BNORMAL)
+ csi->dev->begingroup(csi->dev->user, bbox, 0, 0, gstate->blendmode);
+
if (doinvisible)
csi->dev->ignoretext(csi->dev->user, text, gstate->ctm);
@@ -459,12 +441,6 @@ 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, 0, 0, gstate->blendmode);
- }
-
if (dofill)
{
switch (gstate->fill.kind)
@@ -478,7 +454,6 @@ pdf_flushtext(pdf_csi *csi)
case PDF_MPATTERN:
if (gstate->fill.pattern)
{
- bbox = fz_boundtext(text, gstate->ctm);
csi->dev->cliptext(csi->dev->user, text, gstate->ctm, 0);
pdf_showpattern(csi, gstate->fill.pattern, bbox, PDF_MFILL);
csi->dev->popclip(csi->dev->user);
@@ -508,7 +483,6 @@ pdf_flushtext(pdf_csi *csi)
case PDF_MPATTERN:
if (gstate->stroke.pattern)
{
- bbox = fz_boundtext(text, gstate->ctm);
csi->dev->clipstroketext(csi->dev->user, text, &gstate->strokestate, gstate->ctm);
pdf_showpattern(csi, gstate->stroke.pattern, bbox, PDF_MFILL);
csi->dev->popclip(csi->dev->user);
diff --git a/mupdf/pdf_interpret.c b/mupdf/pdf_interpret.c
index 710b52d..c8a2d0f 100644
--- a/mupdf/pdf_interpret.c
+++ b/mupdf/pdf_interpret.c
@@ -83,6 +83,8 @@ pdf_gsave(pdf_csi *csi)
pdf_keepmaterial(&gs->fill);
if (gs->font)
pdf_keepfont(gs->font);
+ if (gs->softmask)
+ pdf_keepxobject(gs->softmask);
}
void
@@ -101,6 +103,8 @@ pdf_grestore(pdf_csi *csi)
pdf_dropmaterial(&gs->fill);
if (gs->font)
pdf_dropfont(gs->font);
+ if (gs->softmask)
+ pdf_dropxobject(gs->softmask);
csi->gtop --;
@@ -140,13 +144,14 @@ pdf_freecsi(pdf_csi *csi)
* Push gstate, set transform, clip, run, pop gstate.
*/
-static fz_error
+fz_error
pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj)
{
fz_error error;
pdf_gstate *gstate;
fz_matrix oldtopctm;
int oldtop;
+ pdf_xobject *softmask = nil;
pdf_gsave(csi);
@@ -162,6 +167,21 @@ pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj)
/* reset alpha to 1.0 when starting a new Transparency group */
if (xobj->transparency)
{
+ if (gstate->softmask)
+ {
+ softmask = gstate->softmask;
+ gstate->softmask = nil;
+
+ fz_rect bbox = fz_transformrect(gstate->ctm, xobj->bbox);
+ fz_matrix oldctm = gstate->ctm;
+ csi->dev->beginmask(csi->dev->user, bbox, gstate->luminosity, nil, nil);
+ pdf_runxobject(csi, nil, softmask);
+ csi->dev->endmask(csi->dev->user);
+ gstate->ctm = oldctm;
+
+ pdf_dropxobject(softmask);
+ }
+
csi->dev->begingroup(csi->dev->user,
fz_transformrect(gstate->ctm, xobj->bbox),
xobj->isolated, xobj->knockout, gstate->blendmode);
@@ -201,8 +221,13 @@ pdf_runxobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj)
pdf_grestore(csi);
if (xobj->transparency)
+ {
csi->dev->endgroup(csi->dev->user);
+ if (softmask)
+ csi->dev->popclip(csi->dev->user);
+ }
+
return fz_okay;
}
@@ -311,38 +336,13 @@ pdf_runextgstate(pdf_csi *csi, pdf_gstate *gstate, fz_obj *rdb, fz_obj *extgstat
else if (!strcmp(s, "BM"))
{
- static const struct { const char *name; fz_blendmode mode; } bm[] = {
- { "Normal", FZ_BNORMAL },
- { "Multiply", FZ_BMULTIPLY },
- { "Screen", FZ_BSCREEN },
- { "Overlay", FZ_BOVERLAY },
- { "SoftLight", FZ_BSOFTLIGHT },
- { "HardLight", FZ_BHARDLIGHT },
- { "ColorDodge", FZ_BCOLORDODGE },
- { "ColorBurn", FZ_BCOLORBURN },
- { "Darken", FZ_BDARKEN },
- { "Lighten", FZ_BLIGHTEN },
- { "Difference", FZ_BDIFFERENCE },
- { "Exclusion", FZ_BEXCLUSION },
- { "Hue", FZ_BHUE },
- { "Saturation", FZ_BSATURATION },
- { "Color", FZ_BCOLOR },
- { "Luminosity", FZ_BLUMINOSITY }
- };
-
- char *n = fz_toname(val);
if (!fz_isname(val))
return fz_throw("malformed BM");
gstate->blendmode = FZ_BNORMAL;
- for (k = 0; k < nelem(bm); k++)
- {
- if (!strcmp(bm[k].name, n))
- {
- gstate->blendmode = bm[k].mode;
- break;
- }
- }
+ for (k = 0; fz_blendnames[k]; k++)
+ if (!strcmp(fz_blendnames[k], fz_toname(val)))
+ gstate->blendmode = k;
}
else if (!strcmp(s, "SMask"))
@@ -350,30 +350,30 @@ pdf_runextgstate(pdf_csi *csi, pdf_gstate *gstate, fz_obj *rdb, fz_obj *extgstat
if (fz_isdict(val))
{
fz_error error;
- fz_obj *g;
- fz_obj *subtype;
pdf_xobject *xobj;
- pdf_image *img;
+ fz_obj *group, *luminosity;
- fz_warn("ignoring soft mask");
-#if 0
- g = fz_dictgets(val, "G");
- subtype = fz_dictgets(g, "Subtype");
+ fz_warn("not ignoring soft mask");
- if (!strcmp(fz_toname(subtype), "Form"))
+ if (gstate->softmask)
{
- error = pdf_loadxobject(&xobj, csi->xref, g);
- if (error)
- return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_tonum(val), fz_togen(val));
+ pdf_dropxobject(gstate->softmask);
+ gstate->softmask = nil;
}
- else if (!strcmp(fz_toname(subtype), "Image"))
- {
- error = pdf_loadimage(&img, csi->xref, g);
+ group = fz_dictgets(val, "G");
+ error = pdf_loadxobject(&xobj, csi->xref, group);
if (error)
- return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_tonum(val), fz_togen(val));
- }
-#endif
+ return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_tonum(val), fz_togen(val));
+
+ gstate->softmaskctm = fz_concat(xobj->matrix, gstate->ctm);
+ gstate->softmask = xobj;
+
+ luminosity = fz_dictgets(val, "S");
+ if (fz_isname(luminosity) && !strcmp(fz_toname(luminosity), "Luminosity"))
+ gstate->luminosity = 1;
+ else
+ gstate->luminosity = 0;
}
}
--
git/hooks/post-receive
More information about the gs-commits
mailing list