Fix how patterns are applied to image mask objects.
Note, this only really fixes Radial/Axial shading patterns with masks. I'm guessing tiling patterns and mesh patterns would also be broken if applied like the test pdf. Hopefully I'll have some time to make test cases for the other shadings. Fixes #13372
This commit is contained in:
parent
f9a0568f96
commit
5efaaa0fea
@ -13,6 +13,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createMatrix,
|
||||
getShadingPattern,
|
||||
TilingPattern,
|
||||
} from "./pattern_helper.js";
|
||||
import {
|
||||
FONT_IDENTITY_MATRIX,
|
||||
IDENTITY_MATRIX,
|
||||
@ -27,7 +32,6 @@ import {
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import { getShadingPattern, TilingPattern } from "./pattern_helper.js";
|
||||
|
||||
// <canvas> contexts store most of the state we need natively.
|
||||
// However, PDF needs a bit more state, which we store here.
|
||||
@ -193,6 +197,17 @@ function addContextCurrentTransform(ctx) {
|
||||
};
|
||||
}
|
||||
|
||||
function getAdjustmentTransformation(transform, width, height) {
|
||||
// The pattern will be created at the size of the current page or form object,
|
||||
// but the mask is usually scaled differently and offset, so we must account
|
||||
// for these to shift and rescale the pattern to the correctly location.
|
||||
let patternTransform = createMatrix(transform);
|
||||
patternTransform = patternTransform.scale(1 / width, -1 / height);
|
||||
patternTransform = patternTransform.translate(0, -height);
|
||||
patternTransform = patternTransform.inverse();
|
||||
return patternTransform;
|
||||
}
|
||||
|
||||
class CachedCanvases {
|
||||
constructor(canvasFactory) {
|
||||
this.canvasFactory = canvasFactory;
|
||||
@ -2294,8 +2309,16 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
maskCtx.globalCompositeOperation = "source-in";
|
||||
|
||||
let patternTransform = null;
|
||||
if (isPatternFill) {
|
||||
patternTransform = getAdjustmentTransformation(
|
||||
ctx.mozCurrentTransform,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
maskCtx.fillStyle = isPatternFill
|
||||
? fillColor.getPattern(maskCtx, this)
|
||||
? fillColor.getPattern(maskCtx, this, false, patternTransform)
|
||||
: fillColor;
|
||||
maskCtx.fillRect(0, 0, width, height);
|
||||
|
||||
@ -2332,14 +2355,23 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
maskCtx.globalCompositeOperation = "source-in";
|
||||
|
||||
const ctx = this.ctx;
|
||||
let patternTransform = null;
|
||||
if (isPatternFill) {
|
||||
patternTransform = getAdjustmentTransformation(
|
||||
ctx.mozCurrentTransform,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
maskCtx.fillStyle = isPatternFill
|
||||
? fillColor.getPattern(maskCtx, this)
|
||||
? fillColor.getPattern(maskCtx, this, false, patternTransform)
|
||||
: fillColor;
|
||||
maskCtx.fillRect(0, 0, width, height);
|
||||
|
||||
maskCtx.restore();
|
||||
|
||||
const ctx = this.ctx;
|
||||
for (let i = 0, ii = positions.length; i < ii; i += 2) {
|
||||
ctx.save();
|
||||
ctx.transform(
|
||||
@ -2381,8 +2413,17 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
maskCtx.globalCompositeOperation = "source-in";
|
||||
|
||||
let patternTransform = null;
|
||||
if (isPatternFill) {
|
||||
patternTransform = getAdjustmentTransformation(
|
||||
ctx.mozCurrentTransform,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
maskCtx.fillStyle = isPatternFill
|
||||
? fillColor.getPattern(maskCtx, this)
|
||||
? fillColor.getPattern(maskCtx, this, false, patternTransform)
|
||||
: fillColor;
|
||||
maskCtx.fillRect(0, 0, width, height);
|
||||
|
||||
|
@ -72,11 +72,11 @@ class RadialAxialShadingPattern extends BaseShadingPattern {
|
||||
this._matrix = IR[8];
|
||||
}
|
||||
|
||||
getPattern(ctx, owner, shadingFill) {
|
||||
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
|
||||
const tmpCanvas = owner.cachedCanvases.getCanvas(
|
||||
"pattern",
|
||||
ctx.canvas.width,
|
||||
ctx.canvas.height,
|
||||
owner.ctx.canvas.width,
|
||||
owner.ctx.canvas.height,
|
||||
true
|
||||
);
|
||||
|
||||
@ -121,7 +121,11 @@ class RadialAxialShadingPattern extends BaseShadingPattern {
|
||||
tmpCtx.fill();
|
||||
|
||||
const pattern = ctx.createPattern(tmpCanvas.canvas, "repeat");
|
||||
if (patternTransform) {
|
||||
pattern.setTransform(patternTransform);
|
||||
} else {
|
||||
pattern.setTransform(createMatrix(ctx.mozCurrentTransformInverse));
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
@ -376,7 +380,7 @@ class MeshShadingPattern extends BaseShadingPattern {
|
||||
};
|
||||
}
|
||||
|
||||
getPattern(ctx, owner, shadingFill) {
|
||||
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
|
||||
applyBoundingBox(ctx, this._bbox);
|
||||
let scale;
|
||||
if (shadingFill) {
|
||||
@ -599,7 +603,7 @@ class TilingPattern {
|
||||
}
|
||||
}
|
||||
|
||||
getPattern(ctx, owner, shadingFill) {
|
||||
getPattern(ctx, owner, shadingFill = false, patternTransform = null) {
|
||||
ctx = this.ctx;
|
||||
// PDF spec 8.7.2 NOTE 1: pattern's matrix is relative to initial matrix.
|
||||
let matrix = ctx.mozCurrentTransformInverse;
|
||||
@ -627,4 +631,4 @@ class TilingPattern {
|
||||
}
|
||||
}
|
||||
|
||||
export { getShadingPattern, TilingPattern };
|
||||
export { createMatrix, getShadingPattern, TilingPattern };
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -406,6 +406,7 @@
|
||||
!issue13193.pdf
|
||||
!annotation-underline-without-appearance.pdf
|
||||
!issue269_2.pdf
|
||||
!issue13372.pdf
|
||||
!annotation-strikeout.pdf
|
||||
!annotation-strikeout-without-appearance.pdf
|
||||
!annotation-squiggly.pdf
|
||||
|
BIN
test/pdfs/issue13372.pdf
Normal file
BIN
test/pdfs/issue13372.pdf
Normal file
Binary file not shown.
@ -1566,6 +1566,12 @@
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue13372",
|
||||
"file": "pdfs/issue13372.pdf",
|
||||
"md5": "0bc5329623fd554174c5e7653f904e28",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "simpletype3font-text",
|
||||
"file": "pdfs/simpletype3font.pdf",
|
||||
"md5": "b374c7543920840c61999e9e86939f99",
|
||||
|
Loading…
Reference in New Issue
Block a user