[poppler] poppler/SplashOutputDev.cc

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Dec 1 21:08:40 UTC 2020


 poppler/SplashOutputDev.cc |   67 ++++++++++++++++++++++++---------------------
 1 file changed, 37 insertions(+), 30 deletions(-)

New commits:
commit 722f37f7ab39e6d3b7fffb69907433d25f30b5ef
Author: Tobias Deiminger <haxtibal at posteo.de>
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) {


More information about the poppler mailing list