UNPKG

@cantoo/pdf-lib

Version:

Create and modify PDF files with JavaScript

169 lines 6.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const PDFArray_1 = tslib_1.__importDefault(require("../objects/PDFArray")); const PDFDict_1 = tslib_1.__importDefault(require("../objects/PDFDict")); const PDFName_1 = tslib_1.__importDefault(require("../objects/PDFName")); const PDFNumber_1 = tslib_1.__importDefault(require("../objects/PDFNumber")); const PDFPageLeaf_1 = tslib_1.__importDefault(require("./PDFPageLeaf")); const errors_1 = require("../errors"); class PDFPageTree extends PDFDict_1.default { Parent() { return this.lookup(PDFName_1.default.of('Parent')); } Kids() { return this.lookup(PDFName_1.default.of('Kids'), PDFArray_1.default); } Count() { return this.lookup(PDFName_1.default.of('Count'), PDFNumber_1.default); } pushTreeNode(treeRef) { const Kids = this.Kids(); Kids.push(treeRef); } pushLeafNode(leafRef) { const Kids = this.Kids(); this.insertLeafKid(Kids.size(), leafRef); } /** * Inserts the given ref as a leaf node of this page tree at the specified * index (zero-based). Also increments the `Count` of each page tree in the * hierarchy to accomodate the new page. * * Returns the ref of the PDFPageTree node into which `leafRef` was inserted, * or `undefined` if it was inserted into the root node (the PDFPageTree upon * which the method was first called). */ insertLeafNode(leafRef, targetIndex) { const Kids = this.Kids(); const Count = this.Count().asNumber(); if (targetIndex > Count) { throw new errors_1.InvalidTargetIndexError(targetIndex, Count); } let leafsRemainingUntilTarget = targetIndex; for (let idx = 0, len = Kids.size(); idx < len; idx++) { if (leafsRemainingUntilTarget === 0) { // Insert page and return this.insertLeafKid(idx, leafRef); return undefined; } const kidRef = Kids.get(idx); const kid = this.context.lookup(kidRef); if (kid instanceof PDFPageTree) { if (kid.Count().asNumber() > leafsRemainingUntilTarget) { // Dig in return (kid.insertLeafNode(leafRef, leafsRemainingUntilTarget) || kidRef); } else { // Move on leafsRemainingUntilTarget -= kid.Count().asNumber(); } } if (kid instanceof PDFPageLeaf_1.default) { // Move on leafsRemainingUntilTarget -= 1; } } if (leafsRemainingUntilTarget === 0) { // Insert page at the end and return this.insertLeafKid(Kids.size(), leafRef); return undefined; } // Should never get here if `targetIndex` is valid throw new errors_1.CorruptPageTreeError(targetIndex, 'insertLeafNode'); } /** * Removes the leaf node at the specified index (zero-based) from this page * tree. Also decrements the `Count` of each page tree in the hierarchy to * account for the removed page. * * If `prune` is true, then intermediate tree nodes will be removed from the * tree if they contain 0 children after the leaf node is removed. */ removeLeafNode(targetIndex, prune = true) { const Kids = this.Kids(); const Count = this.Count().asNumber(); if (targetIndex >= Count) { throw new errors_1.InvalidTargetIndexError(targetIndex, Count); } let leafsRemainingUntilTarget = targetIndex; for (let idx = 0, len = Kids.size(); idx < len; idx++) { const kidRef = Kids.get(idx); const kid = this.context.lookup(kidRef); if (kid instanceof PDFPageTree) { if (kid.Count().asNumber() > leafsRemainingUntilTarget) { // Dig in kid.removeLeafNode(leafsRemainingUntilTarget, prune); if (prune && kid.Kids().size() === 0) Kids.remove(idx); return; } else { // Move on leafsRemainingUntilTarget -= kid.Count().asNumber(); } } if (kid instanceof PDFPageLeaf_1.default) { if (leafsRemainingUntilTarget === 0) { // Remove page and return this.removeKid(idx); return; } else { // Move on leafsRemainingUntilTarget -= 1; } } } // Should never get here if `targetIndex` is valid throw new errors_1.CorruptPageTreeError(targetIndex, 'removeLeafNode'); } ascend(visitor) { visitor(this); const Parent = this.Parent(); if (Parent) Parent.ascend(visitor); } /** Performs a Post-Order traversal of this page tree */ traverse(visitor) { const Kids = this.Kids(); for (let idx = 0, len = Kids.size(); idx < len; idx++) { const kidRef = Kids.get(idx); const kid = this.context.lookup(kidRef); if (kid instanceof PDFPageTree) kid.traverse(visitor); visitor(kid, kidRef); } } insertLeafKid(kidIdx, leafRef) { const Kids = this.Kids(); this.ascend((node) => { const newCount = node.Count().asNumber() + 1; node.set(PDFName_1.default.of('Count'), PDFNumber_1.default.of(newCount)); }); Kids.insert(kidIdx, leafRef); } removeKid(kidIdx) { const Kids = this.Kids(); const kid = Kids.lookup(kidIdx); if (kid instanceof PDFPageLeaf_1.default) { this.ascend((node) => { const newCount = node.Count().asNumber() - 1; node.set(PDFName_1.default.of('Count'), PDFNumber_1.default.of(newCount)); }); } Kids.remove(kidIdx); } } PDFPageTree.withContext = (context, parent) => { const dict = new Map(); dict.set(PDFName_1.default.of('Type'), PDFName_1.default.of('Pages')); dict.set(PDFName_1.default.of('Kids'), context.obj([])); dict.set(PDFName_1.default.of('Count'), context.obj(0)); if (parent) dict.set(PDFName_1.default.of('Parent'), parent); return new PDFPageTree(dict, context); }; PDFPageTree.fromMapWithContext = (map, context) => new PDFPageTree(map, context); exports.default = PDFPageTree; //# sourceMappingURL=PDFPageTree.js.map