UNPKG

pdf-lib

Version:

Library for creating and modifying PDF files in JavaScript

119 lines (118 loc) 6.54 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; } Object.defineProperty(exports, "__esModule", { value: true }); var isFunction_1 = __importDefault(require("lodash/isFunction")); var last_1 = __importDefault(require("lodash/last")); var sortBy_1 = __importDefault(require("lodash/sortBy")); var pdf_objects_1 = require("../pdf-objects"); var pdf_structures_1 = require("../pdf-structures"); var PDFXRefStreamFactory_1 = __importDefault(require("../pdf-structures/factories/PDFXRefStreamFactory")); var PDFXRefTableFactory_1 = __importDefault(require("../pdf-structures/factories/PDFXRefTableFactory")); var utils_1 = require("../../utils"); var createIndirectObjectsFromIndex = function (_a) { var index = _a.index; var catalogRef; var streamObjects = []; var nonStreamObjects = []; index.forEach(function (object, ref) { if (object instanceof pdf_structures_1.PDFCatalog) catalogRef = ref; var array = object instanceof pdf_objects_1.PDFStream ? streamObjects : nonStreamObjects; array.push(pdf_objects_1.PDFIndirectObject.of(object).setReference(ref)); }); return { catalogRef: catalogRef, streamObjects: streamObjects, nonStreamObjects: nonStreamObjects }; }; var computeOffsets = function (startingOffset, indirectObjects) { return indirectObjects.map(function (object) { return ({ objectNumber: object.reference.objectNumber, generationNumber: object.reference.generationNumber, startOffset: startingOffset, endOffset: startingOffset += object.bytesSize(), }); }); }; var PDFDocumentWriter = /** @class */ (function () { function PDFDocumentWriter() { } /** * Converts a [[PDFDocument]] object into the raw bytes of a PDF document. * These raw bytes could, for example, be saved as a file and opened in a * PDF reader. * * `options.useObjectStreams` controls whether or not to use Object Streams * when saving the document. Using Object Streams will result in a smaller * file size for many documents. This option is `true` by default. If set to * `false`, then Object Streams will not be used. * * @param pdfDoc The [[PDFDocument]] to be converted to bytes. * @param options An options object. * * @returns A `Uint8Array` containing the raw bytes of a PDF document. */ PDFDocumentWriter.saveToBytes = function (pdfDoc, options) { if (options === void 0) { options = { useObjectStreams: true }; } return options.useObjectStreams === false ? PDFDocumentWriter.saveToBytesWithXRefTable(pdfDoc) : PDFDocumentWriter.saveToBytesWithObjectStreams(pdfDoc); }; PDFDocumentWriter.saveToBytesWithXRefTable = function (pdfDoc) { /* ===== (1) Compute indirect object offsets and sort by objectnumber ===== */ var _a = createIndirectObjectsFromIndex(pdfDoc.index), catalogRef = _a.catalogRef, streamObjects = _a.streamObjects, nonStreamObjects = _a.nonStreamObjects; if (!catalogRef) utils_1.error('Missing PDFCatalog'); streamObjects.forEach(function (streamObj) { if (isFunction_1.default(streamObj.pdfObject.encode)) streamObj.pdfObject.encode(); }); var merged = streamObjects.concat(nonStreamObjects); var offsets = computeOffsets(pdfDoc.header.bytesSize(), merged); var sortedOffsets = sortBy_1.default(offsets, 'objectNumber'); /* ===== (2) Create XRefTable and Trailer ===== */ var table = PDFXRefTableFactory_1.default.forOffsets(sortedOffsets); var tableOffset = last_1.default(offsets).endOffset; var trailer = pdf_structures_1.PDFTrailer.from(tableOffset, pdf_objects_1.PDFDictionary.from({ Size: pdf_objects_1.PDFNumber.fromNumber(last_1.default(sortedOffsets).objectNumber + 1), Root: catalogRef, }, pdfDoc.index)); /* ===== (3) Create buffer and copy objects into it ===== */ var bufferSize = tableOffset + table.bytesSize() + trailer.bytesSize(); var buffer = new Uint8Array(bufferSize); var remaining = pdfDoc.header.copyBytesInto(buffer); remaining = merged.reduce(function (remBytes, indirectObj) { return indirectObj.copyBytesInto(remBytes); }, remaining); remaining = table.copyBytesInto(remaining); remaining = trailer.copyBytesInto(remaining); return buffer; }; PDFDocumentWriter.saveToBytesWithObjectStreams = function (pdfDoc) { /* ===== (1) Split objects into streams and nonstreams ===== */ var _a = createIndirectObjectsFromIndex(pdfDoc.index), catalogRef = _a.catalogRef, streamObjects = _a.streamObjects, nonStreamObjects = _a.nonStreamObjects; if (!catalogRef) utils_1.error('Missing PDFCatalog'); streamObjects.forEach(function (streamObj) { if (isFunction_1.default(streamObj.pdfObject.encode)) streamObj.pdfObject.encode(); }); /* ===== (2) Create ObjectStream ===== */ var objectStream = pdf_structures_1.PDFObjectStream.create(pdfDoc.index, nonStreamObjects); objectStream.encode(); var objectStreamIndObj = pdf_objects_1.PDFIndirectObject.of(objectStream).setReferenceNumbers(pdfDoc.index.highestObjectNumber + 1, 0); streamObjects.push(objectStreamIndObj); /* ===== (3) Compute indirect object offsets ===== */ var offsets = computeOffsets(pdfDoc.header.bytesSize(), streamObjects); var trailerOffset = last_1.default(offsets).endOffset; /* ===== (4) Create XRefStream and Trailer ===== */ var xrefStream = PDFXRefStreamFactory_1.default.forOffsetsAndObjectStream(offsets, objectStreamIndObj, catalogRef, pdfDoc.index); streamObjects.push(xrefStream); var trailer = pdf_structures_1.PDFTrailer.from(trailerOffset); /* ===== (5) Create buffer and copy objects into it ===== */ var bufferSize = trailerOffset + xrefStream.bytesSize() + trailer.bytesSize(); var buffer = new Uint8Array(bufferSize); var remaining = pdfDoc.header.copyBytesInto(buffer); remaining = streamObjects.reduce(function (remBytes, obj) { return obj.copyBytesInto(remBytes); }, remaining); remaining = trailer.copyBytesInto(remaining); return buffer; }; return PDFDocumentWriter; }()); exports.default = PDFDocumentWriter;