Merge 01915d405acf5d690e35b210a981bd2bbd449f87 into ec71e4ed651e659b06a4fa46ef0b18ff9ab2a8c7
This commit is contained in:
commit
15b1bcdf94
@ -73,6 +73,7 @@ import { JpegStream } from "./jpeg_stream.js";
|
|||||||
import { ObjectLoader } from "./object_loader.js";
|
import { ObjectLoader } from "./object_loader.js";
|
||||||
import { OperatorList } from "./operator_list.js";
|
import { OperatorList } from "./operator_list.js";
|
||||||
import { XFAFactory } from "./xfa/factory.js";
|
import { XFAFactory } from "./xfa/factory.js";
|
||||||
|
import { warn } from "../shared/util.js";
|
||||||
|
|
||||||
class AnnotationFactory {
|
class AnnotationFactory {
|
||||||
static createGlobals(pdfManager) {
|
static createGlobals(pdfManager) {
|
||||||
@ -1884,7 +1885,31 @@ class WidgetAnnotation extends Annotation {
|
|||||||
key: "V",
|
key: "V",
|
||||||
getArray: true,
|
getArray: true,
|
||||||
});
|
});
|
||||||
data.fieldValue = this._decodeFormValue(fieldValue);
|
|
||||||
|
let decodedValue = this._decodeFormValue(fieldValue);
|
||||||
|
|
||||||
|
// Handle Name objects, Arrays, and force numeric conversion
|
||||||
|
if (decodedValue instanceof Name) {
|
||||||
|
decodedValue = decodedValue.name;
|
||||||
|
}
|
||||||
|
if (Array.isArray(decodedValue)) {
|
||||||
|
decodedValue = decodedValue[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle potential calculation errors that result in repeating patterns
|
||||||
|
if (typeof decodedValue === "string" && decodedValue.length > 0) {
|
||||||
|
const fixedValue = this._fixRepeatingCalculationValue(decodedValue);
|
||||||
|
if (fixedValue !== null) {
|
||||||
|
decodedValue = fixedValue;
|
||||||
|
} else {
|
||||||
|
let numericStr = decodedValue.replace(/,/g, "");
|
||||||
|
if (!isNaN(numericStr) && numericStr !== "") {
|
||||||
|
decodedValue = Number(numericStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.fieldValue = decodedValue;
|
||||||
|
|
||||||
const defaultFieldValue = getInheritableProperty({
|
const defaultFieldValue = getInheritableProperty({
|
||||||
dict,
|
dict,
|
||||||
@ -1949,6 +1974,89 @@ class WidgetAnnotation extends Annotation {
|
|||||||
this._hasFlag(data.annotationFlags, AnnotationFlag.NOVIEW);
|
this._hasFlag(data.annotationFlags, AnnotationFlag.NOVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix calculation values that show repeating patterns due to JavaScript execution errors
|
||||||
|
* @private
|
||||||
|
* @param {string} value - The potentially malformed calculation result
|
||||||
|
* @returns {number|null} - Fixed numeric value or null if no fix needed
|
||||||
|
*/
|
||||||
|
_fixRepeatingCalculationValue(value) {
|
||||||
|
if (!/^[\d.,]+$/.test(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let match = value.match(/^(\d{1,4})\1{2,}$/);
|
||||||
|
if (match) {
|
||||||
|
const basePattern = match[1];
|
||||||
|
const numericValue = Number(basePattern);
|
||||||
|
if (!isNaN(numericValue)) {
|
||||||
|
warn(
|
||||||
|
`PDF.js: Fixed repeating calculation value "${value}" -> "${basePattern}"`
|
||||||
|
);
|
||||||
|
return numericValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.includes(".")) {
|
||||||
|
const parts = value.split(".");
|
||||||
|
if (parts.length > 2) {
|
||||||
|
const firstPart = parts[0];
|
||||||
|
const secondPart = parts[1];
|
||||||
|
|
||||||
|
if (
|
||||||
|
firstPart.length > 0 &&
|
||||||
|
value.startsWith(firstPart + "." + firstPart)
|
||||||
|
) {
|
||||||
|
const candidate = firstPart;
|
||||||
|
const numericValue = Number(candidate);
|
||||||
|
if (!isNaN(numericValue)) {
|
||||||
|
warn(
|
||||||
|
`PDF.js: Fixed repeating decimal calculation "${value}" -> "${candidate}"`
|
||||||
|
);
|
||||||
|
return numericValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstDecimal = parts[0] + "." + parts[1];
|
||||||
|
const numericValue = Number(firstDecimal);
|
||||||
|
if (!isNaN(numericValue)) {
|
||||||
|
warn(
|
||||||
|
`PDF.js: Fixed multiple decimal calculation "${value}" -> "${firstDecimal}"`
|
||||||
|
);
|
||||||
|
return numericValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length >= 6) {
|
||||||
|
for (
|
||||||
|
let patternLen = 1;
|
||||||
|
patternLen <= Math.floor(value.length / 3);
|
||||||
|
patternLen++
|
||||||
|
) {
|
||||||
|
const pattern = value.substring(0, patternLen);
|
||||||
|
const expectedRepeated = pattern.repeat(
|
||||||
|
Math.floor(value.length / patternLen)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
value.startsWith(expectedRepeated) &&
|
||||||
|
expectedRepeated.length >= value.length * 0.8
|
||||||
|
) {
|
||||||
|
const numericValue = Number(pattern);
|
||||||
|
if (!isNaN(numericValue) && pattern !== "0") {
|
||||||
|
warn(
|
||||||
|
`PDF.js: Fixed repeating pattern calculation "${value}" -> "${pattern}"`
|
||||||
|
);
|
||||||
|
return numericValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode the given form value.
|
* Decode the given form value.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -82,6 +82,101 @@ describe("annotation", function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe("WidgetAnnotation repeating calculation value fix", function () {
|
||||||
|
let dict, xref, annotationGlobals;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
dict = new Dict();
|
||||||
|
xref = new XRefMock();
|
||||||
|
annotationGlobals = {
|
||||||
|
acroForm: new Dict(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fix pure repeating digit patterns", function () {
|
||||||
|
dict.set("Subtype", Name.get("Widget"));
|
||||||
|
dict.set("V", "37037037");
|
||||||
|
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual(37);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fix repeating decimal patterns", function () {
|
||||||
|
dict.set("Subtype", Name.get("Widget"));
|
||||||
|
dict.set("V", "37.037.03");
|
||||||
|
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual(37);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fix multiple repeating patterns", function () {
|
||||||
|
dict.set("Subtype", Name.get("Widget"));
|
||||||
|
dict.set("V", "333333");
|
||||||
|
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not modify valid numeric strings", function () {
|
||||||
|
dict.set("Subtype", Name.get("Widget"));
|
||||||
|
dict.set("V", "123.45");
|
||||||
|
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual(123.45);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not modify non-numeric strings", function () {
|
||||||
|
dict.set("Subtype", Name.get("Widget"));
|
||||||
|
dict.set("V", "ABC123");
|
||||||
|
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual("ABC123");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle edge cases safely", function () {
|
||||||
|
const testCases = [
|
||||||
|
{ input: "", expected: "" },
|
||||||
|
{ input: "0", expected: 0 },
|
||||||
|
{ input: "000", expected: 0 },
|
||||||
|
{ input: "12", expected: 12 },
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach(({ input, expected }) => {
|
||||||
|
dict.set("V", input);
|
||||||
|
const widgetAnnotation = new WidgetAnnotation({
|
||||||
|
dict,
|
||||||
|
xref,
|
||||||
|
annotationGlobals,
|
||||||
|
});
|
||||||
|
expect(widgetAnnotation.data.fieldValue).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
const fontDataReader = new DefaultStandardFontDataFactory({
|
const fontDataReader = new DefaultStandardFontDataFactory({
|
||||||
baseUrl: STANDARD_FONT_DATA_URL,
|
baseUrl: STANDARD_FONT_DATA_URL,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user