UNPKG

@cantoo/pdf-lib

Version:

Create and modify PDF files with JavaScript

179 lines 8.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EntryType = void 0; const tslib_1 = require("tslib"); const PDFName_1 = tslib_1.__importDefault(require("../objects/PDFName")); const PDFRef_1 = tslib_1.__importDefault(require("../objects/PDFRef")); const PDFFlateStream_1 = tslib_1.__importDefault(require("./PDFFlateStream")); const utils_1 = require("../../utils"); var EntryType; (function (EntryType) { EntryType[EntryType["Deleted"] = 0] = "Deleted"; EntryType[EntryType["Uncompressed"] = 1] = "Uncompressed"; EntryType[EntryType["Compressed"] = 2] = "Compressed"; })(EntryType = exports.EntryType || (exports.EntryType = {})); /** * Entries should be added using the [[addDeletedEntry]], * [[addUncompressedEntry]], and [[addCompressedEntry]] methods * **in order of ascending object number**. */ class PDFCrossRefStream extends PDFFlateStream_1.default { constructor(dict, entries, encode = true) { super(dict, encode); // Returns an array of integer pairs for each subsection of the cross ref // section, where each integer pair represents: // firstObjectNumber(OfSection), length(OfSection) this.computeIndex = () => { const subsections = []; let subsectionLength = 0; for (let idx = 0, len = this.entries.length; idx < len; idx++) { const currEntry = this.entries[idx]; const prevEntry = this.entries[idx - 1]; if (idx === 0) { subsections.push(currEntry.ref.objectNumber); } else if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber > 1) { subsections.push(subsectionLength); subsections.push(currEntry.ref.objectNumber); subsectionLength = 0; } subsectionLength += 1; } subsections.push(subsectionLength); return subsections; }; this.computeEntryTuples = () => { const entryTuples = new Array(this.entries.length); for (let idx = 0, len = this.entries.length; idx < len; idx++) { const entry = this.entries[idx]; if (entry.type === EntryType.Deleted) { const { type, nextFreeObjectNumber, ref } = entry; entryTuples[idx] = [type, nextFreeObjectNumber, ref.generationNumber]; } if (entry.type === EntryType.Uncompressed) { const { type, offset, ref } = entry; entryTuples[idx] = [type, offset, ref.generationNumber]; } if (entry.type === EntryType.Compressed) { const { type, objectStreamRef, index } = entry; entryTuples[idx] = [type, objectStreamRef.objectNumber, index]; } } return entryTuples; }; this.computeMaxEntryByteWidths = () => { const entryTuples = this.entryTuplesCache.access(); const widths = [0, 0, 0]; for (let idx = 0, len = entryTuples.length; idx < len; idx++) { const [first, second, third] = entryTuples[idx]; const firstSize = (0, utils_1.sizeInBytes)(first); const secondSize = (0, utils_1.sizeInBytes)(second); const thirdSize = (0, utils_1.sizeInBytes)(third); if (firstSize > widths[0]) widths[0] = firstSize; if (secondSize > widths[1]) widths[1] = secondSize; if (thirdSize > widths[2]) widths[2] = thirdSize; } return widths; }; this.entries = entries || []; this.entryTuplesCache = utils_1.Cache.populatedBy(this.computeEntryTuples); this.maxByteWidthsCache = utils_1.Cache.populatedBy(this.computeMaxEntryByteWidths); this.indexCache = utils_1.Cache.populatedBy(this.computeIndex); dict.set(PDFName_1.default.of('Type'), PDFName_1.default.of('XRef')); } addDeletedEntry(ref, nextFreeObjectNumber) { const type = EntryType.Deleted; this.entries.push({ type, ref, nextFreeObjectNumber }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); this.contentsCache.invalidate(); } addUncompressedEntry(ref, offset) { const type = EntryType.Uncompressed; this.entries.push({ type, ref, offset }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); this.contentsCache.invalidate(); } addCompressedEntry(ref, objectStreamRef, index) { const type = EntryType.Compressed; this.entries.push({ type, ref, objectStreamRef, index }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); this.contentsCache.invalidate(); } clone(context) { const { dict, entries, encode } = this; return PDFCrossRefStream.of(dict.clone(context), entries.slice(), encode); } getContentsString() { const entryTuples = this.entryTuplesCache.access(); const byteWidths = this.maxByteWidthsCache.access(); let value = ''; for (let entryIdx = 0, entriesLen = entryTuples.length; entryIdx < entriesLen; entryIdx++) { const [first, second, third] = entryTuples[entryIdx]; const firstBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(first)); const secondBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(second)); const thirdBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(third)); for (let idx = byteWidths[0] - 1; idx >= 0; idx--) { value += (firstBytes[idx] || 0).toString(2); } for (let idx = byteWidths[1] - 1; idx >= 0; idx--) { value += (secondBytes[idx] || 0).toString(2); } for (let idx = byteWidths[2] - 1; idx >= 0; idx--) { value += (thirdBytes[idx] || 0).toString(2); } } return value; } getUnencodedContents() { const entryTuples = this.entryTuplesCache.access(); const byteWidths = this.maxByteWidthsCache.access(); const buffer = new Uint8Array(this.getUnencodedContentsSize()); let offset = 0; for (let entryIdx = 0, entriesLen = entryTuples.length; entryIdx < entriesLen; entryIdx++) { const [first, second, third] = entryTuples[entryIdx]; const firstBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(first)); const secondBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(second)); const thirdBytes = (0, utils_1.reverseArray)((0, utils_1.bytesFor)(third)); for (let idx = byteWidths[0] - 1; idx >= 0; idx--) { buffer[offset++] = firstBytes[idx] || 0; } for (let idx = byteWidths[1] - 1; idx >= 0; idx--) { buffer[offset++] = secondBytes[idx] || 0; } for (let idx = byteWidths[2] - 1; idx >= 0; idx--) { buffer[offset++] = thirdBytes[idx] || 0; } } return buffer; } getUnencodedContentsSize() { const byteWidths = this.maxByteWidthsCache.access(); const entryWidth = (0, utils_1.sum)(byteWidths); return entryWidth * this.entries.length; } updateDict() { super.updateDict(); const byteWidths = this.maxByteWidthsCache.access(); const index = this.indexCache.access(); const { context } = this.dict; this.dict.set(PDFName_1.default.of('W'), context.obj(byteWidths)); this.dict.set(PDFName_1.default.of('Index'), context.obj(index)); } } PDFCrossRefStream.create = (dict, encode = true) => { const stream = new PDFCrossRefStream(dict, [], encode); stream.addDeletedEntry(PDFRef_1.default.of(0, 65535), 0); return stream; }; PDFCrossRefStream.of = (dict, entries, encode = true) => new PDFCrossRefStream(dict, entries, encode); exports.default = PDFCrossRefStream; //# sourceMappingURL=PDFCrossRefStream.js.map