diff options
-rw-r--r-- | source/fitz/draw-blend.c | 100 | ||||
-rw-r--r-- | source/fitz/draw-device.c | 70 | ||||
-rw-r--r-- | source/fitz/draw-imp.h | 1 |
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); |