poppler/SplashOutputDev.cc | 67 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 30 deletions(-)
New commits: commit 722f37f7ab39e6d3b7fffb69907433d25f30b5ef Author: Tobias Deiminger <[email protected]> Date: Sun Nov 22 22:13:34 2020 +0100 Splash: Fix blitImage in uncolored tiling patterns Roughly spoken, SplashOutputDev::tilingPatternFill first renders a pattern prototype into a temporary buffer, then draws multiple copies of that buffer over the current background, enough copies to fill a region. To draw the copies, we use either blitImage or drawImage. blitImage is faster, but only works if the current transformation is simple enough (no rotation, no skew, no reflection). Else we have to fallback to drawImage. drawImage would generate the final pattern so that it colorizes a greyscale prototype while fetching the prototype via tilingBitmapSrc buffer accessor. blitImage on the other hand has no such accessor and therefore no color to colorize. But we can get the same result if we colorize the pattern prototype up front. This commit rearranges the code so that we can decide blitImage vs. drawImage early enough to make color mode of the prototype and copying pattern color from former Splash dependent on that decision. To test blitImage for uncolored tiling patterns, render PDFJS-8741-p1-patternscaling.pdf from #983. To test drawImage for uncolored tiling patterns, render 745th page, Figure L.9 – Uncoloured tiling pattern from PDF32000_2008.pdf. Fixes #983. diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index b20d01ec..6709ad2b 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -4307,7 +4307,33 @@ bool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat m1.m[4] = -kx; m1.m[5] = -ky; - bitmap = new SplashBitmap(surface_width, surface_height, 1, (paintType == 1) ? colorMode : splashModeMono8, true); + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(doc, this, resDict, &box, nullptr, nullptr, nullptr, gfxA); + // set pattern transformation matrix + gfx->getState()->setCTM(m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]); + if (splashAbs(matc[1]) > splashAbs(matc[0])) { + kx = -matc[1]; + ky = matc[2] - (matc[0] * matc[3]) / matc[1]; + } else { + kx = matc[0]; + ky = matc[3] - (matc[1] * matc[2]) / matc[0]; + } + result_width = surface_width * repeatX; + result_height = surface_height * repeatY; + kx = result_width / (fabs(kx) + 1); + ky = result_height / (fabs(ky) + 1); + state->concatCTM(kx, 0, 0, ky, 0, 0); + ctm = state->getCTM(); + matc[0] = ctm[0]; + matc[1] = ctm[1]; + matc[2] = ctm[2]; + matc[3] = ctm[3]; + + const bool doFastBlit = matc[0] > 0 && matc[1] == 0 && matc[2] == 0 && matc[3] > 0; + bitmap = new SplashBitmap(surface_width, surface_height, 1, (paintType == 1 || doFastBlit) ? colorMode : splashModeMono8, true); if (bitmap->getDataPtr() == nullptr) { SplashBitmap *tBitmap = bitmap; bitmap = formerBitmap; @@ -4316,6 +4342,8 @@ bool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat return false; } splash = new Splash(bitmap, true); + updateCTM(gfx->getState(), m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]); + if (paintType == 2) { SplashColor clearColor; clearColor[0] = (colorMode == splashModeCMYK8 || colorMode == splashModeDeviceN8) ? 0x00 : 0xFF; @@ -4325,18 +4353,16 @@ bool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat } splash->setThinLineMode(formerSplash->getThinLineMode()); splash->setMinLineWidth(s_minLineWidth); - - box.x1 = bbox[0]; - box.y1 = bbox[1]; - box.x2 = bbox[2]; - box.y2 = bbox[3]; - gfx = new Gfx(doc, this, resDict, &box, nullptr, nullptr, nullptr, gfxA); - // set pattern transformation matrix - gfx->getState()->setCTM(m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]); - updateCTM(gfx->getState(), m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]); + if (doFastBlit) { + // drawImage would colorize the greyscale pattern in tilingBitmapSrc buffer accessor while tiling. + // blitImage can't, it has no buffer accessor. We instead colorize the pattern prototype in advance. + splash->setFillPattern(formerSplash->getFillPattern()->copy()); + splash->setStrokePattern(formerSplash->getStrokePattern()->copy()); + } gfx->display(str); delete splash; splash = formerSplash; + TilingSplashOutBitmap imgData; imgData.bitmap = bitmap; imgData.paintType = paintType; @@ -4347,26 +4373,7 @@ bool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat imgData.repeatY = repeatY; SplashBitmap *tBitmap = bitmap; bitmap = formerBitmap; - result_width = tBitmap->getWidth() * imgData.repeatX; - result_height = tBitmap->getHeight() * imgData.repeatY; - - if (splashAbs(matc[1]) > splashAbs(matc[0])) { - kx = -matc[1]; - ky = matc[2] - (matc[0] * matc[3]) / matc[1]; - } else { - kx = matc[0]; - ky = matc[3] - (matc[1] * matc[2]) / matc[0]; - } - kx = result_width / (fabs(kx) + 1); - ky = result_height / (fabs(ky) + 1); - state->concatCTM(kx, 0, 0, ky, 0, 0); - ctm = state->getCTM(); - matc[0] = ctm[0]; - matc[1] = ctm[1]; - matc[2] = ctm[2]; - matc[3] = ctm[3]; - bool minorAxisZero = matc[1] == 0 && matc[2] == 0; - if (matc[0] > 0 && minorAxisZero && matc[3] > 0) { + if (doFastBlit) { // draw the tiles for (int y = 0; y < imgData.repeatY; ++y) { for (int x = 0; x < imgData.repeatX; ++x) { _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
