diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 0e956c7..5c62494 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -1145,6 +1145,11 @@ struct SplashTransparencyGroup { GfxColorSpace *blendingColorSpace; GBool isolated; + //----- for knockout + SplashBitmap *shape; + GBool knockout; + SplashCoord knockoutOpacity; + //----- saved state SplashBitmap *origBitmap; Splash *origSplash; @@ -1631,10 +1636,14 @@ void SplashOutputDev::updateBlendMode(GfxState *state) { void SplashOutputDev::updateFillOpacity(GfxState *state) { splash->setFillAlpha((SplashCoord)state->getFillOpacity()); + if (transpGroupStack != NULL && (SplashCoord)state->getFillOpacity() < transpGroupStack->knockoutOpacity ) + transpGroupStack->knockoutOpacity = (SplashCoord)state->getFillOpacity(); } void SplashOutputDev::updateStrokeOpacity(GfxState *state) { splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); + if (transpGroupStack != NULL && (SplashCoord)state->getStrokeOpacity() < transpGroupStack->knockoutOpacity ) + transpGroupStack->knockoutOpacity = (SplashCoord)state->getStrokeOpacity(); } void SplashOutputDev::updateFillOverprint(GfxState *state) { @@ -3585,6 +3594,9 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, transpGroup->ty = ty; transpGroup->blendingColorSpace = blendingColorSpace; transpGroup->isolated = isolated; + transpGroup->shape = (knockout) ? SplashBitmap::copy(bitmap) : NULL; + transpGroup->knockout = gFalse; + transpGroup->knockoutOpacity = 1.0; transpGroup->next = transpGroupStack; transpGroupStack = transpGroup; @@ -3637,8 +3649,10 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, if (colorMode == splashModeXBGR8) color[3] = 255; splash->clear(color, 0); } else { + SplashBitmap *shape = (knockout) ? transpGroup->shape : (transpGroup->next != NULL && transpGroup->next->shape != NULL) ? + transpGroup->next->shape : transpGroup->origBitmap; splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h); - splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty); + splash->setInNonIsolatedGroup(shape, tx, ty); } transpGroup->tBitmap = bitmap; state->shiftCTM(-tx, -ty); @@ -3671,15 +3685,23 @@ void SplashOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { // paint the transparency group onto the parent bitmap // - the clip path was set in the parent's state) if (tx < bitmap->getWidth() && ty < bitmap->getHeight()) { + SplashCoord knockoutOpacity = (transpGroupStack->next != NULL) ? + transpGroupStack->next->knockoutOpacity : transpGroupStack->knockoutOpacity; splash->setOverprintMask(0xffffffff, gFalse); splash->composite(tBitmap, 0, 0, tx, ty, - tBitmap->getWidth(), tBitmap->getHeight(), - gFalse, !isolated); + tBitmap->getWidth(), tBitmap->getHeight(), + gFalse, !isolated, transpGroupStack->next != NULL && transpGroupStack->next->knockout, knockoutOpacity); + if (transpGroupStack->next != NULL && transpGroupStack->next->shape != NULL) + transpGroupStack->next->knockout = gTrue; } - // pop the stack transpGroup = transpGroupStack; transpGroupStack = transpGroup->next; + if (transpGroupStack != NULL && transpGroup->knockoutOpacity < transpGroupStack->knockoutOpacity) + transpGroupStack->knockoutOpacity = transpGroup->knockoutOpacity; + if (transpGroup->shape) { + delete transpGroup->shape; + } delete transpGroup; delete tBitmap; diff --git a/splash/Splash.cc b/splash/Splash.cc index 0e2058c..625a73a 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -135,6 +135,10 @@ struct SplashPipe { // non-isolated group alpha0 Guchar *alpha0Ptr; + // knockout groups + GBool knockout; + Guchar knockoutOpacity; + // soft mask SplashColorPtr softMaskPtr; @@ -240,7 +244,8 @@ inline void Splash::updateModY(int y) { inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, Guchar aInput, GBool usesShape, - GBool nonIsolatedGroup) { + GBool nonIsolatedGroup, + GBool knockout, Guchar knockoutOpacity) { pipeSetXY(pipe, x, y); pipe->pattern = NULL; @@ -260,6 +265,10 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, pipe->aInput = aInput; pipe->usesShape = usesShape; + // knockout + pipe->knockout = knockout; + pipe->knockoutOpacity = knockoutOpacity; + // result alpha if (aInput == 255 && !state->softMask && !usesShape && !state->inNonIsolatedGroup && !nonIsolatedGroup) { @@ -500,6 +509,9 @@ void Splash::pipeRun(SplashPipe *pipe) { break; } cSrc = cSrcNonIso; + // knockout: remove backdrop color + if (pipe->knockout && pipe->shape >= pipe->knockoutOpacity) + aDest = 0; } } else { cSrc = pipe->cSrc; @@ -4651,7 +4663,8 @@ void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha, SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, - GBool noClip, GBool nonIsolated) { + GBool noClip, GBool nonIsolated, + GBool knockout, SplashCoord knockoutOpacity) { SplashPipe pipe; SplashColor pixel; Guchar alpha; @@ -4664,7 +4677,8 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, if (src->alpha) { pipeInit(&pipe, xDest, yDest, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated); + (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated, + knockout, (Guchar)splashRound(knockoutOpacity * 255)); if (noClip) { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); diff --git a/splash/Splash.h b/splash/Splash.h index 53bfa81..bc82faa 100644 --- a/splash/Splash.h +++ b/splash/Splash.h @@ -215,7 +215,8 @@ public: // object. SplashError composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, - GBool noClip, GBool nonIsolated); + GBool noClip, GBool nonIsolated, + GBool knockout = gFalse, SplashCoord knockoutOpacity = 1.0); // Composite this Splash object onto a background color. The // background alpha is assumed to be 1. @@ -274,7 +275,8 @@ private: void pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, Guchar aInput, GBool usesShape, - GBool nonIsolatedGroup); + GBool nonIsolatedGroup, + GBool knockout = gFalse, Guchar knockoutOpacity = 255); void pipeRun(SplashPipe *pipe); void pipeRunSimpleMono1(SplashPipe *pipe); void pipeRunSimpleMono8(SplashPipe *pipe); diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc index ab5176e..db86d9d 100644 --- a/splash/SplashBitmap.cc +++ b/splash/SplashBitmap.cc @@ -111,6 +111,25 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, } } +SplashBitmap *SplashBitmap::copy(SplashBitmap *src) { + SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), + src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0); + Guchar *dataSource = src->getDataPtr(); + Guchar *dataDest = result->getDataPtr(); + int amount = src->getRowSize(); + if (amount < 0) { + dataSource = dataSource + (src->getHeight() - 1) * amount; + dataDest = dataDest + (src->getHeight() - 1) * amount; + amount *= -src->getHeight(); + } else { + amount *= src->getHeight(); + } + memcpy(dataDest, dataSource, amount); + if (src->getAlphaPtr() != NULL) + memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight()); + return result; +} + SplashBitmap::~SplashBitmap() { if (data) { if (rowSize < 0) { diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h index 8bcc941..7fd31a4 100644 --- a/splash/SplashBitmap.h +++ b/splash/SplashBitmap.h @@ -51,6 +51,7 @@ public: SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, GBool topDown = gTrue); + static SplashBitmap *copy(SplashBitmap *src); ~SplashBitmap();