@syncfusion/ej2-pdf
Version:
Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.
334 lines (333 loc) • 13.4 kB
JavaScript
import { _PdfDictionary, _PdfReferenceSet, _PdfReferenceSetCache, _PdfReference, _isName } from './pdf-primitives';
import { FormatError } from './utils';
/**
* Provides access to the PDF catalog and utilities to traverse and cache the page tree.
*
* @private
*/
var _PdfCatalog = /** @class */ (function () {
function _PdfCatalog(xref) {
/**
* List of page indices that have been parsed and cached.
*
* @private
*/
this._parsedPages = [];
/**
* Cache of page dictionaries and references keyed by page index.
*
* @private
*/
this._pageCache = new Map();
this._crossReference = xref;
this._catalogDictionary = xref._getCatalogObj();
if (!(this._catalogDictionary instanceof _PdfDictionary)) {
throw new FormatError('Catalog object is not a dictionary.');
}
else {
this._catalogDictionary.isCatalog = true;
}
this._topPagesDictionary = this._catalogDictionary.get('Pages');
this.pageKidsCountCache = new _PdfReferenceSetCache();
this.pageIndexCache = new _PdfReferenceSetCache();
}
Object.defineProperty(_PdfCatalog.prototype, "version", {
get: function () {
var value;
if (this._catalogDictionary.has('Version')) {
var version = this._catalogDictionary.get('Version');
if (version) {
value = version.name;
}
}
return value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(_PdfCatalog.prototype, "pageCount", {
get: function () {
var obj = this._topPagesDictionary.get('Count');
if (typeof obj === 'undefined' || !Number.isInteger(obj)) {
throw new FormatError('Invalid page count');
}
return obj;
},
enumerable: true,
configurable: true
});
Object.defineProperty(_PdfCatalog.prototype, "acroForm", {
get: function () {
var form;
if (this._catalogDictionary.has('AcroForm')) {
form = this._catalogDictionary.get('AcroForm');
}
if (form === null || typeof form === 'undefined') {
form = this._createForm();
}
return form;
},
enumerable: true,
configurable: true
});
/* eslint-disable */
/**
* Creates and registers a new AcroForm dictionary on the catalog.
*
* @private
* @returns {_PdfDictionary} The created AcroForm dictionary.
*/
_PdfCatalog.prototype._createForm = function () {
var form = new _PdfDictionary(this._crossReference);
var ref = this._crossReference._getNextReference();
this._crossReference._cacheMap.set(ref, form);
this._catalogDictionary.set('AcroForm', ref);
this._catalogDictionary._updated = true;
this._crossReference._allowCatalog = true;
form._updated = true;
return form;
};
_PdfCatalog.prototype._addToCache = function (pageIndex, dictionary, reference) {
this._pageCache.set(pageIndex, {
dictionary: dictionary,
reference: reference,
parent: dictionary.get('Parent')
});
this._parsedPages.push(pageIndex);
};
/**
* Gets the page dictionary and reference for the specified page index, using caches when possible.
*
* @private
* @param {number} pageIndex Zero-based page index to retrieve.
* @returns {{ dictionary: _PdfDictionary, reference: _PdfReference }} The page dictionary and its indirect reference (if any).
*/
_PdfCatalog.prototype._getPageDictionary = function (pageIndex) {
if (pageIndex !== 0 && this._checkPageTreeFormat()) {
var nearestIndex = this._findNearestIndex(pageIndex);
if (nearestIndex > 0) {
var nearestCachedPage = this._pageCache.get(nearestIndex);
if (nearestCachedPage) {
var result = this._traverseFromCached(nearestIndex, nearestCachedPage, pageIndex);
if (result) {
return result;
}
}
}
}
return this._traverseFromRoot(pageIndex);
};
_PdfCatalog.prototype._checkPageTreeFormat = function () {
if (typeof this._hasInvalidPageTree === 'undefined') {
var kids = this._topPagesDictionary.get('Kids');
if (Array.isArray(kids)) {
this._hasInvalidPageTree = this.pageCount === kids.length;
}
}
return this._hasInvalidPageTree;
};
_PdfCatalog.prototype._findNearestIndex = function (targetIndex) {
var length = this._parsedPages.length;
var nearest = this._parsedPages[0];
var minDistance = Math.abs(nearest - targetIndex);
for (var i = 1; i < length; i++) {
var index = this._parsedPages[i];
var distance = Math.abs(index - targetIndex);
if (distance < minDistance) {
nearest = index;
minDistance = distance;
}
}
return nearest;
};
_PdfCatalog.prototype._traverseFromCached = function (index, cachedPage, targetIndex) {
var visitedNodes = new _PdfReferenceSet();
var direction = targetIndex > index ? 1 : -1;
var currentNode = cachedPage.dictionary;
var currentIndex = index;
var parent = cachedPage.parent;
var currentReference = cachedPage.reference;
if (currentIndex === targetIndex && _isName(currentNode.get('Type'), 'Page')) {
return { dictionary: currentNode, reference: currentReference };
}
while (currentNode && currentIndex !== targetIndex) {
if (currentNode instanceof _PdfReference) {
if (visitedNodes.has(currentNode)) {
throw new FormatError('Pages tree contains circular reference.');
}
visitedNodes.put(currentNode);
}
var nextPage = this._findNextPage(currentNode, parent, direction);
if (!nextPage) {
break;
}
currentNode = nextPage.dictionary;
currentReference = nextPage.reference;
currentIndex += direction;
if (currentIndex === targetIndex && _isName(currentNode.get('Type'), 'Page')) {
this._addToCache(currentIndex, nextPage.dictionary, nextPage.reference);
return {
dictionary: currentNode,
reference: currentReference
};
}
}
return null;
};
_PdfCatalog.prototype._findNextPage = function (currentPage, parent, direction) {
var _this = this;
if (!parent || !parent.has('Kids')) {
return null;
}
var kids = parent.getRaw('Kids');
if (kids instanceof _PdfReference) {
kids = this._crossReference._fetch(kids);
}
if (!Array.isArray(kids)) {
throw new FormatError('Page dictionary kids object is not an array.');
}
var currentIndex = -1;
if (currentPage._reference) {
currentIndex = kids.indexOf(currentPage._reference);
}
else {
currentIndex = kids.findIndex(function (kid) {
if (kid instanceof _PdfReference) {
kid = _this._crossReference._fetch(kid);
}
return kid === currentPage;
});
}
if (currentIndex === -1) {
return null;
}
var nextIndex = currentIndex + direction;
if (nextIndex < 0 || nextIndex >= kids.length) {
return null;
}
var nextKid = kids[nextIndex];
var nextDict = nextKid instanceof _PdfReference ? this._crossReference._fetch(nextKid) : nextKid;
if (!(nextDict instanceof _PdfDictionary)) {
throw new FormatError('Invalid page dictionary type.');
}
return {
dictionary: nextDict,
reference: nextKid instanceof _PdfReference ? nextKid : null
};
};
_PdfCatalog.prototype._traverseFromRoot = function (pageIndex) {
var nodesToVisit = [this._topPagesDictionary];
var visitedNodes = new _PdfReferenceSet();
var pagesRef = this._catalogDictionary.getRaw('Pages');
if (pagesRef && pagesRef instanceof _PdfReference) {
visitedNodes.put(pagesRef);
}
var xref = this._crossReference;
var pageKidsCountCache = this.pageKidsCountCache;
var pageIndexCache = this.pageIndexCache;
var currentPageIndex = 0;
while (nodesToVisit.length > 0) {
var currentNode = nodesToVisit.pop();
if (currentNode && currentNode instanceof _PdfReference) {
var count_1 = pageKidsCountCache.get(currentNode);
if (count_1 >= 0 && currentPageIndex + count_1 <= pageIndex) {
currentPageIndex += count_1;
continue;
}
if (visitedNodes.has(currentNode)) {
throw new FormatError('Pages tree contains circular reference.');
}
visitedNodes.put(currentNode);
var obj = xref._fetch(currentNode);
if (obj && obj instanceof _PdfDictionary) {
var type = obj.getRaw('Type');
if (type instanceof _PdfReference) {
type = xref._fetch(type);
}
if (_isName(type, 'Page') || !obj.has('Kids')) {
if (!pageKidsCountCache.has(currentNode)) {
pageKidsCountCache.put(currentNode, 1);
}
if (!pageIndexCache.has(currentNode)) {
pageIndexCache.put(currentNode, currentPageIndex);
}
if (currentPageIndex === pageIndex) {
this._addToCache(currentPageIndex, obj, currentNode);
return { dictionary: obj, reference: currentNode };
}
currentPageIndex++;
continue;
}
}
nodesToVisit.push(obj);
continue;
}
if (!(currentNode instanceof _PdfDictionary)) {
throw new FormatError('Page dictionary kid reference points to wrong type of object.');
}
var objId = currentNode.objId;
var count = currentNode.get('Count');
if (count instanceof _PdfReference) {
count = xref._fetch(count);
}
if (count !== null && typeof count !== 'undefined' && Number.isInteger(count) && count >= 0) {
if (objId && !pageKidsCountCache.has(objId)) {
pageKidsCountCache.set(objId, count);
}
if (currentPageIndex + count <= pageIndex) {
currentPageIndex += count;
continue;
}
}
var kids = currentNode.getRaw('Kids');
if (kids instanceof _PdfReference) {
kids = xref._fetch(kids);
}
if (!Array.isArray(kids)) {
var type = currentNode.getRaw('Type');
if (type instanceof _PdfReference) {
type = xref._fetch(type);
}
if (_isName(type, 'Page') || !currentNode.has('Kids')) {
if (currentPageIndex === pageIndex) {
this._addToCache(currentPageIndex, currentNode, null);
return { dictionary: currentNode, reference: null };
}
currentPageIndex++;
continue;
}
throw new FormatError('Page dictionary kids object is not an array.');
}
for (var last = kids.length - 1; last >= 0; last--) {
nodesToVisit.push(kids[last]);
}
}
throw new Error("Page index " + pageIndex + " not found.");
};
/**
* Releases catalog and cache resources and clears references.
*
* @private
*/
_PdfCatalog.prototype._destroy = function () {
if (this._catalogDictionary) {
this._catalogDictionary = undefined;
}
if (this._topPagesDictionary) {
this._topPagesDictionary = undefined;
}
if (this.pageIndexCache) {
this.pageIndexCache.clear();
this.pageIndexCache = undefined;
}
if (this.pageKidsCountCache) {
this.pageKidsCountCache.clear();
this.pageKidsCountCache = undefined;
}
this._hasInvalidPageTree = undefined;
this._pageCache.clear();
this._parsedPages = [];
};
return _PdfCatalog;
}());
export { _PdfCatalog };