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

Reply via email to