UNPKG

@syncfusion/ej2-pdf

Version:

Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.

1,980 lines 83 kB
import { _PdfDictionary, _PdfReference, _PdfName } from './pdf-primitives';
import { _areArrayEqual, _checkRotation, _getInheritableProperty, _getPageIndex, _isNullOrUndefined, _stringToBytes } from './utils';
import { PdfAnnotationCollection } from './annotations/annotation-collection';
import { PdfGraphics, PdfBrush } from './graphics/pdf-graphics';
import { _PdfBaseStream, _PdfContentStream } from './base-stream';
import { PdfRotationAngle, PdfDestinationMode, PdfFormFieldsTabOrder, PdfPageOrientation, PdfLayoutBreakType, PdfLayoutType } from './enumerator';
import { PdfTemplate } from './graphics/pdf-template';
import { PdfLayoutResult, _PdfLayoutParameters, PdfLayoutFormat } from './graphics/pdf-layouter';
import { PdfStringFormat } from './fonts/pdf-string-format';
import { _PdfStringLayouter } from './fonts/string-layouter';
/**
 * Represents a page loaded from the PDF document.
 * ```typescript
 * // Load an existing PDF document
 * let document: PdfDocument = new PdfDocument(data);
 * // Access first page
 * let page: PdfPage = document.getPage(0);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfPage = /** @class */ (function () {
    /**
     * Represents a loaded page of the PDF document.
     *
     * @private
     * @param {_PdfCrossReference} crossReference Cross reference object.
     * @param {number} pageIndex page index.
     * @param {_PdfDictionary} dictionary page Dictionary.
     * @param {_PdfReference} reference page reference.
     */
    function PdfPage(crossReference, pageIndex, dictionary, reference) {
        /**
         * Indicates whether annotations have been parsed.
         *
         * @private
         */
        this._isAnnotationParsed = false;
        /**
         * Indicates whether this page is newly created.
         *
         * @private
         */
        this._isNew = false;
        /**
         * Indicates whether this page is a duplicate of another.
         *
         * @private
         */
        this._isDuplicate = false;
        /**
         * Indicates whether the current operation pertains to a line annotation.
         *
         * @private
         */
        this._isLineAnnotation = false;
        /**
         * Indicates whether the page content was accessed before template rendering started.
         *
         * @private
         */
        this._accessedBeforeTemplate = false;
        /**
         * Indicates whether all templates have been rendered for the document or section.
         *
         * @private
         */
        this._templatesRendered = false;
        this._pageIndex = pageIndex;
        this._pageDictionary = dictionary;
        this._crossReference = crossReference;
        this._ref = reference;
    }
    Object.defineProperty(PdfPage.prototype, "annotations", {
        /**
         * Gets the collection of the page's annotations (Read only).
         *
         * @returns {PdfAnnotationCollection} Annotation collection.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the annotation collection
         * let annotations: PdfAnnotationCollection = page.annotations;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._annotations === 'undefined') {
                if (this._pageDictionary && this._pageDictionary.has('Annots')) {
                    var annots = this._getProperty('Annots');
                    if (_isNullOrUndefined(annots) && Array.isArray(annots)) {
                        var widgets_1;
                        if (this._crossReference._document._catalog._catalogDictionary.has('AcroForm')) {
                            widgets_1 = this._crossReference._document.form._parseWidgetReferences();
                        }
                        if (widgets_1 && widgets_1.length > 0) {
                            var validAnnotations_1 = [];
                            annots.forEach(function (entry) {
                                if (widgets_1.indexOf(entry) === -1) {
                                    validAnnotations_1.push(entry);
                                }
                            });
                            this._annotations = new PdfAnnotationCollection(validAnnotations_1, this._crossReference, this);
                        }
                        else {
                            this._annotations = new PdfAnnotationCollection(annots, this._crossReference, this);
                        }
                    }
                }
                if (typeof this._annotations === 'undefined') {
                    this._annotations = new PdfAnnotationCollection([], this._crossReference, this);
                }
                this._annotations._getAnnotations();
            }
            return this._annotations;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "size", {
        /**
         * Gets the size of the page (Read only).
         *
         * @returns {Size} The size of the PDF page.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the width and height of the PDF page as number array
         * let size: Size = page.size;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._size === 'undefined' || typeof this._size.width === 'undefined' || typeof this._size.height === 'undefined') {
                var mBox = _getInheritableProperty(this._pageDictionary, 'MediaBox', false, true, 'Parent', 'P');
                var cBox = _getInheritableProperty(this._pageDictionary, 'CropBox', false, true, 'Parent', 'P');
                var width = 0;
                var height = 0;
                var rotate = this._pageDictionary && this._pageDictionary.has('Rotate')
                    ? _getInheritableProperty(this._pageDictionary, 'Rotate', false, true, 'Parent')
                    : 0;
                cBox = this._parseBoxValues(cBox, 'CropBox');
                mBox = this._parseBoxValues(mBox, 'MediaBox');
                if (cBox && rotate !== null && typeof rotate !== 'undefined') {
                    width = cBox[2] - cBox[0];
                    height = cBox[3] - cBox[1];
                    var isValidCropBox = !(mBox && (mBox[2] - mBox[0]) < width);
                    if (!(((rotate === 0 || rotate === 180) && (width < height)) ||
                        ((rotate === 90 || rotate === 270) && (width > height) || isValidCropBox)) && (rotate === 0 && mBox)) {
                        width = mBox[2] - mBox[0];
                        height = mBox[3] !== 0 ? mBox[3] - mBox[1] : mBox[1];
                    }
                }
                else if (mBox) {
                    width = mBox[2] - mBox[0];
                    height = mBox[3] !== 0 ? mBox[3] - mBox[1] : mBox[1];
                }
                else {
                    this._pageDictionary.update('MediaBox', [0, 0, 612, 792]);
                    width = 612;
                    height = 792;
                }
                this._size = { width: Math.abs(width), height: Math.abs(height) };
            }
            return this._size;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "rotation", {
        /**
         * Gets the rotation angle of the page (Read only).
         *
         * @returns {PdfRotationAngle} Page rotation angle.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the rotation angle of the page
         * let rotation: PdfRotationAngle = page.rotation;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            var angle = 0;
            if (typeof this._rotation === 'undefined') {
                angle = _getInheritableProperty(this._pageDictionary, 'Rotate', false, true, 'Parent');
                if (angle < 0) {
                    angle += 360;
                }
                this._rotation = (typeof angle !== 'undefined') ? ((angle / 90) % 4) : PdfRotationAngle.angle0;
            }
            return this._rotation;
        },
        /**
         * Sets the rotation angle of the PDF page
         *
         * @param {PdfRotationAngle} value rotation angle.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Sets the rotation angle of the PDF page
         * page.rotate = PdfRotationAngle.angle90;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!this._isNew) {
                this._rotation = value;
                var rotate = Math.floor(this._rotation) * 90;
                if (rotate >= 360) {
                    rotate = rotate % 360;
                }
                this._pageDictionary.update('Rotate', rotate);
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "tabOrder", {
        /**
         * Gets the tab order of a PDF form field.
         *
         * @returns {PdfFormFieldsTabOrder} tab order.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the tab order of a PDF form field.
         * let tabOrder: PdfFormFieldsTabOrder = page.tabOrder;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._obtainTabOrder();
        },
        /**
         * Sets the tab order of a PDF form field.
         *
         * @param {PdfFormFieldsTabOrder} value tab order.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Sets the tab order of a PDF form field.
         * page.tabOrder = PdfFormFieldsTabOrder.row;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            this._tabOrder = value;
            var tabs = '';
            if (this._tabOrder !== PdfFormFieldsTabOrder.none) {
                if (this._tabOrder === PdfFormFieldsTabOrder.row) {
                    tabs = 'R';
                }
                else if (this._tabOrder === PdfFormFieldsTabOrder.column) {
                    tabs = 'C';
                }
                else if (this._tabOrder === PdfFormFieldsTabOrder.structure) {
                    tabs = 'S';
                }
            }
            this._pageDictionary.update('Tabs', _PdfName.get(tabs));
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "cropBox", {
        /**
         * Gets the bounds that define the area intended for display or printing in the PDF viewer application (Read only).
         *
         * @returns {number[]} Page size as number array.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the cropBox of the PDF page as number array
         * let cropBox: number[] = page.cropBox;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._cBox === 'undefined') {
                this._cBox = _getInheritableProperty(this._pageDictionary, 'CropBox', false, true, 'Parent', 'P');
            }
            if (typeof this._cBox === 'undefined') {
                this._cBox = [0, 0, 0, 0];
            }
            return this._cBox;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "mediaBox", {
        /**
         * Gets the size that specify the width and height of the page (Read only).
         *
         * @returns {number[]} Page size as number array.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the mediaBox of the PDF page as number array
         * let mediaBox: number[] = page.mediaBox;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._mBox === 'undefined') {
                this._mBox = _getInheritableProperty(this._pageDictionary, 'MediaBox', false, true, 'Parent', 'P');
            }
            if (typeof this._mBox === 'undefined') {
                this._mBox = [0, 0, 0, 0];
            }
            return this._mBox;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "orientation", {
        /**
         * Gets the orientation of the page (Read only).
         *
         * @returns {PdfPageOrientation} Page orientation.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the orientation of the PDF page
         * let orientation: number[] = page.orientation;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._orientation === 'undefined') {
                if (typeof this.size !== 'undefined') {
                    var size = this.size;
                    if (size.width > size.height) {
                        this._orientation = PdfPageOrientation.landscape;
                    }
                    else {
                        this._orientation = PdfPageOrientation.portrait;
                    }
                }
            }
            return this._orientation;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "_origin", {
        /**
         * Gets the origin coordinates derived from the MediaBox.
         *
         * @returns {number[]} Origin as a two-element array [x, y].
         */
        get: function () {
            if (typeof this._o === 'undefined' || (this._o[0] === 0 && this._o[1] === 0)) {
                this._o = [this.mediaBox[0], this._mBox[1]];
            }
            return this._o;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPage.prototype, "graphics", {
        /**
         * Gets the graphics of the page (Read only).
         *
         * @returns {PdfGraphics} Page graphics.
         *
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access first page
         * let page: PdfPage = document.getPage(0);
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * //Create a new pen.
         * let pen: PdfPen = new PdfPen({r: 0, g: 0, b: 0}, 1);
         * //Draw line on the page graphics.
         * graphics.drawLine(pen, {x: 10, y: 10}, {x: 100, y: 100});
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (typeof this._g === 'undefined' || this._needInitializeGraphics) {
                this._parseGraphics();
            }
            else {
                if (this._crossReference && this._crossReference._document &&
                    this._crossReference._document._hasTemplateContentValue && !this._templatesRendered &&
                    !this._crossReference._document._templateRenderingStarted) {
                    this._accessedBeforeTemplate = true;
                }
            }
            return this._g;
        },
        enumerable: true,
        configurable: true
    });
    PdfPage.prototype.drawTextElement = function (element, locationOrBounds) {
        if (typeof element === 'undefined' || element === null) {
            throw new Error('PdfTextElement cannot be null or undefined');
        }
        if (typeof element.text !== 'string' || element.text.length === 0) {
            throw new Error('PdfTextElement.text must be a non-empty string');
        }
        if (typeof element.font === 'undefined' || element.font === null) {
            throw new Error('PdfTextElement.font is required');
        }
        if (typeof element.layoutFormat !== 'undefined' && element.layoutFormat !== null && !(element.layoutFormat instanceof PdfLayoutFormat)) {
            throw new Error('PdfTextElement.layoutFormat must be an instance of PdfLayoutFormat');
        }
        var bounds = this.graphics._isRectangle(locationOrBounds) ?
            { x: locationOrBounds.x, y: locationOrBounds.y, width: locationOrBounds.width, height: locationOrBounds.height } :
            { x: locationOrBounds.x, y: locationOrBounds.y, width: 0, height: 0 };
        var brush = element.brush ? element.brush : new PdfBrush({ r: 0, g: 0, b: 0 });
        if (element.layoutFormat || (typeof bounds.width === 'number' && typeof bounds.height === 'number' && (bounds.width > 0 || bounds.height > 0))) {
            var params = new _PdfLayoutParameters();
            var actualBounds = this._getActualBounds(this._pageSettings);
            if (bounds.y < 0) {
                bounds.y = 0;
            }
            if (bounds.height === 0) {
                bounds.height = actualBounds[3] - bounds.y;
            }
            else {
                var maxHeight = actualBounds[3] - bounds.y;
                if (bounds.height > maxHeight) {
                    bounds.height = maxHeight;
                }
            }
            params._page = this;
            params._bounds = [bounds.x, bounds.y, bounds.width, bounds.height];
            params._format = element.layoutFormat ? element.layoutFormat : new PdfLayoutFormat();
            params._graphics = this.graphics;
            return this._layoutTextElement(params, element);
        }
        this.graphics.drawString(element.text, element.font, bounds, element.pen, brush, element.stringFormat);
        return new PdfLayoutResult(this, bounds);
    };
    /**
     * Adds a widget annotation reference to the page's Annots array.
     *
     * @private
     * @param {_PdfReference} reference Widget annotation reference to add.
     * @returns {void} nothing.
     */
    PdfPage.prototype._addWidget = function (reference) {
        var annots;
        if (this._pageDictionary.has('Annots')) {
            var annotsRef = this._pageDictionary.getRaw('Annots'); // eslint-disable-line
            annots = this._getProperty('Annots');
            if (annotsRef && annotsRef instanceof _PdfReference) {
                delete this._pageDictionary._map.Annots;
                this._pageDictionary.update('Annots', annots);
            }
        }
        if (annots && Array.isArray(annots)) {
            annots.push(reference);
        }
        else {
            this._pageDictionary.update('Annots', [reference]);
        }
        this._pageDictionary._updated = true;
    };
    /**
     * Resolves an inheritable page property from the page tree.
     *
     * @private
     * @param {string} key The dictionary key to fetch.
     * @param {boolean} [getArray=false] Whether to return an array value as-is.
     * @returns {any} Resolved value or merged dictionary.
     */
    PdfPage.prototype._getProperty = function (key, getArray) {
        if (getArray === void 0) { getArray = false; }
        var value = _getInheritableProperty(this._pageDictionary, key, getArray, false); // eslint-disable-line
        if (!Array.isArray(value)) {
            return value;
        }
        if (value.length === 1 || !(value[0] instanceof _PdfDictionary)) {
            return value[0];
        }
        return _PdfDictionary.merge(this._crossReference, value);
    };
    /**
     * Initializes content streams and graphics for drawing operations.
     *
     * @private
     * @returns {void} nothing.
     */
    PdfPage.prototype._parseGraphics = function () {
        this._loadContents();
        var saveStream = new _PdfContentStream([32, 113, 32, 10]);
        var saveReference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(saveReference, saveStream);
        this._contents.splice(0, 0, saveReference);
        var restoreStream = new _PdfContentStream([32, 81, 32, 10]);
        var restoreReference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(restoreReference, restoreStream);
        this._contents.push(restoreReference);
        var contentStream = new _PdfContentStream([]);
        var contentReference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(contentReference, contentStream);
        this._contents.push(contentReference);
        this._pageDictionary.set('Contents', this._contents);
        this._pageDictionary._updated = true;
        this._initializeGraphics(contentStream);
    };
    /**
     * Loads the page's Contents entry into the internal reference list.
     *
     * @private
     * @returns {void} nothing.
     */
    PdfPage.prototype._loadContents = function () {
        var contents = this._pageDictionary.getRaw('Contents'); // eslint-disable-line
        var ref;
        if (contents !== null && typeof contents !== 'undefined' && contents instanceof _PdfReference) {
            ref = contents;
            contents = this._crossReference._fetch(ref);
        }
        if (contents && contents instanceof _PdfBaseStream) {
            this._contents = [ref];
        }
        else if (contents && Array.isArray(contents)) {
            this._contents = contents;
        }
        else {
            this._contents = [];
        }
    };
    /**
     * Creates the graphics context and applies initial transforms and rotation.
     *
     * @private
     * @param {_PdfContentStream} stream Target content stream to draw into.
     * @returns {void} nothing.
     */
    PdfPage.prototype._initializeGraphics = function (stream) {
        var isInvalidCase = false;
        var llx = 0;
        var lly = 0;
        var urx = 0;
        var ury = 0;
        var size = this.size;
        var mbox = this.mediaBox;
        if (mbox && mbox.length >= 4) {
            llx = mbox[0];
            lly = mbox[1];
            urx = mbox[2];
            ury = mbox[3];
        }
        var cbox;
        if (this._pageDictionary.has('CropBox')) {
            cbox = this.cropBox;
            if (cbox && cbox.length >= 4) {
                var cx = cbox[0];
                var cy = cbox[1];
                var crx = cbox[2];
                var cry = cbox[3];
                var isValid = (cx < 0 || cy < 0 || crx < 0 || cry < 0) &&
                    (Math.floor(Math.abs(cy)) === Math.floor(Math.abs(size.height))) &&
                    (Math.floor(Math.abs(cx)) === Math.floor(Math.abs(size.width)));
                if (isValid) {
                    this._g = new PdfGraphics({ width: Math.max(cx, crx), height: Math.max(cy, cry) }, stream, this._crossReference, this);
                }
                else {
                    this._g = new PdfGraphics(size, stream, this._crossReference, this);
                    this._g._cropBox = cbox;
                }
            }
            else {
                this._g = new PdfGraphics(size, stream, this._crossReference, this);
            }
        }
        else if ((llx < 0 || lly < 0 || urx < 0 || ury < 0) &&
            (Math.floor(Math.abs(lly)) === Math.floor(Math.abs(size.height))) &&
            (Math.floor(Math.abs(urx)) === Math.floor(Math.abs(size.width)))) {
            var width = Math.max(llx, urx);
            var height = Math.max(lly, ury);
            if (width <= 0 || height <= 0) {
                isInvalidCase = true;
                if (llx < 0) {
                    llx = -llx;
                }
                if (lly < 0) {
                    lly = -lly;
                }
                if (urx < 0) {
                    urx = -urx;
                }
                if (ury < 0) {
                    ury = -ury;
                }
                width = Math.max(llx, urx);
                height = Math.max(lly, ury);
            }
            this._g = new PdfGraphics({ width: width, height: height }, stream, this._crossReference, this);
        }
        else {
            this._g = new PdfGraphics(size, stream, this._crossReference, this);
        }
        if (this._pageDictionary.has('MediaBox')) {
            this._g._mediaBoxUpperRightBound = isInvalidCase ? -lly : ury;
        }
        this._graphicsState = this._g.save();
        var origin = this._origin;
        if ((origin[0] >= 0 && origin[1] >= 0) || Math.sign(origin[0]) !== Math.sign(origin[1])) {
            this._g._initializeCoordinates();
        }
        else {
            this._g._initializeCoordinates(this);
        }
        if (!this._isNew) {
            var rotation = this.rotation;
            if (!Number.isNaN(rotation) && (rotation !== PdfRotationAngle.angle0 || this._pageDictionary.has('Rotate'))) {
                var rotate = void 0;
                if (this._pageDictionary.has('Rotate')) {
                    rotate = this._pageDictionary.get('Rotate');
                }
                else {
                    rotate = rotation * 90;
                }
                var clip = this._g._clipBounds;
                if (rotate === 90) {
                    this._g.translateTransform({ x: 0, y: size.height });
                    this._g.rotateTransform(-90);
                    this._g._clipBounds = [clip[0], clip[1], size.width, size.height];
                }
                else if (rotate === 180) {
                    this._g.translateTransform({ x: size.width, y: size.height });
                    this._g.rotateTransform(-180);
                }
                else if (rotate === 270) {
                    this._g.translateTransform({ x: size.width, y: 0 });
                    this._g.rotateTransform(-270);
                    this._g._clipBounds = [clip[0], clip[1], size.height, size.width];
                }
            }
        }
        if (this._isNew && this._pageSettings && !this._isLineAnnotation) {
            var clipBounds = this._getActualBounds(this._pageSettings);
            if (!this._crossReference._document._hasTemplateContentValue) {
                this._g._clipTranslateMargins(clipBounds);
            }
            else {
                var bounds = [
                    clipBounds[0],
                    clipBounds[1],
                    this._pageSettings.margins._left,
                    this._pageSettings.margins._top,
                    this._pageSettings.margins._right,
                    this._pageSettings.margins._bottom
                ];
                this._g._clipTranslateMarginsWithBounds(bounds);
            }
        }
        this._needInitializeGraphics = false;
    };
    /**
     * Computes the effective drawable content bounds of the page by excluding
     * both page margins and the space reserved for document templates on all sides.
     *
     * @private
     * @param {PdfPageSettings} pageSettings - The page settings that define the page size and margins.
     * @param {boolean} [includeMargins] - Specifies whether the calculation should use the full page size
     * (including margins) or the already adjusted content size.
     * @returns {number[]} An array representing the computed bounds in the format:
     * [x, y, width, height], where:
     * - x: left offset including margin and left template space
     * - y: top offset including margin and top template space
     * - width: usable width after excluding left and right template spaces
     * - height: usable height after excluding top and bottom template spaces.
     */
    PdfPage.prototype._getActualBounds = function (pageSettings, includeMargins) {
        var actualSize = includeMargins ? [pageSettings.size.width, pageSettings.size.height] : pageSettings._getActualSize();
        var templateReserved = this._getTemplateReservedSpace(includeMargins);
        return [
            pageSettings.margins.left + templateReserved[3],
            pageSettings.margins.top + templateReserved[0],
            actualSize[0] - templateReserved[3] - templateReserved[1],
            actualSize[1] - templateReserved[0] - templateReserved[2]
        ];
    };
    /**
     * Calculates the effective template bounds of the page by excluding space
     * reserved for other document templates on each side.
     *
     * @private
     * @param {PdfPageSettings} pageSettings - The page settings that determine the actual page size.
     * @param {boolean} [includeMargins] - Specifies whether page margins should be included in the reserved space calculation.
     * @returns {number[]} An array representing the effective bounds in the format: * [x, y, width, height], where:
     * - x: left offset
     * - y: top offset
     * - width: available width after excluding left and right reserved space
     * - height: available height after excluding top and bottom reserved space
     */
    PdfPage.prototype._getActualTemplateBounds = function (pageSettings, includeMargins) {
        var actualSize = pageSettings._getActualSize();
        var templateReserved = this._getTemplateReservedSpace(includeMargins);
        return [
            templateReserved[3],
            templateReserved[0],
            actualSize[0] - templateReserved[3] - templateReserved[1],
            actualSize[1] - templateReserved[0] - templateReserved[2]
        ];
    };
    /**
     * Calculates the space reserved by document templates on all four edges.
     *
     * @private
     * @param {boolean} includeMargins - Indicates whether page margins should be
     * included along with template space in the calculation.
     * @returns {number[]} An array representing the reserved space in the order: [top, right, bottom, left], in page units.
     */
    PdfPage.prototype._getTemplateReservedSpace = function (includeMargins) {
        var margin = includeMargins ? true : false;
        var top = this._crossReference._document._getTopIndentHeight(this, margin);
        var right = this._crossReference._document._getRightIndentWidth(this, margin);
        var bottom = this._crossReference._document._getBottomIndentHeight(this, margin);
        var left = this._crossReference._document._getLeftIndentWidth(this, margin);
        return [top, right, bottom, left];
    };
    /**
     * Fetches or creates the resources dictionary for the page.
     *
     * @private
     * @returns {_PdfDictionary} Resources dictionary.
     */
    PdfPage.prototype._fetchResources = function () {
        if (typeof this._resourceObject === 'undefined') {
            if (this._pageDictionary && this._pageDictionary.has('Resources')) {
                var obj = this._pageDictionary.getRaw('Resources'); // eslint-disable-line
                if (obj !== null && typeof obj !== 'undefined' && obj instanceof _PdfReference) {
                    this._hasResourceReference = true;
                    this._resourceObject = this._crossReference._fetch(obj);
                }
                else if (obj && obj instanceof _PdfDictionary) {
                    this._resourceObject = obj;
                }
            }
            else {
                this._resourceObject = new _PdfDictionary(this._crossReference);
                this._pageDictionary.update('Resources', this._resourceObject);
            }
        }
        return this._resourceObject;
    };
    /**
     * Returns the CropBox or MediaBox of the page, preferring CropBox when available.
     *
     * @private
     * @returns {number[]} The selected box array.
     */
    PdfPage.prototype._getCropOrMediaBox = function () {
        var box;
        if (this._pageDictionary) {
            if (this._pageDictionary.has('CropBox')) {
                box = this._pageDictionary.getArray('CropBox');
            }
            else if (this._pageDictionary.has('MediaBox')) {
                box = this._pageDictionary.getArray('MediaBox');
            }
        }
        return box;
    };
    /**
     * Finalizes the graphics state and marks that graphics need reinitialization on next access.
     *
     * @private
     * @returns {void}
     */
    PdfPage.prototype._beginSave = function () {
        if (typeof this._graphicsState !== 'undefined') {
            this.graphics.restore(this._graphicsState);
            this._graphicsState = null;
            this._needInitializeGraphics = true;
        }
    };
    /**
     * Releases page resources and cached values.
     *
     * @private
     * @returns {void}
     */
    PdfPage.prototype._destroy = function () {
        this._pageDictionary = undefined;
        this._size = undefined;
        this._mBox = undefined;
        this._cBox = undefined;
        this._o = undefined;
        this._g = undefined;
        this._graphicsState = undefined;
        this._contents = undefined;
    };
    /**
     * Resolves the current tab order from the page dictionary.
     *
     * @private
     * @returns {PdfFormFieldsTabOrder} The resolved tab order.
     */
    PdfPage.prototype._obtainTabOrder = function () {
        if (this._pageDictionary && this._pageDictionary.has('Tabs')) {
            var tabOrder = this._pageDictionary.get('Tabs');
            if (tabOrder === _PdfName.get('R')) {
                this._tabOrder = PdfFormFieldsTabOrder.row;
            }
            else if (tabOrder === _PdfName.get('C')) {
                this._tabOrder = PdfFormFieldsTabOrder.column;
            }
            else if (tabOrder === _PdfName.get('S')) {
                this._tabOrder = PdfFormFieldsTabOrder.structure;
            }
            else if (tabOrder === _PdfName.get('W')) {
                this._tabOrder = PdfFormFieldsTabOrder.widget;
            }
        }
        if (this._tabOrder === null || typeof this._tabOrder === 'undefined') {
            this._tabOrder = PdfFormFieldsTabOrder.none;
        }
        return this._tabOrder;
    };
    /**
     * Removes the specified annotation reference from the page's Annots array.
     *
     * @private
     * @param {_PdfReference} reference Annotation reference to remove.
     * @returns {void} nothing.
     */
    PdfPage.prototype._removeAnnotation = function (reference) {
        if (this._pageDictionary && this._pageDictionary.has('Annots')) {
            var annots = this._getProperty('Annots');
            if (_isNullOrUndefined(annots) && Array.isArray(annots)) {
                annots = annots.filter(function (item) { return item !== reference; });
                this._pageDictionary.set('Annots', annots);
                this._pageDictionary._updated = true;
            }
        }
    };
    Object.defineProperty(PdfPage.prototype, "_contentTemplate", {
        /**
         * Gets the page's combined content as a reusable template.
         *
         * @returns {PdfTemplate} Generated template containing the page content.
         */
        get: function () {
            this._fetchResources();
            var targetArray = this._combineContent();
            var targetStream = new _PdfContentStream(Array.from(targetArray));
            var template = new PdfTemplate(targetStream, this._crossReference);
            template._content.dictionary.set('Resources', this._resourceObject);
            if (this.cropBox[0] > 0 || this.cropBox[1] > 0) {
                template._content.dictionary.set('BBox', this.cropBox);
                if (_areArrayEqual(this.cropBox, this.mediaBox)) {
                    template._size = { width: this.cropBox[0], height: this.cropBox[1] };
                }
                else {
                    template._size = { width: this.cropBox[2], height: this.cropBox[3] };
                }
            }
            else if (this.mediaBox[0] > 0 || this.mediaBox[1] > 0) {
                template._content.dictionary.set('BBox', this.mediaBox);
                template._size = { width: this.mediaBox[0], height: this.mediaBox[1] };
            }
            else {
                template._content.dictionary.set('BBox', [0, 0, this.size.width, this.size.height]);
                template._size = { width: this.size.width, height: this.size.height };
            }
            return template;
        },
        enumerable: true,
        configurable: true
    });
    PdfPage.prototype._combineIntoSingleArray = function (arrays) {
        var totalLength = arrays.reduce(function (length, arr) { return length + arr.length; }, 0);
        var targetArray = new Uint8Array(totalLength);
        var offset = 0;
        arrays.forEach(function (sourceArray) {
            targetArray.set(sourceArray, offset);
            offset += sourceArray.length;
        });
        return targetArray;
    };
    /**
     * Concatenates multiple byte arrays into a single array.
     *
     * @private
     * @returns {Uint8Array} Combined array.
     */
    PdfPage.prototype._combineContent = function () {
        var _this = this;
        var list = [];
        var array;
        this._loadContents();
        list.push(new Uint8Array([32, 113, 32, 10]));
        var contents = this._contents;
        contents.forEach(function (reference) {
            var base = _this._crossReference._fetch(reference); // eslint-disable-line
            if (base) {
                if (base instanceof _PdfContentStream) {
                    array = new Uint8Array(base._bytes);
                }
                else if (base instanceof _PdfBaseStream) {
                    array = base.getBytes();
                }
                if (array) {
                    list.push(array);
                    list.push(new Uint8Array([13, 10]));
                }
            }
        });
        list.push(new Uint8Array([32, 81, 32, 10]));
        list.push(new Uint8Array([13, 10]));
        var targetArray = this._combineIntoSingleArray(list);
        return targetArray;
    };
    /**
     * Lays out and renders text within layout bounds, supporting column flow and pagination.
     *
     * @private
     * @param {_PdfLayoutParameters} params Layout parameters defining page context, bounds, and layout behavior.
     * @param {PdfTextElement} element Text element containing content, font, brush, and formatting information.
     * @returns {PdfLayoutResult} The layout result containing the final page, bounds, and any remaining text.
     */
    PdfPage.prototype._layoutTextElement = function (params, element) {
        var format = params._format;
        var text = element.text ? element.text : '';
        var page = params._page;
        var initialBounds = params._bounds.slice();
        var paginateBounds = format && format.paginateBounds;
        var usePaginateBounds = format && format.usePaginateBounds && paginateBounds;
        var result;
        var isFirstPage = true;
        var hasDrawnAfterFirstPage = false;
        while (text.length > 0) {
            var bounds = void 0;
            if (isFirstPage) {
                bounds = initialBounds.slice();
            }
            else if (usePaginateBounds) {
                bounds = [paginateBounds.x, paginateBounds.y, paginateBounds.width, paginateBounds.height];
            }
            else {
                bounds = [initialBounds[0], 0, initialBounds[2], initialBounds[3]];
            }
            var previousText = text;
            result = this._layoutOnPage(text, page, bounds, params, element);
            text = result.remainingText ? result.remainingText : '';
            if (format.layout === PdfLayoutType.onePage &&
                format.break === PdfLayoutBreakType.fitElement) {
                return result;
            }
            if ((format.break === PdfLayoutBreakType.fitElement
                || format.break === PdfLayoutBreakType.fitPage) &&
                isFirstPage && text === previousText) {
                var document_1 = page._crossReference._document;
                page = page._pageIndex + 1 < document_1.pageCount
                    ? document_1.getPage(page._pageIndex + 1)
                    : document_1.addPage();
                isFirstPage = false;
                continue;
            }
            if (result._hasRenderedContent && !isFirstPage) {
                hasDrawnAfterFirstPage = true;
            }
            var breakType = format.break;
            if (format.layout === PdfLayoutType.paginate &&
                breakType === PdfLayoutBreakType.fitElement &&
                hasDrawnAfterFirstPage) {
                return result;
            }
            if (text === previousText) {
                break;
            }
            if (!text || text.length === 0) {
                break;
            }
            if (format.layout === PdfLayoutType.onePage) {
                break;
            }
            var document_2 = page._crossReference._document;
            page = page._pageIndex + 1 < document_2.pageCount
                ? document_2.getPage(page._pageIndex + 1)
                : document_2.addPage();
            isFirstPage = false;
        }
        return result;
    };
    /**
     * Parses a PDF box array and updates _PdfReference entries to numeric values.
     *
     * @param {any[]} boxValues - Array containing box coordinates.
     * @param {string} key - Contains box name.
     * @returns {number[]} Parsed box values as a number array.
     */
    PdfPage.prototype._parseBoxValues = function (boxValues, key) {
        if (!Array.isArray(boxValues) || boxValues.length !== 4) {
            return boxValues;
        }
        var value = new Array(4);
        for (var i = 0; i < 4; i++) {
            var ref = boxValues[parseInt(i.toString(), 10)]; // eslint-disable-line
            if (!(ref instanceof _PdfReference)) {
                return boxValues;
            }
            value[parseInt(i.toString(), 10)] = Number(this._crossReference._fetch(ref));
        }
        this._pageDictionary.update(key, value);
        return value;
    };
    /**
     * Lays out and renders text within the specified bounds on a page, supporting multi-column flow and FitElement behavior, and returns layout details including remaining text.
     *
     * @private
     * @param {string} text The input text content to be processed and rendered.
     * @param {PdfPage} page The target page on which the text is laid out and drawn.
     * @param {number[]} bounds The layout bounds as [x, y, width, height].
     * @param {_PdfLayoutParameters} params Layout parameters providing page context and formatting options.
     * @param {PdfTextElement} element The text element containing font, brush, and formatting settings.
     * @returns {PdfLayoutResult} The result containing the rendered bounds, last line info, and any remaining text.
     */
    PdfPage.prototype._layoutOnPage = function (text, page, bounds, params, element) {
        var font = element.font;
        var brush = element.brush ? element.brush : new PdfBrush({ r: 0, g: 0, b: 0 });
        var format = params._format;
        var stringFormat = element.stringFormat ? element.stringFormat : new PdfStringFormat();
        var layouter = new _PdfStringLayouter();
        var clientHeight = page.graphics.clientSize.height;
        var availableHeight = clientHeight - bounds[1];
        var columns = format && format._columns ? Math.max(1, format._columns) : 1;
        var gutter = format && format._columnGutter ? format._columnGutter : 0;
        var totalWidth = bounds[2];
        var columnWidth = (totalWidth - (columns - 1) * gutter) / columns;
        var tempText = text;
        for (var col = 0; col < columns && tempText.length > 0; col++) {
            var lr = layouter._layout(tempText, font, stringFormat, [columnWidth, availableHeight]);
            if (lr._empty) {
                return new PdfLayoutResult(page, { x: bounds[0], y: bounds[1], width: 0, height: 0 }, undefined, tempText);
            }
            tempText = lr._remainder ? lr._remainder : '';
        }
        var textFinished = !tempText || tempText.length === 0;
        var isFirstPage = page === params._page;
        if (format.break === PdfLayoutBreakType.fitElement && isFirstPage &&
            !textFinished) {
            return new PdfLayoutResult(page, { x: bounds[0], y: bounds[1], width: 0, height: 0 }, undefined, text);
        }
        var remainingText = text;
        var lastBounds = { x: bounds[0], y: bounds[1], width: 0, height: 0 };
        var lastLineBounds = lastBounds;
        var didDraw = false;
        for (var col = 0; col < columns && remainingText.length > 0; col++) {
            var x = bounds[0] + col * (columnWidth + gutter);
            var y = bounds[1];
            var lr = layouter._layout(remainingText, font, stringFormat, [columnWidth, availableHeight]);
            if (lr._empty) {
                return new PdfLayoutResult(page, lastBounds, lastLineBounds, remainingText);
            }
            var remainder = lr._remainder ? lr._remainder : '';
            if (remainder === remainingText) {
                break;
            }
            var consumedLength = remainingText.length - remainder.length;
            var columnText = remainingText.substring(0, consumedLength);
            page.graphics.drawString(columnText, font, { x: x, y: y, width: columnWidth,
                height: lr._actualSize.height }, brush, stringFormat);
            didDraw = true;
            lastBounds = { x: x, y: y, width: lr._actualSize.width, height: lr._actualSize.height };
            lastLineBounds = { x: x, y: y + Math.max(0, lr._actualSize.height - lr._lineHeight),
                width: lr._actualSize.width, height: lr._lineHeight };
            remainingText = remainder;
        }
        var result = new PdfLayoutResult(page, lastBounds, lastLineBounds, remainingText);
        result._hasRenderedContent = didDraw;
        return result;
    };
    PdfPage.prototype._getSectionIndex = function () {
        var parent = this._pageDictionary.getRaw('Parent');
        if (!parent) {
            return -1;
        }
        var document = this._crossReference._document;
        return document._getSectionIndexByPage(parent);
    };
    return PdfPage;
}());
export { PdfPage };
/**
 * `PdfDestination` class represents the PDF destination.
 * ```typescript
 * // Load an existing PDF document
 * let document: PdfDocument = new PdfDocument(data, password);
 * // Access the annotation at index 0
 * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
 * // Initializes a new instance of the `PdfDestination` class.
 * let destination: PdfDestination = new PdfDestination();
 * // Sets the zoom factor.
 * destination.zoom = 20;
 * // Sets the page where the destination is situated.
 * destination.page = page;
 * // Sets the mode of the destination.
 * destination.mode = PdfDestinationMode.fitToPage;
 * // Sets the location of the destination.
 * destination.location = {x: 20, y: 20};
 * // Sets the bounds of the destination.
 * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
 * // Sets destination to  document link annotation.
 * annotation.destination = destination;
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfDestination = /** @class */ (function () {
    function PdfDestination(arg1, arg2, arg3) {
        /**
         * @private
         */
        this._location = { x: 0, y: 0 };
        /**
         * @private
         */
        this._destinationMode = PdfDestinationMode.location;
        /**
         * @private
         */
        this._zoom = 0;
        /**
         * @private
         */
        this._isValid = true;
        /**
         * @private
         */
        this._destinationBounds = { x: 0, y: 0, width: 0, height: 0 };
        /**
         * @private
         */
        this._array = Array(); // eslint-disable-line
        if (typeof arg1 !== 'undefined' && arg1 !== null) {
            if (arg1.rotation === PdfRotationAngle.angle180) {
                this._location = { x: arg1.graphics._size.width, y: this._location.y };
            }
            else if (arg1.rotation === PdfRotationAngle.angle90) {
                this._location = { x: 0, y: 0 };
            }
            else if (arg1.rotation === PdfRotationAngle.angle270) {
                this._location = { x: arg1.graphics._size.width, y: 0 };
            }
            else {
                this._location = { x: 0, y: this._location.y };
            }
            this._page = arg1;
            this._index = arg1._pageIndex;
        }
        if (arg2 !== null && typeof arg2 !== 'undefined') {
            this._location = { x: arg2.x, y: arg2.y };
            if ('width' in arg2 && 'height' in arg2 && typeof arg2.width === 'number' && typeof arg2.height === 'number') {
                this._destinationBounds = arg2;
            }
        }
        if (arg3 !== null && typeof arg3 !== 'undefined') {
            if ('mode' in arg3 && arg3.mode !== null && typeof arg3.mode !== 'undefined') {
                this.mode = arg3.mode;
            }
            if ('zoom' in arg3 && arg3.zoom !== null && typeof arg3.zoom !== 'undefined') {
                this.zoom = arg3.zoom;
            }
        }
    }
    Object.defineProperty(PdfDestination.prototype, "zoom", {
        /**
         * Gets the zoom factor.
         *
         * @returns {number} zoom.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * //Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = page.annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the zoom factor of the destination.
         * let zoom: number = annot.destination.zoom;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._zoom;
        },
        /**
         * Sets the zoom factor.
         *
         * @param {number} value zoom.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Initializes a new instance of the `PdfDestination` class.
         * let destination: PdfDestination = new PdfDestination();
         * // Sets the zoom factor.
         * destination.zoom = 20;
         * // Sets the page where the destination is situated.
         * destination.page = page;
         * // Sets the mode of the destination.
         * destination.mode = PdfDestinationMode.fitToPage;
         * // Sets the location of the destination.
         * destination.location = {x: 20, y: 20};
         * // Sets the bounds of the destination.
         * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
         * // Sets destination to  document link annotation.
         * annotation.destination = destination;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (value !== this._zoom) {
                this._zoom = value;
                this._initializePrimitive();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "page", {
        /**
         * Gets the page where the destination is situated.
         *
         * @returns {PdfPage} page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * //Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the page of the destination.
         * let page: PdfPage = annot.destination.page;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._page;
        },
        /**
         * Sets the page where the destination is situated.
         *
         * @param {PdfPage} value page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Initializes a new instance of the `PdfDestination` class.
         * let destination: PdfDestination = new PdfDestination();
         * // Sets the zoom factor.
         * destination.zoom = 20;
         * // Sets the page where the destination is situated.
         * destination.page = page;
         * // Sets the mode of the destination.
         * destination.mode = PdfDestinationMode.fitToPage;
         * // Sets the location of the destination.
         * destination.location = {x: 20, y: 20};
         * // Sets the bounds of the destination.
         * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
         * // Sets destination to  document link annotation.
         * annotation.destination = destination;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (value !== this._page) {
                this._page = value;
                this._initializePrimitive();
                this._index = value._pageIndex;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "pageIndex", {
        /**
         * Gets the page index of bookmark destination (Read only).
         *
         * @returns {number} index.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * //Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the page index of the destination.
         * let pageIndex: number = annot.destination.pageIndex;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._index;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "mode", {
        /**
         * Gets the mode of the destination.
         *
         * @returns {PdfDestinationMode} page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * //Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the mode of the destination.
         * let mode: PdfDestinationMode = annot.destination.mode;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._destinationMode;
        },
        /**
         * Sets the mode of the destination.
         *
         * @param {PdfDestinationMode} value page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Initializes a new instance of the `PdfDestination` class.
         * let destination: PdfDestination = new PdfDestination();
         * // Sets the zoom factor.
         * destination.zoom = 20;
         * // Sets the page where the destination is situated.
         * destination.page = page;
         * // Sets the mode of the destination.
         * destination.mode = PdfDestinationMode.fitToPage;
         * // Sets the location of the destination.
         * destination.location = {x: 20, y: 20};
         * // Sets the bounds of the destination.
         * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
         * // Sets destination to document link annotation.
         * annotation.destination = destination;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (value !== this._destinationMode) {
                this._destinationMode = value;
                this._initializePrimitive();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "location", {
        /**
         * Gets the location of the destination.
         *
         * @returns {Point} page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the location of the destination.
         * let location: Point = annot.destination.location;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._location;
        },
        /**
         * Sets the location of the destination.
         *
         * @param {Point} value page.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Initializes a new instance of the `PdfDestination` class.
         * let destination: PdfDestination = new PdfDestination();
         * // Sets the zoom factor.
         * destination.zoom = 20;
         * // Sets the page where the destination is situated.
         * destination.page = page;
         * // Sets the mode of the destination.
         * destination.mode = PdfDestinationMode.fitToPage;
         * // Sets the location of the destination.
         * destination.location = {x: 20, y: 20};
         * // Sets the bounds of the destination.
         * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
         * // Sets destination to  document link annotation.
         * annotation.destination = destination;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (value !== this._location) {
                this._location = value;
                this._initializePrimitive();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "destinationBounds", {
        /**
         * Gets the bounds of the destination.
         *
         * @returns {Rectangle} bounds.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets the bounds of the destination.
         * let destinationBounds: Rectangle = annot.destination.destinationBounds;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._destinationBounds;
        },
        /**
         * Sets the bounds of the destination.
         *
         * @param {Rectangle} value bounds.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annotation: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Initializes a new instance of the `PdfDestination` class.
         * let destination: PdfDestination = new PdfDestination();
         * // Sets the zoom factor.
         * destination.zoom = 20;
         * // Sets the page where the destination is situated.
         * destination.page = page;
         * // Sets the mode of the destination.
         * destination.mode = PdfDestinationMode.fitToPage;
         * // Sets the location of the destination.
         * destination.location = {x: 20, y: 20};
         * // Sets the bounds of the destination.
         * destination.destinationBounds = {x: 20, y: 20, width: 100, height: 50};
         * // Sets destination to  document link annotation.
         * annotation.destination = destination;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (value !== this._destinationBounds) {
                this._destinationBounds = value;
                this._initializePrimitive();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfDestination.prototype, "isValid", {
        /**
         * Gets a value indicating whether this instance is valid (Read only).
         *
         * @returns {boolean} value indicating whether this instance is valid.
         * ```typescript
         * // Load an existing PDF document
         * let document: PdfDocument = new PdfDocument(data, password);
         * // Access the annotation at index 0
         * let annot: PdfDocumentLinkAnnotation = document.getPage(0).annotations.at(0) as PdfDocumentLinkAnnotation;
         * // Gets a value indicating whether this instance is valid.
         * let isValid: boolean = annot.destination.isValid;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._isValid;
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Sets the internal validation flag for the destination.
     *
     * @private
     * @param {boolean} value True to mark as valid; otherwise false.
     * @returns {void} nothing.
     */
    PdfDestination.prototype._setValidation = function (value) {
        this._isValid = value;
    };
    /**
     * Builds the internal PDF array representation and updates the parent dictionary.
     *
     * @private
     * @returns {void}
     */
    PdfDestination.prototype._initializePrimitive = function () {
        this._array = [];
        var page = this._page;
        if (page && page._pageDictionary) {
            var element = page._pageDictionary;
            if (typeof element !== 'undefined' && element !== null) {
                this._array.push(this._page._ref);
            }
            switch (this._destinationMode) {
                case PdfDestinationMode.location:
                    this._array.push(_PdfName.get('XYZ'));
                    this._array.push(this._location.x);
                    this._array.push(this._page.graphics._size.height - this._location.y);
                    this._array.push(this._zoom);
                    break;
                case PdfDestinationMode.fitToPage:
                    this._array.push(_PdfName.get('Fit'));
                    break;
                case PdfDestinationMode.fitR:
                    this._array.push(_PdfName.get('FitR'));
                    this._array.push(this._destinationBounds.x);
                    this._array.push(this._destinationBounds.y);
                    this._array.push(this._destinationBounds.width);
                    this._array.push(this._destinationBounds.height);
                    break;
                case PdfDestinationMode.fitH:
                    this._array.push(_PdfName.get('FitH'));
                    this._array.push((typeof page !== 'undefined' && page !== null) ? page.size.height - this._location.y : 0);
                    break;
            }
            if (this._parent) {
                this._parent._dictionary.set(this._isBookmark ? 'Dest' : 'D', this._array);
                this._parent._dictionary._updated = true;
            }
        }
    };
    return PdfDestination;
}());
export { PdfDestination };
/**
 * Provides utilities to resolve and parse destination arrays from dictionaries and Names trees.
 *
 * @private
 */
var _PdfDestinationHelper = /** @class */ (function () {
    function _PdfDestinationHelper(dictionary, value) {
        if (dictionary && typeof value === 'string') {
            this._dictionary = dictionary;
            this._key = value;
        }
    }
    /**
     * Obtains the `PdfDestination` from the source dictionary or Names tree.
     *
     * @private
     * @returns {PdfDestination} Resolved destination instance, if any.
     */
    _PdfDestinationHelper.prototype._obtainDestination = function () {
        var destination;
        var page;
        var loadedDocument;
        if (!this._dictionary || (!this._dictionary.has(this._key) && !this._dictionary.has('D'))) {
            return undefined;
        }
        else if (this._dictionary && this._dictionary._crossReference && this._dictionary._crossReference._document) {
            loadedDocument = this._dictionary._crossReference._document;
        }
        if (this._dictionary.has('D')) {
            this._key = 'D';
        }
        var destinationArray = this._dictionary.getArray(this._key); // eslint-disable-line
        if ((typeof destinationArray === 'string' || (destinationArray instanceof _PdfName && typeof destinationArray.name === 'string')) && loadedDocument) {
            destinationArray = this._getDestination(destinationArray, loadedDocument);
        }
        var value; // eslint-disable-line
        if (Array.isArray(destinationArray) && destinationArray.length > 0) {
            value = destinationArray[0];
        }
        var mode;
        var left;
        var top;
        var bottom;
        var right;
        var zoom;
        var index;
        var topValue;
        var leftValue;
        if (typeof value === 'number') {
            index = value;
        }
        else if (value instanceof _PdfDictionary) {
            index = _getPageIndex(loadedDocument, value);
        }
        else if (value instanceof _PdfReference) {
            var pageDictionary = loadedDocument._crossReference._fetch(value);
            if (pageDictionary && pageDictionary instanceof _PdfDictionary) {
                index = _getPageIndex(loadedDocument, pageDictionary);
            }
        }
        if (!page && typeof index === 'number' && (index >= 0 && index < loadedDocument.pageCount)) {
            page = loadedDocument.getPage(index);
        }
        if (Array.isArray(destinationArray) && destinationArray.length > 0) {
            mode = destinationArray[1];
        }
        if (mode && page && destinationArray) {
            switch (mode.name) {
                case 'XYZ':
                    left = destinationArray[2];
                    top = destinationArray[3];
                    zoom = destinationArray[4];
                    topValue = typeof top === 'number' ? (page.size.height - top) : 0;
                    leftValue = typeof left === 'number' ? left : 0;
                    if (page.rotation !== PdfRotationAngle.angle0) {
                        topValue = _checkRotation(page, top, left);
                    }
                    destination = new PdfDestination(page, { x: leftValue, y: topValue });
                    destination._index = page._pageIndex;
                    destination.zoom = (typeof zoom !== 'undefined' && zoom !== null) ? zoom : 0;
                    if (left === null || top === null || zoom === null || typeof left === 'undefined' ||
                        typeof top === 'undefined' || typeof zoom === 'undefined') {
                        destination._setValidation(false);
                    }
                    break;
                case 'FitR':
                    if (destinationArray.length > 2) {
                        left = destinationArray[2];
                    }
                    if (destinationArray.length > 3) {
                        bottom = destinationArray[3];
                    }
                    if (destinationArray.length > 4) {
                        right = destinationArray[4];
                    }
                    if (destinationArray.length > 5) {
                        top = destinationArray[5];
                    }
                    left = (typeof left !== 'undefined' && left !== null) ? left : 0;
                    bottom = (typeof bottom !== 'undefined' && bottom !== null) ? bottom : 0;
                    right = (typeof right !== 'undefined' && right !== null) ? right : 0;
                    top = (typeof top !== 'undefined' && top !== null) ? top : 0;
                    destination = new PdfDestination(page, { x: left, y: bottom, width: right, height: top });
                    destination._index = page._pageIndex;
                    destination.mode = PdfDestinationMode.fitR;
                    break;
                case 'FitH':
                case 'FitBH':
                    if (destinationArray.length > 2) {
                        top = destinationArray[2];
                    }
                    topValue = typeof top === 'number' ? (page.size.height - top) : 0;
                    destination = new PdfDestination(page, { x: 0, y: topValue });
                    destination._index = page._pageIndex;
                    destination.mode = PdfDestinationMode.fitH;
                    if (top === null || typeof top === 'undefined') {
                        destination._setValidation(false);
                    }
                    break;
                case 'Fit':
                    destination = new PdfDestination(page);
                    destination._index = page._pageIndex;
                    destination.mode = PdfDestinationMode.fitToPage;
                    break;
            }
        }
        else if (Array.isArray(destinationArray)) {
            destination = new PdfDestination();
            if (destinationArray.length > 4) {
                zoom = destinationArray[4];
            }
            if (destinationArray.length > 1) {
                mode = destinationArray[1];
            }
            if (typeof zoom === 'number') {
                destination.zoom = zoom;
            }
            if (mode) {
                if (mode.name === 'Fit') {
                    destination.mode = PdfDestinationMode.fitToPage;
                }
                else if (mode.name === 'XYZ') {
                    if (destinationArray.length > 2) {
                        left = destinationArray[2];
                    }
                    if (destinationArray.length > 3) {
                        topValue = destinationArray[3];
                    }
                    if ((typeof left === 'undefined' || left === null) || (typeof topValue === 'undefined' || topValue === null)
                        || (typeof zoom === 'undefined' || zoom === null)) {
                        destination._setValidation(false);
                    }
                }
            }
            if (typeof index === 'number' && (index >= 0 && index < loadedDocument.pageCount)) {
                destination._index = index;
            }
        }
        return destination;
    };
    /**
     * Looks up a destination array by name from the document.
     *
     * @private
     * @param {_PdfName | string} name Named destination identifier.
     * @param {PdfDocument} document Document to search.
     * @returns {any[]} The resolved destination array if found.
     */
    _PdfDestinationHelper.prototype._getDestination = function (name, document) {
        var destinationArray; // eslint-disable-line
        if (document) {
            destinationArray = this._getNamedDestination(document, name);
        }
        return destinationArray;
    };
    /**
     * Resolves a named destination from the Names tree or Dests dictionary.
     *
     * @private
     * @param {PdfDocument} document Source document.
     * @param {_PdfName | string} result Name key to resolve.
     * @returns {any[]} Destination array or undefined.
     */
    _PdfDestinationHelper.prototype._getNamedDestination = function (document, result) {
        var destination; // eslint-disable-line
        var catalog = document._catalog;
        if (catalog && catalog._catalogDictionary) {
            if (result && typeof result === 'string') {
                if (catalog._catalogDictionary.has('Names')) {
                    var names = catalog._catalogDictionary.get('Names');
                    if (names && names.has('Dests')) {
                        var kids = names.get('Dests');
                        if (kids) {
                            var ref = this._getNamedObjectFromTree(kids, result);
                            destination = this._extractDestination(ref, document);
                        }
                    }
                }
            }
            else if (result && result instanceof _PdfName) {
                var destinations = catalog._catalogDictionary.get('Dests');
                if (destinations) {
                    destination = destinations.get(result.name);
                }
            }
        }
        return destination;
    };
    /**
     * Extracts a destination array from a referenced dictionary or array.
     *
     * @private
     * @param {any} ref Reference or array pointing to a destination.
     * @param {PdfDocument} document Document to use for dereferencing.
     * @returns {any[]} The destination array if available.
     */
    _PdfDestinationHelper.prototype._extractDestination = function (ref, document) {
        var dict; // eslint-disable-line
        var destinationArray; // eslint-disable-line
        if (ref && ref instanceof _PdfReference) {
            dict = document._crossReference._fetch(ref);
        }
        if (dict) {
            if (dict instanceof _PdfDictionary && dict.has('D')) {
                destinationArray = dict.getRaw('D');
            }
            else if (Array.isArray(dict)) {
                destinationArray = dict;
            }
        }
        return destinationArray ? destinationArray : ref;
    };
    /**
     * Traverses the Names tree to find a named object reference.
     *
     * @private
     * @param {_PdfDictionary} kids Current node in the Names tree.
     * @param {string} name Name to locate.
     * @returns {_PdfReference} Reference to the matching named object.
     */
    _PdfDestinationHelper.prototype._getNamedObjectFromTree = function (kids, name) {
        var found = false;
        var currentDictionary = kids;
        var reference;
        while (!found && currentDictionary) {
            if (currentDictionary && currentDictionary.has('Kids')) {
                currentDictionary = this._getProperKid(currentDictionary, name);
            }
            else if (currentDictionary && currentDictionary.has('Names')) {
                reference = this._findName(currentDictionary, name);
                found = true;
            }
        }
        return reference;
    };
    /**
     * Performs a binary search in a Names array for the given name.
     *
     * @private
     * @param {_PdfDictionary} current Dictionary containing a 'Names' array.
     * @param {string} target Name to search for.
     * @returns {_PdfReference} Reference associated with the found name.
     */
    _PdfDestinationHelper.prototype._findName = function (current, target) {
        var reference;
        var names = current.get('Names'); // eslint-disable-line
        if (!Array.isArray(names) || names.length === 0) {
            return reference;
        }
        for (var i = 0; i < names.length; i += 2) {
            var key = names[i]; // eslint-disable-line
            if (key instanceof _PdfReference) {
                key = current._crossReference._fetch(key);
            }
            if (this._stringCompare(target, key) === 0) {
                reference = names[i + 1];
                return reference;
            }
        }
        return reference;
    };
    /**
     * Selects the child dictionary whose Limits bracket the specified name.
     *
     * @private
     * @param {_PdfDictionary} kids Parent dictionary with Kids array.
     * @param {string} name Name to bracket.
     * @returns {_PdfDictionary} The child dictionary likely containing the name.
     */
    _PdfDestinationHelper.prototype._getProperKid = function (kids, name) {
        var kidsArray; // eslint-disable-line
        var kid;
        if (kids && kids.has('Kids')) {
            kidsArray = kids.getRaw('Kids');
        }
        if (kidsArray && Array.isArray(kidsArray) && kidsArray.length !== 0) {
            kidsArray = kids.getArray('Kids');
            for (var i = kidsArray.length - 1; i >= 0; i--) {
                kid = kidsArray[Number.parseInt(i.toString(), 10)];
                if (this._checkLimits(kid, name)) {
                    break;
                }
            }
        }
        return kid;
    };
    /**
     * Checks whether the given name falls within the Limits of the node.
     *
     * @private
     * @param {_PdfDictionary} kid Node to test.
     * @param {string} result Name to compare.
     * @returns {boolean} True if within limits; otherwise false.
     */
    _PdfDestinationHelper.prototype._checkLimits = function (kid, result) {
        var found = false;
        if (kid && kid.has('Limits')) {
            var limits = kid.get('Limits'); // eslint-disable-line
            var lowerLimit = limits[0];
            var higherLimit = limits[1];
            var lowCompare = this._stringCompare(lowerLimit, result);
            var highCompare = this._stringCompare(higherLimit, result);
            found = (lowCompare === 0 || highCompare === 0 || (lowCompare < 0 && highCompare > 0));
        }
        return found;
    };
    /**
     * Compares two strings using byte-wise comparison.
     *
     * @private
     * @param {string} limits First string to compare.
     * @param {string} result Second string to compare.
     * @returns {number} Negative if limits < result, positive if limits > result, zero if equal.
     */
    _PdfDestinationHelper.prototype._stringCompare = function (limits, result) {
        var byteArray = _stringToBytes(limits);
        var byteArray1 = _stringToBytes(result);
        var commonSize = Math.min(byteArray.length, byteArray1.length);
        var resultValue = 0;
        for (var i = 0; i < commonSize; i++) {
            var byte = byteArray[Number.parseInt(i.toString(), 10)];
            var byte1 = byteArray1[Number.parseInt(i.toString(), 10)];
            resultValue = byte - byte1;
            if (resultValue !== 0) {
                break;
            }
        }
        if (resultValue === 0) {
            resultValue = byteArray.length - byteArray1.length;
        }
        return resultValue;
    };
    return _PdfDestinationHelper;
}());
export { _PdfDestinationHelper };