Skip to content

Commit d6deb95

Browse files
authored
Merge pull request #13565 from brendandahl/fix-pattern-mask
Fix how patterns are applied to image mask objects.
2 parents 4733222 + 5efaaa0 commit d6deb95

File tree

5 files changed

+64
-12
lines changed

5 files changed

+64
-12
lines changed

src/display/canvas.js

+46-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
* limitations under the License.
1414
*/
1515

16+
import {
17+
createMatrix,
18+
getShadingPattern,
19+
TilingPattern,
20+
} from "./pattern_helper.js";
1621
import {
1722
FONT_IDENTITY_MATRIX,
1823
IDENTITY_MATRIX,
@@ -27,7 +32,6 @@ import {
2732
Util,
2833
warn,
2934
} from "../shared/util.js";
30-
import { getShadingPattern, TilingPattern } from "./pattern_helper.js";
3135

3236
// <canvas> contexts store most of the state we need natively.
3337
// However, PDF needs a bit more state, which we store here.
@@ -193,6 +197,17 @@ function addContextCurrentTransform(ctx) {
193197
};
194198
}
195199

200+
function getAdjustmentTransformation(transform, width, height) {
201+
// The pattern will be created at the size of the current page or form object,
202+
// but the mask is usually scaled differently and offset, so we must account
203+
// for these to shift and rescale the pattern to the correctly location.
204+
let patternTransform = createMatrix(transform);
205+
patternTransform = patternTransform.scale(1 / width, -1 / height);
206+
patternTransform = patternTransform.translate(0, -height);
207+
patternTransform = patternTransform.inverse();
208+
return patternTransform;
209+
}
210+
196211
class CachedCanvases {
197212
constructor(canvasFactory) {
198213
this.canvasFactory = canvasFactory;
@@ -2294,8 +2309,16 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
22942309

22952310
maskCtx.globalCompositeOperation = "source-in";
22962311

2312+
let patternTransform = null;
2313+
if (isPatternFill) {
2314+
patternTransform = getAdjustmentTransformation(
2315+
ctx.mozCurrentTransform,
2316+
width,
2317+
height
2318+
);
2319+
}
22972320
maskCtx.fillStyle = isPatternFill
2298-
? fillColor.getPattern(maskCtx, this)
2321+
? fillColor.getPattern(maskCtx, this, false, patternTransform)
22992322
: fillColor;
23002323
maskCtx.fillRect(0, 0, width, height);
23012324

@@ -2332,14 +2355,23 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
23322355

23332356
maskCtx.globalCompositeOperation = "source-in";
23342357

2358+
const ctx = this.ctx;
2359+
let patternTransform = null;
2360+
if (isPatternFill) {
2361+
patternTransform = getAdjustmentTransformation(
2362+
ctx.mozCurrentTransform,
2363+
width,
2364+
height
2365+
);
2366+
}
2367+
23352368
maskCtx.fillStyle = isPatternFill
2336-
? fillColor.getPattern(maskCtx, this)
2369+
? fillColor.getPattern(maskCtx, this, false, patternTransform)
23372370
: fillColor;
23382371
maskCtx.fillRect(0, 0, width, height);
23392372

23402373
maskCtx.restore();
23412374

2342-
const ctx = this.ctx;
23432375
for (let i = 0, ii = positions.length; i < ii; i += 2) {
23442376
ctx.save();
23452377
ctx.transform(
@@ -2381,8 +2413,17 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
23812413

23822414
maskCtx.globalCompositeOperation = "source-in";
23832415

2416+
let patternTransform = null;
2417+
if (isPatternFill) {
2418+
patternTransform = getAdjustmentTransformation(
2419+
ctx.mozCurrentTransform,
2420+
width,
2421+
height
2422+
);
2423+
}
2424+
23842425
maskCtx.fillStyle = isPatternFill
2385-
? fillColor.getPattern(maskCtx, this)
2426+
? fillColor.getPattern(maskCtx, this, false, patternTransform)
23862427
: fillColor;
23872428
maskCtx.fillRect(0, 0, width, height);
23882429

src/display/pattern_helper.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ class RadialAxialShadingPattern extends BaseShadingPattern {
7272
this._matrix = IR[8];
7373
}
7474

75-
getPattern(ctx, owner, shadingFill) {
75+
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
7676
const tmpCanvas = owner.cachedCanvases.getCanvas(
7777
"pattern",
78-
ctx.canvas.width,
79-
ctx.canvas.height,
78+
owner.ctx.canvas.width,
79+
owner.ctx.canvas.height,
8080
true
8181
);
8282

@@ -121,7 +121,11 @@ class RadialAxialShadingPattern extends BaseShadingPattern {
121121
tmpCtx.fill();
122122

123123
const pattern = ctx.createPattern(tmpCanvas.canvas, "repeat");
124-
pattern.setTransform(createMatrix(ctx.mozCurrentTransformInverse));
124+
if (patternTransform) {
125+
pattern.setTransform(patternTransform);
126+
} else {
127+
pattern.setTransform(createMatrix(ctx.mozCurrentTransformInverse));
128+
}
125129
return pattern;
126130
}
127131
}
@@ -376,7 +380,7 @@ class MeshShadingPattern extends BaseShadingPattern {
376380
};
377381
}
378382

379-
getPattern(ctx, owner, shadingFill) {
383+
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
380384
applyBoundingBox(ctx, this._bbox);
381385
let scale;
382386
if (shadingFill) {
@@ -599,7 +603,7 @@ class TilingPattern {
599603
}
600604
}
601605

602-
getPattern(ctx, owner, shadingFill) {
606+
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
603607
ctx = this.ctx;
604608
// PDF spec 8.7.2 NOTE 1: pattern's matrix is relative to initial matrix.
605609
let matrix = ctx.mozCurrentTransformInverse;
@@ -627,4 +631,4 @@ class TilingPattern {
627631
}
628632
}
629633

630-
export { getShadingPattern, TilingPattern };
634+
export { createMatrix, getShadingPattern, TilingPattern };

test/pdfs/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@
406406
!issue13193.pdf
407407
!annotation-underline-without-appearance.pdf
408408
!issue269_2.pdf
409+
!issue13372.pdf
409410
!annotation-strikeout.pdf
410411
!annotation-strikeout-without-appearance.pdf
411412
!annotation-squiggly.pdf

test/pdfs/issue13372.pdf

83.4 KB
Binary file not shown.

test/test_manifest.json

+6
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,12 @@
15661566
"rounds": 1,
15671567
"type": "eq"
15681568
},
1569+
{ "id": "issue13372",
1570+
"file": "pdfs/issue13372.pdf",
1571+
"md5": "0bc5329623fd554174c5e7653f904e28",
1572+
"rounds": 1,
1573+
"type": "eq"
1574+
},
15691575
{ "id": "simpletype3font-text",
15701576
"file": "pdfs/simpletype3font.pdf",
15711577
"md5": "b374c7543920840c61999e9e86939f99",

0 commit comments

Comments
 (0)