Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 38 additions & 56 deletions examples/node/getinfo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,62 +15,44 @@ const pdfPath =
// Will be using promises to load document, pages and misc data instead of
// callback.
const loadingTask = getDocument({ url: pdfPath });
loadingTask.promise
.then(function (doc) {
const numPages = doc.numPages;
console.log("# Document Loaded");
console.log("Number of Pages: " + numPages);
try {
const pdfDoc = await loadingTask.promise;

const { numPages } = pdfDoc;
console.log("# Document Loaded");
console.log(`Number of Pages: ${numPages}`);
console.log();

const { info, metadata } = await pdfDoc.getMetadata();
console.log("# Metadata is Loaded");
console.log("## Info");
console.log(JSON.stringify(info, null, 2));
console.log();
if (metadata) {
console.log("## Metadata");
console.log(JSON.stringify(Object.fromEntries(metadata), null, 2));
console.log();
}

let lastPromise; // will be used to chain promises
lastPromise = doc.getMetadata().then(function (data) {
console.log("# Metadata Is Loaded");
console.log("## Info");
console.log(JSON.stringify(data.info, null, 2));
console.log();
if (data.metadata) {
console.log("## Metadata");
console.log(JSON.stringify(data.metadata.getAll(), null, 2));
console.log();
}
});
for (let i = 1; i <= numPages; i++) {
const pdfPage = await pdfDoc.getPage(i);
console.log(`# Page ${i}`);
const viewport = pdfPage.getViewport({ scale: 1.0 });
console.log(`Size: ${viewport.width}x${viewport.height}`);
console.log();

const { items } = await pdfPage.getTextContent();
// Content contains lots of information about the text layout and
// styles, but we need only strings at the moment
console.log("## Text Content");
console.log(items.map(item => item.str).join(" "));
console.log();
// Release page resources.
pdfPage.cleanup();
}

const loadPage = function (pageNum) {
return doc.getPage(pageNum).then(function (page) {
console.log("# Page " + pageNum);
const viewport = page.getViewport({ scale: 1.0 });
console.log("Size: " + viewport.width + "x" + viewport.height);
console.log();
return page
.getTextContent()
.then(function (content) {
// Content contains lots of information about the text layout and
// styles, but we need only strings at the moment
const strings = content.items.map(function (item) {
return item.str;
});
console.log("## Text Content");
console.log(strings.join(" "));
// Release page resources.
page.cleanup();
})
.then(function () {
console.log();
});
});
};
// Loading of the first page will wait on metadata and subsequent loadings
// will wait on the previous pages.
for (let i = 1; i <= numPages; i++) {
lastPromise = lastPromise.then(loadPage.bind(null, i));
}
return lastPromise;
})
.then(
function () {
console.log("# End of Document");
},
function (err) {
console.error("Error: " + err);
}
);
await loadingTask.destroy();
console.log("# End of Document");
} catch (ex) {
console.error(`Error: ${ex}`);
}
6 changes: 1 addition & 5 deletions src/core/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,13 +918,9 @@ class Catalog {
case "A":
case "a":
const LIMIT = 26; // Use only the characters A-Z, or a-z.
const A_UPPER_CASE = 0x41,
A_LOWER_CASE = 0x61;

const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE;
const letterIndex = currentIndex - 1;
const character = String.fromCharCode(
baseCharCode + (letterIndex % LIMIT)
style.charCodeAt(0) + (letterIndex % LIMIT)
);
currentLabel = character.repeat(Math.floor(letterIndex / LIMIT) + 1);
break;
Expand Down
69 changes: 35 additions & 34 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,44 +327,45 @@ class Page {
async #replaceIdByRef(annotations, deletedAnnotations, existingAnnotations) {
const promises = [];
for (const annotation of annotations) {
if (annotation.id) {
const ref = Ref.fromString(annotation.id);
if (!ref) {
warn(`A non-linked annotation cannot be modified: ${annotation.id}`);
continue;
}
if (annotation.deleted) {
deletedAnnotations.put(ref, ref);
if (annotation.popupRef) {
const popupRef = Ref.fromString(annotation.popupRef);
if (popupRef) {
deletedAnnotations.put(popupRef, popupRef);
}
}
continue;
}
if (annotation.popup?.deleted) {
if (!annotation.id) {
continue;
}
const ref = Ref.fromString(annotation.id);
if (!ref) {
warn(`A non-linked annotation cannot be modified: ${annotation.id}`);
continue;
}
if (annotation.deleted) {
deletedAnnotations.put(ref);
if (annotation.popupRef) {
const popupRef = Ref.fromString(annotation.popupRef);
if (popupRef) {
deletedAnnotations.put(popupRef, popupRef);
deletedAnnotations.put(popupRef);
}
}
existingAnnotations?.put(ref);
annotation.ref = ref;
promises.push(
this.xref.fetchAsync(ref).then(
obj => {
if (obj instanceof Dict) {
annotation.oldAnnotation = obj.clone();
}
},
() => {
warn(`Cannot fetch \`oldAnnotation\` for: ${ref}.`);
}
)
);
delete annotation.id;
continue;
}
if (annotation.popup?.deleted) {
const popupRef = Ref.fromString(annotation.popupRef);
if (popupRef) {
deletedAnnotations.put(popupRef);
}
}
existingAnnotations?.put(ref);
annotation.ref = ref;
promises.push(
this.xref.fetchAsync(ref).then(
obj => {
if (obj instanceof Dict) {
annotation.oldAnnotation = obj.clone();
}
},
() => {
warn(`Cannot fetch \`oldAnnotation\` for: ${ref}.`);
}
)
);
delete annotation.id;
}
await Promise.all(promises);
}
Expand All @@ -375,7 +376,7 @@ class Page {
}
const partialEvaluator = this.#createPartialEvaluator(handler);

const deletedAnnotations = new RefMap();
const deletedAnnotations = new RefSet();
const existingAnnotations = new RefSet();
await this.#replaceIdByRef(
annotations,
Expand Down
40 changes: 15 additions & 25 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,16 @@ class PartialEvaluator {
}
}

#createTransferMap(fn) {
const transferFn = this._pdfFunctionFactory.create(fn),
tmp = new Float32Array(1);
return Uint8Array.from({ length: 256 }, (_, i) => {
tmp[0] = i / 255;
transferFn(tmp, 0, tmp, 0);
return (tmp[0] * 255) | 0;
});
}

handleSMask(
smask,
resources,
Expand All @@ -904,15 +914,7 @@ class PartialEvaluator {
// we will build a map of integer values in range 0..255 to be fast.
const transferObj = smask.get("TR");
if (isPDFFunction(transferObj)) {
const transferFn = this._pdfFunctionFactory.create(transferObj);
const transferMap = new Uint8Array(256);
const tmp = new Float32Array(1);
for (let i = 0; i < 256; i++) {
tmp[0] = i / 255;
transferFn(tmp, 0, tmp, 0);
transferMap[i] = (tmp[0] * 255) | 0;
}
smaskOptions.transferMap = transferMap;
smaskOptions.transferMap = this.#createTransferMap(transferObj);
}

return this.buildFormXObject(
Expand All @@ -930,12 +932,9 @@ class PartialEvaluator {
handleTransferFunction(tr) {
let transferArray;
if (Array.isArray(tr)) {
transferArray = tr;
if (tr.length > 1 && tr.every(map => map === tr[0])) {
// All entries in the array are the same, so we can just use one of
// them.
transferArray = [tr[0]];
}
// If all entries in the array are the same, we can just use one of them.
transferArray =
tr.length > 1 && tr.every(map => map === tr[0]) ? [tr[0]] : tr;
} else if (isPDFFunction(tr)) {
transferArray = [tr];
} else {
Expand All @@ -955,16 +954,7 @@ class PartialEvaluator {
} else if (!isPDFFunction(transferObj)) {
return null; // Not a valid transfer function object.
}

const transferFn = this._pdfFunctionFactory.create(transferObj);
const transferMap = new Uint8Array(256),
tmp = new Float32Array(1);
for (let j = 0; j < 256; j++) {
tmp[0] = j / 255;
transferFn(tmp, 0, tmp, 0);
transferMap[j] = (tmp[0] * 255) | 0;
}
transferMaps.push(transferMap);
transferMaps.push(this.#createTransferMap(transferObj));
numEffectfulFns++;
}

Expand Down
23 changes: 7 additions & 16 deletions src/core/primitives.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Dict {
return this.#map.size;
}

#getValue(isAsync, key1, key2, key3) {
#getValue(isAsync, key1, key2) {
let value = this.#map.get(key1);
if (value === undefined && key2 !== undefined) {
if (
Expand All @@ -99,15 +99,6 @@ class Dict {
unreachable("Dict.#getValue: Expected keys to be ordered by length.");
}
value = this.#map.get(key2);
if (value === undefined && key3 !== undefined) {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
key3.length < key2.length
) {
unreachable("Dict.#getValue: Expected keys to be ordered by length.");
}
value = this.#map.get(key3);
}
}
if (value instanceof Ref && this.xref) {
return isAsync
Expand All @@ -118,18 +109,18 @@ class Dict {
}

// Automatically dereferences Ref objects.
get(key1, key2, key3) {
return this.#getValue(/* isAsync = */ false, key1, key2, key3);
get(key1, key2) {
return this.#getValue(/* isAsync = */ false, key1, key2);
}

// Same as get(), but returns a promise and uses fetchIfRefAsync().
async getAsync(key1, key2, key3) {
return this.#getValue(/* isAsync = */ true, key1, key2, key3);
async getAsync(key1, key2) {
return this.#getValue(/* isAsync = */ true, key1, key2);
}

// Same as get(), but dereferences all elements if the result is an Array.
getArray(key1, key2, key3) {
let value = this.#getValue(/* isAsync = */ false, key1, key2, key3);
getArray(key1, key2) {
let value = this.#getValue(/* isAsync = */ false, key1, key2);

if (Array.isArray(value)) {
value = value.slice(); // Ensure that we don't modify the Dict data.
Expand Down
Loading
Loading