summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/fitz/draw-blend.c100
-rw-r--r--source/fitz/draw-device.c70
-rw-r--r--source/fitz/draw-imp.h1
3 files changed, 149 insertions, 22 deletions
diff --git a/source/fitz/draw-blend.c b/source/fitz/draw-blend.c
index ac9e0492..6c2c58c7 100644
--- a/source/fitz/draw-blend.c
+++ b/source/fitz/draw-blend.c
@@ -1250,3 +1250,103 @@ fz_blend_pixmap(fz_context *ctx, fz_pixmap * restrict dst, fz_pixmap * restrict
verify_premultiply(ctx, dst);
#endif
}
+
+static inline void
+fz_blend_knockout(byte * restrict bp, int bal, const byte * restrict sp, int sal, int n1, int w, const byte * restrict hp)
+{
+ int k;
+ do
+ {
+ int ha = *hp++;
+
+ if (ha != 0)
+ {
+ int sa = (sal ? sp[n1] : 255);
+ int ba = (bal ? bp[n1] : 255);
+ if (ba == 0 && ha == 0xFF)
+ {
+ memcpy(bp, sp, n1);
+ if (bal)
+ bp[n1] = sa;
+ }
+ else
+ {
+ int hasa = fz_mul255(ha, sa);
+ /* ugh, division to get non-premul components */
+ int invsa = sa ? 255 * 256 / sa : 0;
+ int invba = ba ? 255 * 256 / ba : 0;
+ int ra = hasa + fz_mul255(255-ha, ba);
+
+ /* Process colorants + spots */
+ for (k = 0; k < n1; k++)
+ {
+ int sc = (sp[k] * invsa) >> 8;
+ int bc = (bp[k] * invba) >> 8;
+ int rc = fz_mul255(255 - ha, bc) + fz_mul255(ha, sc);
+
+ bp[k] = fz_mul255(ra, rc);
+ }
+
+ if (bal)
+ bp[k] = ra;
+ }
+ }
+ sp += n1 + sal;
+ bp += n1 + bal;
+ }
+ while (--w);
+}
+
+void
+fz_blend_pixmap_knockout(fz_context *ctx, fz_pixmap * restrict dst, fz_pixmap * restrict src, const fz_pixmap * restrict shape)
+{
+ unsigned char *sp;
+ unsigned char *dp;
+ fz_irect bbox;
+ fz_irect bbox2;
+ int x, y, w, h, n;
+ int da, sa;
+ const unsigned char *hp;
+
+ fz_pixmap_bbox_no_ctx(dst, &bbox);
+ fz_pixmap_bbox_no_ctx(src, &bbox2);
+ fz_intersect_irect(&bbox, &bbox2);
+
+ x = bbox.x0;
+ y = bbox.y0;
+ w = bbox.x1 - bbox.x0;
+ h = bbox.y1 - bbox.y0;
+
+ if (w == 0 || h == 0)
+ return;
+
+ n = src->n;
+ sp = src->samples + (unsigned int)((y - src->y) * src->stride + (x - src->x) * src->n);
+ sa = src->alpha;
+ dp = dst->samples + (unsigned int)((y - dst->y) * dst->stride + (x - dst->x) * dst->n);
+ da = dst->alpha;
+ hp = shape->samples + (unsigned int)((y - shape->y) * shape->stride + (x - shape->x));
+
+#ifdef PARANOID_PREMULTIPLY
+ if (sa)
+ verify_premultiply(ctx, src);
+ if (da)
+ verify_premultiply(ctx, dst);
+#endif
+
+ n -= sa;
+ assert(n == dst->n - da);
+
+ while (h--)
+ {
+ fz_blend_knockout(dp, da, sp, sa, n, w, hp);
+ sp += src->stride;
+ dp += dst->stride;
+ hp += shape->stride;
+ }
+
+#ifdef PARANOID_PREMULTIPLY
+ if (da)
+ verify_premultiply(ctx, dst);
+#endif
+}
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index 64de42ae..260ca59e 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -195,8 +195,9 @@ static void emergency_pop_stack(fz_context *ctx, fz_draw_device *dev, fz_draw_st
static fz_draw_state *
fz_knockout_begin(fz_context *ctx, fz_draw_device *dev)
{
- fz_irect bbox;
+ fz_irect bbox, ga_bbox;
fz_pixmap *dest, *shape;
+ fz_pixmap *ga = NULL;
fz_draw_state *state = &dev->stack[dev->top];
int isolated = state->blendmode & FZ_BLEND_ISOLATED;
@@ -209,26 +210,47 @@ fz_knockout_begin(fz_context *ctx, fz_draw_device *dev)
fz_pixmap_bbox(ctx, state->dest, &bbox);
fz_intersect_irect(&bbox, &state->scissor);
dest = fz_new_pixmap_with_bbox(ctx, state->dest->colorspace, &bbox, state->dest->seps, state->dest->alpha);
+ if (state[0].group_alpha)
+ {
+ fz_pixmap_bbox(ctx, state->group_alpha, &ga_bbox);
+ fz_intersect_irect(&ga_bbox, &state->scissor);
+ ga = fz_new_pixmap_with_bbox(ctx, state->group_alpha->colorspace, &ga_bbox, state->group_alpha->seps, state->group_alpha->alpha);
+ }
if (isolated)
{
fz_clear_pixmap(ctx, dest);
+ if (ga)
+ fz_clear_pixmap(ctx, ga);
}
else
{
/* Find the last but one destination to copy */
int i = dev->top-1; /* i = the one on entry (i.e. the last one) */
- fz_pixmap *prev = state->dest;
+ fz_draw_state *prev = state;
while (i > 0)
{
- prev = dev->stack[--i].dest;
- if (prev != state->dest)
+ prev = &dev->stack[--i];
+ if (prev->dest != state->dest)
break;
}
- if (prev)
- fz_copy_pixmap_rect(ctx, dest, prev, &bbox, dev->default_cs);
+ if (prev->dest)
+ {
+ fz_copy_pixmap_rect(ctx, dest, prev->dest, &bbox, dev->default_cs);
+ if (ga)
+ {
+ if (prev->group_alpha)
+ fz_copy_pixmap_rect(ctx, ga, prev->group_alpha, &ga_bbox, dev->default_cs);
+ else
+ fz_clear_pixmap(ctx, ga);
+ }
+ }
else
+ {
fz_clear_pixmap(ctx, dest);
+ if (ga)
+ fz_clear_pixmap(ctx, ga);
+ }
}
/* Knockout groups (and only knockout groups) rely on shape */
@@ -239,8 +261,11 @@ fz_knockout_begin(fz_context *ctx, fz_draw_device *dev)
fz_dump_blend(ctx, "Knockout begin: background is ", dest);
if (shape)
fz_dump_blend(ctx, "/S=", shape);
+ if (ga)
+ fz_dump_blend(ctx, "/GA=", ga);
printf("\n");
#endif
+ state[1].group_alpha = ga;
state[1].scissor = bbox;
state[1].dest = dest;
state[1].shape = shape;
@@ -252,8 +277,6 @@ fz_knockout_begin(fz_context *ctx, fz_draw_device *dev)
static void fz_knockout_end(fz_context *ctx, fz_draw_device *dev)
{
fz_draw_state *state;
- int blendmode;
- int isolated;
if (dev->top == 0)
{
@@ -265,8 +288,8 @@ static void fz_knockout_end(fz_context *ctx, fz_draw_device *dev)
if ((state[0].blendmode & FZ_BLEND_KNOCKOUT) == 0)
return;
- blendmode = state->blendmode & FZ_BLEND_MODEMASK;
- isolated = state->blendmode & FZ_BLEND_ISOLATED;
+ assert((state[1].blendmode & FZ_BLEND_ISOLATED) == 0);
+ assert((state[1].blendmode & FZ_BLEND_MODEMASK) == 0);
#ifdef DUMP_GROUP_BLENDS
dump_spaces(dev->top, "");
@@ -280,32 +303,32 @@ static void fz_knockout_end(fz_context *ctx, fz_draw_device *dev)
fz_dump_blend(ctx, "/S=", state[0].shape);
if (state[0].group_alpha)
fz_dump_blend(ctx, "/GA=", state[0].group_alpha);
- if (blendmode != 0)
- printf(" (blend %d)", blendmode);
- if (isolated != 0)
+ if ((state->blendmode & FZ_BLEND_MODEMASK) != 0)
+ printf(" (blend %d)", state->blendmode & FZ_BLEND_MODEMASK);
+ if ((state->blendmode & FZ_BLEND_ISOLATED) != 0)
printf(" (isolated)");
printf(" (knockout)");
#endif
assert(state[1].shape);
- fz_blend_pixmap(ctx, state[0].dest, state[1].dest, 255, blendmode, 0, state[1].shape);
+ fz_blend_pixmap_knockout(ctx, state[0].dest, state[1].dest, state[1].shape);
/* The following test should not be required, but just occasionally
* errors can cause the stack to get out of sync, and this saves our
* bacon. */
if (state[0].dest != state[1].dest)
fz_drop_pixmap(ctx, state[1].dest);
+ if (state[1].group_alpha && state[0].group_alpha != state[1].group_alpha)
+ {
+ if (state[0].group_alpha)
+ fz_blend_pixmap_knockout(ctx, state[0].group_alpha, state[1].group_alpha, state[1].shape);
+ fz_drop_pixmap(ctx, state[1].group_alpha);
+ }
if (state[0].shape != state[1].shape)
{
if (state[0].shape)
fz_paint_pixmap(state[0].shape, state[1].shape, 255);
fz_drop_pixmap(ctx, state[1].shape);
}
- if (state[0].group_alpha != state[1].group_alpha)
- {
- if (state[0].group_alpha)
- fz_paint_pixmap(state[0].group_alpha, state[1].group_alpha, 255);
- fz_drop_pixmap(ctx, state[1].group_alpha);
- }
#ifdef DUMP_GROUP_BLENDS
fz_dump_blend(ctx, " to get ", state[0].dest);
if (state[0].shape)
@@ -2260,6 +2283,7 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_co
fz_clear_pixmap(ctx, state[1].group_alpha);
}
+ /* shape is inherited from the previous group */
state[1].alpha = alpha;
#ifdef DUMP_GROUP_BLENDS
dump_spaces(dev->top-1, "");
@@ -2349,12 +2373,14 @@ fz_draw_end_group(fz_context *ctx, fz_device *devp)
if (state[0].shape != state[1].shape)
{
+ /* The 'D' on page 7 of Altona_Technical_v20_x4.pdf goes wrong if this
+ * isn't alpha * 255, as the blend back fails to take account of alpha. */
if (state[0].shape)
{
if (state[1].shape)
- fz_paint_pixmap(state[0].shape, state[1].shape, 255);
+ fz_paint_pixmap(state[0].shape, state[1].shape, alpha * 255);
else
- fz_paint_pixmap_alpha(state[0].shape, state[1].dest, 255);
+ fz_paint_pixmap_alpha(state[0].shape, state[1].dest, alpha * 255);
}
fz_drop_pixmap(ctx, state[1].shape);
}
diff --git a/source/fitz/draw-imp.h b/source/fitz/draw-imp.h
index e855b40a..f6cc1367 100644
--- a/source/fitz/draw-imp.h
+++ b/source/fitz/draw-imp.h
@@ -464,6 +464,7 @@ void fz_paint_pixmap_with_bbox(fz_pixmap * restrict dst, const fz_pixmap * restr
void fz_paint_pixmap_with_overprint(fz_pixmap * restrict dst, const fz_pixmap * restrict src, const fz_overprint *op);
void fz_blend_pixmap(fz_context *ctx, fz_pixmap * restrict dst, fz_pixmap * restrict src, int alpha, int blendmode, int isolated, const fz_pixmap * restrict shape);
+void fz_blend_pixmap_knockout(fz_context *ctx, fz_pixmap * restrict dst, fz_pixmap * restrict src, const fz_pixmap * restrict shape);
void fz_paint_glyph(const unsigned char * restrict colorbv, fz_pixmap * restrict dst, unsigned char * restrict dp, const fz_glyph * restrict glyph, int w, int h, int skip_x, int skip_y, const fz_overprint * restrict eop);