Compare commits

..

No commits in common. "06f44916c8936b92f464d337fe3a0a6b2b78d5b4" and "91bfe12f3865ff05b345903894227bf9bfd1001e" have entirely different histories.

7 changed files with 94 additions and 59 deletions

View File

@ -1062,15 +1062,13 @@ class Catalog {
if (obj instanceof Dict && obj.has("XFAImages")) { if (obj instanceof Dict && obj.has("XFAImages")) {
const nameTree = new NameTree(obj.getRaw("XFAImages"), this.xref); const nameTree = new NameTree(obj.getRaw("XFAImages"), this.xref);
for (const [key, value] of nameTree.getAll()) { for (const [key, value] of nameTree.getAll()) {
if (value instanceof BaseStream) { xfaImages ??= new Dict(this.xref);
xfaImages ??= new Map();
xfaImages.set( xfaImages.set(
stringToPDFString(key, /* keepEscapeSequence = */ true), stringToPDFString(key, /* keepEscapeSequence = */ true),
value.getBytes() value
); );
} }
} }
}
return shadow(this, "xfaImages", xfaImages); return shadow(this, "xfaImages", xfaImages);
} }

View File

@ -1237,15 +1237,28 @@ class PDFDocument {
return this.xfaFactory ? this.xfaFactory.getPages() : null; return this.xfaFactory ? this.xfaFactory.getPages() : null;
} }
async #loadXfaImages() { async loadXfaImages() {
const xfaImages = await this.pdfManager.ensureCatalog("xfaImages"); const xfaImagesDict = await this.pdfManager.ensureCatalog("xfaImages");
if (!xfaImages) { if (!xfaImagesDict) {
return; return;
} }
const keys = xfaImagesDict.getKeys();
const objectLoader = new ObjectLoader(xfaImagesDict, keys, this.xref);
await objectLoader.load();
const xfaImages = new Map();
for (const key of keys) {
const stream = xfaImagesDict.get(key);
if (stream instanceof BaseStream) {
xfaImages.set(key, stream.getBytes());
}
}
this.xfaFactory.setImages(xfaImages); this.xfaFactory.setImages(xfaImages);
} }
async #loadXfaFonts(handler, task) { async loadXfaFonts(handler, task) {
const acroForm = await this.pdfManager.ensureCatalog("acroForm"); const acroForm = await this.pdfManager.ensureCatalog("acroForm");
if (!acroForm) { if (!acroForm) {
return; return;
@ -1264,19 +1277,18 @@ class PDFDocument {
const options = Object.assign( const options = Object.assign(
Object.create(null), Object.create(null),
this.pdfManager.evaluatorOptions, this.pdfManager.evaluatorOptions
{ useSystemFonts: false }
); );
const { builtInCMapCache, fontCache, standardFontDataCache } = this.catalog; options.useSystemFonts = false;
const partialEvaluator = new PartialEvaluator({ const partialEvaluator = new PartialEvaluator({
xref: this.xref, xref: this.xref,
handler, handler,
pageIndex: -1, pageIndex: -1,
idFactory: this._globalIdFactory, idFactory: this._globalIdFactory,
fontCache, fontCache: this.catalog.fontCache,
builtInCMapCache, builtInCMapCache: this.catalog.builtInCMapCache,
standardFontDataCache, standardFontDataCache: this.catalog.standardFontDataCache,
options, options,
}); });
const operatorList = new OperatorList(); const operatorList = new OperatorList();
@ -1293,23 +1305,6 @@ class PDFDocument {
}, },
}; };
const parseFont = (fontName, fallbackFontDict, cssFontInfo) =>
partialEvaluator
.handleSetFont(
resources,
[Name.get(fontName), 1],
/* fontRef = */ null,
operatorList,
task,
initialState,
fallbackFontDict,
cssFontInfo
)
.catch(reason => {
warn(`loadXfaFonts: "${reason}".`);
return null;
});
const promises = []; const promises = [];
for (const [fontName, font] of fontRes) { for (const [fontName, font] of fontRes) {
const descriptor = font.get("FontDescriptor"); const descriptor = font.get("FontDescriptor");
@ -1331,7 +1326,21 @@ class PDFDocument {
continue; continue;
} }
promises.push( promises.push(
parseFont(fontName, /* fallbackFontDict = */ null, cssFontInfo) partialEvaluator
.handleSetFont(
resources,
[Name.get(fontName), 1],
/* fontRef = */ null,
operatorList,
task,
initialState,
/* fallbackFontDict = */ null,
/* cssFontInfo = */ cssFontInfo
)
.catch(function (reason) {
warn(`loadXfaFonts: "${reason}".`);
return null;
})
); );
} }
@ -1369,12 +1378,27 @@ class PDFDocument {
{ name: "BoldItalic", fontWeight: 700, italicAngle: 12 }, { name: "BoldItalic", fontWeight: 700, italicAngle: 12 },
]) { ]) {
const name = `${missing}-${fontInfo.name}`; const name = `${missing}-${fontInfo.name}`;
const dict = getXfaFontDict(name);
promises.push( promises.push(
parseFont(name, getXfaFontDict(name), { partialEvaluator
.handleSetFont(
resources,
[Name.get(name), 1],
/* fontRef = */ null,
operatorList,
task,
initialState,
/* fallbackFontDict = */ dict,
/* cssFontInfo = */ {
fontFamily: missing, fontFamily: missing,
fontWeight: fontInfo.fontWeight, fontWeight: fontInfo.fontWeight,
italicAngle: fontInfo.italicAngle, italicAngle: fontInfo.italicAngle,
}
)
.catch(function (reason) {
warn(`loadXfaFonts: "${reason}".`);
return null;
}) })
); );
} }
@ -1384,16 +1408,7 @@ class PDFDocument {
this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts); this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts);
} }
loadXfaResources(handler, task) { async serializeXfaData(annotationStorage) {
return Promise.all([
this.#loadXfaFonts(handler, task).catch(() => {
// Ignore errors, to allow the document to load.
}),
this.#loadXfaImages(),
]);
}
serializeXfaData(annotationStorage) {
return this.xfaFactory return this.xfaFactory
? this.xfaFactory.serializeData(annotationStorage) ? this.xfaFactory.serializeData(annotationStorage)
: null; : null;

View File

@ -95,6 +95,10 @@ class BasePdfManager {
return this._docBaseUrl; return this._docBaseUrl;
} }
get catalog() {
return this.pdfDocument.catalog;
}
ensureDoc(prop, args) { ensureDoc(prop, args) {
return this.ensure(this.pdfDocument, prop, args); return this.ensure(this.pdfDocument, prop, args);
} }
@ -115,6 +119,18 @@ class BasePdfManager {
return this.pdfDocument.fontFallback(id, handler); return this.pdfDocument.fontFallback(id, handler);
} }
loadXfaFonts(handler, task) {
return this.pdfDocument.loadXfaFonts(handler, task);
}
loadXfaImages() {
return this.pdfDocument.loadXfaImages();
}
serializeXfaData(annotationStorage) {
return this.pdfDocument.serializeXfaData(annotationStorage);
}
cleanup(manuallyTriggered = false) { cleanup(manuallyTriggered = false) {
return this.pdfDocument.cleanup(manuallyTriggered); return this.pdfDocument.cleanup(manuallyTriggered);
} }

