Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7dbda09c0 | |||
| 20b6e32907 | |||
|
|
1dc874260b | ||
|
|
2305c6416e | ||
|
|
88a38b6c5b | ||
|
|
e8063c88b1 |
66
examples/forge-functionality/api_examples.js
Normal file
66
examples/forge-functionality/api_examples.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import { getDocument } from "../../build/dist/build/pdf.mjs";
|
||||||
|
|
||||||
|
// Some PDFs need external cmaps.
|
||||||
|
const CMAP_URL = "../../../node_modules/pdfjs-dist/cmaps/";
|
||||||
|
const CMAP_PACKED = true;
|
||||||
|
|
||||||
|
// Where the standard fonts are located.
|
||||||
|
const STANDARD_FONT_DATA_URL =
|
||||||
|
"../../../node_modules/pdfjs-dist/standard_fonts/";
|
||||||
|
|
||||||
|
// Loading file from file system into typed array.
|
||||||
|
const pdfPath =
|
||||||
|
process.argv[2] || "C:\\Users\\kj131\\pdf-forge\\test_pdfs\\ISO_32000-2_2020(en).pdf";
|
||||||
|
const data = new Uint8Array(fs.readFileSync(pdfPath));
|
||||||
|
|
||||||
|
// Load the PDF file.
|
||||||
|
const loadingTask = getDocument({
|
||||||
|
data,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
standardFontDataUrl: STANDARD_FONT_DATA_URL,
|
||||||
|
});
|
||||||
|
test(loadingTask);
|
||||||
|
async function test(loading) {
|
||||||
|
try {
|
||||||
|
const pdfDocument = await loading.promise;
|
||||||
|
console.log("# PDF document loaded.");
|
||||||
|
const page = await pdfDocument.getPage(4);
|
||||||
|
printOpList(page);
|
||||||
|
console.time("contents");
|
||||||
|
const contents = await page.getContents();
|
||||||
|
console.timeEnd("contents");
|
||||||
|
console.time("oplist");
|
||||||
|
const opList = await page.getOperatorList();
|
||||||
|
console.timeEnd("oplist");
|
||||||
|
// console.log(opList);
|
||||||
|
let newContents = "";
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const range = opList.rangeArray[i];
|
||||||
|
if (range) {
|
||||||
|
newContents += contents.slice(range[0], range[1]);
|
||||||
|
newContents += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(newContents);
|
||||||
|
await page.updateContents(newContents);
|
||||||
|
await printOpList(page);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function printOpList(page) {
|
||||||
|
const contents = await page.getContents();
|
||||||
|
const opList = await page.getOperatorList();
|
||||||
|
// console.log(opList);
|
||||||
|
const ops = [];
|
||||||
|
for (let i = 0; i < opList.rangeArray.length; i++) {
|
||||||
|
const range = opList.rangeArray[i];
|
||||||
|
if (range) {
|
||||||
|
ops.push(contents.slice(range[0], range[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(ops.slice(0, 100));
|
||||||
|
}
|
||||||
160
examples/forge-functionality/fetch_primitives.js
Normal file
160
examples/forge-functionality/fetch_primitives.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import { EvaluatorPreprocessor } from "../../src/core/evaluator.js";
|
||||||
|
import {
|
||||||
|
getImageAsBlob,
|
||||||
|
getPrim,
|
||||||
|
getPrimitive,
|
||||||
|
getPrimTree,
|
||||||
|
getStreamAsString,
|
||||||
|
} from "../../src/core/obj_walker.js";
|
||||||
|
import { Lexer, Parser } from "../../src/core/parser.js";
|
||||||
|
import { EOF } from "../../src/core/primitives.js";
|
||||||
|
import fs from "fs";
|
||||||
|
import { PDFDocument } from "../../src/core/document.js";
|
||||||
|
import { Stream } from "../../src/core/stream.js";
|
||||||
|
|
||||||
|
const filePath =
|
||||||
|
"C:\\Users\\kj131\\pdf-forge\\test_pdfs\\ISO_32000-2_2020(en).pdf";
|
||||||
|
|
||||||
|
fs.readFile(filePath, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error reading file:", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Reading file");
|
||||||
|
|
||||||
|
const stream = new Stream(data); // No need for Uint8Array, `data` is already a buffer
|
||||||
|
const manager = { enableXfa: false };
|
||||||
|
const doc = new PDFDocument(manager, stream);
|
||||||
|
|
||||||
|
try {
|
||||||
|
doc.parseStartXRef();
|
||||||
|
doc.parse(false);
|
||||||
|
console.log("Number of pages:", doc.numPages);
|
||||||
|
parse(doc);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse PDF:", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function bytesToString(bytes) {
|
||||||
|
let string = "";
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
string += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parse(doc) {
|
||||||
|
const path = "/Page2/Contents/1";
|
||||||
|
let [stream] = await getPrimitive(path, doc);
|
||||||
|
const lexer = new Lexer(stream);
|
||||||
|
const parser = new Parser({ lexer, xref: doc.xref, trackRanges: true });
|
||||||
|
const objs = [];
|
||||||
|
let [obj, start, end] = parser.getObjWithRange();
|
||||||
|
while (obj !== EOF) {
|
||||||
|
if (obj.cmd) {
|
||||||
|
objs.push([obj.cmd, start, end]);
|
||||||
|
} else {
|
||||||
|
objs.push([obj, start, end]);
|
||||||
|
}
|
||||||
|
[obj, start, end] = parser.getObjWithRange();
|
||||||
|
}
|
||||||
|
[stream] = await getPrimitive(path, doc);
|
||||||
|
const bytes = stream.getBytes();
|
||||||
|
const classes = new Set();
|
||||||
|
for (const o of objs) {
|
||||||
|
// console.log(o[0].constructor.name);
|
||||||
|
classes.add(o[0].constructor.name);
|
||||||
|
const lexemmeBytes = bytes.slice(o[1], o[2]);
|
||||||
|
// console.log(bytesToString(lexemmeBytes));
|
||||||
|
}
|
||||||
|
// console.log("unique classes", classes);
|
||||||
|
[stream] = await getPrimitive(path, doc);
|
||||||
|
const preprocessor = new EvaluatorPreprocessor(stream, doc.xref);
|
||||||
|
const operation = {};
|
||||||
|
operation.args = null;
|
||||||
|
while (preprocessor.read(operation)) {
|
||||||
|
const args = operation.args;
|
||||||
|
const fn = operation.fn;
|
||||||
|
const range = operation.range;
|
||||||
|
const op = bytesToString(bytes.slice(range[0], range[1]));
|
||||||
|
// console.log(args, fn);
|
||||||
|
// console.log(`----------------- ${range} -------------------`);
|
||||||
|
console.log(`${fn}: ${op}`);
|
||||||
|
// console.log(`---------------------------------------------`);
|
||||||
|
}
|
||||||
|
// console.time("xref");
|
||||||
|
// let table = await retrieveXref(doc);
|
||||||
|
// console.timeEnd("xref");
|
||||||
|
// console.time("get prim");
|
||||||
|
// const prim = await getPrim("/Trailer/Root/Names/Dests/Names/1", doc);
|
||||||
|
// console.timeEnd("get prim");
|
||||||
|
// console.log(prim);
|
||||||
|
// const request = {
|
||||||
|
// key: "Page2",
|
||||||
|
// children: [
|
||||||
|
// { key: "CropBox" },
|
||||||
|
// { key: "Contents", children: [{ key: "1" , children: [{ key: "Length" }]}] },
|
||||||
|
// {
|
||||||
|
// key: "Resources",
|
||||||
|
// children: [{ key: "ProcSet" }],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// };
|
||||||
|
// console.time("get tree");
|
||||||
|
// const tree = await getPrimTree([request], doc);
|
||||||
|
// console.timeEnd("get tree");
|
||||||
|
// logTree(tree);
|
||||||
|
// console.time("string");
|
||||||
|
// const string = await getStreamAsString("/Page2/Contents/0/Data", doc);
|
||||||
|
// console.timeEnd("string");
|
||||||
|
// console.log(string);
|
||||||
|
// console.time("image");
|
||||||
|
// // const image = await getStreamAsImage("/Page2/Contents/2/Data", doc);
|
||||||
|
// const blob = await getImageAsBlob(
|
||||||
|
// "/Page2/Resources/XObject/Im0/Data",
|
||||||
|
// doc
|
||||||
|
// );
|
||||||
|
// console.timeEnd("image");
|
||||||
|
// console.log(blob);
|
||||||
|
// saveBlobToFile(blob, "image.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveBlobToFile(blob, imagePath) {
|
||||||
|
const buffer = await blobToBuffer(blob);
|
||||||
|
|
||||||
|
fs.writeFile(imagePath, buffer, err => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error saving file:", err);
|
||||||
|
} else {
|
||||||
|
console.log("File saved successfully!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function blobToBuffer(blob) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => resolve(Buffer.from(reader.result));
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function logTree(tree) {
|
||||||
|
for (const node of tree) {
|
||||||
|
let str = " ".repeat(node.depth);
|
||||||
|
if (!node.container) {
|
||||||
|
str += " ";
|
||||||
|
} else {
|
||||||
|
str += node.expanded ? "v " : "> ";
|
||||||
|
}
|
||||||
|
str += node.key + " | " + node.ptype + " | ";
|
||||||
|
// if (node.sub_type !== "-") {
|
||||||
|
// str += node.sub_type + " | ";
|
||||||
|
// }
|
||||||
|
// str += node.value;
|
||||||
|
str += node.trace.map(t => t.key).join(", ");
|
||||||
|
console.log(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
external/openjpeg/openjpeg.js
vendored
1
external/openjpeg/openjpeg.js
vendored
@ -1,4 +1,3 @@
|
|||||||
/* THIS FILE IS GENERATED - DO NOT EDIT */
|
|
||||||
var OpenJPEG = (() => {
|
var OpenJPEG = (() => {
|
||||||
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
|
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
/* THIS FILE IS GENERATED - DO NOT EDIT */
|
|
||||||
var OpenJPEG = (() => {
|
var OpenJPEG = (() => {
|
||||||
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
|
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"stableVersion": "4.10.38",
|
"stableVersion": "5.0.229",
|
||||||
"baseVersion": "7a57af12e13a47927c460e6b739a6ca132e7603d",
|
"baseVersion": "7a57af12e13a47927c460e6b739a6ca132e7603d",
|
||||||
"versionPrefix": "5.0."
|
"versionPrefix": "5.0."
|
||||||
}
|
}
|
||||||
@ -1787,14 +1787,7 @@ class CipherTransformFactory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (algorithm === 4 && encryptionKey.length < 16) {
|
this.encryptionKey = encryptionKey;
|
||||||
// Extend key to 16 byte minimum (undocumented),
|
|
||||||
// fixes issue19484_1.pdf and issue19484_2.pdf.
|
|
||||||
this.encryptionKey = new Uint8Array(16);
|
|
||||||
this.encryptionKey.set(encryptionKey);
|
|
||||||
} else {
|
|
||||||
this.encryptionKey = encryptionKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (algorithm >= 4) {
|
if (algorithm >= 4) {
|
||||||
const cf = dict.get("CF");
|
const cf = dict.get("CF");
|
||||||
|
|||||||
@ -65,7 +65,7 @@ import { Catalog } from "./catalog.js";
|
|||||||
import { clearGlobalCaches } from "./cleanup_helper.js";
|
import { clearGlobalCaches } from "./cleanup_helper.js";
|
||||||
import { DatasetReader } from "./dataset_reader.js";
|
import { DatasetReader } from "./dataset_reader.js";
|
||||||
import { Linearization } from "./parser.js";
|
import { Linearization } from "./parser.js";
|
||||||
import { NullStream } from "./stream.js";
|
import { NullStream, StringStream } from "./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 { PartialEvaluator } from "./evaluator.js";
|
import { PartialEvaluator } from "./evaluator.js";
|
||||||
@ -107,6 +107,8 @@ class Page {
|
|||||||
this.resourcesPromise = null;
|
this.resourcesPromise = null;
|
||||||
this.xfaFactory = xfaFactory;
|
this.xfaFactory = xfaFactory;
|
||||||
|
|
||||||
|
this.updatedContents = null;
|
||||||
|
|
||||||
const idCounters = {
|
const idCounters = {
|
||||||
obj: 0,
|
obj: 0,
|
||||||
};
|
};
|
||||||
@ -246,10 +248,19 @@ class Page {
|
|||||||
throw reason;
|
throw reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setContents(newContents) {
|
||||||
|
this.updatedContents = newContents;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<BaseStream>}
|
* @returns {Promise<BaseStream>}
|
||||||
*/
|
*/
|
||||||
getContentStream() {
|
getContentStream() {
|
||||||
|
if (this.updatedContents !== null) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
resolve(new StringStream(this.updatedContents));
|
||||||
|
});
|
||||||
|
}
|
||||||
return this.pdfManager.ensure(this, "content").then(content => {
|
return this.pdfManager.ensure(this, "content").then(content => {
|
||||||
if (content instanceof BaseStream) {
|
if (content instanceof BaseStream) {
|
||||||
return content;
|
return content;
|
||||||
@ -426,8 +437,11 @@ class Page {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorage = null,
|
annotationStorage = null,
|
||||||
modifiedIds = null,
|
modifiedIds = null,
|
||||||
|
contentOverride = null,
|
||||||
}) {
|
}) {
|
||||||
const contentStreamPromise = this.getContentStream();
|
const contentStreamPromise = contentOverride
|
||||||
|
? new StringStream(contentOverride)
|
||||||
|
: this.getContentStream();
|
||||||
const resourcesPromise = this.loadResources([
|
const resourcesPromise = this.loadResources([
|
||||||
"ColorSpace",
|
"ColorSpace",
|
||||||
"ExtGState",
|
"ExtGState",
|
||||||
|
|||||||
@ -177,11 +177,17 @@ function normalizeBlendMode(value, parsingArray = false) {
|
|||||||
return "source-over";
|
return "source-over";
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLocallyCachedImageOps(opList, data) {
|
function addLocallyCachedImageOps(opList, data, range) {
|
||||||
if (data.objId) {
|
if (data.objId) {
|
||||||
opList.addDependency(data.objId);
|
opList.addDependency(data.objId);
|
||||||
}
|
}
|
||||||
opList.addImageOps(data.fn, data.args, data.optionalContent, data.hasMask);
|
opList.addImageOps(
|
||||||
|
data.fn,
|
||||||
|
data.args,
|
||||||
|
range,
|
||||||
|
data.optionalContent,
|
||||||
|
data.hasMask
|
||||||
|
);
|
||||||
|
|
||||||
if (data.fn === OPS.paintImageMaskXObject && data.args[0]?.count > 0) {
|
if (data.fn === OPS.paintImageMaskXObject && data.args[0]?.count > 0) {
|
||||||
data.args[0].count++;
|
data.args[0].count++;
|
||||||
@ -455,7 +461,8 @@ class PartialEvaluator {
|
|||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
initialState,
|
initialState,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
range = null
|
||||||
) {
|
) {
|
||||||
const dict = xobj.dict;
|
const dict = xobj.dict;
|
||||||
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
||||||
@ -469,7 +476,11 @@ class PartialEvaluator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (optionalContent !== undefined) {
|
if (optionalContent !== undefined) {
|
||||||
operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
operatorList.addOp(
|
||||||
|
OPS.beginMarkedContentProps,
|
||||||
|
["OC", optionalContent],
|
||||||
|
range
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const group = dict.get("Group");
|
const group = dict.get("Group");
|
||||||
if (group) {
|
if (group) {
|
||||||
@ -511,14 +522,14 @@ class PartialEvaluator {
|
|||||||
smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
|
smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
operatorList.addOp(OPS.beginGroup, [groupOptions]);
|
operatorList.addOp(OPS.beginGroup, [groupOptions], range);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a group, a new canvas will be created that is the size of the
|
// If it's a group, a new canvas will be created that is the size of the
|
||||||
// bounding box and translated to the correct position so we don't need to
|
// bounding box and translated to the correct position so we don't need to
|
||||||
// apply the bounding box to it.
|
// apply the bounding box to it.
|
||||||
const args = group ? [matrix, null] : [matrix, bbox];
|
const args = group ? [matrix, null] : [matrix, bbox];
|
||||||
operatorList.addOp(OPS.paintFormXObjectBegin, args);
|
operatorList.addOp(OPS.paintFormXObjectBegin, args, range);
|
||||||
|
|
||||||
await this.getOperatorList({
|
await this.getOperatorList({
|
||||||
stream: xobj,
|
stream: xobj,
|
||||||
@ -527,14 +538,14 @@ class PartialEvaluator {
|
|||||||
operatorList,
|
operatorList,
|
||||||
initialState,
|
initialState,
|
||||||
});
|
});
|
||||||
operatorList.addOp(OPS.paintFormXObjectEnd, []);
|
operatorList.addOp(OPS.paintFormXObjectEnd, [], range);
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
operatorList.addOp(OPS.endGroup, [groupOptions]);
|
operatorList.addOp(OPS.endGroup, [groupOptions], range);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionalContent !== undefined) {
|
if (optionalContent !== undefined) {
|
||||||
operatorList.addOp(OPS.endMarkedContent, []);
|
operatorList.addOp(OPS.endMarkedContent, [], range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +580,7 @@ class PartialEvaluator {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
range,
|
||||||
}) {
|
}) {
|
||||||
const dict = image.dict;
|
const dict = image.dict;
|
||||||
const imageRef = dict.objId;
|
const imageRef = dict.objId;
|
||||||
@ -627,6 +639,7 @@ class PartialEvaluator {
|
|||||||
operatorList.addImageOps(
|
operatorList.addImageOps(
|
||||||
OPS.paintImageMaskXObject,
|
OPS.paintImageMaskXObject,
|
||||||
args,
|
args,
|
||||||
|
range,
|
||||||
optionalContent
|
optionalContent
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -789,6 +802,7 @@ class PartialEvaluator {
|
|||||||
operatorList.addImageOps(
|
operatorList.addImageOps(
|
||||||
OPS.paintImageXObject,
|
OPS.paintImageXObject,
|
||||||
args,
|
args,
|
||||||
|
range,
|
||||||
optionalContent,
|
optionalContent,
|
||||||
hasMask
|
hasMask
|
||||||
);
|
);
|
||||||
@ -899,7 +913,8 @@ class PartialEvaluator {
|
|||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager,
|
stateManager,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
range
|
||||||
) {
|
) {
|
||||||
const smaskContent = smask.get("G");
|
const smaskContent = smask.get("G");
|
||||||
const smaskOptions = {
|
const smaskOptions = {
|
||||||
@ -929,7 +944,8 @@ class PartialEvaluator {
|
|||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager.state.clone(),
|
stateManager.state.clone(),
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
range
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,7 +1029,7 @@ class PartialEvaluator {
|
|||||||
// Add the dependencies to the parent operator list so they are
|
// Add the dependencies to the parent operator list so they are
|
||||||
// resolved before the sub operator list is executed synchronously.
|
// resolved before the sub operator list is executed synchronously.
|
||||||
operatorList.addDependencies(tilingOpList.dependencies);
|
operatorList.addDependencies(tilingOpList.dependencies);
|
||||||
operatorList.addOp(fn, tilingPatternIR);
|
operatorList.addOp(fn, tilingPatternIR, range);
|
||||||
|
|
||||||
if (patternDict.objId) {
|
if (patternDict.objId) {
|
||||||
localTilingPatternCache.set(/* name = */ null, patternDict.objId, {
|
localTilingPatternCache.set(/* name = */ null, patternDict.objId, {
|
||||||
@ -1124,6 +1140,7 @@ class PartialEvaluator {
|
|||||||
stateManager,
|
stateManager,
|
||||||
localGStateCache,
|
localGStateCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
range,
|
||||||
}) {
|
}) {
|
||||||
const gStateRef = gState.objId;
|
const gStateRef = gState.objId;
|
||||||
let isSimpleGState = true;
|
let isSimpleGState = true;
|
||||||
@ -1180,7 +1197,8 @@ class PartialEvaluator {
|
|||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager,
|
stateManager,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
range
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
gStateObj.push([key, true]);
|
gStateObj.push([key, true]);
|
||||||
@ -1218,7 +1236,7 @@ class PartialEvaluator {
|
|||||||
await promise;
|
await promise;
|
||||||
|
|
||||||
if (gStateObj.length > 0) {
|
if (gStateObj.length > 0) {
|
||||||
operatorList.addOp(OPS.setGState, [gStateObj]);
|
operatorList.addOp(OPS.setGState, [gStateObj], range);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSimpleGState) {
|
if (isSimpleGState) {
|
||||||
@ -1387,7 +1405,7 @@ class PartialEvaluator {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPath(operatorList, fn, args, parsingText = false) {
|
buildPath(operatorList, fn, args, parsingText = false, range = null) {
|
||||||
const lastIndex = operatorList.length - 1;
|
const lastIndex = operatorList.length - 1;
|
||||||
if (!args) {
|
if (!args) {
|
||||||
args = [];
|
args = [];
|
||||||
@ -1405,7 +1423,7 @@ class PartialEvaluator {
|
|||||||
// *extremely* rare that shouldn't really matter much in practice.
|
// *extremely* rare that shouldn't really matter much in practice.
|
||||||
if (parsingText) {
|
if (parsingText) {
|
||||||
warn(`Encountered path operator "${fn}" inside of a text object.`);
|
warn(`Encountered path operator "${fn}" inside of a text object.`);
|
||||||
operatorList.addOp(OPS.save, null);
|
operatorList.addOp(OPS.save, null, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
let minMax;
|
let minMax;
|
||||||
@ -1428,7 +1446,11 @@ class PartialEvaluator {
|
|||||||
minMax = [Infinity, Infinity, -Infinity, -Infinity];
|
minMax = [Infinity, Infinity, -Infinity, -Infinity];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
operatorList.addOp(OPS.constructPath, [[fn], args, minMax]);
|
operatorList.addOp(
|
||||||
|
OPS.constructPath,
|
||||||
|
[[fn], args, minMax, [range[0], range[1]]],
|
||||||
|
range
|
||||||
|
);
|
||||||
|
|
||||||
if (parsingText) {
|
if (parsingText) {
|
||||||
operatorList.addOp(OPS.restore, null);
|
operatorList.addOp(OPS.restore, null);
|
||||||
@ -1437,8 +1459,12 @@ class PartialEvaluator {
|
|||||||
const opArgs = operatorList.argsArray[lastIndex];
|
const opArgs = operatorList.argsArray[lastIndex];
|
||||||
opArgs[0].push(fn);
|
opArgs[0].push(fn);
|
||||||
opArgs[1].push(...args);
|
opArgs[1].push(...args);
|
||||||
|
opArgs[3].push(...range);
|
||||||
const minMax = opArgs[2];
|
const minMax = opArgs[2];
|
||||||
|
|
||||||
|
const opRange = operatorList.rangeArray[lastIndex];
|
||||||
|
opRange[1] = range[1];
|
||||||
|
|
||||||
// Compute min/max in the worker instead of the main thread.
|
// Compute min/max in the worker instead of the main thread.
|
||||||
// If the current matrix (when drawing) is a scaling one
|
// If the current matrix (when drawing) is a scaling one
|
||||||
// then min/max can be easily computed in using those values.
|
// then min/max can be easily computed in using those values.
|
||||||
@ -1543,7 +1569,8 @@ class PartialEvaluator {
|
|||||||
task,
|
task,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
localTilingPatternCache,
|
localTilingPatternCache,
|
||||||
localShadingPatternCache
|
localShadingPatternCache,
|
||||||
|
range
|
||||||
) {
|
) {
|
||||||
// compile tiling patterns
|
// compile tiling patterns
|
||||||
const patternName = args.pop();
|
const patternName = args.pop();
|
||||||
@ -1562,7 +1589,7 @@ class PartialEvaluator {
|
|||||||
localTilingPattern.dict,
|
localTilingPattern.dict,
|
||||||
color
|
color
|
||||||
);
|
);
|
||||||
operatorList.addOp(fn, tilingPatternIR);
|
operatorList.addOp(fn, tilingPatternIR, range);
|
||||||
return undefined;
|
return undefined;
|
||||||
} catch {
|
} catch {
|
||||||
// Handle any errors during normal TilingPattern parsing.
|
// Handle any errors during normal TilingPattern parsing.
|
||||||
@ -1596,7 +1623,7 @@ class PartialEvaluator {
|
|||||||
});
|
});
|
||||||
if (objId) {
|
if (objId) {
|
||||||
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
||||||
operatorList.addOp(fn, ["Shading", objId, matrix]);
|
operatorList.addOp(fn, ["Shading", objId, matrix], range);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -1771,6 +1798,7 @@ class PartialEvaluator {
|
|||||||
}
|
}
|
||||||
let args = operation.args;
|
let args = operation.args;
|
||||||
let fn = operation.fn;
|
let fn = operation.fn;
|
||||||
|
const range = operation.range;
|
||||||
|
|
||||||
switch (fn | 0) {
|
switch (fn | 0) {
|
||||||
case OPS.paintXObject:
|
case OPS.paintXObject:
|
||||||
@ -1781,7 +1809,7 @@ class PartialEvaluator {
|
|||||||
if (isValidName) {
|
if (isValidName) {
|
||||||
const localImage = localImageCache.getByName(name);
|
const localImage = localImageCache.getByName(name);
|
||||||
if (localImage) {
|
if (localImage) {
|
||||||
addLocallyCachedImageOps(operatorList, localImage);
|
addLocallyCachedImageOps(operatorList, localImage, range);
|
||||||
args = null;
|
args = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1859,6 +1887,7 @@ class PartialEvaluator {
|
|||||||
cacheKey: name,
|
cacheKey: name,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
range,
|
||||||
})
|
})
|
||||||
.then(resolveXObject, rejectXObject);
|
.then(resolveXObject, rejectXObject);
|
||||||
return;
|
return;
|
||||||
@ -1900,7 +1929,11 @@ class PartialEvaluator {
|
|||||||
)
|
)
|
||||||
.then(function (loadedName) {
|
.then(function (loadedName) {
|
||||||
operatorList.addDependency(loadedName);
|
operatorList.addDependency(loadedName);
|
||||||
operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
|
operatorList.addOp(
|
||||||
|
OPS.setFont,
|
||||||
|
[loadedName, fontSize],
|
||||||
|
range
|
||||||
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -1929,6 +1962,7 @@ class PartialEvaluator {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
range,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -1961,7 +1995,7 @@ class PartialEvaluator {
|
|||||||
self.ensureStateFont(stateManager.state);
|
self.ensureStateFont(stateManager.state);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
operatorList.addOp(OPS.nextLine);
|
operatorList.addOp(OPS.nextLine, null, range);
|
||||||
args[0] = self.handleText(args[0], stateManager.state);
|
args[0] = self.handleText(args[0], stateManager.state);
|
||||||
fn = OPS.showText;
|
fn = OPS.showText;
|
||||||
break;
|
break;
|
||||||
@ -1970,9 +2004,9 @@ class PartialEvaluator {
|
|||||||
self.ensureStateFont(stateManager.state);
|
self.ensureStateFont(stateManager.state);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
operatorList.addOp(OPS.nextLine);
|
operatorList.addOp(OPS.nextLine, null, range);
|
||||||
operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
|
operatorList.addOp(OPS.setWordSpacing, [args.shift()], range);
|
||||||
operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
|
operatorList.addOp(OPS.setCharSpacing, [args.shift()], range);
|
||||||
args[0] = self.handleText(args[0], stateManager.state);
|
args[0] = self.handleText(args[0], stateManager.state);
|
||||||
fn = OPS.showText;
|
fn = OPS.showText;
|
||||||
break;
|
break;
|
||||||
@ -2092,7 +2126,8 @@ class PartialEvaluator {
|
|||||||
task,
|
task,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
localTilingPatternCache,
|
localTilingPatternCache,
|
||||||
localShadingPatternCache
|
localShadingPatternCache,
|
||||||
|
range
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -2124,7 +2159,8 @@ class PartialEvaluator {
|
|||||||
task,
|
task,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
localTilingPatternCache,
|
localTilingPatternCache,
|
||||||
localShadingPatternCache
|
localShadingPatternCache,
|
||||||
|
range
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -2175,7 +2211,7 @@ class PartialEvaluator {
|
|||||||
const localGStateObj = localGStateCache.getByName(name);
|
const localGStateObj = localGStateCache.getByName(name);
|
||||||
if (localGStateObj) {
|
if (localGStateObj) {
|
||||||
if (localGStateObj.length > 0) {
|
if (localGStateObj.length > 0) {
|
||||||
operatorList.addOp(OPS.setGState, [localGStateObj]);
|
operatorList.addOp(OPS.setGState, [localGStateObj], range);
|
||||||
}
|
}
|
||||||
args = null;
|
args = null;
|
||||||
continue;
|
continue;
|
||||||
@ -2211,6 +2247,7 @@ class PartialEvaluator {
|
|||||||
stateManager,
|
stateManager,
|
||||||
localGStateCache,
|
localGStateCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
range,
|
||||||
})
|
})
|
||||||
.then(resolveGState, rejectGState);
|
.then(resolveGState, rejectGState);
|
||||||
}).catch(function (reason) {
|
}).catch(function (reason) {
|
||||||
@ -2232,7 +2269,7 @@ class PartialEvaluator {
|
|||||||
case OPS.curveTo3:
|
case OPS.curveTo3:
|
||||||
case OPS.closePath:
|
case OPS.closePath:
|
||||||
case OPS.rectangle:
|
case OPS.rectangle:
|
||||||
self.buildPath(operatorList, fn, args, parsingText);
|
self.buildPath(operatorList, fn, args, parsingText, range);
|
||||||
continue;
|
continue;
|
||||||
case OPS.markPoint:
|
case OPS.markPoint:
|
||||||
case OPS.markPointProps:
|
case OPS.markPointProps:
|
||||||
@ -2248,7 +2285,11 @@ class PartialEvaluator {
|
|||||||
case OPS.beginMarkedContentProps:
|
case OPS.beginMarkedContentProps:
|
||||||
if (!(args[0] instanceof Name)) {
|
if (!(args[0] instanceof Name)) {
|
||||||
warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`);
|
warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`);
|
||||||
operatorList.addOp(OPS.beginMarkedContentProps, ["OC", null]);
|
operatorList.addOp(
|
||||||
|
OPS.beginMarkedContentProps,
|
||||||
|
["OC", null],
|
||||||
|
range
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[0].name === "OC") {
|
if (args[0].name === "OC") {
|
||||||
@ -2256,10 +2297,11 @@ class PartialEvaluator {
|
|||||||
self
|
self
|
||||||
.parseMarkedContentProps(args[1], resources)
|
.parseMarkedContentProps(args[1], resources)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
operatorList.addOp(OPS.beginMarkedContentProps, [
|
operatorList.addOp(
|
||||||
"OC",
|
OPS.beginMarkedContentProps,
|
||||||
data,
|
["OC", data],
|
||||||
]);
|
range
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch(reason => {
|
.catch(reason => {
|
||||||
if (reason instanceof AbortException) {
|
if (reason instanceof AbortException) {
|
||||||
@ -2269,10 +2311,11 @@ class PartialEvaluator {
|
|||||||
warn(
|
warn(
|
||||||
`getOperatorList - ignoring beginMarkedContentProps: "${reason}".`
|
`getOperatorList - ignoring beginMarkedContentProps: "${reason}".`
|
||||||
);
|
);
|
||||||
operatorList.addOp(OPS.beginMarkedContentProps, [
|
operatorList.addOp(
|
||||||
"OC",
|
OPS.beginMarkedContentProps,
|
||||||
null,
|
["OC", null],
|
||||||
]);
|
range
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw reason;
|
throw reason;
|
||||||
@ -2305,7 +2348,7 @@ class PartialEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operatorList.addOp(fn, args);
|
operatorList.addOp(fn, args, range);
|
||||||
}
|
}
|
||||||
if (stop) {
|
if (stop) {
|
||||||
next(deferred);
|
next(deferred);
|
||||||
@ -5101,6 +5144,7 @@ class EvaluatorPreprocessor {
|
|||||||
// avoiding allocations where possible is worthwhile.
|
// avoiding allocations where possible is worthwhile.
|
||||||
//
|
//
|
||||||
read(operation) {
|
read(operation) {
|
||||||
|
const start = this.parser.getPosition();
|
||||||
let args = operation.args;
|
let args = operation.args;
|
||||||
while (true) {
|
while (true) {
|
||||||
const obj = this.parser.getObj();
|
const obj = this.parser.getObj();
|
||||||
@ -5177,6 +5221,8 @@ class EvaluatorPreprocessor {
|
|||||||
|
|
||||||
operation.fn = fn;
|
operation.fn = fn;
|
||||||
operation.args = args;
|
operation.args = args;
|
||||||
|
const end = this.parser.getEnd();
|
||||||
|
operation.range = [start, end];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj === EOF) {
|
if (obj === EOF) {
|
||||||
|
|||||||
384
src/core/obj_walker.js
Normal file
384
src/core/obj_walker.js
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
import { Dict, Name, Ref } from "./primitives.js";
|
||||||
|
import { BaseStream } from "./base_stream.js";
|
||||||
|
import { LocalColorSpaceCache } from "./image_utils.js";
|
||||||
|
import { PDFFunctionFactory } from "./function.js";
|
||||||
|
import { PDFImage } from "./image.js";
|
||||||
|
|
||||||
|
async function getPrim(path, doc) {
|
||||||
|
const [prim, trace] = await getPrimitive(path, doc);
|
||||||
|
return toModel(trace.at(-1).key, trace, prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStreamAsString(path, doc) {
|
||||||
|
if (!path.endsWith("Data")) {
|
||||||
|
throw new Error(`Path ${path} does not end with Data!`);
|
||||||
|
}
|
||||||
|
const [prim] = await getPrimitive(path.replace("/Data", ""), doc);
|
||||||
|
if ((!prim) instanceof BaseStream) {
|
||||||
|
throw new Error(`Selected primitive with path ${path} is not a Stream!`);
|
||||||
|
}
|
||||||
|
const bytes = prim.getBytes();
|
||||||
|
let string = "";
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
string += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getImageAsBlob(path, doc) {
|
||||||
|
if (!path.endsWith("Data")) {
|
||||||
|
throw new Error(`Path ${path} does not end with Data!`);
|
||||||
|
}
|
||||||
|
const [prim] = await getPrimitive(path.replace("/Data", ""), doc);
|
||||||
|
if ((!prim) instanceof BaseStream) {
|
||||||
|
throw new Error(`Selected primitive with path ${path} is not a Stream!`);
|
||||||
|
}
|
||||||
|
const info = prim.dict;
|
||||||
|
if (!info || info.getRaw("Subtype")?.name !== "Image") {
|
||||||
|
throw new Error(`Selected Stream is not an Image!"`);
|
||||||
|
}
|
||||||
|
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||||
|
xref: doc.xref,
|
||||||
|
isEvalSupported: true,
|
||||||
|
});
|
||||||
|
const pdfImage = new PDFImage({
|
||||||
|
xref: doc.xref,
|
||||||
|
image: prim,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
|
});
|
||||||
|
return pdfImage.createImageData(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPrimitive(path, doc) {
|
||||||
|
const xref = doc.xref;
|
||||||
|
let path_arr = parsePath(path);
|
||||||
|
let [prim, trace] = await getRoot(path_arr[0], doc);
|
||||||
|
while (path_arr.length > 1) {
|
||||||
|
path_arr = path_arr.slice(1);
|
||||||
|
[prim, trace] = resolveStep(xref, prim, trace, path_arr[0]);
|
||||||
|
}
|
||||||
|
return [prim, trace];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPrimTree(request, doc) {
|
||||||
|
let results = [];
|
||||||
|
for (const item of request) {
|
||||||
|
results = results.concat(await _getPrimTree(item, doc));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _getPrimTree(request, doc) {
|
||||||
|
const results = [];
|
||||||
|
const [prim, trace] = await getRoot(request.key, doc);
|
||||||
|
const root = toModel(request.key, trace, prim);
|
||||||
|
results.push(toTreeModel(root, 0, true));
|
||||||
|
addChildren(root, request, results, prim, doc, trace, 1);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addChildren(model, request, results, prim, doc, trace, depth) {
|
||||||
|
for (const child of model.children) {
|
||||||
|
const childRequest = request.children?.find(c => c.key === child.key);
|
||||||
|
if (childRequest) {
|
||||||
|
results.push(toTreeModel(child, depth, true));
|
||||||
|
expandPrim(results, prim, childRequest, doc, trace, depth + 1);
|
||||||
|
} else {
|
||||||
|
results.push(toTreeModel(child, depth, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandPrim(results, rootPrim, request, doc, trace, depth) {
|
||||||
|
if (depth > 20) {
|
||||||
|
throw new Error(`Depth limit exceeded: ${depth}`);
|
||||||
|
}
|
||||||
|
const [prim, _trace] = resolveStep(doc.xref, rootPrim, trace, request.key);
|
||||||
|
const model = toModel(request.key, _trace, prim);
|
||||||
|
addChildren(model, request, results, prim, doc, _trace, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toTreeModel(primModel, depth, expand) {
|
||||||
|
return new TreeViewModel(
|
||||||
|
depth,
|
||||||
|
primModel.key,
|
||||||
|
primModel.ptype,
|
||||||
|
primModel.sub_type,
|
||||||
|
primModel.value,
|
||||||
|
primModel.container,
|
||||||
|
expand,
|
||||||
|
primModel.trace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isContainer(prim) {
|
||||||
|
return (
|
||||||
|
prim instanceof Dict || Array.isArray(prim) || isRef(prim) || isStream(prim)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getRoot(first, doc) {
|
||||||
|
let root;
|
||||||
|
const trace = [];
|
||||||
|
if (first === "Trailer") {
|
||||||
|
root = doc.xref.trailer;
|
||||||
|
trace.push({ key: first, last_jump: first });
|
||||||
|
} else if (first.startsWith("Page")) {
|
||||||
|
const page = await doc.getPage(+first.replace("Page", "") - 1);
|
||||||
|
const ref = page.ref;
|
||||||
|
root = doc.xref.fetch(ref);
|
||||||
|
trace.push({ key: first, last_jump: ref.num });
|
||||||
|
} else {
|
||||||
|
const ref = Ref.get(+first, 0);
|
||||||
|
root = doc.xref.fetch(ref);
|
||||||
|
trace.push({ key: first, last_jump: ref.num });
|
||||||
|
}
|
||||||
|
return [root, trace];
|
||||||
|
}
|
||||||
|
|
||||||
|
function parsePath(path) {
|
||||||
|
if (Array.isArray(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
if (path.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return path.split("/").filter(x => x !== "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRef(obj) {
|
||||||
|
return obj instanceof Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveStep(xref, root, trace, step) {
|
||||||
|
let prim;
|
||||||
|
const last_jump = trace.at(-1).last_jump;
|
||||||
|
if (root instanceof Dict) {
|
||||||
|
prim = root.getRaw(step);
|
||||||
|
} else if (Array.isArray(root)) {
|
||||||
|
const _step = +step;
|
||||||
|
if (isNaN(_step) || _step >= root.length || _step < 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid step ${step} for Array of length: ${root.length}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
prim = root[_step];
|
||||||
|
} else if (root instanceof BaseStream && root.dict) {
|
||||||
|
prim = root.dict.getRaw(step);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Unexpected step ${step} at trace: /${trace.map(t => t.key).join("/")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const _trace = copy(trace);
|
||||||
|
if (isRef(prim)) {
|
||||||
|
const num = prim.num;
|
||||||
|
prim = xref.fetch(prim);
|
||||||
|
_trace.push({ key: step, last_jump: num });
|
||||||
|
} else {
|
||||||
|
_trace.push({ key: step, last_jump });
|
||||||
|
}
|
||||||
|
return [prim, _trace];
|
||||||
|
}
|
||||||
|
|
||||||
|
function toModel(name, trace, prim) {
|
||||||
|
const [type, subType] = toType(prim);
|
||||||
|
let value = primToString(prim);
|
||||||
|
const children = [];
|
||||||
|
if (prim instanceof Dict) {
|
||||||
|
value = format_dict_content(prim);
|
||||||
|
const keys = prim.getKeys();
|
||||||
|
const last = trace.at(-1);
|
||||||
|
keys.forEach(child => {
|
||||||
|
const _trace = copy(trace);
|
||||||
|
_trace.push({ key: child, last_jump: last.last_jump });
|
||||||
|
children.push(toModel(child, _trace, prim.getRaw(child)));
|
||||||
|
});
|
||||||
|
} else if (Array.isArray(prim)) {
|
||||||
|
value = format_arr_content(prim);
|
||||||
|
const last = trace.at(-1);
|
||||||
|
for (let i = 0; i < prim.length; i++) {
|
||||||
|
const _trace = copy(trace);
|
||||||
|
_trace.push({ key: i.toString(), last_jump: last.last_jump });
|
||||||
|
children.push(toModel(i.toString(), _trace, prim[i]));
|
||||||
|
}
|
||||||
|
} else if (isStream(prim)) {
|
||||||
|
const info_dict = prim.dict;
|
||||||
|
if (info_dict) {
|
||||||
|
value = format_dict_content(info_dict);
|
||||||
|
const keys = info_dict.getKeys();
|
||||||
|
const last = trace.at(-1);
|
||||||
|
keys.forEach(child => {
|
||||||
|
const _trace = copy(trace);
|
||||||
|
_trace.push({ key: child, last_jump: last.last_jump });
|
||||||
|
children.push(toModel(child, _trace, info_dict.getRaw(child)));
|
||||||
|
});
|
||||||
|
const _trace = copy(trace);
|
||||||
|
_trace.push({ key: "Data", last_jump: last.last_jump });
|
||||||
|
children.push(
|
||||||
|
new PrimitiveModel("Data", "-", "-", "Stream Data", false, [], _trace)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new PrimitiveModel(
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
subType,
|
||||||
|
value,
|
||||||
|
isContainer(prim),
|
||||||
|
children,
|
||||||
|
trace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toType(prim) {
|
||||||
|
if (prim instanceof Dict) {
|
||||||
|
const subType = prim.getRaw("Type");
|
||||||
|
return ["Dictionary", subType ? subType.name : "-"];
|
||||||
|
} else if (Array.isArray(prim)) {
|
||||||
|
return ["Array", "-"];
|
||||||
|
} else if (isStream(prim)) {
|
||||||
|
const subType = prim.dict?.getRaw("Subtype");
|
||||||
|
return ["Stream", subType ? subType.name : "-"];
|
||||||
|
} else if (prim instanceof Name) {
|
||||||
|
return ["Name", "-"];
|
||||||
|
} else if (isInt(prim)) {
|
||||||
|
return ["Integer", "-"];
|
||||||
|
} else if (isNum(prim)) {
|
||||||
|
return ["Number", "-"];
|
||||||
|
} else if (isBool(prim)) {
|
||||||
|
return ["Boolean", "-"];
|
||||||
|
} else if (isString(prim)) {
|
||||||
|
return ["String", "-"];
|
||||||
|
} else if (isRef(prim)) {
|
||||||
|
return ["Reference", "-"];
|
||||||
|
} else if (prim === null) {
|
||||||
|
return ["Null", "-"];
|
||||||
|
}
|
||||||
|
throw new Error("Unknown prim");
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy(trace) {
|
||||||
|
const _trace = [];
|
||||||
|
for (let i = 0; i < trace.length; i++) {
|
||||||
|
_trace.push(trace[i]);
|
||||||
|
}
|
||||||
|
return _trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBool(v) {
|
||||||
|
return typeof v === "boolean";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInt(v) {
|
||||||
|
return typeof v === "number" && (v | 0) === v;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNum(v) {
|
||||||
|
return typeof v === "number";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isString(v) {
|
||||||
|
return typeof v === "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStream(v) {
|
||||||
|
return v instanceof BaseStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
function primToString(prim) {
|
||||||
|
if (prim instanceof Dict) {
|
||||||
|
return "Dictionary";
|
||||||
|
} else if (Array.isArray(prim)) {
|
||||||
|
return "Array";
|
||||||
|
} else if (isStream(prim)) {
|
||||||
|
return "Stream";
|
||||||
|
} else if (prim instanceof Name) {
|
||||||
|
return prim.name;
|
||||||
|
} else if (isInt(prim)) {
|
||||||
|
return prim.toString();
|
||||||
|
} else if (isNum(prim)) {
|
||||||
|
return prim.toString();
|
||||||
|
} else if (isBool(prim)) {
|
||||||
|
return prim.toString();
|
||||||
|
} else if (isString(prim)) {
|
||||||
|
return prim;
|
||||||
|
} else if (isRef(prim)) {
|
||||||
|
return "XRef(" + prim.num + ", " + prim.gen + ")";
|
||||||
|
} else if (prim === null) {
|
||||||
|
return "Null";
|
||||||
|
}
|
||||||
|
throw new Error("Unknown prim");
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_dict_content(dict) {
|
||||||
|
let result = "{";
|
||||||
|
const keys = dict.getKeys();
|
||||||
|
result += keys
|
||||||
|
.slice(0, 4)
|
||||||
|
.map(key => key + ": " + primToString(dict.getRaw(key)))
|
||||||
|
.join(", ");
|
||||||
|
if (keys.length > 4) {
|
||||||
|
result += ",...";
|
||||||
|
}
|
||||||
|
result += "}";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_arr_content(arr) {
|
||||||
|
let result = "[";
|
||||||
|
result += arr
|
||||||
|
.slice(0, 4)
|
||||||
|
.map(p => primToString(p))
|
||||||
|
.join(", ");
|
||||||
|
if (arr.length > 4) {
|
||||||
|
result += ",...";
|
||||||
|
}
|
||||||
|
result += "]";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimitiveModel {
|
||||||
|
constructor(
|
||||||
|
key,
|
||||||
|
ptype,
|
||||||
|
sub_type,
|
||||||
|
value,
|
||||||
|
container,
|
||||||
|
children = [],
|
||||||
|
trace = []
|
||||||
|
) {
|
||||||
|
this.key = key;
|
||||||
|
this.ptype = ptype;
|
||||||
|
this.sub_type = sub_type;
|
||||||
|
this.value = value;
|
||||||
|
this.children = children;
|
||||||
|
this.trace = trace;
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TreeViewModel {
|
||||||
|
constructor(depth, key, ptype, sub_type, value, container, expanded, trace) {
|
||||||
|
this.depth = depth;
|
||||||
|
this.key = key;
|
||||||
|
this.ptype = ptype;
|
||||||
|
this.sub_type = sub_type;
|
||||||
|
this.value = value;
|
||||||
|
this.container = container;
|
||||||
|
this.expanded = expanded;
|
||||||
|
this.trace = trace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getImageAsBlob,
|
||||||
|
getPrim,
|
||||||
|
getPrimitive,
|
||||||
|
getPrimTree,
|
||||||
|
getStreamAsString,
|
||||||
|
PrimitiveModel,
|
||||||
|
toType,
|
||||||
|
TreeViewModel,
|
||||||
|
};
|
||||||
@ -477,9 +477,10 @@ class NullOptimizer {
|
|||||||
|
|
||||||
_optimize() {}
|
_optimize() {}
|
||||||
|
|
||||||
push(fn, args) {
|
push(fn, args, range) {
|
||||||
this.queue.fnArray.push(fn);
|
this.queue.fnArray.push(fn);
|
||||||
this.queue.argsArray.push(args);
|
this.queue.argsArray.push(args);
|
||||||
|
this.queue.rangeArray.push(range);
|
||||||
this._optimize();
|
this._optimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,6 +590,7 @@ class OperatorList {
|
|||||||
this._streamSink = streamSink;
|
this._streamSink = streamSink;
|
||||||
this.fnArray = [];
|
this.fnArray = [];
|
||||||
this.argsArray = [];
|
this.argsArray = [];
|
||||||
|
this.rangeArray = [];
|
||||||
this.optimizer =
|
this.optimizer =
|
||||||
streamSink && !(intent & RenderingIntentFlag.OPLIST)
|
streamSink && !(intent & RenderingIntentFlag.OPLIST)
|
||||||
? new QueueOptimizer(this)
|
? new QueueOptimizer(this)
|
||||||
@ -620,8 +622,8 @@ class OperatorList {
|
|||||||
return this._totalLength + this.length;
|
return this._totalLength + this.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
addOp(fn, args) {
|
addOp(fn, args, range = null) {
|
||||||
this.optimizer.push(fn, args);
|
this.optimizer.push(fn, args, range);
|
||||||
this.weight++;
|
this.weight++;
|
||||||
if (this._streamSink) {
|
if (this._streamSink) {
|
||||||
if (this.weight >= OperatorList.CHUNK_SIZE) {
|
if (this.weight >= OperatorList.CHUNK_SIZE) {
|
||||||
@ -636,7 +638,7 @@ class OperatorList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addImageOps(fn, args, optionalContent, hasMask = false) {
|
addImageOps(fn, args, range, optionalContent, hasMask = false) {
|
||||||
if (hasMask) {
|
if (hasMask) {
|
||||||
this.addOp(OPS.save);
|
this.addOp(OPS.save);
|
||||||
this.addOp(OPS.setGState, [[["SMask", false]]]);
|
this.addOp(OPS.setGState, [[["SMask", false]]]);
|
||||||
@ -645,7 +647,7 @@ class OperatorList {
|
|||||||
this.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
this.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addOp(fn, args);
|
this.addOp(fn, args, range);
|
||||||
|
|
||||||
if (optionalContent !== undefined) {
|
if (optionalContent !== undefined) {
|
||||||
this.addOp(OPS.endMarkedContent, []);
|
this.addOp(OPS.endMarkedContent, []);
|
||||||
@ -678,7 +680,7 @@ class OperatorList {
|
|||||||
this.dependencies.add(dependency);
|
this.dependencies.add(dependency);
|
||||||
}
|
}
|
||||||
for (let i = 0, ii = opList.length; i < ii; i++) {
|
for (let i = 0, ii = opList.length; i < ii; i++) {
|
||||||
this.addOp(opList.fnArray[i], opList.argsArray[i]);
|
this.addOp(opList.fnArray[i], opList.argsArray[i], opList.rangeArray[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,6 +688,7 @@ class OperatorList {
|
|||||||
return {
|
return {
|
||||||
fnArray: this.fnArray,
|
fnArray: this.fnArray,
|
||||||
argsArray: this.argsArray,
|
argsArray: this.argsArray,
|
||||||
|
rangeArray: this.rangeArray,
|
||||||
length: this.length,
|
length: this.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -717,6 +720,7 @@ class OperatorList {
|
|||||||
{
|
{
|
||||||
fnArray: this.fnArray,
|
fnArray: this.fnArray,
|
||||||
argsArray: this.argsArray,
|
argsArray: this.argsArray,
|
||||||
|
rangeArray: this.rangeArray,
|
||||||
lastChunk,
|
lastChunk,
|
||||||
separateAnnots,
|
separateAnnots,
|
||||||
length,
|
length,
|
||||||
@ -728,6 +732,7 @@ class OperatorList {
|
|||||||
this.dependencies.clear();
|
this.dependencies.clear();
|
||||||
this.fnArray.length = 0;
|
this.fnArray.length = 0;
|
||||||
this.argsArray.length = 0;
|
this.argsArray.length = 0;
|
||||||
|
this.rangeArray.length = 0;
|
||||||
this.weight = 0;
|
this.weight = 0;
|
||||||
this.optimizer.reset();
|
this.optimizer.reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,24 +64,34 @@ class Parser {
|
|||||||
this.xref = xref;
|
this.xref = xref;
|
||||||
this.allowStreams = allowStreams;
|
this.allowStreams = allowStreams;
|
||||||
this.recoveryMode = recoveryMode;
|
this.recoveryMode = recoveryMode;
|
||||||
|
|
||||||
this.imageCache = Object.create(null);
|
this.imageCache = Object.create(null);
|
||||||
this._imageId = 0;
|
this._imageId = 0;
|
||||||
this.refill();
|
this.refill();
|
||||||
}
|
}
|
||||||
|
|
||||||
refill() {
|
refill() {
|
||||||
this.buf1 = this.lexer.getObj();
|
const [buf1, start1, end1] = this.lexer.getObjWithRange();
|
||||||
this.buf2 = this.lexer.getObj();
|
const [buf2, start2, end2] = this.lexer.getObjWithRange();
|
||||||
|
this.buf1 = buf1;
|
||||||
|
this.range1 = [start1, end1];
|
||||||
|
this.buf2 = buf2;
|
||||||
|
this.range2 = [start2, end2];
|
||||||
}
|
}
|
||||||
|
|
||||||
shift() {
|
shift() {
|
||||||
if (this.buf2 instanceof Cmd && this.buf2.cmd === "ID") {
|
if (this.buf2 instanceof Cmd && this.buf2.cmd === "ID") {
|
||||||
this.buf1 = this.buf2;
|
this.buf1 = this.buf2;
|
||||||
this.buf2 = null;
|
this.buf2 = null;
|
||||||
|
this.lastEnd = this.range1[1];
|
||||||
|
this.range1 = this.range2;
|
||||||
|
this.range2 = null;
|
||||||
} else {
|
} else {
|
||||||
this.buf1 = this.buf2;
|
this.buf1 = this.buf2;
|
||||||
this.buf2 = this.lexer.getObj();
|
this.lastEnd = this.range1[1];
|
||||||
|
this.range1 = this.range2;
|
||||||
|
const [buf2, start2, end2] = this.lexer.getObjWithRange();
|
||||||
|
this.buf2 = buf2;
|
||||||
|
this.range2 = [start2, end2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +109,21 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPosition() {
|
||||||
|
return this.range1 ? this.range1[0] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEnd() {
|
||||||
|
return this.lastEnd ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getObjWithRange(cipherTransform = null) {
|
||||||
|
const start = this.range1[0];
|
||||||
|
const obj = this.getObj(cipherTransform);
|
||||||
|
const end = this.range1[0];
|
||||||
|
return [obj, start, end];
|
||||||
|
}
|
||||||
|
|
||||||
getObj(cipherTransform = null) {
|
getObj(cipherTransform = null) {
|
||||||
const buf1 = this.buf1;
|
const buf1 = this.buf1;
|
||||||
this.shift();
|
this.shift();
|
||||||
@ -1204,7 +1229,19 @@ class Lexer {
|
|||||||
return strBuf.join("");
|
return strBuf.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
getObj() {
|
getObjWithRange() {
|
||||||
|
const ch = this._skipWhitespaceAndComments();
|
||||||
|
if (ch === EOF) {
|
||||||
|
return [ch, -1, -1];
|
||||||
|
}
|
||||||
|
// currentChar is always at pos - 1
|
||||||
|
const start = Math.max(this.stream.pos - 1, 0);
|
||||||
|
const obj = this.getObj();
|
||||||
|
const end = this.stream.pos - 1;
|
||||||
|
return [obj, start, end];
|
||||||
|
}
|
||||||
|
|
||||||
|
_skipWhitespaceAndComments() {
|
||||||
// Skip whitespace and comments.
|
// Skip whitespace and comments.
|
||||||
let comment = false;
|
let comment = false;
|
||||||
let ch = this.currentChar;
|
let ch = this.currentChar;
|
||||||
@ -1223,7 +1260,14 @@ class Lexer {
|
|||||||
}
|
}
|
||||||
ch = this.nextChar();
|
ch = this.nextChar();
|
||||||
}
|
}
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
getObj() {
|
||||||
|
let ch = this._skipWhitespaceAndComments();
|
||||||
|
if (ch === EOF) {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
// Start reading a token.
|
// Start reading a token.
|
||||||
switch (ch | 0) {
|
switch (ch | 0) {
|
||||||
case 0x30: // '0'
|
case 0x30: // '0'
|
||||||
|
|||||||
37
src/core/retrieve_xref.js
Normal file
37
src/core/retrieve_xref.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Ref } from "./primitives.js";
|
||||||
|
import { toType } from "./obj_walker.js";
|
||||||
|
|
||||||
|
async function retrieveXref(doc) {
|
||||||
|
const result = new XRefTable(doc.xref.entries.length);
|
||||||
|
for (let i = 0; i < doc.xref.entries.length; i++) {
|
||||||
|
result.entries.push(to_model(i, doc.xref.entries[i], doc.xref));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_model(i, entry, xref) {
|
||||||
|
if (entry.free) {
|
||||||
|
return new XRefEntry("Free", i, entry.gen, entry.offset);
|
||||||
|
}
|
||||||
|
const fetched = xref.fetch(Ref.get(i, entry.gen));
|
||||||
|
const [type] = toType(fetched);
|
||||||
|
return new XRefEntry(type, i, entry.gen, entry.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
class XRefTable {
|
||||||
|
constructor(size) {
|
||||||
|
this.size = size;
|
||||||
|
this.entries = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XRefEntry {
|
||||||
|
constructor(obj_type, obj_num, gen_num, offset) {
|
||||||
|
this.obj_type = obj_type;
|
||||||
|
this.obj_num = obj_num;
|
||||||
|
this.gen_num = gen_num;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { retrieveXref, XRefEntry, XRefTable };
|
||||||
@ -31,12 +31,19 @@ import {
|
|||||||
XRefParseException,
|
XRefParseException,
|
||||||
} from "./core_utils.js";
|
} from "./core_utils.js";
|
||||||
import { Dict, isDict, Ref, RefSetCache } from "./primitives.js";
|
import { Dict, isDict, Ref, RefSetCache } from "./primitives.js";
|
||||||
|
import {
|
||||||
|
getImageAsBlob,
|
||||||
|
getPrim,
|
||||||
|
getPrimTree,
|
||||||
|
getStreamAsString
|
||||||
|
} from "./obj_walker.js";
|
||||||
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js";
|
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js";
|
||||||
import { MessageHandler, wrapReason } from "../shared/message_handler.js";
|
import { MessageHandler, wrapReason } from "../shared/message_handler.js";
|
||||||
import { AnnotationFactory } from "./annotation.js";
|
import { AnnotationFactory } from "./annotation.js";
|
||||||
import { clearGlobalCaches } from "./cleanup_helper.js";
|
import { clearGlobalCaches } from "./cleanup_helper.js";
|
||||||
import { incrementalUpdate } from "./writer.js";
|
import { incrementalUpdate } from "./writer.js";
|
||||||
import { PDFWorkerStream } from "./worker_stream.js";
|
import { PDFWorkerStream } from "./worker_stream.js";
|
||||||
|
import { retrieveXref } from "./retrieve_xref.js";
|
||||||
import { StructTreeRoot } from "./struct_tree.js";
|
import { StructTreeRoot } from "./struct_tree.js";
|
||||||
|
|
||||||
class WorkerTask {
|
class WorkerTask {
|
||||||
@ -116,7 +123,7 @@ class WorkerMessageHandler {
|
|||||||
if (apiVersion !== workerVersion) {
|
if (apiVersion !== workerVersion) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The API version "${apiVersion}" does not match ` +
|
`The API version "${apiVersion}" does not match ` +
|
||||||
`the Worker version "${workerVersion}".`
|
`the Worker version "${workerVersion}".`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +141,8 @@ class WorkerMessageHandler {
|
|||||||
if (enumerableProperties.length) {
|
if (enumerableProperties.length) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"The `Array.prototype` contains unexpected enumerable properties: " +
|
"The `Array.prototype` contains unexpected enumerable properties: " +
|
||||||
enumerableProperties.join(", ") +
|
enumerableProperties.join(", ") +
|
||||||
"; thus breaking e.g. `for...in` iteration of `Array`s."
|
"; thus breaking e.g. `for...in` iteration of `Array`s."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,15 +206,15 @@ class WorkerMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getPdfManager({
|
async function getPdfManager({
|
||||||
data,
|
data,
|
||||||
password,
|
password,
|
||||||
disableAutoFetch,
|
disableAutoFetch,
|
||||||
rangeChunkSize,
|
rangeChunkSize,
|
||||||
length,
|
length,
|
||||||
docBaseUrl,
|
docBaseUrl,
|
||||||
enableXfa,
|
enableXfa,
|
||||||
evaluatorOptions,
|
evaluatorOptions,
|
||||||
}) {
|
}) {
|
||||||
const pdfManagerArgs = {
|
const pdfManagerArgs = {
|
||||||
source: null,
|
source: null,
|
||||||
disableAutoFetch,
|
disableAutoFetch,
|
||||||
@ -235,7 +242,7 @@ class WorkerMessageHandler {
|
|||||||
loaded = 0;
|
loaded = 0;
|
||||||
|
|
||||||
fullRequest.headersReady
|
fullRequest.headersReady
|
||||||
.then(function () {
|
.then(function() {
|
||||||
if (!fullRequest.isRangeSupported) {
|
if (!fullRequest.isRangeSupported) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -256,13 +263,13 @@ class WorkerMessageHandler {
|
|||||||
pdfManagerCapability.resolve(newPdfManager);
|
pdfManagerCapability.resolve(newPdfManager);
|
||||||
cancelXHRs = null;
|
cancelXHRs = null;
|
||||||
})
|
})
|
||||||
.catch(function (reason) {
|
.catch(function(reason) {
|
||||||
pdfManagerCapability.reject(reason);
|
pdfManagerCapability.reject(reason);
|
||||||
cancelXHRs = null;
|
cancelXHRs = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
new Promise(function (resolve, reject) {
|
new Promise(function(resolve, reject) {
|
||||||
const readChunk = function ({ value, done }) {
|
const readChunk = function({ value, done }) {
|
||||||
try {
|
try {
|
||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
if (done) {
|
if (done) {
|
||||||
@ -307,7 +314,7 @@ class WorkerMessageHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
fullRequest.read().then(readChunk, reject);
|
fullRequest.read().then(readChunk, reject);
|
||||||
}).catch(function (e) {
|
}).catch(function(e) {
|
||||||
pdfManagerCapability.reject(e);
|
pdfManagerCapability.reject(e);
|
||||||
cancelXHRs = null;
|
cancelXHRs = null;
|
||||||
});
|
});
|
||||||
@ -334,12 +341,12 @@ class WorkerMessageHandler {
|
|||||||
|
|
||||||
handler
|
handler
|
||||||
.sendWithPromise("PasswordRequest", ex)
|
.sendWithPromise("PasswordRequest", ex)
|
||||||
.then(function ({ password }) {
|
.then(function({ password }) {
|
||||||
finishWorkerTask(task);
|
finishWorkerTask(task);
|
||||||
pdfManager.updatePassword(password);
|
pdfManager.updatePassword(password);
|
||||||
pdfManagerReady();
|
pdfManagerReady();
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function() {
|
||||||
finishWorkerTask(task);
|
finishWorkerTask(task);
|
||||||
handler.send("DocException", ex);
|
handler.send("DocException", ex);
|
||||||
});
|
});
|
||||||
@ -352,7 +359,7 @@ class WorkerMessageHandler {
|
|||||||
function pdfManagerReady() {
|
function pdfManagerReady() {
|
||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
|
|
||||||
loadDocument(false).then(onSuccess, function (reason) {
|
loadDocument(false).then(onSuccess, function(reason) {
|
||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
|
|
||||||
// Try again with recoveryMode == true
|
// Try again with recoveryMode == true
|
||||||
@ -360,7 +367,7 @@ class WorkerMessageHandler {
|
|||||||
onFailure(reason);
|
onFailure(reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pdfManager.requestLoadedStream().then(function () {
|
pdfManager.requestLoadedStream().then(function() {
|
||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
|
|
||||||
loadDocument(true).then(onSuccess, onFailure);
|
loadDocument(true).then(onSuccess, onFailure);
|
||||||
@ -371,7 +378,7 @@ class WorkerMessageHandler {
|
|||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
|
|
||||||
getPdfManager(data)
|
getPdfManager(data)
|
||||||
.then(function (newPdfManager) {
|
.then(function(newPdfManager) {
|
||||||
if (terminated) {
|
if (terminated) {
|
||||||
// We were in a process of setting up the manager, but it got
|
// We were in a process of setting up the manager, but it got
|
||||||
// terminated in the middle.
|
// terminated in the middle.
|
||||||
@ -389,14 +396,14 @@ class WorkerMessageHandler {
|
|||||||
.then(pdfManagerReady, onFailure);
|
.then(pdfManagerReady, onFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.on("GetPage", function (data) {
|
handler.on("GetPage", function(data) {
|
||||||
return pdfManager.getPage(data.pageIndex).then(function (page) {
|
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
pdfManager.ensure(page, "rotate"),
|
pdfManager.ensure(page, "rotate"),
|
||||||
pdfManager.ensure(page, "ref"),
|
pdfManager.ensure(page, "ref"),
|
||||||
pdfManager.ensure(page, "userUnit"),
|
pdfManager.ensure(page, "userUnit"),
|
||||||
pdfManager.ensure(page, "view"),
|
pdfManager.ensure(page, "view"),
|
||||||
]).then(function ([rotate, ref, userUnit, view]) {
|
]).then(function([rotate, ref, userUnit, view]) {
|
||||||
return {
|
return {
|
||||||
rotate,
|
rotate,
|
||||||
ref,
|
ref,
|
||||||
@ -408,84 +415,104 @@ class WorkerMessageHandler {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPageIndex", function (data) {
|
handler.on("GetPageIndex", function(data) {
|
||||||
const pageRef = Ref.get(data.num, data.gen);
|
const pageRef = Ref.get(data.num, data.gen);
|
||||||
return pdfManager.ensureCatalog("getPageIndex", [pageRef]);
|
return pdfManager.ensureCatalog("getPageIndex", [pageRef]);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetDestinations", function (data) {
|
handler.on("GetDestinations", function(data) {
|
||||||
return pdfManager.ensureCatalog("destinations");
|
return pdfManager.ensureCatalog("destinations");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetDestination", function (data) {
|
handler.on("GetDestination", function(data) {
|
||||||
return pdfManager.ensureCatalog("getDestination", [data.id]);
|
return pdfManager.ensureCatalog("getDestination", [data.id]);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPageLabels", function (data) {
|
handler.on("GetPageLabels", function(data) {
|
||||||
return pdfManager.ensureCatalog("pageLabels");
|
return pdfManager.ensureCatalog("pageLabels");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPageLayout", function (data) {
|
handler.on("GetPageLayout", function(data) {
|
||||||
return pdfManager.ensureCatalog("pageLayout");
|
return pdfManager.ensureCatalog("pageLayout");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPageMode", function (data) {
|
handler.on("GetPageMode", function(data) {
|
||||||
return pdfManager.ensureCatalog("pageMode");
|
return pdfManager.ensureCatalog("pageMode");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetViewerPreferences", function (data) {
|
handler.on("GetViewerPreferences", function(data) {
|
||||||
return pdfManager.ensureCatalog("viewerPreferences");
|
return pdfManager.ensureCatalog("viewerPreferences");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetOpenAction", function (data) {
|
handler.on("GetOpenAction", function(data) {
|
||||||
return pdfManager.ensureCatalog("openAction");
|
return pdfManager.ensureCatalog("openAction");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetAttachments", function (data) {
|
handler.on("GetAttachments", function(data) {
|
||||||
return pdfManager.ensureCatalog("attachments");
|
return pdfManager.ensureCatalog("attachments");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetDocJSActions", function (data) {
|
handler.on("GetDocJSActions", function(data) {
|
||||||
return pdfManager.ensureCatalog("jsActions");
|
return pdfManager.ensureCatalog("jsActions");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPageJSActions", function ({ pageIndex }) {
|
handler.on("GetPageJSActions", function({ pageIndex }) {
|
||||||
return pdfManager.getPage(pageIndex).then(function (page) {
|
return pdfManager.getPage(pageIndex).then(function(page) {
|
||||||
return pdfManager.ensure(page, "jsActions");
|
return pdfManager.ensure(page, "jsActions");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetOutline", function (data) {
|
handler.on("GetOutline", function(data) {
|
||||||
return pdfManager.ensureCatalog("documentOutline");
|
return pdfManager.ensureCatalog("documentOutline");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetOptionalContentConfig", function (data) {
|
handler.on("GetOptionalContentConfig", function(data) {
|
||||||
return pdfManager.ensureCatalog("optionalContentConfig");
|
return pdfManager.ensureCatalog("optionalContentConfig");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetPermissions", function (data) {
|
handler.on("GetPermissions", function(data) {
|
||||||
return pdfManager.ensureCatalog("permissions");
|
return pdfManager.ensureCatalog("permissions");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetMetadata", function (data) {
|
handler.on("GetMetadata", function(data) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
pdfManager.ensureDoc("documentInfo"),
|
pdfManager.ensureDoc("documentInfo"),
|
||||||
pdfManager.ensureCatalog("metadata"),
|
pdfManager.ensureCatalog("metadata"),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetMarkInfo", function (data) {
|
handler.on("GetMarkInfo", function(data) {
|
||||||
return pdfManager.ensureCatalog("markInfo");
|
return pdfManager.ensureCatalog("markInfo");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetData", function (data) {
|
handler.on("GetData", function(data) {
|
||||||
return pdfManager.requestLoadedStream().then(function (stream) {
|
return pdfManager.requestLoadedStream().then(function(stream) {
|
||||||
return stream.bytes;
|
return stream.bytes;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetAnnotations", function ({ pageIndex, intent }) {
|
handler.on("GetPrimitiveByPath", function(path_str) {
|
||||||
return pdfManager.getPage(pageIndex).then(function (page) {
|
return getPrim(path_str, pdfManager.pdfDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("GetXRefEntries", function(data) {
|
||||||
|
return retrieveXref(pdfManager.pdfDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("GetPrimTree", function(request) {
|
||||||
|
return getPrimTree(request, pdfManager.pdfDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("GetImageData", function(path) {
|
||||||
|
return getImageAsBlob(path, pdfManager.pdfDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("GetStreamAsString", function(path) {
|
||||||
|
return getStreamAsString(path, pdfManager.pdfDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("GetAnnotations", function({ pageIndex, intent }) {
|
||||||
|
return pdfManager.getPage(pageIndex).then(function(page) {
|
||||||
const task = new WorkerTask(`GetAnnotations: page ${pageIndex}`);
|
const task = new WorkerTask(`GetAnnotations: page ${pageIndex}`);
|
||||||
startWorkerTask(task);
|
startWorkerTask(task);
|
||||||
|
|
||||||
@ -502,23 +529,23 @@ class WorkerMessageHandler {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetFieldObjects", function (data) {
|
handler.on("GetFieldObjects", function(data) {
|
||||||
return pdfManager
|
return pdfManager
|
||||||
.ensureDoc("fieldObjects")
|
.ensureDoc("fieldObjects")
|
||||||
.then(fieldObjects => fieldObjects?.allFields || null);
|
.then(fieldObjects => fieldObjects?.allFields || null);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("HasJSActions", function (data) {
|
handler.on("HasJSActions", function(data) {
|
||||||
return pdfManager.ensureDoc("hasJSActions");
|
return pdfManager.ensureDoc("hasJSActions");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetCalculationOrderIds", function (data) {
|
handler.on("GetCalculationOrderIds", function(data) {
|
||||||
return pdfManager.ensureDoc("calculationOrderIds");
|
return pdfManager.ensureDoc("calculationOrderIds");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on(
|
handler.on(
|
||||||
"SaveDocument",
|
"SaveDocument",
|
||||||
async function ({ isPureXfa, numPages, annotationStorage, filename }) {
|
async function({ isPureXfa, numPages, annotationStorage, filename }) {
|
||||||
const globalPromises = [
|
const globalPromises = [
|
||||||
pdfManager.requestLoadedStream(),
|
pdfManager.requestLoadedStream(),
|
||||||
pdfManager.ensureCatalog("acroForm"),
|
pdfManager.ensureCatalog("acroForm"),
|
||||||
@ -588,7 +615,7 @@ class WorkerMessageHandler {
|
|||||||
imagePromises,
|
imagePromises,
|
||||||
changes
|
changes
|
||||||
)
|
)
|
||||||
.finally(function () {
|
.finally(function() {
|
||||||
finishWorkerTask(task);
|
finishWorkerTask(task);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -625,13 +652,13 @@ class WorkerMessageHandler {
|
|||||||
} else {
|
} else {
|
||||||
for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
|
for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
|
||||||
promises.push(
|
promises.push(
|
||||||
pdfManager.getPage(pageIndex).then(function (page) {
|
pdfManager.getPage(pageIndex).then(function(page) {
|
||||||
const task = new WorkerTask(`Save: page ${pageIndex}`);
|
const task = new WorkerTask(`Save: page ${pageIndex}`);
|
||||||
startWorkerTask(task);
|
startWorkerTask(task);
|
||||||
|
|
||||||
return page
|
return page
|
||||||
.save(handler, task, annotationStorage, changes)
|
.save(handler, task, annotationStorage, changes)
|
||||||
.finally(function () {
|
.finally(function() {
|
||||||
finishWorkerTask(task);
|
finishWorkerTask(task);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -721,6 +748,31 @@ class WorkerMessageHandler {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
handler.on("StreamContents", function(data, sink) {
|
||||||
|
const pageIndex = data.pageIndex;
|
||||||
|
pdfManager.getPage(pageIndex).then(function(page) {
|
||||||
|
page.getContentStream().then(stream => {
|
||||||
|
let byte;
|
||||||
|
let string = "";
|
||||||
|
while ((byte = stream.getByte()) !== -1) {
|
||||||
|
string += String.fromCharCode(byte);
|
||||||
|
}
|
||||||
|
sink.enqueue(string, string.length);
|
||||||
|
sink.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on("UpdateContents", function (data) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const pageIndex = data.pageIndex;
|
||||||
|
pdfManager.getPage(pageIndex).then(function (page) {
|
||||||
|
page.setContents(data.value);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
handler.on("GetOperatorList", function (data, sink) {
|
handler.on("GetOperatorList", function (data, sink) {
|
||||||
const pageIndex = data.pageIndex;
|
const pageIndex = data.pageIndex;
|
||||||
pdfManager.getPage(pageIndex).then(function (page) {
|
pdfManager.getPage(pageIndex).then(function (page) {
|
||||||
@ -740,6 +792,7 @@ class WorkerMessageHandler {
|
|||||||
cacheKey: data.cacheKey,
|
cacheKey: data.cacheKey,
|
||||||
annotationStorage: data.annotationStorage,
|
annotationStorage: data.annotationStorage,
|
||||||
modifiedIds: data.modifiedIds,
|
modifiedIds: data.modifiedIds,
|
||||||
|
contentOverride: data.contentOverride,
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
function (operatorListInfo) {
|
function (operatorListInfo) {
|
||||||
|
|||||||
@ -17,10 +17,25 @@
|
|||||||
* @module pdfjsLib
|
* @module pdfjsLib
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DOMCMapReaderFactory } from "display-cmap_reader_factory";
|
||||||
|
import { PDFFetchStream } from "display-fetch_stream";
|
||||||
|
import { PDFNetworkStream } from "display-network";
|
||||||
|
import { PDFNodeStream } from "display-node_stream";
|
||||||
|
import {
|
||||||
|
NodeCanvasFactory,
|
||||||
|
NodeCMapReaderFactory,
|
||||||
|
NodeFilterFactory,
|
||||||
|
NodeStandardFontDataFactory,
|
||||||
|
NodeWasmFactory,
|
||||||
|
} from "display-node_utils";
|
||||||
|
import { DOMStandardFontDataFactory } from "display-standard_fontdata_factory";
|
||||||
|
import { DOMWasmFactory } from "display-wasm_factory";
|
||||||
|
import { MessageHandler, wrapReason } from "../shared/message_handler.js";
|
||||||
import {
|
import {
|
||||||
AbortException,
|
AbortException,
|
||||||
AnnotationMode,
|
AnnotationMode,
|
||||||
assert,
|
assert,
|
||||||
|
djb2Hash,
|
||||||
FeatureTest,
|
FeatureTest,
|
||||||
getVerbosityLevel,
|
getVerbosityLevel,
|
||||||
info,
|
info,
|
||||||
@ -37,7 +52,8 @@ import {
|
|||||||
PrintAnnotationStorage,
|
PrintAnnotationStorage,
|
||||||
SerializableEmpty,
|
SerializableEmpty,
|
||||||
} from "./annotation_storage.js";
|
} from "./annotation_storage.js";
|
||||||
import { FontFaceObject, FontLoader } from "./font_loader.js";
|
import { CanvasGraphics } from "./canvas.js";
|
||||||
|
import { DOMCanvasFactory } from "./canvas_factory.js";
|
||||||
import {
|
import {
|
||||||
isDataScheme,
|
isDataScheme,
|
||||||
isValidFetchUrl,
|
isValidFetchUrl,
|
||||||
@ -45,28 +61,13 @@ import {
|
|||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
StatTimer,
|
StatTimer,
|
||||||
} from "./display_utils.js";
|
} from "./display_utils.js";
|
||||||
import { MessageHandler, wrapReason } from "../shared/message_handler.js";
|
|
||||||
import {
|
|
||||||
NodeCanvasFactory,
|
|
||||||
NodeCMapReaderFactory,
|
|
||||||
NodeFilterFactory,
|
|
||||||
NodeStandardFontDataFactory,
|
|
||||||
NodeWasmFactory,
|
|
||||||
} from "display-node_utils";
|
|
||||||
import { CanvasGraphics } from "./canvas.js";
|
|
||||||
import { DOMCanvasFactory } from "./canvas_factory.js";
|
|
||||||
import { DOMCMapReaderFactory } from "display-cmap_reader_factory";
|
|
||||||
import { DOMFilterFactory } from "./filter_factory.js";
|
import { DOMFilterFactory } from "./filter_factory.js";
|
||||||
import { DOMStandardFontDataFactory } from "display-standard_fontdata_factory";
|
import { FontFaceObject, FontLoader } from "./font_loader.js";
|
||||||
import { DOMWasmFactory } from "display-wasm_factory";
|
|
||||||
import { GlobalWorkerOptions } from "./worker_options.js";
|
|
||||||
import { Metadata } from "./metadata.js";
|
import { Metadata } from "./metadata.js";
|
||||||
import { OptionalContentConfig } from "./optional_content_config.js";
|
import { OptionalContentConfig } from "./optional_content_config.js";
|
||||||
import { PDFDataTransportStream } from "./transport_stream.js";
|
|
||||||
import { PDFFetchStream } from "display-fetch_stream";
|
|
||||||
import { PDFNetworkStream } from "display-network";
|
|
||||||
import { PDFNodeStream } from "display-node_stream";
|
|
||||||
import { TextLayer } from "./text_layer.js";
|
import { TextLayer } from "./text_layer.js";
|
||||||
|
import { PDFDataTransportStream } from "./transport_stream.js";
|
||||||
|
import { GlobalWorkerOptions } from "./worker_options.js";
|
||||||
import { XfaText } from "./xfa_text.js";
|
import { XfaText } from "./xfa_text.js";
|
||||||
|
|
||||||
const DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
|
const DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
|
||||||
@ -1100,6 +1101,46 @@ class PDFDocumentProxy {
|
|||||||
return this._transport.downloadInfoCapability.promise;
|
return this._transport.downloadInfoCapability.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<PrimitiveModel>} A promise that is resolved to a view of
|
||||||
|
* a primitive inside the document.
|
||||||
|
*/
|
||||||
|
getPrimitiveByPath(path) {
|
||||||
|
return this._transport.getPrimitiveByPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<TreeViewModel[]>} A promise that is resolved to a tree
|
||||||
|
* view of a primitive inside the document.
|
||||||
|
*/
|
||||||
|
getPrimitiveTree(request) {
|
||||||
|
return this._transport.getPrimitiveTree(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<XRefTable>} A promise that is resolved to a view of
|
||||||
|
* the Cross-Reference Table.
|
||||||
|
*/
|
||||||
|
getXRefEntries() {
|
||||||
|
return this._transport.getXrefEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<string>} A promise that is resolved to a string
|
||||||
|
* representing the streams decoded contents.
|
||||||
|
*/
|
||||||
|
getStreamAsString(path) {
|
||||||
|
return this._transport.getStreamAsString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<ImageData>} A promise that is resolved to ImageData.
|
||||||
|
* Throws an Error if the path does not lead to an image!
|
||||||
|
*/
|
||||||
|
getImageDataByPath(path) {
|
||||||
|
return this._transport.getImageDataByPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up resources allocated by the document on both the main and worker
|
* Cleans up resources allocated by the document on both the main and worker
|
||||||
* threads.
|
* threads.
|
||||||
@ -1620,6 +1661,37 @@ class PDFPageProxy {
|
|||||||
return renderTask;
|
return renderTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateContents(newContents) {
|
||||||
|
if (!newContents) {
|
||||||
|
throw new Error("Contents may not be null or undefined");
|
||||||
|
}
|
||||||
|
this._intentStates.clear();
|
||||||
|
return this._transport.updateContents(newContents, this._pageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
getContents() {
|
||||||
|
const readableStream = this._transport.streamContents(this._pageIndex);
|
||||||
|
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
function pump() {
|
||||||
|
reader.read().then(function ({ value, done }) {
|
||||||
|
if (done) {
|
||||||
|
resolve(textContent.text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textContent.text += value;
|
||||||
|
pump();
|
||||||
|
}, reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = readableStream.getReader();
|
||||||
|
const textContent = {
|
||||||
|
text: "",
|
||||||
|
};
|
||||||
|
pump();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {GetOperatorListParameters} params - Page getOperatorList
|
* @param {GetOperatorListParameters} params - Page getOperatorList
|
||||||
* parameters.
|
* parameters.
|
||||||
@ -1631,6 +1703,7 @@ class PDFPageProxy {
|
|||||||
annotationMode = AnnotationMode.ENABLE,
|
annotationMode = AnnotationMode.ENABLE,
|
||||||
printAnnotationStorage = null,
|
printAnnotationStorage = null,
|
||||||
isEditing = false,
|
isEditing = false,
|
||||||
|
contentOverride = null,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("GENERIC")) {
|
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("GENERIC")) {
|
||||||
throw new Error("Not implemented: getOperatorList");
|
throw new Error("Not implemented: getOperatorList");
|
||||||
@ -1648,7 +1721,8 @@ class PDFPageProxy {
|
|||||||
annotationMode,
|
annotationMode,
|
||||||
printAnnotationStorage,
|
printAnnotationStorage,
|
||||||
isEditing,
|
isEditing,
|
||||||
/* isOpList = */ true
|
/* isOpList = */ true,
|
||||||
|
contentOverride
|
||||||
);
|
);
|
||||||
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
||||||
if (!intentState) {
|
if (!intentState) {
|
||||||
@ -1665,6 +1739,7 @@ class PDFPageProxy {
|
|||||||
intentState.operatorList = {
|
intentState.operatorList = {
|
||||||
fnArray: [],
|
fnArray: [],
|
||||||
argsArray: [],
|
argsArray: [],
|
||||||
|
rangeArray: [],
|
||||||
lastChunk: false,
|
lastChunk: false,
|
||||||
separateAnnots: null,
|
separateAnnots: null,
|
||||||
};
|
};
|
||||||
@ -1842,6 +1917,11 @@ class PDFPageProxy {
|
|||||||
for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
|
for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
|
||||||
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
|
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
|
||||||
intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
|
intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
|
||||||
|
if (intentState.operatorList.rangeArray) {
|
||||||
|
intentState.operatorList.rangeArray.push(
|
||||||
|
operatorListChunk.rangeArray[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
|
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
|
||||||
intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
|
intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
|
||||||
@ -1864,6 +1944,7 @@ class PDFPageProxy {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorageSerializable,
|
annotationStorageSerializable,
|
||||||
modifiedIds,
|
modifiedIds,
|
||||||
|
contentOverride,
|
||||||
}) {
|
}) {
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||||
assert(
|
assert(
|
||||||
@ -1881,6 +1962,7 @@ class PDFPageProxy {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorage: map,
|
annotationStorage: map,
|
||||||
modifiedIds,
|
modifiedIds,
|
||||||
|
contentOverride,
|
||||||
},
|
},
|
||||||
transfer
|
transfer
|
||||||
);
|
);
|
||||||
@ -2482,7 +2564,8 @@ class WorkerTransport {
|
|||||||
annotationMode = AnnotationMode.ENABLE,
|
annotationMode = AnnotationMode.ENABLE,
|
||||||
printAnnotationStorage = null,
|
printAnnotationStorage = null,
|
||||||
isEditing = false,
|
isEditing = false,
|
||||||
isOpList = false
|
isOpList = false,
|
||||||
|
contentOverride = null
|
||||||
) {
|
) {
|
||||||
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
||||||
let annotationStorageSerializable = SerializableEmpty;
|
let annotationStorageSerializable = SerializableEmpty;
|
||||||
@ -2540,11 +2623,16 @@ class WorkerTransport {
|
|||||||
modifiedIdsHash,
|
modifiedIdsHash,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (contentOverride) {
|
||||||
|
cacheKeyBuf.push(djb2Hash(contentOverride));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
renderingIntent,
|
renderingIntent,
|
||||||
cacheKey: cacheKeyBuf.join("_"),
|
cacheKey: cacheKeyBuf.join("_"),
|
||||||
annotationStorageSerializable,
|
annotationStorageSerializable,
|
||||||
modifiedIds,
|
modifiedIds,
|
||||||
|
contentOverride,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2908,6 +2996,43 @@ class WorkerTransport {
|
|||||||
return this.messageHandler.sendWithPromise("GetData", null);
|
return this.messageHandler.sendWithPromise("GetData", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPrimitiveByPath(path) {
|
||||||
|
return this.messageHandler.sendWithPromise("GetPrimitiveByPath", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrimitiveTree(request) {
|
||||||
|
return this.messageHandler.sendWithPromise("GetPrimTree", request);
|
||||||
|
}
|
||||||
|
|
||||||
|
getImageDataByPath(path) {
|
||||||
|
return this.messageHandler.sendWithPromise("GetImageData", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStreamAsString(path) {
|
||||||
|
return this.messageHandler.sendWithPromise("GetStreamAsString", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
getXrefEntries() {
|
||||||
|
return this.messageHandler.sendWithPromise("GetXRefEntries", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamContents(pageIndex) {
|
||||||
|
return this.messageHandler.sendWithStream("StreamContents", {
|
||||||
|
pageIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<void>} A promise that is resolved once the contents
|
||||||
|
* are updated.
|
||||||
|
*/
|
||||||
|
updateContents(newContents, pageIndex) {
|
||||||
|
return this.messageHandler.sendWithPromise("UpdateContents", {
|
||||||
|
value: newContents,
|
||||||
|
pageIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
saveDocument() {
|
saveDocument() {
|
||||||
if (this.annotationStorage.size <= 0) {
|
if (this.annotationStorage.size <= 0) {
|
||||||
warn(
|
warn(
|
||||||
@ -3478,6 +3603,9 @@ class InternalRenderTask {
|
|||||||
|
|
||||||
this.callback();
|
this.callback();
|
||||||
}
|
}
|
||||||
|
if (this.stepper) {
|
||||||
|
this.stepper.finished = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -628,12 +628,6 @@ class DrawingEditor extends AnnotationEditor {
|
|||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
let baseX, baseY;
|
|
||||||
if (this._isCopy) {
|
|
||||||
baseX = this.x;
|
|
||||||
baseY = this.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
const div = super.render();
|
const div = super.render();
|
||||||
div.classList.add("draw");
|
div.classList.add("draw");
|
||||||
|
|
||||||
@ -646,10 +640,6 @@ class DrawingEditor extends AnnotationEditor {
|
|||||||
this._uiManager.addShouldRescale(this);
|
this._uiManager.addShouldRescale(this);
|
||||||
this.disableEditing();
|
this.disableEditing();
|
||||||
|
|
||||||
if (this._isCopy) {
|
|
||||||
this._moveAfterPaste(baseX, baseY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,8 +85,6 @@ class AnnotationEditor {
|
|||||||
|
|
||||||
#touchManager = null;
|
#touchManager = null;
|
||||||
|
|
||||||
_isCopy = false;
|
|
||||||
|
|
||||||
_editToolbar = null;
|
_editToolbar = null;
|
||||||
|
|
||||||
_initialOptions = Object.create(null);
|
_initialOptions = Object.create(null);
|
||||||
@ -444,17 +442,6 @@ class AnnotationEditor {
|
|||||||
this.fixAndSetPosition();
|
this.fixAndSetPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
_moveAfterPaste(baseX, baseY) {
|
|
||||||
const [parentWidth, parentHeight] = this.parentDimensions;
|
|
||||||
this.setAt(
|
|
||||||
baseX * parentWidth,
|
|
||||||
baseY * parentHeight,
|
|
||||||
this.width * parentWidth,
|
|
||||||
this.height * parentHeight
|
|
||||||
);
|
|
||||||
this._onTranslated();
|
|
||||||
}
|
|
||||||
|
|
||||||
#translate([width, height], x, y) {
|
#translate([width, height], x, y) {
|
||||||
[x, y] = this.screenToPageTranslation(x, y);
|
[x, y] = this.screenToPageTranslation(x, y);
|
||||||
|
|
||||||
@ -1610,7 +1597,6 @@ class AnnotationEditor {
|
|||||||
});
|
});
|
||||||
editor.rotation = data.rotation;
|
editor.rotation = data.rotation;
|
||||||
editor.#accessibilityData = data.accessibilityData;
|
editor.#accessibilityData = data.accessibilityData;
|
||||||
editor._isCopy = data.isCopy || false;
|
|
||||||
|
|
||||||
const [pageWidth, pageHeight] = editor.pageDimensions;
|
const [pageWidth, pageHeight] = editor.pageDimensions;
|
||||||
const [x, y, width, height] = editor.getRectInCurrentCoords(
|
const [x, y, width, height] = editor.getRectInCurrentCoords(
|
||||||
|
|||||||
@ -553,7 +553,7 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let baseX, baseY;
|
let baseX, baseY;
|
||||||
if (this._isCopy || this.annotationElementId) {
|
if (this.width) {
|
||||||
baseX = this.x;
|
baseX = this.x;
|
||||||
baseY = this.y;
|
baseY = this.y;
|
||||||
}
|
}
|
||||||
@ -581,7 +581,7 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
bindEvents(this, this.div, ["dblclick", "keydown"]);
|
bindEvents(this, this.div, ["dblclick", "keydown"]);
|
||||||
|
|
||||||
if (this._isCopy || this.annotationElementId) {
|
if (this.width) {
|
||||||
// This editor was created in using copy (ctrl+c).
|
// This editor was created in using copy (ctrl+c).
|
||||||
const [parentWidth, parentHeight] = this.parentDimensions;
|
const [parentWidth, parentHeight] = this.parentDimensions;
|
||||||
if (this.annotationElementId) {
|
if (this.annotationElementId) {
|
||||||
@ -627,7 +627,12 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
|
this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
|
||||||
} else {
|
} else {
|
||||||
this._moveAfterPaste(baseX, baseY);
|
this.setAt(
|
||||||
|
baseX * parentWidth,
|
||||||
|
baseY * parentHeight,
|
||||||
|
this.width * parentWidth,
|
||||||
|
this.height * parentHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#setContent();
|
this.#setContent();
|
||||||
@ -842,7 +847,6 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
if (isForCopying) {
|
if (isForCopying) {
|
||||||
// Don't add the id when copying because the pasted editor mustn't be
|
// Don't add the id when copying because the pasted editor mustn't be
|
||||||
// linked to an existing annotation.
|
// linked to an existing annotation.
|
||||||
serialized.isCopy = true;
|
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -246,7 +246,6 @@ class InkEditor extends DrawingEditor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isForCopying) {
|
if (isForCopying) {
|
||||||
serialized.isCopy = true;
|
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -111,22 +111,6 @@ class SignatureEditor extends DrawingEditor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
get telemetryFinalData() {
|
|
||||||
return {
|
|
||||||
type: "signature",
|
|
||||||
hasDescription: !!this.#description,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static computeTelemetryFinalData(data) {
|
|
||||||
const hasDescriptionStats = data.get("hasDescription");
|
|
||||||
return {
|
|
||||||
hasAltText: hasDescriptionStats.get(true) ?? 0,
|
|
||||||
hasNoAltText: hasDescriptionStats.get(false) ?? 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
get isResizable() {
|
get isResizable() {
|
||||||
return true;
|
return true;
|
||||||
@ -146,15 +130,6 @@ class SignatureEditor extends DrawingEditor {
|
|||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
let baseX, baseY;
|
|
||||||
const { _isCopy } = this;
|
|
||||||
if (_isCopy) {
|
|
||||||
// No need to adjust the position when rendering in DrawingEditor.
|
|
||||||
this._isCopy = false;
|
|
||||||
baseX = this.x;
|
|
||||||
baseY = this.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.render();
|
super.render();
|
||||||
this.div.setAttribute("role", "figure");
|
this.div.setAttribute("role", "figure");
|
||||||
|
|
||||||
@ -188,11 +163,6 @@ class SignatureEditor extends DrawingEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isCopy) {
|
|
||||||
this._isCopy = true;
|
|
||||||
this._moveAfterPaste(baseX, baseY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,14 +265,6 @@ class SignatureEditor extends DrawingEditor {
|
|||||||
this._uiManager.addToAnnotationStorage(this);
|
this._uiManager.addToAnnotationStorage(this);
|
||||||
this.setUuid(uuid);
|
this.setUuid(uuid);
|
||||||
|
|
||||||
this._reportTelemetry({
|
|
||||||
action: "pdfjs.signature.inserted",
|
|
||||||
data: {
|
|
||||||
hasBeenSaved: !!uuid,
|
|
||||||
hasDescription: !!description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.div.hidden = false;
|
this.div.hidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +348,6 @@ class SignatureEditor extends DrawingEditor {
|
|||||||
if (isForCopying) {
|
if (isForCopying) {
|
||||||
serialized.paths = { lines, points };
|
serialized.paths = { lines, points };
|
||||||
serialized.uuid = this.#signatureUUID;
|
serialized.uuid = this.#signatureUUID;
|
||||||
serialized.isCopy = true;
|
|
||||||
} else {
|
} else {
|
||||||
serialized.lines = lines;
|
serialized.lines = lines;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -346,7 +346,7 @@ class StampEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let baseX, baseY;
|
let baseX, baseY;
|
||||||
if (this._isCopy) {
|
if (this.width) {
|
||||||
baseX = this.x;
|
baseX = this.x;
|
||||||
baseY = this.y;
|
baseY = this.y;
|
||||||
}
|
}
|
||||||
@ -365,8 +365,15 @@ class StampEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._isCopy) {
|
if (this.width && !this.annotationElementId) {
|
||||||
this._moveAfterPaste(baseX, baseY);
|
// This editor was created in using copy (ctrl+c).
|
||||||
|
const [parentWidth, parentHeight] = this.parentDimensions;
|
||||||
|
this.setAt(
|
||||||
|
baseX * parentWidth,
|
||||||
|
baseY * parentHeight,
|
||||||
|
this.width * parentWidth,
|
||||||
|
this.height * parentHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._uiManager.addShouldRescale(this);
|
this._uiManager.addShouldRescale(this);
|
||||||
@ -847,7 +854,6 @@ class StampEditor extends AnnotationEditor {
|
|||||||
// hence we serialize the bitmap to a data url.
|
// hence we serialize the bitmap to a data url.
|
||||||
serialized.bitmapUrl = this.#serializeBitmap(/* toUrl = */ true);
|
serialized.bitmapUrl = this.#serializeBitmap(/* toUrl = */ true);
|
||||||
serialized.accessibilityData = this.serializeAltText(true);
|
serialized.accessibilityData = this.serializeAltText(true);
|
||||||
serialized.isCopy = true;
|
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -80,16 +80,12 @@ class FontLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSystemFont({
|
async loadSystemFont({ systemFontInfo: info, _inspectFont }) {
|
||||||
systemFontInfo: info,
|
|
||||||
disableFontFace,
|
|
||||||
_inspectFont,
|
|
||||||
}) {
|
|
||||||
if (!info || this.#systemFonts.has(info.loadedName)) {
|
if (!info || this.#systemFonts.has(info.loadedName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(
|
assert(
|
||||||
!disableFontFace,
|
!this.disableFontFace,
|
||||||
"loadSystemFont shouldn't be called when `disableFontFace` is set."
|
"loadSystemFont shouldn't be called when `disableFontFace` is set."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -578,6 +578,16 @@ function objectFromMap(map) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fast and easy hash
|
||||||
|
function djb2Hash(str) {
|
||||||
|
let hash = 5381;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = (hash << 5) + hash + str.charCodeAt(i);
|
||||||
|
hash &= hash; // Convert to 32-bit integer
|
||||||
|
}
|
||||||
|
return hash >>> 0; // Convert to unsigned
|
||||||
|
}
|
||||||
|
|
||||||
// Checks the endianness of the platform.
|
// Checks the endianness of the platform.
|
||||||
function isLittleEndian() {
|
function isLittleEndian() {
|
||||||
const buffer8 = new Uint8Array(4);
|
const buffer8 = new Uint8Array(4);
|
||||||
@ -1136,6 +1146,7 @@ export {
|
|||||||
BASELINE_FACTOR,
|
BASELINE_FACTOR,
|
||||||
bytesToString,
|
bytesToString,
|
||||||
createValidAbsoluteUrl,
|
createValidAbsoluteUrl,
|
||||||
|
djb2Hash,
|
||||||
DocumentActionEventType,
|
DocumentActionEventType,
|
||||||
FeatureTest,
|
FeatureTest,
|
||||||
FONT_IDENTITY_MATRIX,
|
FONT_IDENTITY_MATRIX,
|
||||||
|
|||||||
@ -348,7 +348,13 @@ describe("Signature Editor", () => {
|
|||||||
|
|
||||||
const editorSelector = getEditorSelector(0);
|
const editorSelector = getEditorSelector(0);
|
||||||
await page.waitForSelector(editorSelector, { visible: true });
|
await page.waitForSelector(editorSelector, { visible: true });
|
||||||
const originalRect = await getRect(page, editorSelector);
|
await page.waitForSelector(
|
||||||
|
`.canvasWrapper > svg use[href="#path_p1_0"]`,
|
||||||
|
{ visible: true }
|
||||||
|
);
|
||||||
|
const originalPath = await page.$eval("#path_p1_0", el =>
|
||||||
|
el.getAttribute("d")
|
||||||
|
);
|
||||||
const originalDescription = await page.$eval(
|
const originalDescription = await page.$eval(
|
||||||
`${editorSelector} .altText.editDescription`,
|
`${editorSelector} .altText.editDescription`,
|
||||||
el => el.title
|
el => el.title
|
||||||
@ -359,15 +365,21 @@ describe("Signature Editor", () => {
|
|||||||
|
|
||||||
const pastedEditorSelector = getEditorSelector(1);
|
const pastedEditorSelector = getEditorSelector(1);
|
||||||
await page.waitForSelector(pastedEditorSelector, { visible: true });
|
await page.waitForSelector(pastedEditorSelector, { visible: true });
|
||||||
const pastedRect = await getRect(page, pastedEditorSelector);
|
await page.waitForSelector(
|
||||||
|
`.canvasWrapper > svg use[href="#path_p1_1"]`,
|
||||||
|
{ visible: true }
|
||||||
|
);
|
||||||
|
const pastedPath = await page.$eval("#path_p1_1", el =>
|
||||||
|
el.getAttribute("d")
|
||||||
|
);
|
||||||
const pastedDescription = await page.$eval(
|
const pastedDescription = await page.$eval(
|
||||||
`${pastedEditorSelector} .altText.editDescription`,
|
`${pastedEditorSelector} .altText.editDescription`,
|
||||||
el => el.title
|
el => el.title
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(pastedRect)
|
expect(pastedPath)
|
||||||
.withContext(`In ${browserName}`)
|
.withContext(`In ${browserName}`)
|
||||||
.not.toEqual(originalRect);
|
.toEqual(originalPath);
|
||||||
expect(pastedDescription)
|
expect(pastedDescription)
|
||||||
.withContext(`In ${browserName}`)
|
.withContext(`In ${browserName}`)
|
||||||
.toEqual(originalDescription);
|
.toEqual(originalDescription);
|
||||||
|
|||||||
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -106,7 +106,6 @@
|
|||||||
!issue9084.pdf
|
!issue9084.pdf
|
||||||
!issue12963.pdf
|
!issue12963.pdf
|
||||||
!issue9105_reduced.pdf
|
!issue9105_reduced.pdf
|
||||||
!issue19484_2.pdf
|
|
||||||
!issue9105_other.pdf
|
!issue9105_other.pdf
|
||||||
!issue9252.pdf
|
!issue9252.pdf
|
||||||
!issue9262_reduced.pdf
|
!issue9262_reduced.pdf
|
||||||
@ -482,7 +481,6 @@
|
|||||||
!openoffice.pdf
|
!openoffice.pdf
|
||||||
!js-buttons.pdf
|
!js-buttons.pdf
|
||||||
!issue7014.pdf
|
!issue7014.pdf
|
||||||
!issue19484_1.pdf
|
|
||||||
!issue8187.pdf
|
!issue8187.pdf
|
||||||
!annotation-link-text-popup.pdf
|
!annotation-link-text-popup.pdf
|
||||||
!issue9278.pdf
|
!issue9278.pdf
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -3629,14 +3629,6 @@
|
|||||||
"link": false,
|
"link": false,
|
||||||
"type": "text"
|
"type": "text"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "issue19484_1",
|
|
||||||
"file": "pdfs/issue19484_1.pdf",
|
|
||||||
"md5": "4e9e78a84226dbdddbd735388ccc2dcd",
|
|
||||||
"rounds": 1,
|
|
||||||
"link": false,
|
|
||||||
"type": "eq"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "issue5644",
|
"id": "issue5644",
|
||||||
"file": "pdfs/issue5644.pdf",
|
"file": "pdfs/issue5644.pdf",
|
||||||
@ -5051,14 +5043,6 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "issue19484_2",
|
|
||||||
"file": "pdfs/issue19484_2.pdf",
|
|
||||||
"md5": "cd3050eda9fa18a7e6a78c702f9890bb",
|
|
||||||
"rounds": 1,
|
|
||||||
"link": false,
|
|
||||||
"type": "eq"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "bug894572",
|
"id": "bug894572",
|
||||||
"file": "pdfs/bug894572.pdf",
|
"file": "pdfs/bug894572.pdf",
|
||||||
|
|||||||
@ -537,11 +537,7 @@ class SignatureStorage {
|
|||||||
|
|
||||||
async isFull() {
|
async isFull() {
|
||||||
// We want to store at most 5 signatures.
|
// We want to store at most 5 signatures.
|
||||||
return (await this.size()) === 5;
|
return (await this.getAll()).size === 5;
|
||||||
}
|
|
||||||
|
|
||||||
async size() {
|
|
||||||
return (await this.getAll()).size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data) {
|
async create(data) {
|
||||||
|
|||||||
@ -70,11 +70,7 @@ class SignatureStorage {
|
|||||||
|
|
||||||
async isFull() {
|
async isFull() {
|
||||||
// Only allow 5 signatures to be saved.
|
// Only allow 5 signatures to be saved.
|
||||||
return (await this.size()) === 5;
|
return (await this.getAll()).size === 5;
|
||||||
}
|
|
||||||
|
|
||||||
async size() {
|
|
||||||
return (await this.getAll()).size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data) {
|
async create(data) {
|
||||||
|
|||||||
@ -176,12 +176,6 @@ class SignatureManager {
|
|||||||
clearButton.addEventListener(
|
clearButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
() => {
|
||||||
this.#reportTelemetry({
|
|
||||||
action: "pdfjs.signature.clear",
|
|
||||||
data: {
|
|
||||||
type: this.#currentTab,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.#initTab(null);
|
this.#initTab(null);
|
||||||
},
|
},
|
||||||
{ passive: true }
|
{ passive: true }
|
||||||
@ -259,9 +253,7 @@ class SignatureManager {
|
|||||||
#resetCommon() {
|
#resetCommon() {
|
||||||
this.#hasDescriptionChanged = false;
|
this.#hasDescriptionChanged = false;
|
||||||
this.#description.value = "";
|
this.#description.value = "";
|
||||||
if (this.#currentTab) {
|
this.#tabsToAltText.set(this.#currentTab, "");
|
||||||
this.#tabsToAltText.get(this.#currentTab).value = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#resetTab(name) {
|
#resetTab(name) {
|
||||||
@ -291,7 +283,7 @@ class SignatureManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.#currentTab) {
|
if (this.#currentTab) {
|
||||||
this.#tabsToAltText.get(this.#currentTab).value = this.#description.value;
|
this.#tabsToAltText.set(this.#currentTab, this.#description.value);
|
||||||
}
|
}
|
||||||
if (name) {
|
if (name) {
|
||||||
this.#currentTab = name;
|
this.#currentTab = name;
|
||||||
@ -302,7 +294,7 @@ class SignatureManager {
|
|||||||
if (reset) {
|
if (reset) {
|
||||||
this.#resetCommon();
|
this.#resetCommon();
|
||||||
} else {
|
} else {
|
||||||
this.#description.value = this.#tabsToAltText.get(this.#currentTab).value;
|
this.#description.value = this.#tabsToAltText.get(this.#currentTab);
|
||||||
}
|
}
|
||||||
this.#clearDescription.disabled = this.#description.value === "";
|
this.#clearDescription.disabled = this.#description.value === "";
|
||||||
this.#currentTabAC?.abort();
|
this.#currentTabAC?.abort();
|
||||||
@ -343,8 +335,7 @@ class SignatureManager {
|
|||||||
() => {
|
() => {
|
||||||
const { value } = this.#typeInput;
|
const { value } = this.#typeInput;
|
||||||
if (!this.#hasDescriptionChanged) {
|
if (!this.#hasDescriptionChanged) {
|
||||||
this.#tabsToAltText.get("type").default = this.#description.value =
|
this.#description.value = value;
|
||||||
value;
|
|
||||||
this.#clearDescription.disabled = value === "";
|
this.#clearDescription.disabled = value === "";
|
||||||
}
|
}
|
||||||
this.#disableButtons(value);
|
this.#disableButtons(value);
|
||||||
@ -407,7 +398,6 @@ class SignatureManager {
|
|||||||
this.#l10n
|
this.#l10n
|
||||||
.get(SignatureManager.#l10nDescription.signature)
|
.get(SignatureManager.#l10nDescription.signature)
|
||||||
.then(description => {
|
.then(description => {
|
||||||
this.#tabsToAltText.get("draw").default = description;
|
|
||||||
this.#description.value ||= description;
|
this.#description.value ||= description;
|
||||||
this.#clearDescription.disabled = this.#description.value === "";
|
this.#clearDescription.disabled = this.#description.value === "";
|
||||||
});
|
});
|
||||||
@ -619,7 +609,6 @@ class SignatureManager {
|
|||||||
this.#imageSVG.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
this.#imageSVG.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
||||||
this.#imageSVG.append(path);
|
this.#imageSVG.append(path);
|
||||||
path.setAttribute("d", outline.toSVGPath());
|
path.setAttribute("d", outline.toSVGPath());
|
||||||
this.#tabsToAltText.get("image").default = file.name;
|
|
||||||
if (this.#description.value === "") {
|
if (this.#description.value === "") {
|
||||||
this.#description.value = file.name || "";
|
this.#description.value = file.name || "";
|
||||||
this.#clearDescription.disabled = this.#description.value === "";
|
this.#clearDescription.disabled = this.#description.value === "";
|
||||||
@ -644,16 +633,6 @@ class SignatureManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#reportTelemetry(data) {
|
|
||||||
this.#eventBus.dispatch("reporttelemetry", {
|
|
||||||
source: this,
|
|
||||||
details: {
|
|
||||||
type: "editing",
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#addToolbarButton(signatureData, uuid, description) {
|
#addToolbarButton(signatureData, uuid, description) {
|
||||||
const { curves, areContours, thickness, width, height } = signatureData;
|
const { curves, areContours, thickness, width, height } = signatureData;
|
||||||
const maxDim = Math.max(width, height);
|
const maxDim = Math.max(width, height);
|
||||||
@ -737,12 +716,6 @@ class SignatureManager {
|
|||||||
deleteButton.addEventListener("click", async () => {
|
deleteButton.addEventListener("click", async () => {
|
||||||
if (await this.#signatureStorage.delete(uuid)) {
|
if (await this.#signatureStorage.delete(uuid)) {
|
||||||
div.remove();
|
div.remove();
|
||||||
this.#reportTelemetry({
|
|
||||||
action: "pdfjs.signature.delete_saved",
|
|
||||||
data: {
|
|
||||||
savedCount: await this.#signatureStorage.size(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const deleteSpan = document.createElement("span");
|
const deleteSpan = document.createElement("span");
|
||||||
@ -832,7 +805,7 @@ class SignatureManager {
|
|||||||
|
|
||||||
async open({ uiManager, editor }) {
|
async open({ uiManager, editor }) {
|
||||||
this.#tabsToAltText ||= new Map(
|
this.#tabsToAltText ||= new Map(
|
||||||
this.#tabButtons.keys().map(name => [name, { value: "", default: "" }])
|
this.#tabButtons.keys().map(name => [name, ""])
|
||||||
);
|
);
|
||||||
this.#uiManager = uiManager;
|
this.#uiManager = uiManager;
|
||||||
this.#currentEditor = editor;
|
this.#currentEditor = editor;
|
||||||
@ -878,8 +851,7 @@ class SignatureManager {
|
|||||||
|
|
||||||
async #add() {
|
async #add() {
|
||||||
let data;
|
let data;
|
||||||
const type = this.#currentTab;
|
switch (this.#currentTab) {
|
||||||
switch (type) {
|
|
||||||
case "type":
|
case "type":
|
||||||
data = this.#getOutlineForType();
|
data = this.#getOutlineForType();
|
||||||
break;
|
break;
|
||||||
@ -891,8 +863,8 @@ class SignatureManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let uuid = null;
|
let uuid = null;
|
||||||
const description = this.#description.value;
|
|
||||||
if (this.#saveCheckbox.checked) {
|
if (this.#saveCheckbox.checked) {
|
||||||
|
const description = this.#description.value;
|
||||||
const { newCurves, areContours, thickness, width, height } = data;
|
const { newCurves, areContours, thickness, width, height } = data;
|
||||||
const signatureData = await SignatureExtractor.compressSignature({
|
const signatureData = await SignatureExtractor.compressSignature({
|
||||||
outlines: newCurves,
|
outlines: newCurves,
|
||||||
@ -921,18 +893,6 @@ class SignatureManager {
|
|||||||
console.warn("SignatureManager.add: cannot save the signature.");
|
console.warn("SignatureManager.add: cannot save the signature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const altText = this.#tabsToAltText.get(type);
|
|
||||||
this.#reportTelemetry({
|
|
||||||
action: "pdfjs.signature.created",
|
|
||||||
data: {
|
|
||||||
type,
|
|
||||||
saved: !!uuid,
|
|
||||||
savedCount: await this.#signatureStorage.size(),
|
|
||||||
descriptionChanged: description !== altText.default,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#currentEditor.addSignature(
|
this.#currentEditor.addSignature(
|
||||||
data,
|
data,
|
||||||
DEFAULT_HEIGHT_IN_PAGE,
|
DEFAULT_HEIGHT_IN_PAGE,
|
||||||
@ -980,7 +940,7 @@ class EditDescriptionDialog {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cancelButton.addEventListener("click", this.#cancel.bind(this));
|
cancelButton.addEventListener("click", this.#finish.bind(this));
|
||||||
updateButton.addEventListener("click", this.#update.bind(this));
|
updateButton.addEventListener("click", this.#update.bind(this));
|
||||||
|
|
||||||
const clearDescription = description.lastElementChild;
|
const clearDescription = description.lastElementChild;
|
||||||
@ -1023,24 +983,12 @@ class EditDescriptionDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #update() {
|
async #update() {
|
||||||
// The description has been changed because the button isn't disabled.
|
const description = this.#description.value;
|
||||||
this.#currentEditor._reportTelemetry({
|
if (this.#previousDescription === description) {
|
||||||
action: "pdfjs.signature.edit_description",
|
this.#finish();
|
||||||
data: {
|
return;
|
||||||
hasBeenChanged: true,
|
}
|
||||||
},
|
this.#currentEditor.description = description;
|
||||||
});
|
|
||||||
this.#currentEditor.description = this.#description.value;
|
|
||||||
this.#finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
#cancel() {
|
|
||||||
this.#currentEditor._reportTelemetry({
|
|
||||||
action: "pdfjs.signature.edit_description",
|
|
||||||
data: {
|
|
||||||
hasBeenChanged: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.#finish();
|
this.#finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user