pdf-lib
Version:
Library for creating and modifying PDF files in JavaScript
119 lines (118 loc) • 6.54 kB
JavaScript
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;
;