View File

@ -118,7 +118,7 @@ class StructTreeRoot {
pdfManager, pdfManager,
changes, changes,
}) { }) {
const root = await pdfManager.ensureCatalog("cloneDict"); const root = pdfManager.catalog.cloneDict();
const cache = new RefSetCache(); const cache = new RefSetCache();
cache.put(catalogRef, root); cache.put(catalogRef, root);

View File

@ -170,11 +170,18 @@ class WorkerMessageHandler {
const isPureXfa = await pdfManager.ensureDoc("isPureXfa"); const isPureXfa = await pdfManager.ensureDoc("isPureXfa");
if (isPureXfa) { if (isPureXfa) {
const task = new WorkerTask("loadXfaResources"); const task = new WorkerTask("loadXfaFonts");
startWorkerTask(task); startWorkerTask(task);
await pdfManager.ensureDoc("loadXfaResources", [handler, task]); await Promise.all([
finishWorkerTask(task); pdfManager
.loadXfaFonts(handler, task)
.catch(reason => {
// Ignore errors, to allow the document to load.
})
.then(() => finishWorkerTask(task)),
pdfManager.loadXfaImages(),
]);
} }
const [numPages, fingerprints] = await Promise.all([ const [numPages, fingerprints] = await Promise.all([
@ -610,9 +617,7 @@ class WorkerMessageHandler {
} }
if (isPureXfa) { if (isPureXfa) {
promises.push( promises.push(pdfManager.serializeXfaData(annotationStorage));
pdfManager.ensureDoc("serializeXfaData", [annotationStorage])
);
} else { } else {
for (let pageIndex = 0; pageIndex < numPages; pageIndex++) { for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
promises.push( promises.push(

View File

@ -43,7 +43,7 @@ class XFAFactory {
} }
isValid() { isValid() {
return !!(this.root && this.form); return this.root && this.form;
} }
/** /**

View File

@ -3412,7 +3412,8 @@ class Image extends StringObject {
return HTMLResult.EMPTY; return HTMLResult.EMPTY;
} }
let buffer = this[$globalData].images?.get(this.href); let buffer =
this[$globalData].images && this[$globalData].images.get(this.href);
if (!buffer && (this.href || !this[$content])) { if (!buffer && (this.href || !this[$content])) {
// In general, we don't get remote data and use what we have // In general, we don't get remote data and use what we have
// in the pdf itself, so no picture for non null href. // in the pdf itself, so no picture for non null href.