Skip to content

Commit

Permalink
Use integer coordinates when drawing images (bug 1264608, issue #3351)…
Browse files Browse the repository at this point in the history
… - it aims to fix https://bugzilla.mozilla.org/show_bug.cgi?id=1264608; - it's only a partial fix for #3351; - some tiled images have some spurious white lines between the tiles. When the current transform is applyed the corners of an image can have some non-integer coordinates leading to some extra transparency added to handle that. So with this patch the current transform is applied on the point and on the dimensions in order to have at the end only integer values.
  • Loading branch information
calixteman committed Apr 28, 2022
1 parent b72a448 commit 858409f
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 8 deletions.
90 changes: 82 additions & 8 deletions src/display/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,64 @@ class CachedCanvases {
}
}

function drawImageAtIntegerCoords(
ctx,
srcImg,
srcX,
srcY,
srcW,
srcH,
destX,
destY,
destW,
destH
) {
const [a, b, c, d, tx, ty] = ctx.mozCurrentTransform;
let scaleX, scaleY;
// The cases of a diagonal or anti-diagonal matrices are treated separately
// in order to avoid some rounding errors which can lead to mis-position
// some images (it's visible in commenting the two ifs and with the pdf in
// https://github.com/mozilla/pdf.js/issues/3351#issue-15307536).
if (b === 0 && c === 0) {
scaleX = Math.abs(a);
scaleY = Math.abs(d);
ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), 0, 0);
} else if (a === 0 && d === 0) {
scaleX = Math.abs(c);
scaleY = Math.abs(b);
ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, 0, 0);
} else {
const absDet = Math.abs(a * d - b * c);
scaleX = absDet / Math.hypot(a, c);
scaleY = absDet / Math.hypot(b, d);
ctx.setTransform(a / scaleX, b / scaleY, c / scaleX, d / scaleY, 0, 0);
}

// top-left corner is at (X, Y) and
// bottom-right one is at (X + width, Y + height).

// If leftX is 4.321 then it's rounded to 4.
// If width is 10.432 then it's rounded to 11 because
// rightX = leftX + width = 14.753 which is rounded to 15
// so after rounding the total width is 11 (15 - 4).
// It's why we can't just floor/ceil uniformly, it just depends
// on the values we've.

const tlX = destX * scaleX + tx;
const rTlX = Math.round(tlX);
const tlY = destY * scaleY + ty;
const rTlY = Math.round(tlY);
const brX = (destX + destW) * scaleX + tx;
const rWidth = Math.round(brX) - rTlX;
const brY = (destY + destH) * scaleY + ty;
const rHeight = Math.round(brY) - rTlY;

ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, rTlX, rTlY, rWidth, rHeight);
ctx.setTransform(a, b, c, d, tx, ty);

return [rWidth, rHeight];
}

function compileType3Glyph(imgData) {
const POINT_TO_PROCESS_LIMIT = 1000;
const POINT_TYPES = new Uint8Array([
Expand Down Expand Up @@ -1461,8 +1519,8 @@ class CanvasGraphics {
const cord1 = Util.applyTransform([0, 0], maskToCanvas);
const cord2 = Util.applyTransform([width, height], maskToCanvas);
const rect = Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]);
const drawnWidth = Math.ceil(rect[2] - rect[0]);
const drawnHeight = Math.ceil(rect[3] - rect[1]);
const drawnWidth = Math.round(rect[2] - rect[0]);
const drawnHeight = Math.round(rect[3] - rect[1]);
const fillCanvas = this.cachedCanvases.getCanvas(
"fillCanvas",
drawnWidth,
Expand Down Expand Up @@ -1496,7 +1554,9 @@ class CanvasGraphics {
fillCtx.mozCurrentTransform,
img.interpolate
);
fillCtx.drawImage(

drawImageAtIntegerCoords(
fillCtx,
scaled,
0,
0,
Expand Down Expand Up @@ -3005,7 +3065,18 @@ class CanvasGraphics {
ctx.save();
ctx.transform.apply(ctx, image.transform);
ctx.scale(1, -1);
ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
drawImageAtIntegerCoords(
ctx,
maskCanvas.canvas,
0,
0,
width,
height,
0,
-1,
1,
1
);
ctx.restore();
}
this.compose();
Expand Down Expand Up @@ -3085,7 +3156,9 @@ class CanvasGraphics {
ctx.mozCurrentTransform,
imgData.interpolate
);
ctx.drawImage(

const [rWidth, rHeight] = drawImageAtIntegerCoords(
ctx,
scaled.img,
0,
0,
Expand All @@ -3103,8 +3176,8 @@ class CanvasGraphics {
imgData,
left: position[0],
top: position[1],
width: width / ctx.mozCurrentTransformInverse[0],
height: height / ctx.mozCurrentTransformInverse[3],
width: rWidth,
height: rHeight,
});
}
this.compose();
Expand Down Expand Up @@ -3133,7 +3206,8 @@ class CanvasGraphics {
ctx.save();
ctx.transform.apply(ctx, entry.transform);
ctx.scale(1, -1);
ctx.drawImage(
drawImageAtIntegerCoords(
ctx,
tmpCanvas.canvas,
entry.x,
entry.y,
Expand Down
2 changes: 2 additions & 0 deletions test/pdfs/issue3351.1.pdf.link
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://github.com/mozilla/pdf.js/files/8582209/Doc2.pdf

2 changes: 2 additions & 0 deletions test/pdfs/issue3351.2.pdf.link
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://bugzilla.mozilla.org/attachment.cgi?id=8741330

2 changes: 2 additions & 0 deletions test/pdfs/issue3351.3.pdf.link
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://bugzilla.mozilla.org/attachment.cgi?id=8741334

24 changes: 24 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6403,5 +6403,29 @@
"link": true,
"lastPage": 1,
"type": "eq"
},
{ "id": "issue3351.1",
"file": "pdfs/issue3351.1.pdf",
"md5": "4216245a5f18bb3eac80575ccf0b272d",
"rounds": 1,
"link": true,
"lastPage": 1,
"type": "eq"
},
{ "id": "issue3351.2",
"file": "pdfs/issue3351.2.pdf",
"md5": "fa3fd1659c409c7824ef8838c3071efc",
"rounds": 1,
"link": true,
"lastPage": 1,
"type": "eq"
},
{ "id": "issue3351.3",
"file": "pdfs/issue3351.3.pdf",
"md5": "60e2f2c480b6bc0e7f726743c6896520",
"rounds": 1,
"link": true,
"lastPage": 1,
"type": "eq"
}
]

0 comments on commit 858409f

Please sign in to comment.