mirror of
https://github.com/zen-browser/pdf.js.git
synced 2025-07-08 17:30:09 +02:00
Merge pull request #18493 from calixteman/fix_utf16_alt_text
[Editor] Correctly save a non-ascii alt text
This commit is contained in:
commit
2efa3e460c
4 changed files with 67 additions and 27 deletions
|
@ -42,12 +42,12 @@ import {
|
||||||
escapeString,
|
escapeString,
|
||||||
getInheritableProperty,
|
getInheritableProperty,
|
||||||
getRotationMatrix,
|
getRotationMatrix,
|
||||||
isAscii,
|
|
||||||
isNumberArray,
|
isNumberArray,
|
||||||
lookupMatrix,
|
lookupMatrix,
|
||||||
lookupNormalRect,
|
lookupNormalRect,
|
||||||
lookupRect,
|
lookupRect,
|
||||||
numberToString,
|
numberToString,
|
||||||
|
stringToAsciiOrUTF16BE,
|
||||||
stringToUTF16String,
|
stringToUTF16String,
|
||||||
} from "./core_utils.js";
|
} from "./core_utils.js";
|
||||||
import {
|
import {
|
||||||
|
@ -2133,9 +2133,12 @@ class WidgetAnnotation extends Annotation {
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
const encoder = val =>
|
dict.set(
|
||||||
isAscii(val) ? val : stringToUTF16String(val, /* bigEndian = */ true);
|
"V",
|
||||||
dict.set("V", Array.isArray(value) ? value.map(encoder) : encoder(value));
|
Array.isArray(value)
|
||||||
|
? value.map(stringToAsciiOrUTF16BE)
|
||||||
|
: stringToAsciiOrUTF16BE(value)
|
||||||
|
);
|
||||||
this.amendSavedDict(annotationStorage, dict);
|
this.amendSavedDict(annotationStorage, dict);
|
||||||
|
|
||||||
const maybeMK = this._getMKDict(rotation);
|
const maybeMK = this._getMKDict(rotation);
|
||||||
|
@ -3852,21 +3855,13 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||||
freetext.set("Rect", rect);
|
freetext.set("Rect", rect);
|
||||||
const da = `/Helv ${fontSize} Tf ${getPdfColor(color, /* isFill */ true)}`;
|
const da = `/Helv ${fontSize} Tf ${getPdfColor(color, /* isFill */ true)}`;
|
||||||
freetext.set("DA", da);
|
freetext.set("DA", da);
|
||||||
freetext.set(
|
freetext.set("Contents", stringToAsciiOrUTF16BE(value));
|
||||||
"Contents",
|
|
||||||
isAscii(value)
|
|
||||||
? value
|
|
||||||
: stringToUTF16String(value, /* bigEndian = */ true)
|
|
||||||
);
|
|
||||||
freetext.set("F", 4);
|
freetext.set("F", 4);
|
||||||
freetext.set("Border", [0, 0, 0]);
|
freetext.set("Border", [0, 0, 0]);
|
||||||
freetext.set("Rotate", rotation);
|
freetext.set("Rotate", rotation);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
freetext.set(
|
freetext.set("T", stringToAsciiOrUTF16BE(user));
|
||||||
"T",
|
|
||||||
isAscii(user) ? user : stringToUTF16String(user, /* bigEndian = */ true)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apRef || ap) {
|
if (apRef || ap) {
|
||||||
|
@ -4600,10 +4595,7 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||||
highlight.set("CA", opacity);
|
highlight.set("CA", opacity);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
highlight.set(
|
highlight.set("T", stringToAsciiOrUTF16BE(user));
|
||||||
"T",
|
|
||||||
isAscii(user) ? user : stringToUTF16String(user, /* bigEndian = */ true)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apRef || ap) {
|
if (apRef || ap) {
|
||||||
|
@ -4885,10 +4877,7 @@ class StampAnnotation extends MarkupAnnotation {
|
||||||
stamp.set("Rotate", rotation);
|
stamp.set("Rotate", rotation);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
stamp.set(
|
stamp.set("T", stringToAsciiOrUTF16BE(user));
|
||||||
"T",
|
|
||||||
isAscii(user) ? user : stringToUTF16String(user, /* bigEndian = */ true)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apRef || ap) {
|
if (apRef || ap) {
|
||||||
|
|
|
@ -613,6 +613,10 @@ function getNewAnnotationsMap(annotationStorage) {
|
||||||
return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null;
|
return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stringToAsciiOrUTF16BE(str) {
|
||||||
|
return isAscii(str) ? str : stringToUTF16String(str, /* bigEndian = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
function isAscii(str) {
|
function isAscii(str) {
|
||||||
return /^[\x00-\x7F]*$/.test(str);
|
return /^[\x00-\x7F]*$/.test(str);
|
||||||
}
|
}
|
||||||
|
@ -699,6 +703,7 @@ export {
|
||||||
readUint16,
|
readUint16,
|
||||||
readUint32,
|
readUint32,
|
||||||
recoverJsURL,
|
recoverJsURL,
|
||||||
|
stringToAsciiOrUTF16BE,
|
||||||
stringToUTF16HexString,
|
stringToUTF16HexString,
|
||||||
stringToUTF16String,
|
stringToUTF16String,
|
||||||
toRomanNumerals,
|
toRomanNumerals,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
import { AnnotationPrefix, stringToPDFString, warn } from "../shared/util.js";
|
import { AnnotationPrefix, stringToPDFString, warn } from "../shared/util.js";
|
||||||
import { Dict, isName, Name, Ref, RefSetCache } from "./primitives.js";
|
import { Dict, isName, Name, Ref, RefSetCache } from "./primitives.js";
|
||||||
import { NumberTree } from "./name_number_tree.js";
|
import { NumberTree } from "./name_number_tree.js";
|
||||||
|
import { stringToAsciiOrUTF16BE } from "./core_utils.js";
|
||||||
import { writeObject } from "./writer.js";
|
import { writeObject } from "./writer.js";
|
||||||
|
|
||||||
const MAX_DEPTH = 40;
|
const MAX_DEPTH = 40;
|
||||||
|
@ -316,19 +317,19 @@ class StructTreeRoot {
|
||||||
tagDict.set("S", Name.get(type));
|
tagDict.set("S", Name.get(type));
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
tagDict.set("T", title);
|
tagDict.set("T", stringToAsciiOrUTF16BE(title));
|
||||||
}
|
}
|
||||||
if (lang) {
|
if (lang) {
|
||||||
tagDict.set("Lang", lang);
|
tagDict.set("Lang", lang);
|
||||||
}
|
}
|
||||||
if (alt) {
|
if (alt) {
|
||||||
tagDict.set("Alt", alt);
|
tagDict.set("Alt", stringToAsciiOrUTF16BE(alt));
|
||||||
}
|
}
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
tagDict.set("E", expanded);
|
tagDict.set("E", stringToAsciiOrUTF16BE(expanded));
|
||||||
}
|
}
|
||||||
if (actualText) {
|
if (actualText) {
|
||||||
tagDict.set("ActualText", actualText);
|
tagDict.set("ActualText", stringToAsciiOrUTF16BE(actualText));
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.#updateParentTag({
|
await this.#updateParentTag({
|
||||||
|
|
|
@ -2524,6 +2524,21 @@ describe("api", function () {
|
||||||
alt: "Hello World",
|
alt: "Hello World",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Test if an alt-text using utf-16 is correctly handled.
|
||||||
|
// The Mahjong tile code is 0x1F000.
|
||||||
|
pdfDoc.annotationStorage.setValue("pdfjs_internal_editor_1", {
|
||||||
|
annotationType: AnnotationEditorType.STAMP,
|
||||||
|
rect: [128, 400, 148, 420],
|
||||||
|
rotation: 0,
|
||||||
|
bitmap: structuredClone(bitmap),
|
||||||
|
bitmapId: "im2",
|
||||||
|
pageIndex: 0,
|
||||||
|
structTreeParentId: "p3R_mc14",
|
||||||
|
accessibilityData: {
|
||||||
|
type: "Figure",
|
||||||
|
alt: "Γειά σου with a Mahjong tile 🀀",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const data = await pdfDoc.saveDocument();
|
const data = await pdfDoc.saveDocument();
|
||||||
await loadingTask.destroy();
|
await loadingTask.destroy();
|
||||||
|
@ -2532,7 +2547,7 @@ describe("api", function () {
|
||||||
pdfDoc = await loadingTask.promise;
|
pdfDoc = await loadingTask.promise;
|
||||||
const page = await pdfDoc.getPage(1);
|
const page = await pdfDoc.getPage(1);
|
||||||
const tree = await page.getStructTree();
|
const tree = await page.getStructTree();
|
||||||
const [predecessor, leaf] = findNode(
|
let [predecessor, leaf] = findNode(
|
||||||
null,
|
null,
|
||||||
tree,
|
tree,
|
||||||
0,
|
0,
|
||||||
|
@ -2560,6 +2575,36 @@ describe("api", function () {
|
||||||
alt: "Hello World",
|
alt: "Hello World",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
[predecessor, leaf] = findNode(null, tree, 0, node => {
|
||||||
|
if (node.role === "Figure") {
|
||||||
|
count += 1;
|
||||||
|
return count === 2;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(predecessor).toEqual({
|
||||||
|
role: "Span",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "content",
|
||||||
|
id: "p3R_mc14",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(leaf).toEqual({
|
||||||
|
role: "Figure",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "annotation",
|
||||||
|
id: "pdfjs_internal_id_481R",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
alt: "Γειά σου with a Mahjong tile 🀀",
|
||||||
|
});
|
||||||
|
|
||||||
await loadingTask.destroy();
|
await loadingTask.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue