pdf-lib
Version:
Library for creating and modifying PDF files in JavaScript
106 lines (105 loc) • 4.95 kB
JavaScript
import { PDFArray, PDFDictionary, PDFIndirectReference, PDFStream, } from '../pdf-objects';
import { PDFPage } from '../pdf-structures';
/**
* PDFObjectCopier copies PDFObjects from a src index to a dest index.
* The primary use case for this is to copy pages between PDFs.
*
* _Copying_ an object with a PDFObjectCopier is different from _cloning_ an
* object with its [[PDFObject.clone]] method:
*
* ```
* const origObject = ...
* const copiedObject = PDFObjectCopier.for(srcIndex, destIndex).copy(origObject);
* const clonedObject = originalObject.clone();
* ```
*
* Copying an object is equivalent to cloning it and then copying over any other
* objects that it references. Note that only dictionaries, arrays, and streams
* (or structures build from them) can contain indirect references to other
* objects. Copying a PDFObject that is not a dictionary, array, or stream is
* supported, but is equivalent to cloning it.
*/
var PDFObjectCopier = /** @class */ (function () {
function PDFObjectCopier(srcIndex, destIndex) {
var _this = this;
this.traversedObjects = new Map();
// prettier-ignore
this.copy = function (object) { return (object instanceof PDFPage ? _this.copyPDFPage(object)
: object instanceof PDFDictionary ? _this.copyPDFDict(object)
: object instanceof PDFArray ? _this.copyPDFArray(object)
: object instanceof PDFStream ? _this.copyPDFStream(object)
: object instanceof PDFIndirectReference ? _this.copyPDFIndirectObject(object)
: object.clone()); };
this.copyPDFPage = function (originalPage) {
var clonedPage = originalPage.clone();
// Move any entries that the originalPage is inheriting from its parent
// tree nodes directly into originalPage so they are preserved during
// the copy.
clonedPage.Parent.ascend(function (parentNode) {
PDFPage.INHERITABLE_ENTRIES.forEach(function (key) {
if (!clonedPage.getMaybe(key) && parentNode.getMaybe(key)) {
clonedPage.set(key, parentNode.get(key));
}
});
}, true);
// Remove the parent reference to prevent the whole donor document's page
// tree from being copied when we only need a single page.
clonedPage.delete('Parent');
return _this.copyPDFDict(clonedPage);
};
this.copyPDFDict = function (originalDict) {
if (_this.traversedObjects.has(originalDict)) {
return _this.traversedObjects.get(originalDict);
}
var clonedDict = originalDict.clone();
clonedDict.index = _this.dest;
_this.traversedObjects.set(originalDict, clonedDict);
originalDict.map.forEach(function (value, key) {
clonedDict.set(key, _this.copy(value));
});
return clonedDict;
};
this.copyPDFArray = function (originalArray) {
if (_this.traversedObjects.has(originalArray)) {
return _this.traversedObjects.get(originalArray);
}
var clonedArray = originalArray.clone();
clonedArray.index = _this.dest;
_this.traversedObjects.set(originalArray, clonedArray);
originalArray.forEach(function (value, idx) {
clonedArray.set(idx, _this.copy(value));
});
return clonedArray;
};
this.copyPDFStream = function (originalStream) {
if (_this.traversedObjects.has(originalStream)) {
return _this.traversedObjects.get(originalStream);
}
var clonedStream = originalStream.clone();
clonedStream.dictionary.index = _this.dest;
_this.traversedObjects.set(originalStream, clonedStream);
originalStream.dictionary.map.forEach(function (value, key) {
clonedStream.dictionary.set(key, _this.copy(value));
});
return clonedStream;
};
this.copyPDFIndirectObject = function (ref) {
var alreadyMapped = _this.traversedObjects.has(ref);
if (!alreadyMapped) {
var newRef = _this.dest.nextObjectNumber();
_this.traversedObjects.set(ref, newRef);
var dereferencedValue = _this.src.lookup(ref);
var cloned = _this.copy(dereferencedValue);
_this.dest.assign(newRef, cloned);
}
return _this.traversedObjects.get(ref);
};
this.src = srcIndex;
this.dest = destIndex;
}
PDFObjectCopier.for = function (srcIndex, destIndex) {
return new PDFObjectCopier(srcIndex, destIndex);
};
return PDFObjectCopier;
}());
export default PDFObjectCopier;