Introduce helper functions for parsing /Matrix and /BBox arrays

This commit is contained in:
Jonas Jenwald 2024-04-30 08:47:14 +02:00
parent 52f7ff155d
commit 9b41bfc374
5 changed files with 63 additions and 69 deletions

View file

@ -44,6 +44,9 @@ import {
getRotationMatrix, getRotationMatrix,
isAscii, isAscii,
isNumberArray, isNumberArray,
lookupMatrix,
lookupNormalRect,
lookupRect,
numberToString, numberToString,
stringToUTF16String, stringToUTF16String,
} from "./core_utils.js"; } from "./core_utils.js";
@ -915,9 +918,7 @@ class Annotation {
* @param {Array} rectangle - The rectangle array with exactly four entries * @param {Array} rectangle - The rectangle array with exactly four entries
*/ */
setRectangle(rectangle) { setRectangle(rectangle) {
this.rectangle = isNumberArray(rectangle, 4) this.rectangle = lookupNormalRect(rectangle, [0, 0, 0, 0]);
? Util.normalizeRect(rectangle)
: [0, 0, 0, 0];
} }
/** /**
@ -1150,14 +1151,11 @@ class Annotation {
["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"], ["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"],
appearance appearance
); );
let bbox = appearanceDict.getArray("BBox"); const bbox = lookupRect(appearanceDict.getArray("BBox"), [0, 0, 1, 1]);
if (!isNumberArray(bbox, 4)) { const matrix = lookupMatrix(
bbox = [0, 0, 1, 1]; appearanceDict.getArray("Matrix"),
} IDENTITY_MATRIX
let matrix = appearanceDict.getArray("Matrix"); );
if (!isNumberArray(matrix, 6)) {
matrix = [1, 0, 0, 1, 0, 0];
}
const transform = getTransformMatrix(rect, bbox, matrix); const transform = getTransformMatrix(rect, bbox, matrix);
const opList = new OperatorList(); const opList = new OperatorList();
@ -1254,14 +1252,8 @@ class Annotation {
if (text.length > 1 || text[0]) { if (text.length > 1 || text[0]) {
const appearanceDict = this.appearance.dict; const appearanceDict = this.appearance.dict;
let bbox = appearanceDict.getArray("BBox"); const bbox = lookupRect(appearanceDict.getArray("BBox"), null);
if (!isNumberArray(bbox, 4)) { const matrix = lookupMatrix(appearanceDict.getArray("Matrix"), null);
bbox = null;
}
let matrix = appearanceDict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = null;
}
this.data.textPosition = this._transformPoint( this.data.textPosition = this._transformPoint(
firstPosition, firstPosition,
@ -2987,8 +2979,10 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
: this.uncheckedAppearance; : this.uncheckedAppearance;
if (appearance) { if (appearance) {
const savedAppearance = this.appearance; const savedAppearance = this.appearance;
const matrix = appearance.dict.getArray("Matrix"); const savedMatrix = lookupMatrix(
const savedMatrix = isNumberArray(matrix, 6) ? matrix : IDENTITY_MATRIX; appearance.dict.getArray("Matrix"),
IDENTITY_MATRIX
);
if (rotation) { if (rotation) {
appearance.dict.set( appearance.dict.set(
@ -3753,11 +3747,7 @@ class PopupAnnotation extends Annotation {
warn("Popup annotation has a missing or invalid parent annotation."); warn("Popup annotation has a missing or invalid parent annotation.");
return; return;
} }
this.data.parentRect = lookupNormalRect(parentItem.getArray("Rect"), null);
const parentRect = parentItem.getArray("Rect");
this.data.parentRect = isNumberArray(parentRect, 4)
? Util.normalizeRect(parentRect)
: null;
const rt = parentItem.get("RT"); const rt = parentItem.get("RT");
if (isName(rt, AnnotationReplyType.GROUP)) { if (isName(rt, AnnotationReplyType.GROUP)) {
@ -4045,10 +4035,7 @@ class LineAnnotation extends MarkupAnnotation {
this.data.hasOwnCanvas = this.data.noRotate; this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false; this.data.noHTML = false;
let lineCoordinates = dict.getArray("L"); const lineCoordinates = lookupRect(dict.getArray("L"), [0, 0, 0, 0]);
if (!isNumberArray(lineCoordinates, 4)) {
lineCoordinates = [0, 0, 0, 0];
}
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates); this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) { if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {

View file

@ -19,6 +19,7 @@ import {
BaseException, BaseException,
objectSize, objectSize,
stringToPDFString, stringToPDFString,
Util,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { Dict, isName, Ref, RefSet } from "./primitives.js"; import { Dict, isName, Ref, RefSet } from "./primitives.js";
@ -248,6 +249,21 @@ function isNumberArray(arr, len) {
); );
} }
// Returns the matrix, or the fallback value if it's invalid.
function lookupMatrix(arr, fallback) {
return isNumberArray(arr, 6) ? arr : fallback;
}
// Returns the rectangle, or the fallback value if it's invalid.
function lookupRect(arr, fallback) {
return isNumberArray(arr, 4) ? arr : fallback;
}
// Returns the normalized rectangle, or the fallback value if it's invalid.
function lookupNormalRect(arr, fallback) {
return isNumberArray(arr, 4) ? Util.normalizeRect(arr) : fallback;
}
/** /**
* AcroForm field names use an array like notation to refer to * AcroForm field names use an array like notation to refer to
* repeated XFA elements e.g. foo.bar[nnn]. * repeated XFA elements e.g. foo.bar[nnn].
@ -671,6 +687,9 @@ export {
isNumberArray, isNumberArray,
isWhiteSpace, isWhiteSpace,
log2, log2,
lookupMatrix,
lookupNormalRect,
lookupRect,
MissingDataException, MissingDataException,
numberToString, numberToString,
ParserEOFException, ParserEOFException,

View file

@ -39,8 +39,8 @@ import {
collectActions, collectActions,
getInheritableProperty, getInheritableProperty,
getNewAnnotationsMap, getNewAnnotationsMap,
isNumberArray,
isWhiteSpace, isWhiteSpace,
lookupNormalRect,
MissingDataException, MissingDataException,
PDF_VERSION_REGEXP, PDF_VERSION_REGEXP,
validateCSSFont, validateCSSFont,
@ -161,10 +161,12 @@ class Page {
if (this.xfaData) { if (this.xfaData) {
return this.xfaData.bbox; return this.xfaData.bbox;
} }
let box = this._getInheritableProperty(name, /* getArray = */ true); const box = lookupNormalRect(
this._getInheritableProperty(name, /* getArray = */ true),
null
);
if (isNumberArray(box, 4)) { if (box) {
box = Util.normalizeRect(box);
if (box[2] - box[0] > 0 && box[3] - box[1] > 0) { if (box[2] - box[0] > 0 && box[3] - box[1] > 0) {
return box; return box;
} }

View file

@ -53,6 +53,7 @@ import {
import { getTilingPatternIR, Pattern } from "./pattern.js"; import { getTilingPatternIR, Pattern } from "./pattern.js";
import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js"; import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js";
import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js"; import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js";
import { isNumberArray, lookupMatrix, lookupNormalRect } from "./core_utils.js";
import { isPDFFunction, PDFFunctionFactory } from "./function.js"; import { isPDFFunction, PDFFunctionFactory } from "./function.js";
import { Lexer, Parser } from "./parser.js"; import { Lexer, Parser } from "./parser.js";
import { import {
@ -73,7 +74,6 @@ import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js"; import { getMetrics } from "./metrics.js";
import { getUnicodeForGlyph } from "./unicode.js"; import { getUnicodeForGlyph } from "./unicode.js";
import { ImageResizer } from "./image_resizer.js"; import { ImageResizer } from "./image_resizer.js";
import { isNumberArray } from "./core_utils.js";
import { MurmurHash3_64 } from "../shared/murmurhash3.js"; import { MurmurHash3_64 } from "../shared/murmurhash3.js";
import { OperatorList } from "./operator_list.js"; import { OperatorList } from "./operator_list.js";
import { PDFImage } from "./image.js"; import { PDFImage } from "./image.js";
@ -460,12 +460,8 @@ class PartialEvaluator {
localColorSpaceCache localColorSpaceCache
) { ) {
const dict = xobj.dict; const dict = xobj.dict;
let matrix = dict.getArray("Matrix"); const matrix = lookupMatrix(dict.getArray("Matrix"), null);
if (!isNumberArray(matrix, 6)) { const bbox = lookupNormalRect(dict.getArray("BBox"), null);
matrix = null;
}
let bbox = dict.getArray("BBox");
bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
let optionalContent, groupOptions; let optionalContent, groupOptions;
if (dict.has("OC")) { if (dict.has("OC")) {
@ -1578,10 +1574,7 @@ class PartialEvaluator {
localShadingPatternCache, localShadingPatternCache,
}); });
if (objId) { if (objId) {
let matrix = dict.getArray("Matrix"); const matrix = lookupMatrix(dict.getArray("Matrix"), null);
if (!isNumberArray(matrix, 6)) {
matrix = null;
}
operatorList.addOp(fn, ["Shading", objId, matrix]); operatorList.addOp(fn, ["Shading", objId, matrix]);
} }
return undefined; return undefined;
@ -3268,8 +3261,8 @@ class PartialEvaluator {
const currentState = stateManager.state.clone(); const currentState = stateManager.state.clone();
const xObjStateManager = new StateManager(currentState); const xObjStateManager = new StateManager(currentState);
const matrix = xobj.dict.getArray("Matrix"); const matrix = lookupMatrix(xobj.dict.getArray("Matrix"), null);
if (isNumberArray(matrix, 6)) { if (matrix) {
xObjStateManager.transform(matrix); xObjStateManager.transform(matrix);
} }
@ -4247,10 +4240,7 @@ class PartialEvaluator {
if (!descriptor) { if (!descriptor) {
if (isType3Font) { if (isType3Font) {
let bbox = dict.getArray("FontBBox"); const bbox = lookupNormalRect(dict.getArray("FontBBox"), [0, 0, 0, 0]);
if (!isNumberArray(bbox, 4)) {
bbox = [0, 0, 0, 0];
}
// FontDescriptor is only required for Type3 fonts when the document // FontDescriptor is only required for Type3 fonts when the document
// is a tagged pdf. Create a barbebones one to get by. // is a tagged pdf. Create a barbebones one to get by.
descriptor = new Dict(null); descriptor = new Dict(null);
@ -4440,14 +4430,14 @@ class PartialEvaluator {
} }
} }
let fontMatrix = dict.getArray("FontMatrix"); const fontMatrix = lookupMatrix(
if (!isNumberArray(fontMatrix, 6)) { dict.getArray("FontMatrix"),
fontMatrix = FONT_IDENTITY_MATRIX; FONT_IDENTITY_MATRIX
} );
let bbox = descriptor.getArray("FontBBox") || dict.getArray("FontBBox"); const bbox = lookupNormalRect(
if (!isNumberArray(bbox, 4)) { descriptor.getArray("FontBBox") || dict.getArray("FontBBox"),
bbox = undefined; undefined
} );
let ascent = descriptor.get("Ascent"); let ascent = descriptor.get("Ascent");
if (typeof ascent !== "number") { if (typeof ascent !== "number") {
ascent = undefined; ascent = undefined;

View file

@ -25,6 +25,8 @@ import {
import { import {
isBooleanArray, isBooleanArray,
isNumberArray, isNumberArray,
lookupMatrix,
lookupNormalRect,
MissingDataException, MissingDataException,
} from "./core_utils.js"; } from "./core_utils.js";
import { BaseStream } from "./base_stream.js"; import { BaseStream } from "./base_stream.js";
@ -129,8 +131,7 @@ class RadialAxialShading extends BaseShading {
pdfFunctionFactory, pdfFunctionFactory,
localColorSpaceCache, localColorSpaceCache,
}); });
const bbox = dict.getArray("BBox"); this.bbox = lookupNormalRect(dict.getArray("BBox"), null);
this.bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
let t0 = 0.0, let t0 = 0.0,
t1 = 1.0; t1 = 1.0;
@ -461,8 +462,7 @@ class MeshShading extends BaseShading {
} }
const dict = stream.dict; const dict = stream.dict;
this.shadingType = dict.get("ShadingType"); this.shadingType = dict.get("ShadingType");
const bbox = dict.getArray("BBox"); this.bbox = lookupNormalRect(dict.getArray("BBox"), null);
this.bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
const cs = ColorSpace.parse({ const cs = ColorSpace.parse({
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"), cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
xref, xref,
@ -988,12 +988,8 @@ class DummyShading extends BaseShading {
} }
function getTilingPatternIR(operatorList, dict, color) { function getTilingPatternIR(operatorList, dict, color) {
let matrix = dict.getArray("Matrix"); const matrix = lookupMatrix(dict.getArray("Matrix"), IDENTITY_MATRIX);
if (!isNumberArray(matrix, 6)) { const bbox = lookupNormalRect(dict.getArray("BBox"), null);
matrix = IDENTITY_MATRIX;
}
let bbox = dict.getArray("BBox");
bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
// Ensure that the pattern has a non-zero width and height, to prevent errors // Ensure that the pattern has a non-zero width and height, to prevent errors
// in `pattern_helper.js` (fixes issue8330.pdf). // in `pattern_helper.js` (fixes issue8330.pdf).
if (!bbox || bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) { if (!bbox || bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {