UNPKG

@syncfusion/ej2-pdf

Version:

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

3,474 lines 146 kB
import { PdfPage } from './../pdf-page';
import { _PdfStreamWriter } from './pdf-stream-writer';
import { _PdfBaseStream, _PdfStream } from './../base-stream';
import { _floatToString, _addProcSet, _reverseMapBlendMode, _mapBlendMode, _getNewGuidString, _getBezierArc, _numberToString, _bytesToString, _stringToUnicodeArray, _isNullOrUndefined } from './../utils';
import { _PdfDictionary, _PdfReference, _PdfName } from './../pdf-primitives';
import { PdfCjkStandardFont, PdfFont, PdfFontStyle, PdfStandardFont, PdfTrueTypeFont } from './../fonts/pdf-standard-font';
import { _PdfStringLayouter, _LineType, _StringTokenizer } from './../fonts/string-layouter';
import { PdfTextAlignment, PdfTextDirection, PdfSubSuperScript, PdfBlendMode, PdfLineJoin, PdfLineCap, PdfDashStyle, PdfFillMode, PathPointType, PdfRotationAngle } from './../enumerator';
import { PdfStringFormat, PdfVerticalAlignment } from './../fonts/pdf-string-format';
import { PdfTemplate } from './pdf-template';
import { PdfLayoutFormat } from './pdf-layouter';
import { PdfPath } from './pdf-path';
import { _UnicodeTrueTypeFont } from '../fonts/unicode-true-type-font';
import { _RtlRenderer } from './../graphics/rightToLeft/text-renderer';
import { PdfImage } from './images/pdf-image';
import { initializeTelemetryFeature } from '@syncfusion/ej2-base';
/**
 * Represents a graphics from a PDF page.
 * ```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();
 * ```
 */
var PdfGraphics = /** @class */ (function () {
    /**
     * Initializes a new instance of the `PdfGraphics` class.
     *
     * @param {Size} size The graphics client size.
     * @param {_PdfContentStream} content Content stream.
     * @param {_PdfCrossReference} xref Cross reference.
     * @param {PdfPage | PdfTemplate} source Source object of the graphics.
     * @private
     */
    function PdfGraphics(size, content, xref, source) {
        /**
         * Resources waiting to be written into the cross-reference when saving.
         *
         * @private
         */
        this._pendingResource = []; // eslint-disable-line
        /**
         * Indicates whether italic text style is active.
         *
         * @private
         */
        this._isItalic = false;
        /**
         * Indicates whether the current graphics context is in layouter mode.
         *
         * @private
         */
        this._isLayouter = false;
        this._hasResourceReference = false;
        if (source instanceof PdfPage) {
            this._source = source._pageDictionary;
            this._page = source;
        }
        else if (source instanceof PdfTemplate) {
            this._source = source._content.dictionary;
            this._template = source;
        }
        if (this._source) {
            var obj = void 0; // eslint-disable-line
            if (this._source.has('Resources')) {
                obj = this._source.getRaw('Resources');
            }
            else if (this._source.has('Parent')) {
                var parentPage = this._source.get('Parent');
                if (parentPage && parentPage.has('Resources')) {
                    obj = parentPage.getRaw('Resources');
                    if (obj && obj instanceof _PdfDictionary) {
                        this._source.update('Resources', obj);
                    }
                }
            }
            if (obj && obj instanceof _PdfReference) {
                this._hasResourceReference = true;
                this._resourceObject = xref._fetch(obj);
                if (this._resourceObject && this._resourceObject instanceof _PdfStream) {
                    this._resourceObject = this._resourceObject.dictionary;
                }
            }
            else if (obj && obj instanceof _PdfDictionary) {
                this._resourceObject = obj;
            }
            else {
                this._resourceObject = new _PdfDictionary();
                this._source.update('Resources', this._resourceObject);
            }
        }
        this._crossReference = xref;
        this._sw = new _PdfStreamWriter(content);
        this._size = size;
        _addProcSet('PDF', this._resourceObject);
        this._initialize();
    }
    Object.defineProperty(PdfGraphics.prototype, "_matrix", {
        /**
         * Lazily creates and returns the current graphics transformation matrix.
         *
         * @private
         * @returns {_PdfTransformationMatrix} The current transformation matrix.
         */
        get: function () {
            if (typeof this._m === 'undefined') {
                this._m = new _PdfTransformationMatrix();
            }
            return this._m;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfGraphics.prototype, "_resources", {
        /**
         * Builds and returns the local resource name map by scanning page/template resources
         *  Populates transparency cache when available.
         *
         * @private
         * @returns {Map<_PdfReference, _PdfName>} The mapping of references to resource names.
         */
        get: function () {
            var _this = this;
            if (typeof this._resourceMap === 'undefined') {
                this._resourceMap = new Map();
                if (this._resourceObject && this._resourceObject.has('Font')) {
                    var fonts = this._resourceObject.get('Font');
                    if (fonts && fonts.size > 0) {
                        fonts.forEach(function (key, value) {
                            if (value !== null && typeof value !== 'undefined' && value instanceof _PdfReference) {
                                _this._resourceMap.set(value, _PdfName.get(key));
                            }
                        });
                    }
                }
                if (this._resourceObject.has('XObject')) {
                    var other = this._resourceObject.get('XObject');
                    if (other && other.size > 0) {
                        other.forEach(function (key, value) {
                            if (value !== null && typeof value !== 'undefined' && value instanceof _PdfReference) {
                                _this._resourceMap.set(value, _PdfName.get(key));
                            }
                        });
                    }
                }
                if (this._resourceObject.has('ExtGState')) {
                    var state = this._resourceObject.get('ExtGState');
                    if (state && state.size > 0) {
                        if (!this._transparencies) {
                            this._transparencies = new Map();
                        }
                        state.forEach(function (key, value) {
                            if (value !== null && typeof value !== 'undefined' && value instanceof _PdfReference) {
                                _this._setTransparencyData(value, _PdfName.get(key));
                            }
                        });
                    }
                }
            }
            return this._resourceMap;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfGraphics.prototype, "clientSize", {
        /**
         * Gets the size of the canvas reduced by margins and page templates (Read only).
         *
         * @returns {Size} The width and height of the client area 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 graphics client size.
         * let size: Size = page.graphics.clientSize;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            if (this._page && this._crossReference && this._crossReference._document._hasTemplateContentValue) {
                var includeMargins = this._isLayouter ? true : false;
                var bounds = this._page._getActualBounds(this._page._pageSettings, includeMargins);
                return { width: bounds[2], height: bounds[3] };
            }
            return { width: this._clipBounds[2], height: this._clipBounds[3] };
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Save the current graphics state.
     *
     * ```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 font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Save the graphics
     * let state: PdfGraphicsState = graphics.save();
     * //Set graphics translate transform.
     * graphics.translateTransform({x: 100, y: 100});
     * //Draws the String.
     * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * //Restore the graphics.
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @returns {PdfGraphicsState} graphics state.
     */
    PdfGraphics.prototype.save = function () {
        var state = new PdfGraphicsState(this, this._matrix);
        state._textRenderingMode = this._textRenderingMode;
        state._charSpacing = this._characterSpacing;
        state._textScaling = this._textScaling;
        state._wordSpacing = this._wordSpacing;
        state._currentBrush = this._currentBrush;
        state._currentPen = this._currentPen;
        state._currentFont = this._currentFont;
        this._graphicsState.push(state);
        this._sw._saveGraphicsState();
        return state;
    };
    /**
     * Restore the graphics state.
     *
     * ```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 font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Save the graphics
     * let state: PdfGraphicsState = graphics.save();
     * //Set graphics translate transform.
     * graphics.translateTransform({x: 100, y: 100});
     * //Draws the String.
     * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * //Restore the graphics.
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {PdfGraphicsState} state graphics state.
     * @returns {void} restore of the graphics state.
     */
    PdfGraphics.prototype.restore = function (state) {
        if (this._graphicsState.length > 0) {
            if (typeof state === 'undefined') {
                this._doRestore();
            }
            else {
                if (this._graphicsState.length > 0 && this._graphicsState.indexOf(state) !== -1) {
                    while (this._graphicsState.length > 0) {
                        if (this._doRestore() === state) {
                            break;
                        }
                    }
                }
            }
        }
    };
    /**
     * Represents a scale transform of the graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Create a new font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Save the current graphics state
     * let state: PdfGraphicsState = graphics.save();
     * // Apply scale transform
     * graphics.scaleTransform(0.5, 0.5);
     * // Draw a string with the scaled transformation
     * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {number} scaleX Scale factor in the x direction.
     * @param {number} scaleY Scale factor in the y direction.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.scaleTransform = function (scaleX, scaleY) {
        var matrix = new _PdfTransformationMatrix();
        matrix._scale(scaleX, scaleY);
        this._sw._modifyCtm(matrix);
        this._matrix._multiply(matrix);
    };
    /**
     * Represents a translate transform of the graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Create a new font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Save the current graphics state
     * let state: PdfGraphicsState = graphics.save();
     * // Apply translate transform
     * graphics.translateTransform({x: 100, y: 100});
     * // Draw a string with the translation applied
     * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {Point} location (x, y) coordinates of the translation.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.translateTransform = function (location) {
        var matrix = new _PdfTransformationMatrix();
        matrix._translate(location.x, -location.y);
        this._sw._modifyCtm(matrix);
        this._matrix._multiply(matrix);
    };
    /**
     * Represents a rotate transform of the graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Create a new font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Save the current graphics state
     * let state: PdfGraphicsState = graphics.save();
     * // Apply rotate transform
     * graphics.rotateTransform(-90);
     * // Draw a string with the rotation applied
     * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {number} angle Angle of rotation in degrees.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.rotateTransform = function (angle) {
        var matrix = new _PdfTransformationMatrix();
        matrix._rotate(-angle);
        this._sw._modifyCtm(matrix);
        this._matrix._multiply(matrix);
    };
    /**
     * Represents a clipping region of this graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Create a new font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Set clipping region
     * graphics.setClip({x: 0, y: 0, width: 50, height: 12}, PdfFillMode.alternate);
     * // Draw a string within the clipping region
     * graphics.drawString('Hello world!', font, {x: 0, y: 0, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {Rectangle} bounds Rectangle structure that represents the new clip region.
     * @param {PdfFillMode} mode Member of the PdfFillMode enumeration that specifies the filling operation to use.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.setClip = function (bounds, mode) {
        if (typeof mode === 'undefined') {
            mode = PdfFillMode.winding;
        }
        this._sw._appendRectangle(bounds.x, bounds.y, bounds.width, bounds.height);
        this._sw._clipPath(mode === PdfFillMode.alternate);
    };
    /**
     * Sets the transparency for the graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Create a new font
     * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
     * // Set transparency
     * graphics.setTransparency(0.5, 0.5, PdfBlendMode.multiply);
     * // Draw the string
     * graphics.drawString('Hello world!', font, {x: 0, y: 0, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {number} stroke The transparency value for strokes.
     * @param {number} fill The transparency value for fills.
     * @param {PdfBlendMode} mode The blend mode to use.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.setTransparency = function (stroke, fill, mode) {
        if (typeof fill === 'undefined') {
            fill = stroke;
        }
        if (typeof mode === 'undefined') {
            mode = PdfBlendMode.normal;
        }
        if (typeof this._transparencies === 'undefined') {
            this._transparencies = new Map();
        }
        var transparencyKey = 'CA:' + stroke.toString() + '_ca:' + fill.toString() + '_BM:' + mode.toString();
        var transparencyData;
        if (this._transparencies.size > 0) {
            this._transparencies.forEach(function (value, key) {
                if (value === transparencyKey) {
                    transparencyData = key;
                }
            });
        }
        if (!transparencyData) {
            transparencyData = new _TransparencyData();
            var transparencyDict = new _PdfDictionary();
            transparencyDict.update('CA', stroke);
            transparencyDict.update('ca', fill);
            transparencyDict.update('BM', _reverseMapBlendMode(mode));
            transparencyData._dictionary = transparencyDict;
            transparencyData._key = transparencyKey;
            transparencyData._name = _PdfName.get(_getNewGuidString());
            var dictionary = void 0;
            var isReference = false;
            if (this._resourceObject.has('ExtGState')) {
                var obj = this._resourceObject.getRaw('ExtGState'); // eslint-disable-line
                if (obj !== null && typeof obj !== 'undefined') {
                    if (obj instanceof _PdfReference) {
                        isReference = true;
                        dictionary = this._crossReference._fetch(obj);
                    }
                    else if (obj instanceof _PdfDictionary) {
                        dictionary = obj;
                    }
                }
            }
            else {
                dictionary = new _PdfDictionary(this._crossReference);
                this._resourceObject.update('ExtGState', dictionary);
            }
            if (this._crossReference) {
                var ref = this._crossReference._getNextReference();
                this._crossReference._cacheMap.set(ref, transparencyDict);
                transparencyData._reference = ref;
                dictionary.update(transparencyData._name.name, ref);
            }
            else {
                this._pendingResource.push({ 'resource': transparencyDict, 'key': transparencyData._name, 'source': dictionary });
            }
            if (isReference) {
                this._resourceObject._updated = true;
            }
            if (this._hasResourceReference) {
                this._source._updated = true;
            }
        }
        this._sw._setGraphicsState(transparencyData._name);
    };
    /**
     * Draws a line on the page graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the 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 a 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();
     * ```
     *
     * @param {PdfPen} pen The pen that determines the stroke color, width, and style of the line.
     * @param {Point} start The (x, y) coordinates of the starting point of the line.
     * @param {Point} end The (x, y) coordinates of the ending point of the line.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.drawLine = function (pen, start, end) {
        this._beginMarkContent();
        this._stateControl(pen);
        this._sw._beginPath(start.x, start.y);
        this._sw._appendLineSegment(end.x, end.y);
        this._sw._strokePath();
        _addProcSet('PDF', this._resourceObject);
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawRectangle = function (bounds, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._sw._appendRectangle(bounds.x, bounds.y, bounds.width, bounds.height);
        this._drawGraphicsPath(result.pen, result.brush);
        this._endMarkContent();
    };
    /**
     * Draws a Bezier curve using a specified pen and coordinates for the start point, two control points, and end point.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the 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 a Bezier curve on the page graphics
     * graphics.drawBezier({x: 50, y: 100}, {x: 200, y: 50}, {x: 100, y: 150}, {x: 150, y: 100}, pen);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {Point} start The (x, y) coordinates of the starting point of the Bezier curve.
     * @param {Point} first The (x, y) coordinates of the first control point of the Bezier curve.
     * @param {Point} second The (x, y) coordinates of the second control point of the Bezier curve.
     * @param {Point} end The (x, y) coordinates of the ending point of the Bezier curve.
     * @param {PdfPen} pen The pen that determines the stroke color, width, and style of the Bezier curve.
     * @returns {void} Nothing
     */
    PdfGraphics.prototype.drawBezier = function (start, first, second, end, pen) {
        this._beginMarkContent();
        this._stateControl(pen, null, null);
        this._sw._beginPath(start.x, start.y);
        this._sw._appendBezierSegment(first.x, first.y, second.x, second.y, end.x, end.y);
        this._drawGraphicsPath(pen);
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawPie = function (bounds, startAngle, sweepAngle, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._constructPiePath(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height, startAngle, sweepAngle);
        this._sw._appendLineSegment(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
        this._drawGraphicsPath(result.pen, result.brush, null, true);
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawPolygon = function (points, first, second) {
        var _this = this;
        this._beginMarkContent();
        if (points.length > 0) {
            var result = this._setPenBrush(first, second);
            this._sw._beginPath(points[0].x, points[0].y);
            points.forEach(function (point, index) {
                if (index > 0) {
                    _this._sw._appendLineSegment(point.x, point.y);
                }
            });
            this._drawGraphicsPath(result.pen, result.brush, PdfFillMode.winding, true);
        }
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawEllipse = function (bounds, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._constructArcPath(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height, 0, 360);
        this._drawGraphicsPath(result.pen, result.brush, PdfFillMode.winding, true);
        this._endMarkContent();
    };
    /**
     * Draw arc on the page graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the 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 an arc on the page graphics
     * graphics.drawArc({x: 10, y: 20, width: 100, height: 200}, 20, 30, pen);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {Rectangle} bounds The bounding rectangle that defines the ellipse from which the arc shape comes.
     * @param {number} startAngle Angle measured in degrees clockwise from the x-axis to the first side of the arc shape.
     * @param {number} sweepAngle Angle measured in degrees clockwise from the startAngle parameter to the second side of the arc shape.
     * @param {PdfPen} pen Pen that determines the stroke color, width, and style of the arc.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.drawArc = function (bounds, startAngle, sweepAngle, pen) {
        if (sweepAngle !== 0) {
            this._beginMarkContent();
            this._stateControl(pen);
            this._constructArcPath(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height, startAngle, sweepAngle);
            this._drawGraphicsPath(pen, null, PdfFillMode.winding, false);
            this._endMarkContent();
        }
    };
    PdfGraphics.prototype.drawImage = function (arg1, arg2) {
        initializeTelemetryFeature('ImageToPDF', 'PDFLibrary');
        this._beginMarkContent();
        if (arg2 && this._isRectangle(arg2)) {
            arg1._save();
            var matrix = new _PdfTransformationMatrix();
            this._getTranslateTransform(arg2.x, (arg2.y + arg2.height), matrix);
            this._getScaleTransform(arg2.width, arg2.height, matrix);
            this._sw._write('q');
            this._sw._modifyCtm(matrix);
            var sourceDictionary = void 0;
            var keyName = void 0;
            var isNew = true;
            if (this._resourceObject.has('XObject')) {
                var obj = this._resourceObject.getRaw('XObject'); // eslint-disable-line
                if (obj instanceof _PdfDictionary) {
                    sourceDictionary = obj;
                }
                else if (obj instanceof _PdfReference && this._crossReference) {
                    sourceDictionary = this._crossReference._fetch(obj);
                }
                if (sourceDictionary) {
                    isNew = false;
                }
            }
            if (isNew) {
                sourceDictionary = new _PdfDictionary(this._crossReference);
                this._resourceObject.update('XObject', sourceDictionary);
            }
            if (typeof keyName === 'undefined') {
                if (!arg1._key) {
                    arg1._key = _getNewGuidString();
                }
                keyName = _PdfName.get(arg1._key);
            }
            if (this._crossReference) {
                this._updateImageResource(arg1, keyName, sourceDictionary, this._crossReference);
                this._source.update('Resources', this._resourceObject);
                this._source._updated = true;
            }
            else {
                this._pendingResource.push({ 'resource': arg1, 'key': keyName, 'source': sourceDictionary });
            }
            this._sw._executeObject(keyName);
            this._sw._write('Q');
            this._sw._write('\r\n');
            _addProcSet('ImageB', this._resourceObject);
            _addProcSet('ImageC', this._resourceObject);
            _addProcSet('ImageI', this._resourceObject);
            _addProcSet('Text', this._resourceObject);
        }
        else {
            var size = arg1.physicalDimension;
            this.drawImage(arg1, { x: arg2.x, y: arg2.y, width: size.width, height: size.height });
        }
        this._endMarkContent();
    };
    /**
     * Draws a PDF template onto the page graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Gets the first annotation of the page
     * let annotation: PdfRubberStampAnnotation = page.annotations.at(0) as PdfRubberStampAnnotation;
     * // Gets the appearance template of the annotation
     * let template: PdfTemplate = annotation.createTemplate();
     * // Gets the graphics of the PDF page
     * let graphics: PdfGraphics = page.graphics;
     * // Draw the template on the page graphics within the specified bounds
     * graphics.drawTemplate(template, { x: 10, y: 20, width: template.size.width, height: template.size.height });
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {PdfTemplate} template The PDF template to be drawn.
     * @param {Rectangle} bounds The bounds of the template.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.drawTemplate = function (template, bounds) {
        var _this = this;
        this._beginMarkContent();
        var hasPendingTemplate = true;
        if (typeof template !== 'undefined') {
            if (template._isExported || template._isResourceExport) {
                if (this._crossReference) {
                    template._crossReference = this._crossReference;
                    template._importStream(true, template._isResourceExport);
                }
                else {
                    template._importStream(false, template._isResourceExport);
                    this._pendingResource.push(template);
                    hasPendingTemplate = false;
                }
            }
            var scaleX = void 0;
            var scaleY = void 0;
            if (this._page &&
                this._page.rotation &&
                template._isSignature &&
                this._page._size.width > this._page._size.height &&
                this._page.rotation === PdfRotationAngle.angle270 && template._content &&
                template._content.dictionary &&
                template._content.dictionary.has('Matrix')) {
                scaleX = (template && template._size.width > 0) ? bounds.width / template._size.height : 1;
                scaleY = (template && template._size.height > 0) ? bounds.height / template._size.width : 1;
            }
            else {
                scaleX = (template && template._size.width > 0) ? bounds.width / template._size.width : 1;
                scaleY = (template && template._size.height > 0) ? bounds.height / template._size.height : 1;
            }
            var needScale = !(Math.trunc(scaleX * 1000) / 1000 === 1 && Math.trunc(scaleY * 1000) / 1000 === 1);
            var cropBox = void 0;
            var mediaBox = void 0;
            if (this._page) {
                cropBox = this._page.cropBox;
                mediaBox = this._page.mediaBox;
                if (this._page._pageDictionary.has('CropBox') && this._page._pageDictionary.has('MediaBox')) {
                    if (cropBox[0] > 0 && cropBox[1] > 0 && mediaBox[0] < 0 && mediaBox[1] < 0) {
                        this.translateTransform({ x: cropBox[0], y: -cropBox[1] });
                        bounds.x = -cropBox[0];
                        bounds.y = cropBox[1];
                    }
                }
            }
            var state = this.save();
            var matrix = new _PdfTransformationMatrix();
            if (this._page) {
                var needTransform = (this._page._pageDictionary.has('CropBox') &&
                    this._page._pageDictionary.has('MediaBox') && cropBox && mediaBox &&
                    cropBox[0] === mediaBox[0] && cropBox[1] === mediaBox[1] && cropBox[2] === mediaBox[2] && cropBox[3] === mediaBox[3]) ||
                    (this._page._pageDictionary.has('MediaBox') && mediaBox && mediaBox[3] === 0);
                var yAxis = (bounds.y + ((this._page._origin[0] >= 0 || needTransform) ? bounds.height : 0));
                if (template && template._isSignature &&
                    template._content && template._content.dictionary &&
                    template._content.dictionary.has('BBox')) {
                    var bbox = template._content.dictionary.get('BBox');
                    var hasValidBBoxSize = bbox[2] !== 0 && bbox[3] !== 0;
                    var xTranslate = (bbox[0] > 0 && hasValidBBoxSize) ? 0 : bounds.x;
                    var yTranslate = (bbox[1] > 0 && hasValidBBoxSize) ? this._page.size.height : yAxis;
                    matrix._translate(xTranslate, -yTranslate);
                }
                else {
                    matrix._translate(bounds.x, -yAxis);
                }
            }
            else {
                matrix._translate(bounds.x, -(bounds.y + bounds.height));
            }
            var scaleApplied = false;
            if (template._content && template._content.dictionary) {
                var dictionary = template._content.dictionary;
                if (dictionary.has('Matrix') && dictionary.has('BBox')) {
                    var templateMatrix = dictionary.getArray('Matrix');
                    var templateBox = dictionary.getArray('BBox');
                    if (templateMatrix && templateBox && templateMatrix.length > 5 && templateBox.length > 3) {
                        var templateScaleX = Number.parseFloat(_numberToString(-templateMatrix[1]));
                        var templateScaleY = Number.parseFloat(_numberToString(templateMatrix[2]));
                        var roundScaleX = Number.parseFloat(_numberToString(scaleX));
                        var roundScaleY = Number.parseFloat(_numberToString(scaleY));
                        if (roundScaleX === templateScaleX &&
                            roundScaleY === templateScaleY &&
                            templateBox[2] === template._size.width &&
                            templateBox[3] === template._size.height && template._isAnnotationTemplate
                            && template._needScale && needScale) {
                            matrix = new _PdfTransformationMatrix();
                            matrix._translate(bounds.x - templateMatrix[4], -(bounds.y + templateMatrix[5]));
                            matrix._scale(1, 1);
                            scaleApplied = true;
                        }
                        else if (templateBox[0] !== 0 && templateBox[1] !== 0 && templateBox[0] === bounds.x &&
                            this._page && template._isSignature) {
                            matrix._translate(bounds.x - templateBox[0], -this._page.size.height);
                            matrix._scale(scaleX, scaleY);
                            scaleApplied = true;
                        }
                    }
                }
            }
            if (needScale && !scaleApplied) {
                matrix._scale(scaleX, scaleY);
            }
            this._sw._modifyCtm(matrix);
            var sourceDictionary = void 0;
            var isReference = false;
            var keyName_1;
            var isNew = true;
            var ref_1;
            if (this._resourceObject.has('XObject')) {
                var obj = this._resourceObject.getRaw('XObject'); // eslint-disable-line
                if (obj) {
                    if (obj instanceof _PdfReference) {
                        isReference = true;
                        sourceDictionary = this._crossReference._fetch(obj);
                    }
                    else if (obj instanceof _PdfDictionary) {
                        sourceDictionary = obj;
                    }
                }
                if (sourceDictionary) {
                    isNew = false;
                    this._resources.forEach(function (value, key) {
                        if (key && key instanceof _PdfReference) {
                            var base = _this._crossReference._fetch(key);
                            if (base && template && base === template._content) {
                                keyName_1 = value;
                                ref_1 = key;
                            }
                        }
                    });
                }
            }
            if (isNew) {
                sourceDictionary = new _PdfDictionary(this._crossReference);
                this._resourceObject.update('XObject', sourceDictionary);
            }
            if (typeof keyName_1 === 'undefined') {
                if (!template._key) {
                    template._key = _getNewGuidString();
                }
                keyName_1 = _PdfName.get(template._key);
                if (template && template._content.reference) {
                    ref_1 = template._content.reference;
                }
                else if (this._crossReference) {
                    ref_1 = this._crossReference._getNextReference();
                }
                else {
                    this._pendingResource.push({ 'resource': template._content, 'key': keyName_1, 'source': sourceDictionary });
                    if (this._template && hasPendingTemplate) {
                        this._pendingResource.push(template);
                    }
                }
                if (ref_1 && this._crossReference) {
                    if (!this._crossReference._cacheMap.has(ref_1) && template && template._content) {
                        this._crossReference._cacheMap.set(ref_1, template._content);
                    }
                    sourceDictionary.update(keyName_1.name, ref_1);
                    this._resources.set(ref_1, keyName_1);
                }
                this._resourceObject._updated = true;
            }
            if (template._isNew && this._crossReference) {
                template.graphics._processResources(this._crossReference);
            }
            if (isReference) {
                this._resourceObject._updated = true;
            }
            if (this._hasResourceReference) {
                this._source._updated = true;
            }
            this._sw._executeObject(keyName_1);
            this.restore(state);
            _addProcSet('ImageB', this._resourceObject);
            _addProcSet('ImageC', this._resourceObject);
            _addProcSet('ImageI', this._resourceObject);
            _addProcSet('Text', this._resourceObject);
        }
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawPath = function (path, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        if (result.pen || result.brush) {
            this._buildUpPath(path._points, path._pathTypes);
            this._drawGraphicsPath(result.pen, result.brush, path.fillMode, false);
        }
        this._endMarkContent();
    };
    /**
     * Draws a rounded rectangle on the page graphics.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the 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);
     * // Create a new brush
     * let brush: PdfBrush = new PdfBrush({r: 0, g: 0, b: 255});
     * // Draw a rounded rectangle on the page graphics
     * graphics.drawRoundedRectangle({x: 10, y: 20, width: 100, height: 200}, 5, pen, brush);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     *
     * @param {Rectangle} bounds The bounding rectangle of the rounded rectangle.
     * @param {number} radius The radius of the rounded corners of the rectangle.
     * @param {PdfPen} pen The pen that determines the stroke color, width, and style of the rectangle.
     * @param {PdfBrush} brush The brush that determines the fill color and texture of the rectangle.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype.drawRoundedRectangle = function (bounds, radius, pen, brush) {
        if (pen === null || typeof pen === 'undefined') {
            throw new Error('Pen cannot be null or undefined');
        }
        if (brush === null || typeof brush === 'undefined') {
            throw new Error('Brush cannot be null or undefined');
        }
        var diameter = radius * 2;
        var size = [diameter, diameter];
        var arc = [bounds.x, bounds.y, size[0], size[1]];
        var path = new PdfPath();
        if (radius === 0) {
            path.addRectangle(bounds);
            this.drawPath(path, pen, brush);
        }
        else {
            path._isRoundedRectangle = true;
            path.addArc({ x: arc[0], y: arc[1], width: arc[2], height: arc[3] }, 180, 90);
            arc[0] = (bounds.x + bounds.width) - diameter;
            path.addArc({ x: arc[0], y: arc[1], width: arc[2], height: arc[3] }, 270, 90);
            arc[1] = (bounds.y + bounds.height) - diameter;
            path.addArc({ x: arc[0], y: arc[1], width: arc[2], height: arc[3] }, 0, 90);
            arc[0] = bounds.x;
            path.addArc({ x: arc[0], y: arc[1], width: arc[2], height: arc[3] }, 90, 90);
            path.closeFigure();
            this.drawPath(path, pen, brush);
        }
    };
    PdfGraphics.prototype.drawString = function (value, font, bounds, arg1, arg2, arg3) {
        var pen;
        var brush;
        var format;
        if (arg1 instanceof PdfPen) {
            pen = arg1;
            if (arg2 instanceof PdfBrush) {
                brush = arg2;
                if (arg3 instanceof PdfStringFormat) {
                    format = arg3;
                }
            }
            else if (arg2 instanceof PdfStringFormat) {
                format = arg2;
            }
        }
        else if (arg1 instanceof PdfBrush) {
            brush = arg1;
            if (arg2 instanceof PdfStringFormat) {
                format = arg2;
            }
        }
        else if (arg2 instanceof PdfBrush) {
            brush = arg2;
        }
        if (arg2 && arg2 instanceof PdfStringFormat) {
            format = arg2;
        }
        if (arg3 && arg3 instanceof PdfStringFormat) {
            format = arg3;
        }
        this._beginMarkContent();
        if (font && font._document && font._document._crossReference) {
            this._crossReference = font._document._crossReference;
        }
        var layouter = this._stringLayouter;
        if (typeof layouter === 'undefined') {
            layouter = new _PdfStringLayouter();
            this._stringLayouter = layouter;
        }
        if (!format) {
            format = new PdfStringFormat();
        }
        if (value) {
            value = this._normalizeText(font, value);
        }
        if (this._isRectangle(bounds)) {
            var result = layouter._layout(value, font, format, [bounds.width, bounds.height]);
            if (!result._empty) {
                var rect = this._checkCorrectLayoutRectangle([result._actualSize.width, result._actualSize.height], bounds.x, bounds.y, format);
                if (bounds.width <= 0) {
                    bounds.x = rect[0];
                    bounds.width = rect[2];
                }
                if (bounds.height <= 0) {
                    bounds.y = rect[1];
                    bounds.height = rect[3];
                }
                this._drawStringLayoutResult(result, font, pen, brush, [bounds.x, bounds.y, bounds.width, bounds.height], format);
            }
        }
        _addProcSet('Text', this._resourceObject);
        this._endMarkContent();
    };
    PdfGraphics.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._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 defaultBrush = new PdfBrush({ r: 0, g: 0, b: 0 });
        var brushToUse = (typeof element.brush === 'undefined' || element.brush === null) ? defaultBrush : element.brush;
        this.drawString(element.text, element.font, bounds, element.pen, brushToUse, element.stringFormat);
    };
    /**
     * Pops and restores a graphics state from the stack and emits the 'Q' operator.
     *
     * @private
     * @returns {PdfGraphicsState} The restored graphics state.
     */
    PdfGraphics.prototype._doRestore = function () {
        var state = this._graphicsState.pop();
        this._m = state._transformationMatrix;
        this._currentBrush = state._currentBrush;
        this._currentPen = state._currentPen;
        this._currentFont = state._currentFont;
        this._characterSpacing = state._charSpacing;
        this._wordSpacing = state._wordSpacing;
        this._textScaling = state._textScaling;
        this._textRenderingMode = state._textRenderingMode;
        this._sw._restoreGraphicsState();
        return state;
    };
    PdfGraphics.prototype._beginMarkContent = function () {
        if (this._layer) {
            this._layer._beginLayer(this);
        }
    };
    PdfGraphics.prototype._endMarkContent = function () {
        if (this._layer) {
            if (this._layer._isEndState && this._layer._parentLayer.length !== 0) {
                for (var i = 0; i < this._layer._parentLayer.length; i++) {
                    this._sw._write('EMC');
                }
            }
            if (this._layer._isEndState) {
                this._sw._write('EMC');
            }
        }
    };
    /**
     * Resolves and writes all pending resources images, fonts, templates, streams
     * into the cross-reference table and updates resource dictionaries.
     *
     * @private
     * @param {_PdfCrossReference} crossReference The target cross-reference table.
     * @returns {void}
     */
    PdfGraphics.prototype._processResources = function (crossReference) {
        var _this = this;
        this._crossReference = crossReference;
        if (this._pendingResource.length > 0) {
            this._pendingResource.forEach(function (entry, index) {
                if (entry instanceof PdfTemplate) {
                    entry._crossReference = crossReference;
                    if (entry._isNew) {
                        entry.graphics._processResources(crossReference);
                    }
                    else {
                        entry._updatePendingResource(crossReference);
                    }
                }
                else if (entry.resource instanceof _PdfBaseStream || entry.resource instanceof _PdfDictionary) {
                    var reference = void 0;
                    if (entry.resource._reference) {
                        reference = entry.resource._reference;
                    }
                    else {
                        reference = crossReference._getNextReference();
                        entry.resource._reference = reference;
                    }
                    if (!crossReference._cacheMap.has(reference) && entry.resource) {
                        crossReference._cacheMap.set(reference, entry.resource);
                    }
                    entry.source.update(entry.key.name, reference);
                    _this._resources.set(reference, entry.key);
                }
                else if (entry.resource instanceof PdfImage) {
                    _this._updateImageResource(entry.resource, entry.key, entry.source, crossReference);
                }
                else if (entry.resource instanceof PdfFont) {
                    _this._updateFontResource(entry.resource, entry.key, entry.source, crossReference);
                }
                _this._source.update('Resources', _this._resourceObject);
                _this._source._updated = true;
            });
            this._pendingResource = [];
        }
    };
    /**
     * Registers an image and optional soft mask into the resource dictionary and
     * caches the streams in the cross-reference.
     *
     * @private
     * @param {PdfImage} image The image to register.
     * @param {_PdfName} keyName The resource name to use under `XObject`.
     * @param {_PdfDictionary} source The `XObject` dictionary to update.
     * @param {_PdfCrossReference} crossReference The cross-reference to populate.
     * @returns {void}
     */
    PdfGraphics.prototype._updateImageResource = function (image, keyName, source, crossReference) {
        var reference;
        if (image._reference) {
            reference = image._reference;
        }
        else {
            reference = crossReference._getNextReference();
            image._reference = reference;
        }
        if (!crossReference._cacheMap.has(reference)) {
            if (image && image._imageStream && image._imageStream.dictionary) {
                crossReference._cacheMap.set(reference, image._imageStream);
                image._imageStream.dictionary._updated = true;
                if (image._maskStream && image._maskStream.dictionary) {
                    var ref = void 0;
                    if (image._maskReference) {
                        ref = image._maskReference;
                    }
                    else {
                        ref = crossReference._getNextReference();
                        image._maskReference = ref;
                    }
                    crossReference._cacheMap.set(ref, image._maskStream);
                    image._maskStream.dictionary._updated = true;
                    image._imageStream.dictionary.set('SMask', ref);
                }
            }
        }
        source.update(keyName.name, reference);
        this._resources.set(reference, keyName);
        this._resourceObject._updated = true;
    };
    /**
     * Registers a font resource standard or TrueType and ensures its dictionary is
     * cached and referenced from the page/template resources.
     *
     * @private
     * @param {PdfFont} font The font to register.
     * @param {_PdfName} keyName The resource name to use under `Font`.
     * @param {_PdfDictionary} source The `Font` dictionary to update.
     * @param {_PdfCrossReference} crossReference The cross-reference to populate.
     * @returns {void}
     */
    PdfGraphics.prototype._updateFontResource = function (font, keyName, source, crossReference) {
        var reference;
        if (font._reference) {
            reference = font._reference;
        }
        else {
            reference = crossReference._getNextReference();
            font._reference = reference;
        }
        if (!crossReference._cacheMap.has(reference)) {
            if (font._dictionary) {
                crossReference._cacheMap.set(reference, font._dictionary);
                source.update(keyName.name, reference);
                this._resources.set(reference, keyName);
            }
            else if (font instanceof PdfTrueTypeFont) {
                var internal = font._fontInternal;
                if (internal && internal._fontDictionary) {
                    crossReference._cacheMap.set(reference, internal._fontDictionary);
                }
                source.update(keyName.name, reference);
                this._resources.set(reference, keyName);
            }
        }
    };
    /**
     * Emits a Bezier-approximated elliptical arc path into the content stream.
     *
     * @private
     * @param {number} x1 Left of bounding box.
     * @param {number} y1 Top of bounding box.
     * @param {number} x2 Right of bounding box.
     * @param {number} y2 Bottom of bounding box.
     * @param {number} start Start angle in degrees (clockwise from +X).
     * @param {number} sweep Sweep angle in degrees (clockwise).
     * @returns {void}
     */
    PdfGraphics.prototype._constructArcPath = function (x1, y1, x2, y2, start, sweep) {
        var points = _getBezierArc(x1, y1, x2, y2, start, sweep);
        if (points.length === 0) {
            return;
        }
        var point = [points[0], points[1], points[2], points[3], points[4], points[5], points[6], points[7]];
        this._sw._beginPath(point[0], point[1]);
        for (var i = 0; i < points.length; i = i + 8) {
            point = [points[i],
                points[i + 1],
                points[i + 2],
                points[i + 3],
                points[i + 4],
                points[i + 5],
                points[i + 6],
                points[i + 7]];
            this._sw._appendBezierSegment(point[2], point[3], point[4], point[5], point[6], point[7]);
        }
    };
    /**
     * Emits a Bezier-approximated pie-arc path without closing to center for pie slices.
     *
     * @private
     * @param {number} x1 Left of bounding box.
     * @param {number} y1 Top of bounding box.
     * @param {number} x2 Right of bounding box.
     * @param {number} y2 Bottom of bounding box.
     * @param {number} start Start angle in degrees (clockwise from +X).
     * @param {number} sweep Sweep angle in degrees (clockwise).
     * @returns {void}
     */
    PdfGraphics.prototype._constructPiePath = function (x1, y1, x2, y2, start, sweep) {
        var points = _getBezierArc(x1, y1, x2, y2, start, sweep);
        if (points.length === 8) {
            var point = [points[0], points[1], points[2], points[3], points[4], points[5], points[6], points[7]];
            this._sw._beginPath(point[0], point[1]);
            for (var i = 0; i < points.length; i = i + 8) {
                point = [points[i],
                    points[i + 1],
                    points[i + 2],
                    points[i + 3],
                    points[i + 4],
                    points[i + 5],
                    points[i + 6],
                    points[i + 7]];
                this._sw._appendBezierSegment(point[2], point[3], point[4], point[5], point[6], point[7]);
            }
        }
    };
    /**
     * Applies pen stroke properties dash, width, join, cap, miter, color to the stream.
     *
     * @private
     * @param {PdfPen} pen The pen to apply.
     * @returns {void}
     */
    PdfGraphics.prototype._writePen = function (pen) {
        var lineWidth = pen._width;
        var pattern = pen._dashPattern;
        this._sw._setLineDashPattern(pattern, pen._dashOffset * lineWidth);
        this._sw._setLineWidth(pen._width);
        this._sw._setLineJoin(pen._lineJoin);
        this._sw._setLineCap(pen._lineCap);
        if (pen._miterLimit > 0) {
            this._sw._setMiterLimit(pen._miterLimit);
        }
        this._sw._setColor([pen._color.r, pen._color.g, pen._color.b], true);
    };
    /**
     * Type guard that determines if the given bounds represent a rectangle.
     *
     * @private
     * @param {Rectangle | Point} bounds A point or rectangle.
     * @returns {Rectangle} True if `bounds` is a rectangle.
     */
    PdfGraphics.prototype._isRectangle = function (bounds) {
        return 'width' in bounds && 'height' in bounds;
    };
    /**
     * Normalizes text for non-Unicode standard fonts by removing unsupported code points
     * returning a printable subset.
     *
     * @private
     * @param {PdfFont} font The target font.
     * @param {string} value The input text.
     * @returns {string} The normalized text.
     */
    PdfGraphics.prototype._normalizeText = function (font, value) {
        var resultantValue = '';
        if (font instanceof PdfStandardFont) {
            var result = [];
            if (value !== null && typeof value !== 'undefined' && value.length > 0) {
                for (var i = 0; i < value.length; i++) {
                    var charCode = value.charCodeAt(i);
                    if (charCode >= 0x4E00 && charCode <= 0x9FFF) {
                        continue;
                    }
                    else {
                        result.push(charCode);
                    }
                }
            }
            if (result && result.length > 0) {
                for (var i = 0; i < result.length; ++i) {
                    resultantValue += String.fromCharCode(result[Number.parseInt(i.toString(), 10)]);
                }
            }
        }
        else {
            resultantValue = value;
        }
        return resultantValue;
    };
    /**
     * Builds a vector path from points and point types, emitting move/line/bezier segments.
     *
     * @private
     * @param {Point[]} points The path points.
     * @param {PathPointType[]} types The corresponding point types.
     * @returns {void}
     * @throws {Error} If path formation is incorrect.
     */
    PdfGraphics.prototype._buildUpPath = function (points, types) {
        for (var i = 0; i < points.length; i++) {
            var point = points[i];
            var type = types[i];
            switch (type & 0xf) {
                case PathPointType.start:
                    this._sw._beginPath(point.x, point.y);
                    break;
                case PathPointType.bezier:
                    var result = this._getBezierPoint(points, types, i); // eslint-disable-line
                    i = result.index;
                    var first = result.point; // eslint-disable-line
                    result = this._getBezierPoint(points, types, i);
                    i = result.index;
                    var second = result.point; // eslint-disable-line
                    this._sw._appendBezierSegment(point.x, point.y, first.x, first.y, second.x, second.y);
                    break;
                case PathPointType.line:
                    this._sw._appendLineSegment(point.x, point.y);
                    break;
                default:
                    throw new Error('Incorrect path formation.');
            }
            type = types[Number.parseInt(i.toString(), 10)];
            if ((type & PathPointType.closePath) === PathPointType.closePath) {
                this._sw._closePath();
            }
        }
    };
    /**
     * Reads the next Bezier control point and advances the index.
     *
     * @private
     * @param {Point[]} points The path points.
     * @param {PathPointType[]} types The point types.
     * @param {number} index The current index (at a Bezier marker).
     * @returns {{ index: number, point: Point }} The updated index and point.
     * @throws {Error} If the current type is not `bezier`.
     */
    PdfGraphics.prototype._getBezierPoint = function (points, types, index) {
        if (types[index] !== PathPointType.bezier) {
            throw new Error('Malforming path.');
        }
        index++;
        return { 'index': index, 'point': points[index] };
    };
    /**
     * Initializes internal graphics defaults state stack, color space flag, CTM caches, etc.
     *
     * @private
     * @returns {void}
     */
    PdfGraphics.prototype._initialize = function () {
        this._mediaBoxUpperRightBound = 0;
        this._characterSpacing = -1;
        this._wordSpacing = -1;
        this._textScaling = -100;
        this._textRenderingMode = -1;
        this._graphicsState = [];
        this._clipBounds = [0, 0, this._size.width, this._size.height];
        this._colorSpaceInitialized = false;
        this._startCutIndex = -1;
    };
    /**
     * Ensures both stroking and non-stroking color spaces are set to `DeviceRGB` once.
     *
     * @private
     * @returns {void}
     */
    PdfGraphics.prototype._initializeCurrentColorSpace = function () {
        if (!this._colorSpaceInitialized) {
            this._sw._setColorSpace('DeviceRGB', true);
            this._sw._setColorSpace('DeviceRGB', false);
            this._colorSpaceInitialized = true;
        }
    };
    /**
     * Applies the brush non-stroking color and caches it as the current brush.
     *
     * @private
     * @param {PdfBrush} brush The brush to apply.
     * @returns {void}
     */
    PdfGraphics.prototype._brushControl = function (brush) {
        this._sw._setColor([brush._color.r, brush._color.g, brush._color.b], false);
        this._currentBrush = brush;
    };
    /**
     * Applies the pen stroking attributes and caches it as the current pen.
     *
     * @private
     * @param {PdfPen} pen The pen to apply.
     * @returns {void}
     */
    PdfGraphics.prototype._penControl = function (pen) {
        this._currentPen = pen;
        this._writePen(pen);
        this._currentPen = pen;
    };
    /**
     * Registers/selects the font in resources if needed, sets size, and updates the text state.
     *
     * @private
     * @param {PdfFont} font The font to select.
     * @param {PdfStringFormat} format The text format (used for size resolution).
     * @returns {void}
     */
    PdfGraphics.prototype._fontControl = function (font, format) {
        var _this = this;
        var size = font._getSize(format);
        this._currentFont = font;
        var sourceDictionary;
        var isReference = false;
        var keyName;
        var isNew = true;
        var ref;
        var hasResource = false;
        if (this._resourceObject.has('Font')) {
            var obj = this._resourceObject.getRaw('Font'); // eslint-disable-line
            if (obj !== null && typeof obj !== 'undefined') {
                if (obj instanceof _PdfReference) {
                    isReference = true;
                    sourceDictionary = this._crossReference._fetch(obj);
                }
                else if (obj instanceof _PdfDictionary) {
                    sourceDictionary = obj;
                }
            }
            if (typeof sourceDictionary !== 'undefined' && sourceDictionary !== null) {
                isNew = false;
                this._resources.forEach(function (value, key) {
                    if (_this._crossReference) {
                        if (key !== null && typeof key !== 'undefined') {
                            var dictionary = _this._crossReference._fetch(key);
                            if (dictionary && ((font instanceof PdfStandardFont && dictionary === font._dictionary) ||
                                (font instanceof PdfTrueTypeFont && dictionary === font._fontInternal._fontDictionary) ||
                                (font instanceof PdfCjkStandardFont && dictionary === font._dictionary))) {
                                keyName = value;
                                ref = key;
                                hasResource = true;
                            }
                        }
                    }
                    else if (font._reference && font._reference === key) {
                        keyName = value;
                        ref = key;
                        hasResource = true;
                    }
                });
            }
        }
        if (isNew) {
            sourceDictionary = new _PdfDictionary(this._crossReference);
            this._resourceObject.update('Font', sourceDictionary);
        }
        if (typeof keyName === 'undefined') {
            if (!font._key) {
                font._key = _getNewGuidString();
            }
            keyName = _PdfName.get(font._key);
            if (!ref) {
                if (font._reference) {
                    ref = font._reference;
                    sourceDictionary.update(keyName.name, ref);
                }
                else if (this._crossReference) {
                    ref = this._crossReference._getNextReference();
                }
                else {
                    this._pendingResource.push({ 'resource': font, 'key': keyName, 'source': sourceDictionary });
                }
            }
            if (ref && this._crossReference) {
                if (!font._reference) {
                    font._reference = ref;
                }
                if (font._dictionary) {
                    this._crossReference._cacheMap.set(ref, font._dictionary);
                    sourceDictionary.update(keyName.name, ref);
                }
                else if (font instanceof PdfTrueTypeFont) {
                    var internal = font._fontInternal;
                    if (internal && internal._fontDictionary && !internal._fontDictionary._currentObj) {
                        this._crossReference._cacheMap.set(ref, internal._fontDictionary);
                    }
                    sourceDictionary.update(keyName.name, ref);
                }
            }
            if (!hasResource && ref) {
                this._resources.set(ref, keyName);
            }
        }
        if (isReference) {
            this._resourceObject._updated = true;
        }
        if (this._hasResourceReference) {
            this._source._updated = true;
        }
        this._sw._setFont(keyName.name, size);
    };
    /**
     * Resolves pen/brush overloads to a structured `{pen, brush}` result and applies state.
     *
     * @private
     * @param {PdfPen | PdfBrush} [first] Pen or brush.
     * @param {PdfBrush} [second] Optional brush.
     * @returns {{pen: PdfPen, brush: PdfBrush}} The resolved pen/brush.
     */
    PdfGraphics.prototype._setPenBrush = function (first, second) {
        var pen;
        var brush;
        if (first) {
            if (first instanceof PdfPen) {
                pen = first;
            }
            else {
                brush = first;
            }
        }
        if (second && second instanceof PdfBrush) {
            brush = second;
        }
        this._stateControl(pen, brush, null);
        return { pen: pen, brush: brush };
    };
    /**
     * Applies pen/brush/font state and initializes color spaces when needed.
     *
     * @private
     * @param {PdfPen} [pen] Optional pen to apply.
     * @param {PdfBrush} [brush] Optional brush to apply.
     * @param {PdfFont} [font] Optional font to select.
     * @param {PdfStringFormat} [format] Optional text format for font selection.
     * @returns {void}
     */
    PdfGraphics.prototype._stateControl = function (pen, brush, font, format) {
        if (pen || brush) {
            this._initializeCurrentColorSpace();
        }
        if (pen) {
            this._penControl(pen);
        }
        if (brush) {
            this._brushControl(brush);
        }
        if (font) {
            this._fontControl(font, format);
        }
    };
    /**
     * Renders a laid-out text result into the content stream with alignment, line spacing,
     * clipping, italic simulation, and resource finalization.
     *
     * @private
     * @param {_PdfStringLayoutResult} result The layout computation result.
     * @param {PdfFont} font The font to use.
     * @param {PdfPen} pen Optional pen for stroke text.
     * @param {PdfBrush} brush Optional brush for fill text.
     * @param {number[]} layoutRectangle [x, y, width, height] in user units.
     * @param {PdfStringFormat} format Text format settings.
     * @returns {void}
     */
    PdfGraphics.prototype._drawStringLayoutResult = function (result, font, pen, brush, layoutRectangle, format) {
        var _this = this;
        if (!result._empty) {
            var allowPartialLines = (format && typeof format.lineLimit !== 'undefined' && !format.lineLimit);
            var shouldClip = (typeof format === 'undefined' || (format && typeof format.noClip !== 'undefined'
                && !format.noClip));
            var clipRegion = allowPartialLines && shouldClip;
            var state = void 0;
            if (clipRegion) {
                state = this.save();
                var clipBounds = [layoutRectangle[0], layoutRectangle[1], result._actualSize.width, result._actualSize.height];
                if (layoutRectangle[2] > 0) {
                    clipBounds[2] = layoutRectangle[2];
                }
                if (format.lineAlignment === PdfVerticalAlignment.middle) {
                    clipBounds[1] += (layoutRectangle[3] - clipBounds[3]) / 2;
                }
                else if (format.lineAlignment === PdfVerticalAlignment.bottom) {
                    clipBounds[1] += (layoutRectangle[3] - clipBounds[3]);
                }
                this.setClip({ x: clipBounds[0], y: clipBounds[1], width: clipBounds[2], height: clipBounds[3] });
            }
            if (font && font instanceof PdfTrueTypeFont && font._fontInternal &&
                font._fontInternal instanceof _UnicodeTrueTypeFont && font.isItalic) {
                if (!font._fontInternal._ttfMetrics._isItalic) {
                    state = this.save();
                    this._isItalic = true;
                }
            }
            this._applyStringSettings(font, pen, brush, format);
            var textScaling = (typeof format !== 'undefined' && format !== null) ? format.horizontalScalingFactor : 100.0;
            if (textScaling !== this._textScaling) {
                this._sw._setTextScaling(textScaling);
                this._textScaling = textScaling;
            }
            var verticalAlignShift = this._getTextVerticalAlignShift(result._actualSize.height, layoutRectangle[3], format);
            var height = (typeof format === 'undefined' || format === null || format.lineSpacing === 0) ?
                font._getHeight(format) :
                format.lineSpacing + font._getHeight(format);
            var script = (format !== null && typeof format !== 'undefined' &&
                format.subSuperScript === PdfSubSuperScript.subScript);
            var shift = 0;
            shift = (script) ? height - (font.height + font._getDescent(format)) : (height - font._getAscent(format));
            if (format && format.lineAlignment === PdfVerticalAlignment.bottom) {
                var layoutStr = _numberToString(layoutRectangle[3]);
                var fontHeightStr = _numberToString(font._getHeight(format));
                if (layoutRectangle[3] - result._actualSize.height !== 0 &&
                    (layoutRectangle[3] - result._actualSize.height) < (font._size / 2) - 1) {
                    var layoutNum = +layoutStr;
                    var fontHeightNum = +fontHeightStr;
                    if (layoutNum <= fontHeightNum) {
                        shift = -(height / font._size);
                    }
                }
            }
            var matrix = new _PdfTransformationMatrix();
            if (this._isItalic) {
                this.translateTransform({ x: layoutRectangle[0] + font.size / 5, y: layoutRectangle[1] - shift + verticalAlignShift });
                this._skewTransform(0, -11);
            }
            else {
                matrix._translate(layoutRectangle[0], (-(layoutRectangle[1] + font._getHeight(format)) -
                    (font._getDescent(format) > 0 ? -font._getDescent(format) : font._getDescent(format))) -
                    verticalAlignShift);
                this._sw._modifyTM(matrix);
            }
            if (layoutRectangle[3] < font._size) {
                if ((result._actualSize.height - layoutRectangle[3]) < (font._size / 2) - 1) {
                    verticalAlignShift = 0;
                }
            }
            if (verticalAlignShift !== 0) {
                if (format !== null && format.lineAlignment === PdfVerticalAlignment.bottom) {
                    if (layoutRectangle[3] - result._actualSize.height !== 0 &&
                        (layoutRectangle[3] - result._actualSize.height) > (font._size / 2) - 1) {
                        verticalAlignShift -= (shift - (height - font._size)) / 2;
                    }
                }
            }
            if (this._isItalic) {
                this._sw._startNextLine(0, 0);
                this._sw._setLeading(+height);
            }
            this._drawLayoutResult(result, font, format, layoutRectangle);
            var internal_1 = this._currentFont._fontInternal;
            if ((font instanceof PdfTrueTypeFont) && font.isUnicode &&
                internal_1 && internal_1._fontDictionary && internal_1._fontDictionary._currentObj) {
                this._resourceMap.forEach(function (value, key) {
                    if (_this._crossReference && _this._crossReference._cacheMap
                        && !_this._crossReference._cacheMap.has(key)) {
                        internal_1._fontDictionary._currentObj._beginSave();
                        _this._crossReference._writeFontDictionary(internal_1._fontDictionary);
                        _this._crossReference._cacheMap.set(key, internal_1._fontDictionary);
                    }
                });
            }
            if (verticalAlignShift !== 0) {
                this._sw._startNextLine(0, -(verticalAlignShift - result._lineHeight));
            }
            _addProcSet('Text', this._resourceObject);
            this._sw._endText();
            if (this._isItalic) {
                this.restore(state);
            }
            this._underlineStrikeoutText(brush, result, font, layoutRectangle, format);
            if (clipRegion) {
                this.restore(state);
            }
        }
    };
    /**
     * Returns the next page if any, or creates and returns a new page at the end.
     *
     * @private
     * @returns {PdfPage} The next or newly created page.
     */
    PdfGraphics.prototype._getNextPage = function () {
        var page;
        var pageCount = this._crossReference._document.pageCount;
        if (this._page._pageIndex <= pageCount - 2) {
            page = this._crossReference._document.getPage(this._page._pageIndex + 1);
        }
        else {
            page = this._crossReference._document.addPage();
        }
        return page;
    };
    /**
     * Begins text object, applies text rendering mode, spacing, optional bold
     * emulation line width, and selects brush/pen/font as needed.
     *
     * @private
     * @param {PdfFont} font The font.
     * @param {PdfPen} pen Optional pen for stroke text.
     * @param {PdfBrush} brush Optional brush for fill text.
     * @param {PdfStringFormat} format Text format.
     * @returns {void}
     */
    PdfGraphics.prototype._applyStringSettings = function (font, pen, brush, format) {
        var tm = _TextRenderingMode.fill;
        var setLineWidth = false;
        if (pen && brush) {
            tm = _TextRenderingMode.fillStroke;
        }
        else if (pen) {
            tm = _TextRenderingMode.stroke;
        }
        else if (brush) {
            tm = _TextRenderingMode.fill;
        }
        if (font && font instanceof PdfTrueTypeFont && (font.isUnicode || (font._style & PdfFontStyle.bold) !== 0)) {
            var fontName = font._fontInternal._metrics._postScriptName;
            var isBoldFont = false;
            if (fontName && fontName.toLocaleLowerCase().includes('bold')) {
                isBoldFont = true;
            }
            if (font._fontInternal && font._fontInternal._metrics && font._fontInternal._metrics._isBold !==
                font.isBold && font.isBold === true && !isBoldFont) {
                if (!pen && brush) {
                    pen = new PdfPen(brush._color, 1);
                }
                tm = _TextRenderingMode.fillStroke;
                setLineWidth = true;
            }
        }
        if (format && format.clipPath) {
            tm |= _TextRenderingMode.clipFlag;
        }
        this._sw._beginText();
        this._stateControl(pen, brush, font, format);
        if (tm !== this._textRenderingMode) {
            this._sw._setTextRenderingMode(tm);
            this._textRenderingMode = tm;
        }
        var cs = (typeof format !== 'undefined' && format !== null) ? format.characterSpacing : 0;
        if (cs !== this._characterSpacing) {
            this._sw._setCharacterSpacing(cs);
            this._characterSpacing = cs;
        }
        var ws = (typeof format !== 'undefined' && format !== null) ? format.wordSpacing : 0;
        if (ws !== this._wordSpacing) {
            this._sw._setWordSpacing(ws);
            this._wordSpacing = ws;
        }
        if (font && setLineWidth) {
            this._sw._setLineWidth(font.size / 30);
        }
    };
    /**
     * Iterates through laid-out lines, applies horizontal alignment/indents, and writes
     * text runs with the appropriate encoding pipeline.
     *
     * @private
     * @param {_PdfStringLayoutResult} result The layout result.
     * @param {PdfFont} font The font in use.
     * @param {PdfStringFormat} format Text format.
     * @param {number[]} layoutRectangle [x, y, width, height] area for the text.
     * @returns {void}
     */
    PdfGraphics.prototype._drawLayoutResult = function (result, font, format, layoutRectangle) {
        var height = (typeof format === 'undefined' || format === null || format.lineSpacing === 0) ?
            font._getHeight(format) :
            format.lineSpacing + font._getHeight(format);
        var lines = result._lines;
        var ttfFont = font;
        var unicode = (ttfFont !== null && ttfFont.isUnicode);
        for (var i = 0, len = lines.length; (i < len && i !== this._startCutIndex); i++) {
            var lineInfo = lines[i];
            var lineWidth = lineInfo._width;
            var hAlignShift = this._getHorizontalAlignShift(lineWidth, layoutRectangle[2], format) +
                this._getLineIndent(lineInfo, format, layoutRectangle[2], (i === 0));
            if (hAlignShift !== 0) {
                this._sw._startNextLine(hAlignShift, 0);
            }
            if (font instanceof PdfCjkStandardFont) {
                this._drawCjkString(lineInfo, layoutRectangle, font, format);
            }
            else if (unicode) {
                this._drawUnicodeLine(lineInfo, layoutRectangle[2], font, format);
            }
            else {
                this._drawAsciiLine(lineInfo, layoutRectangle[2], format, font);
            }
            if (i + 1 !== len) {
                var vAlignShift = this._getTextVerticalAlignShift(result._actualSize.height, layoutRectangle[3], format);
                var matrix = new _PdfTransformationMatrix();
                var baseline = ((-(layoutRectangle[1] + font._getHeight(format)) -
                    font._getDescent(format)) -
                    vAlignShift) -
                    (height * (i + 1));
                matrix._translate(layoutRectangle[0], baseline);
                this._sw._modifyTM(matrix);
            }
        }
    };
    /**
     * Encodes and writes a CJK line, applying justification spacing when required.
     *
     * @private
     * @param {_LineInfo} lineInfo The line to render.
     * @param {number[]} layoutRectangle [x, y, width, height].
     * @param {PdfFont} font The CJK font.
     * @param {PdfStringFormat} format Text format.
     * @returns {void}
     */
    PdfGraphics.prototype._drawCjkString = function (lineInfo, layoutRectangle, font, format) {
        if (font) {
            this._justifyLine(lineInfo, layoutRectangle[2], format, font);
            var line = lineInfo._text;
            var lines = this._getCjkString(line);
            var value = _bytesToString(lines);
            this._sw._showNextLineText('(' + value + ')', false);
        }
    };
    /**
     * Converts a string to a UTF 16BE byte array and escapes PDF literal string symbols.
     *
     * @private
     * @param {string} line The input text.
     * @returns {Uint8Array} The escaped byte array.
     * @throws {Error} If the input is null or undefined.
     */
    PdfGraphics.prototype._getCjkString = function (line) {
        if (line === null || typeof line === 'undefined') {
            throw new Error('line cannot be null');
        }
        var value = _stringToUnicodeArray(line);
        value = this._escapeSymbols(value);
        return value;
    };
    /**
     * Escapes '(', ')', '\\', and CR for safe inclusion in a PDF literal string.
     *
     * @private
     * @param {Uint8Array} data The raw bytes.
     * @returns {Uint8Array} The escaped bytes.
     * @throws {Error} If `data` is null.
     */
    PdfGraphics.prototype._escapeSymbols = function (data) {
        if (data === null) {
            throw new Error('data cannot be null');
        }
        var escaped = [];
        for (var i = 0, len = data.length; i < len; i++) {
            var bt = data[i]; // eslint-disable-line
            switch (bt) {
                case 40:
                case 41:
                case 92:
                    escaped.push(92);
                    escaped.push(bt);
                    break;
                case 13:
                    escaped.push(92);
                    escaped.push(114);
                    break;
                default:
                    escaped.push(bt);
                    break;
            }
        }
        return new Uint8Array(escaped);
    };
    /**
     * Draws a Unicode line, handling BiDi/RTL, Arabic shaping, word-space justification,
     * and per-word encoding when required.
     *
     * @private
     * @param {_LineInfo} lineInfo The line info.
     * @param {number} width Available width for justification.
     * @param {PdfFont} font A Unicode TrueType font.
     * @param {PdfStringFormat} format Text format.
     * @returns {void}
     */
    PdfGraphics.prototype._drawUnicodeLine = function (lineInfo, width, font, format) {
        var line = lineInfo._text;
        var rtl = (format !== null && typeof format !== 'undefined' && format.rightToLeft);
        var useWordSpace = (format !== null && typeof format !== 'undefined' && format.wordSpacing > 0);
        var ttfFont = font;
        var wordSpacing = this._justifyLine(lineInfo, width, format, ttfFont);
        var rtlRender = new _RtlRenderer();
        if (rtl || (format !== null && typeof format !== 'undefined' && format.textDirection !== PdfTextDirection.none)) {
            var blocks = [];
            var rightAlign = (format !== null && typeof format !== 'undefined' && format.alignment === PdfTextAlignment.right);
            if (format !== null && typeof format !== 'undefined' && format.textDirection !== PdfTextDirection.none) {
                blocks = rtlRender._layout(line, ttfFont, (format.textDirection === PdfTextDirection.rightToLeft) ? true : false, useWordSpace, format);
            }
            else {
                blocks = rtlRender._layout(line, ttfFont, rightAlign, useWordSpace, format);
            }
            var words = [];
            if (blocks.length > 1) {
                if (format !== null && typeof format !== 'undefined' && format.textDirection !== PdfTextDirection.none) {
                    words = rtlRender._splitLayout(line, ttfFont, (format.textDirection === PdfTextDirection.rightToLeft) ? true : false, useWordSpace, format);
                }
            }
            else {
                words = [line];
            }
            this._drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing);
        }
        else {
            if (useWordSpace) {
                var result = this._breakUnicodeLine(line, ttfFont, null);
                var blocks = result.tokens;
                var words = result.words;
                this._drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing);
            }
            else {
                var token = this._convertToUnicode(line, ttfFont);
                this._sw._showNextLineText(token, true);
            }
        }
    };
    /**
     * Renders tokenized Unicode runs with explicit positioning to account for
     * word spacing and character spacing.
     *
     * @private
     * @param {string[]} blocks Encoded tokens matching `words`.
     * @param {string[]} words Original word tokens (visual order).
     * @param {PdfTrueTypeFont} font The TrueType font.
     * @param {PdfStringFormat} format Text format.
     * @param {number} wordSpacing Computed justification word spacing (extra).
     * @returns {void}
     */
    PdfGraphics.prototype._drawUnicodeBlocks = function (blocks, words, font, format, wordSpacing) {
        if (blocks !== null && typeof blocks !== 'undefined' && blocks.length > 0 && words !== null && typeof words !== 'undefined' &&
            words.length > 0 && font !== null && typeof font !== 'undefined') {
            this._sw._startNextLine();
            var x = 0;
            var xShift = 0;
            var firstLineIndent = 0;
            var paragraphIndent = 0;
            try {
                if (format !== null && typeof format !== 'undefined') {
                    firstLineIndent = format.firstLineIndent;
                    paragraphIndent = format.paragraphIndent;
                    format.firstLineIndent = 0;
                    format.paragraphIndent = 0;
                }
                var spaceWidth = font._getCharacterWidth(_StringTokenizer._whiteSpace, format) + wordSpacing;
                var characterSpacing = (format !== null) ? format.characterSpacing : 0;
                var wordSpace = (format !== null && typeof format !== 'undefined' && wordSpacing === 0) ? format.wordSpacing : 0;
                spaceWidth += characterSpacing + wordSpace;
                for (var i = 0; i < blocks.length; i++) {
                    var token = blocks[i]; //eslint-disable-line
                    var word = words[i]; //eslint-disable-line
                    var tokenWidth = 0;
                    if (x !== 0) {
                        this._sw._startNextLine(x, 0);
                    }
                    if (word.length > 0) {
                        tokenWidth += font.measureString(word, format).width;
                        tokenWidth += characterSpacing;
                        this._sw._showText(token);
                    }
                    if (i !== blocks.length - 1) {
                        x = tokenWidth + spaceWidth;
                        xShift += x;
                    }
                }
                if (xShift > 0) {
                    this._sw._startNextLine(-xShift, 0);
                }
            }
            finally {
                if (format !== null && typeof format !== 'undefined') {
                    format.firstLineIndent = firstLineIndent;
                    format.paragraphIndent = paragraphIndent;
                }
            }
        }
    };
    /**
     * Splits a Unicode line into words, converts each word via the font reader,
     * and returns both the encoded tokens and original words.
     *
     * @private
     * @param {string} line The line to split.
     * @param {PdfTrueTypeFont} ttfFont The TrueType font.
     * @param {string[]} words Output word array (ignored on input).
     * @returns {{tokens: string[], words: string[]}} The encoded tokens and raw words.
     */
    PdfGraphics.prototype._breakUnicodeLine = function (line, ttfFont, words) {
        var tokens = [];
        if (line !== null && typeof line !== 'undefined' && line.length > 0) {
            words = line.split(null);
            for (var i = 0; i < words.length; i++) {
                var word = words[i];
                var token = this._convertToUnicode(word, ttfFont);
                tokens.push(token);
            }
        }
        return { tokens: tokens, words: words };
    };
    /**
     * Converts a string using the font's TrueType reader and returns a PDF-safe
     * UTF-16BE literal string.
     *
     * @private
     * @param {string} text The text to convert.
     * @param {PdfTrueTypeFont} ttfFont The font used for conversion.
     * @returns {string} The converted PDF string (literal).
     */
    PdfGraphics.prototype._convertToUnicode = function (text, ttfFont) {
        var token = null;
        if (text !== null && typeof text !== 'undefined' && ttfFont !== null && typeof ttfFont !== 'undefined' &&
            ttfFont._fontInternal instanceof _UnicodeTrueTypeFont) {
            var ttfReader = ttfFont._fontInternal._ttfReader;
            ttfFont._setSymbols(text);
            token = ttfReader._convertString(text);
            var bytes = _stringToUnicodeArray(token);
            token = _bytesToString(bytes);
        }
        return token;
    };
    /**
     * Computes the vertical offset needed to achieve the requested vertical alignment.
     *
     * @private
     * @param {number} textHeight Height of laid-out text.
     * @param {number} boundsHeight Height of layout rectangle.
     * @param {PdfStringFormat} format Text format.
     * @returns {number} The vertical shift in user units.
     */
    PdfGraphics.prototype._getTextVerticalAlignShift = function (textHeight, boundsHeight, format) {
        var shift = 0;
        if (boundsHeight >= 0 && (typeof format !== 'undefined' && format !== null) && format.lineAlignment !== PdfVerticalAlignment.top) {
            switch (format.lineAlignment) {
                case PdfVerticalAlignment.middle:
                    shift = (boundsHeight - textHeight) / 2;
                    break;
                case PdfVerticalAlignment.bottom:
                    shift = boundsHeight - textHeight;
                    break;
            }
        }
        return shift;
    };
    /**
     * Computes the horizontal offset needed to achieve the requested horizontal alignment.
     *
     * @private
     * @param {number} lineWidth The width of the rendered line.
     * @param {number} boundsWidth The available width.
     * @param {PdfStringFormat} format Text format.
     * @returns {number} The horizontal shift in user units.
     */
    PdfGraphics.prototype._getHorizontalAlignShift = function (lineWidth, boundsWidth, format) {
        var shift = 0;
        if (boundsWidth >= 0 && (typeof format !== 'undefined' && format !== null) && format.alignment !== PdfTextAlignment.left) {
            switch (format.alignment) {
                case PdfTextAlignment.center:
                    shift = (boundsWidth - lineWidth) / 2;
                    break;
                case PdfTextAlignment.right:
                    shift = boundsWidth - lineWidth;
                    break;
            }
        }
        return shift;
    };
    /**
     * Resolves paragraph/first line indents for the given line respecting bounds width.
     *
     * @private
     * @param {_LineInfo} lineInfo The line info.
     * @param {PdfStringFormat} format Text format.
     * @param {number} width The line width bound.
     * @param {boolean} firstLine True if this is the first line of the paragraph.
     * @returns {number} The indent in user units.
     */
    PdfGraphics.prototype._getLineIndent = function (lineInfo, format, width, firstLine) {
        var lineIndent = 0;
        var firstParagraphLine = ((lineInfo._lineType & _LineType.firstParagraphLine) > 0);
        if (format && firstParagraphLine) {
            lineIndent = (firstLine) ? format.firstLineIndent : format.paragraphIndent;
            lineIndent = (width > 0) ? Math.min(width, lineIndent) : lineIndent;
        }
        return lineIndent;
    };
    /**
     * Writes an ASCII line as a PDF literal string, escaping parentheses,
     * and applying justification if required.
     *
     * @private
     * @param {_LineInfo} lineInfo The line to draw.
     * @param {number} width Available width for justification.
     * @param {PdfStringFormat} format Text format.
     * @param {PdfFont} font The font used to measure.
     * @returns {void}
     */
    PdfGraphics.prototype._drawAsciiLine = function (lineInfo, width, format, font) {
        this._justifyLine(lineInfo, width, format, font);
        var value = '';
        if (lineInfo._text.indexOf('(') !== -1 || lineInfo._text.indexOf(')') !== -1 ||
            lineInfo._text.indexOf('\\') !== -1 || lineInfo._text.indexOf('\r') !== -1) {
            var text = lineInfo._text;
            for (var i = 0, len = text.length; i < len; i++) {
                var char = text[i];
                if (char === '(') {
                    value += '\\(';
                }
                else if (char === ')') {
                    value += '\\)';
                }
                else if (char === '\\') {
                    value += '\\\\';
                }
                else if (char === '\r') {
                    value += '\\r';
                }
                else {
                    value += char;
                }
            }
        }
        if (value === '') {
            value = lineInfo._text;
        }
        this._sw._showNextLineText('(' + value + ')');
    };
    /**
     * Applies word spacing justification to the current line if conditions are met.
     *
     * @private
     * @param {_LineInfo} lineInfo The line info.
     * @param {number} boundsWidth The line width bound.
     * @param {PdfStringFormat} format Text format.
     * @param {PdfFont} font Font for measuring spaces.
     * @returns {number} The extra word spacing applied per whitespace.
     */
    PdfGraphics.prototype._justifyLine = function (lineInfo, boundsWidth, format, font) {
        var line = lineInfo._text;
        var lineWidth = lineInfo._width;
        var shouldJustify = this._shouldJustify(lineInfo, boundsWidth, format, font);
        var hasWordSpacing = (format && format.wordSpacing !== 0);
        var whitespacesCount = font._getCharacterCount(line, [' ', '\t']);
        var wordSpace = 0;
        if (shouldJustify) {
            if (hasWordSpacing) {
                lineWidth -= (whitespacesCount * format.wordSpacing);
            }
            wordSpace = (boundsWidth - lineWidth) / whitespacesCount;
            this._sw._setWordSpacing(wordSpace);
        }
        else if (format && format.alignment === PdfTextAlignment.justify) {
            this._sw._setWordSpacing(0);
        }
        return wordSpace;
    };
    /**
     * Determines whether the current line should be justified based on alignment,
     * width, whitespace presence, and line break type.
     *
     * @private
     * @param {_LineInfo} lineInfo The line info.
     * @param {number} boundsWidth The width bound.
     * @param {PdfStringFormat} format Text format.
     * @param {PdfFont} font Font for character counting.
     * @returns {boolean} True if justification should be applied.
     */
    PdfGraphics.prototype._shouldJustify = function (lineInfo, boundsWidth, format, font) {
        var line = lineInfo._text;
        var lineWidth = lineInfo._width;
        var justifyStyle = (format && format.alignment === PdfTextAlignment.justify);
        var goodWidth = (boundsWidth >= 0 && lineWidth < boundsWidth);
        var whitespacesCount = font._getCharacterCount(line, [' ', '\t']);
        var hasSpaces = (whitespacesCount > 0 && line[0] !== ' ');
        var goodLineBreakStyle = ((lineInfo._lineType & _LineType.layoutBreak) > 0);
        return (justifyStyle && goodWidth && hasSpaces && goodLineBreakStyle);
    };
    /**
     * Draws underline and/or strikeout lines over the rendered text according to font flags.
     *
     * @private
     * @param {PdfBrush} brush The brush used to color the decoration lines.
     * @param {_PdfStringLayoutResult} result The layout result.
     * @param {PdfFont} font The font used.
     * @param {number[]} layoutRectangle [x, y, width, height] text bounds.
     * @param {PdfStringFormat} format Text format.
     * @returns {void}
     */
    PdfGraphics.prototype._underlineStrikeoutText = function (brush, result, font, layoutRectangle, format) {
        if (font.isUnderline || font.isStrikeout) {
            var linePen = this._createUnderlineStrikeoutPen(brush, font);
            if (typeof linePen !== 'undefined' && linePen !== null) {
                var shift = this._getTextVerticalAlignShift(result._actualSize.height, layoutRectangle[3], format);
                var underlineYOffset = layoutRectangle[1] + shift + font._getAscent(format) + 1.5 * linePen._width;
                var strikeoutYOffset = layoutRectangle[1] + shift + font._getHeight(format) / 2 + 1.5 * linePen._width;
                var lines = result._lines;
                for (var i = 0, len = lines.length; i < len; i++) {
                    var lineInfo = lines[i];
                    var lineWidth = lineInfo._width;
                    var hShift = this._getHorizontalAlignShift(lineWidth, layoutRectangle[2], format);
                    var lineIndent = this._getLineIndent(lineInfo, format, layoutRectangle[2], (i === 0));
                    var x1 = layoutRectangle[0] + hShift;
                    var x2 = (!this._shouldJustify(lineInfo, layoutRectangle[2], format, font)) ?
                        x1 + lineWidth - lineIndent :
                        x1 + layoutRectangle[2] - lineIndent;
                    if (font.isUnderline) {
                        this.drawLine(linePen, { x: x1, y: underlineYOffset }, { x: x2, y: underlineYOffset });
                        underlineYOffset += result._lineHeight;
                    }
                    if (font.isStrikeout) {
                        this.drawLine(linePen, { x: x1, y: strikeoutYOffset }, { x: x2, y: strikeoutYOffset });
                        strikeoutYOffset += result._lineHeight;
                    }
                }
            }
        }
    };
    /**
     * Creates a pen for underline/strikeout based on the brush color and font size.
     *
     * @private
     * @param {PdfBrush} brush The text fill brush.
     * @param {PdfFont} font The font used .
     * @returns {PdfPen} The decoration pen.
     */
    PdfGraphics.prototype._createUnderlineStrikeoutPen = function (brush, font) {
        var brushColor = brush ? brush._color : undefined;
        return new PdfPen(brushColor, font._size / 20);
    };
    /**
     * Computes the top-left anchor for the text rectangle based on alignment against (x, y).
     *
     * @private
     * @param {number[]} textSize The measured text size as [width, height].
     * @param {number} x Anchor X.
     * @param {number} y Anchor Y.
     * @param {PdfStringFormat} format Text format alignment / line alignment.
     * @returns {number[]} The adjusted rectangle [x, y, width, height].
     */
    PdfGraphics.prototype._checkCorrectLayoutRectangle = function (textSize, x, y, format) {
        var layoutedRectangle = [x, y, textSize[0], textSize[0]];
        if (format) {
            switch (format.alignment) {
                case PdfTextAlignment.center:
                    layoutedRectangle[0] = layoutedRectangle[0] - layoutedRectangle[2] / 2;
                    break;
                case PdfTextAlignment.right:
                    layoutedRectangle[0] = layoutedRectangle[0] - layoutedRectangle[2];
                    break;
            }
            switch (format.lineAlignment) {
                case PdfVerticalAlignment.middle:
                    layoutedRectangle[1] = layoutedRectangle[1] - layoutedRectangle[3] / 2;
                    break;
                case PdfVerticalAlignment.bottom:
                    layoutedRectangle[1] = layoutedRectangle[1] - layoutedRectangle[3];
                    break;
            }
        }
        return layoutedRectangle;
    };
    /**
     * Finishes the current path by stroking/filling/closing based on pen/brush and fill mode.
     *
     * @private
     * @param {PdfPen} [pen] Optional stroke pen.
     * @param {PdfBrush} [brush] Optional fill brush.
     * @param {PdfFillMode} [fillMode=PdfFillMode.winding] Fill rule to use.
     * @param {boolean} [needClosing=false] Whether to close the path before painting.
     * @returns {void}
     */
    PdfGraphics.prototype._drawGraphicsPath = function (pen, brush, fillMode, needClosing) {
        if (typeof fillMode === 'undefined') {
            fillMode = PdfFillMode.winding;
        }
        var isBrush = (typeof brush !== 'undefined' && brush !== null);
        var isPen = (typeof pen !== 'undefined' && pen !== null);
        var isEvenOdd = fillMode === PdfFillMode.alternate;
        if (isPen && isBrush) {
            if (needClosing) {
                this._sw._closeFillStrokePath(isEvenOdd);
            }
            else {
                this._sw._fillStrokePath(isEvenOdd);
            }
        }
        else if (!isPen && !isBrush) {
            this._sw._endPath();
        }
        else if (isPen) {
            if (needClosing) {
                this._sw._closeStrokePath();
            }
            else {
                this._sw._strokePath();
            }
        }
        else {
            if (needClosing) {
                this._sw._closeFillPath(isEvenOdd);
            }
            else {
                this._sw._fillPath(isEvenOdd);
            }
        }
    };
    /**
     * Adjusts the coordinate system for page/template rendering, translating to a
     * top-left origin if needed and honoring CropBox/MediaBox combinations.
     *
     * @private
     * @param {PdfPage} [page] Optional page context.
     * @returns {void}
     */
    PdfGraphics.prototype._initializeCoordinates = function (page) {
        var cbox;
        if (page) {
            var location_1 = [0, 0];
            var needTransformation = false;
            if (page._pageDictionary.has('CropBox') && page._pageDictionary.has('MediaBox')) {
                cbox = page._pageDictionary.getArray('CropBox');
                var mbox = page._pageDictionary.getArray('MediaBox');
                if (cbox[0] === mbox[0] && cbox[1] === mbox[1] && cbox[2] === mbox[2] && cbox[3] === mbox[3]) {
                    needTransformation = true;
                }
                if (cbox[0] > 0 && cbox[3] > 0 && mbox[0] < 0 && mbox[1] < 0) {
                    this.translateTransform({ x: cbox[0], y: -cbox[3] });
                    location_1[0] = -cbox[0];
                    location_1[1] = cbox[3];
                }
                else if (!page._pageDictionary.has('CropBox')) {
                    needTransformation = true;
                }
                if (needTransformation) {
                    this._sw._writeComment('Change co-ordinate system to left/top.');
                    if (this._cropBox) {
                        this.translateTransform({ x: this._cropBox[0], y: -this._cropBox[3] });
                    }
                    else {
                        if (-(page._origin[1]) < this._mediaBoxUpperRightBound || this._mediaBoxUpperRightBound === 0) {
                            this.translateTransform({ x: 0, y: -this._size.height });
                        }
                        else {
                            this.translateTransform({ x: 0, y: -this._mediaBoxUpperRightBound });
                        }
                    }
                }
            }
        }
        else {
            this._sw._writeComment('Change co-ordinate system to left/top.');
            if (this._mediaBoxUpperRightBound !== (-this._size.height)) {
                if (this._cropBox) {
                    cbox = this._cropBox;
                    if (cbox[0] > 0 || cbox[1] > 0 || this._size.width === cbox[2] || this._size.height === cbox[3]) {
                        this.translateTransform({ x: cbox[0], y: -cbox[3] });
                    }
                    else {
                        if (this._mediaBoxUpperRightBound === this._size.height || this._mediaBoxUpperRightBound === 0) {
                            this.translateTransform({ x: 0, y: -this._size.height });
                        }
                        else {
                            this.translateTransform({ x: 0, y: -this._mediaBoxUpperRightBound });
                        }
                    }
                }
                else {
                    if (this._mediaBoxUpperRightBound === this._size.height || this._mediaBoxUpperRightBound === 0) {
                        this.translateTransform({ x: 0, y: -this._size.height });
                    }
                    else {
                        this.translateTransform({ x: 0, y: -this._mediaBoxUpperRightBound });
                    }
                }
            }
        }
    };
    /**
     * Caches an existing transparency `ExtGState` entry in the internal map and
     * reconstructs its composite key.
     *
     * @private
     * @param {_PdfReference} ref The graphics state reference.
     * @param {_PdfName} name The resource name.
     * @returns {void}
     */
    PdfGraphics.prototype._setTransparencyData = function (ref, name) {
        this._resourceMap.set(ref, name);
        var dictionary = this._crossReference._fetch(ref);
        var stroke = 0;
        var fill = 0;
        var mode = 0;
        if (dictionary) {
            if (dictionary.has('CA')) {
                stroke = dictionary.get('CA');
            }
            if (dictionary.has('ca')) {
                fill = dictionary.get('ca');
            }
            if (dictionary.has('ca')) {
                fill = dictionary.get('ca');
            }
            if (dictionary.has('BM')) {
                mode = _mapBlendMode(dictionary.get('BM'));
            }
        }
        var tkey = 'CA:' + stroke.toString() + '_ca:' + fill.toString() + '_BM:' + mode.toString();
        var tdata = new _TransparencyData();
        tdata._dictionary = dictionary;
        tdata._key = tkey;
        tdata._name = name;
        tdata._reference = ref;
        this._transparencies.set(tdata, tkey);
    };
    /**
     * Applies a translation x, -y to the provided matrix and returns it.
     *
     * @private
     * @param {number} x Translation along X.
     * @param {number} y Translation along Y.
     * @param {_PdfTransformationMatrix} input The matrix to mutate.
     * @returns {_PdfTransformationMatrix} The mutated matrix.
     */
    PdfGraphics.prototype._getTranslateTransform = function (x, y, input) {
        input._translate(x, -y);
        return input;
    };
    /**
     * Applies a scale to the provided matrix and returns it.
     *
     * @private
     * @param {number} x Scale along X.
     * @param {number} y Scale along Y.
     * @param {_PdfTransformationMatrix} input The matrix to mutate (or create).
     * @returns {_PdfTransformationMatrix} The mutated matrix.
     */
    PdfGraphics.prototype._getScaleTransform = function (x, y, input) {
        if (input === null || typeof input === 'undefined') {
            input = new _PdfTransformationMatrix();
        }
        input._scale(x, y);
        return input;
    };
    /**
     * Clips to the specified bounds and translates the coordinate system to the
     * new top left origin.
     *
     * @private
     * @param {number[]} clipBounds [x, y, width, height] clipping rectangle.
     * @returns {void}
     */
    PdfGraphics.prototype._clipTranslateMargins = function (clipBounds) {
        this._clipBounds = clipBounds;
        this._sw._writeComment('Clip margins.');
        this._sw._appendRectangle(clipBounds[0], clipBounds[1], clipBounds[2], clipBounds[3]);
        this._sw._closePath();
        this._sw._clipPath(false);
        this._sw._writeComment('Translate co-ordinate system.');
        this.translateTransform({ x: clipBounds[0], y: clipBounds[1] });
    };
    /**
     * Applies a clipping rectangle and translates the graphics coordinate system
     * based on the specified margin and template bounds.
     *
     * @private
     * @param {number[]} clipBounds The bounds used to compute clipping and translation,
     * specified as an array containing margin and template offsets.
     * @returns {void} Nothing.
     */
    PdfGraphics.prototype._clipTranslateMarginsWithBounds = function (clipBounds) {
        var bounds = [clipBounds[2], clipBounds[3], this._size.width - clipBounds[2] - clipBounds[4],
            this._size.height - clipBounds[3] - clipBounds[4]];
        this._clipBounds = bounds;
        this._sw._writeComment('Clip margins.');
        this._sw._appendRectangle(bounds[0], bounds[1], bounds[2], bounds[3]);
        this._sw._closePath();
        this._sw._clipPath(false);
        this._sw._writeComment('Translate co-ordinate system.');
        this.translateTransform({ x: clipBounds[0], y: clipBounds[1] });
    };
    /**
     * Applies a skew to the current CTM by composing a skew matrix into the stream
     * and accumulating it into the local CTM.
     *
     * @private
     * @param {number} angleX Skew angle along X (degrees).
     * @param {number} angleY Skew angle along Y (degrees).
     * @returns {void}
     */
    PdfGraphics.prototype._skewTransform = function (angleX, angleY) {
        var matrix = new _PdfTransformationMatrix();
        this._getSkewTransform(angleX, angleY, matrix);
        this._sw._modifyCtm(matrix);
        matrix._multiply(matrix);
    };
    /**
     * Skews the provided matrix by -angleX, -angleY and returns it.
     *
     * @private
     * @param {number} angleX Skew angle X in degrees.
     * @param {number} angleY Skew angle Y in degrees.
     * @param {_PdfTransformationMatrix} input The matrix to mutate.
     * @returns {_PdfTransformationMatrix} The mutated matrix.
     */
    PdfGraphics.prototype._getSkewTransform = function (angleX, angleY, input) {
        input._skew(-angleX, -angleY);
        return input;
    };
    return PdfGraphics;
}());
export { PdfGraphics };
/**
 * Represents an internal affine transformation matrix used for PDF graphics
 * operations such as translate, scale, rotate, skew, and matrix multiplication.
 *
 * @private
 */
var _PdfTransformationMatrix = /** @class */ (function () {
    /**
     * Initializes a new identity transformation matrix (1 0 0 1 0 0).
     *
     * @private
     */
    function _PdfTransformationMatrix() {
        this._matrix = new _Matrix(1, 0, 0, 1, 0, 0);
    }
    /**
     * Applies a translation to the matrix.
     *
     * @param {number} x Horizontal translation.
     * @param {number} y Vertical translation.
     * @returns {void} nothing.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._translate = function (x, y) {
        this._matrix._translate(x, y);
    };
    /**
     * Replaces the scale components of the transformation matrix.
     *
     * @param {number} x Scale value along X.
     * @param {number} y Scale value along Y.
     * @returns {void} nothing.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._scale = function (x, y) {
        this._matrix._elements[0] = x;
        this._matrix._elements[3] = y;
    };
    /**
     * Rotates the matrix by the specified angle in degrees.
     *
     * @param {number} angle Rotation angle in degrees.
     * @returns {void} nothing.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._rotate = function (angle) {
        angle = (angle * Math.PI) / 180;
        this._matrix._elements[0] = Math.cos(angle);
        this._matrix._elements[1] = Math.sin(angle);
        this._matrix._elements[2] = -Math.sin(angle);
        this._matrix._elements[3] = Math.cos(angle);
    };
    /**
     * Multiplies this transformation matrix with another transformation matrix.
     *
     * @param {_PdfTransformationMatrix} matrix The matrix to multiply with.
     * @returns {void} nothing.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._multiply = function (matrix) {
        this._matrix._multiply(matrix._matrix);
    };
    /**
     * Converts the matrix into a space-separated string representation suitable
     * for writing into a PDF content stream.
     *
     * @returns {string} String representation of the matrix.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._toString = function () {
        var builder = '';
        this._matrix._elements.forEach(function (element) {
            builder += _floatToString(element) + ' ';
        });
        return builder;
    };
    /**
     * Applies a skew transform using tangent based shear operations.
     *
     * @param {number} angleX Skew angle along X axis in degrees.
     * @param {number} angleY Skew angle along Y axis in degrees.
     * @returns {void} nothing.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._skew = function (angleX, angleY) {
        var tanA = Math.tan(this._degreeToRadians(angleX));
        var tanB = Math.tan(this._degreeToRadians(angleY));
        var skew = new _Matrix(1, tanA, tanB, 1, 0, 0);
        this._matrix._multiply(skew);
    };
    /**
     * Converts degrees to radians.
     *
     * @param {number} degreesX Angle in degrees.
     * @returns {number} Equivalent angle in radians.
     *
     * @private
     */
    _PdfTransformationMatrix.prototype._degreeToRadians = function (degreesX) {
        var degreeRadFactor = Math.PI / 180;
        return degreeRadFactor * degreesX;
    };
    return _PdfTransformationMatrix;
}());
export { _PdfTransformationMatrix };
/**
 * Internal low level 2D affine matrix representing the six element PDF transformation matrix.
 *
 * @private
 */
var _Matrix = /** @class */ (function () {
    function _Matrix(arg1, arg2, arg3, arg4, arg5, arg6) {
        if (typeof arg1 === 'undefined') {
            this._elements = [];
        }
        else if (typeof arg1 === 'number') {
            this._elements = [arg1, arg2, arg3, arg4, arg5, arg6];
        }
        else {
            this._elements = arg1;
        }
    }
    Object.defineProperty(_Matrix.prototype, "_offsetX", {
        /**
         * Gets the translation dx component of the matrix.
         *
         * @returns {number} The X offset.
         *
         * @private
         */
        get: function () {
            return this._elements[4];
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_Matrix.prototype, "_offsetY", {
        /**
         * Gets the translation dy component of the matrix.
         *
         * @returns {number} The Y offset.
         *
         * @private
         */
        get: function () {
            return this._elements[5];
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Creates a deep copy of the matrix.
     *
     * @returns {_Matrix} A new matrix with identical values.
     *
     * @private
     */
    _Matrix.prototype._clone = function () {
        return new _Matrix(this._elements.slice());
    };
    /**
     * Overrides the translation components of the matrix.
     *
     * @param {number} x X translation.
     * @param {number} y Y translation.
     * @returns {void} nothing.
     *
     * @private
     */
    _Matrix.prototype._translate = function (x, y) {
        this._elements[4] = x;
        this._elements[5] = y;
    };
    /**
     * Transforms a point using this matrix.
     *
     * @param {Point} points The point to transform.
     * @returns {Point} The transformed point.
     *
     * @private
     */
    _Matrix.prototype._transform = function (points) {
        var x = points.x;
        var y = points.y;
        var x2 = x * this._elements[0] + y * this._elements[2] + this._offsetX;
        var y2 = x * this._elements[1] + y * this._elements[3] + this._offsetY;
        return { x: x2, y: y2 };
    };
    /**
     * Multiplies this matrix with another matrix using affine matrix multiplication rules.
     *
     * @param {_Matrix} matrix The matrix to multiply with.
     * @returns {void} nothing.
     *
     * @private
     */
    _Matrix.prototype._multiply = function (matrix) {
        this._elements = [(this._elements[0] * matrix._elements[0] + this._elements[1] * matrix._elements[2]),
            (this._elements[0] * matrix._elements[1] + this._elements[1] * matrix._elements[3]),
            (this._elements[2] * matrix._elements[0] + this._elements[3] * matrix._elements[2]),
            (this._elements[2] * matrix._elements[1] + this._elements[3] * matrix._elements[3]),
            (this._offsetX * matrix._elements[0] + this._offsetY * matrix._elements[2] + matrix._offsetX),
            (this._offsetX * matrix._elements[1] + this._offsetY * matrix._elements[3] + matrix._offsetY)];
    };
    return _Matrix;
}());
export { _Matrix };
/**
 * Represents a state of the graphics from a PDF page.
 *
 * ```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 font
 * let font: PdfFont = document.embedFont(PdfFontFamily.helvetica, 20, PdfFontStyle.regular);
 * // Save the graphics state
 * let state: PdfGraphicsState = graphics.save();
 * // Set graphics translate transform
 * graphics.translateTransform({x: 100, y: 100});
 * // Draw the string
 * graphics.drawString('Hello world!', font, {x: 10, y: 20, width: 100, height: 200}, new PdfBrush({r: 0, g: 0, b: 255}));
 * // Restore the graphics state
 * graphics.restore(state);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfGraphicsState = /** @class */ (function () {
    /**
     * Initializes a new instance of the `PdfGraphicsState` class.
     *
     * @private
     * @param {PdfGraphics} graphics Graphics.
     * @param {_PdfTransformationMatrix} matrix Matrix.
     *
     */
    function PdfGraphicsState(graphics, matrix) {
        if (graphics) {
            this._g = graphics;
            this._transformationMatrix = matrix;
        }
        this._charSpacing = 0;
        this._wordSpacing = 0;
        this._textScaling = 100;
        this._textRenderingMode = _TextRenderingMode.fill;
    }
    return PdfGraphicsState;
}());
export { PdfGraphicsState };
/**
 * Internal container for an ExtGState transparency object, including its
 * dictionary, name, reference, and unique cache key.
 *
 * @private
 */
var _TransparencyData = /** @class */ (function () {
    function _TransparencyData() {
    }
    return _TransparencyData;
}());
export var _TextRenderingMode;
(function (_TextRenderingMode) {
    _TextRenderingMode[_TextRenderingMode["fill"] = 0] = "fill";
    _TextRenderingMode[_TextRenderingMode["stroke"] = 1] = "stroke";
    _TextRenderingMode[_TextRenderingMode["fillStroke"] = 2] = "fillStroke";
    _TextRenderingMode[_TextRenderingMode["none"] = 3] = "none";
    _TextRenderingMode[_TextRenderingMode["clipFlag"] = 4] = "clipFlag";
    _TextRenderingMode[_TextRenderingMode["clipFill"] = 4] = "clipFill";
    _TextRenderingMode[_TextRenderingMode["clipStroke"] = 5] = "clipStroke";
    _TextRenderingMode[_TextRenderingMode["clipFillStroke"] = 6] = "clipFillStroke";
    _TextRenderingMode[_TextRenderingMode["clip"] = 7] = "clip";
})(_TextRenderingMode || (_TextRenderingMode = {}));
/**
 * Represents a brush for the PDF page.
 *
 * ```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 brush
 * let brush: PdfBrush = new PdfBrush({r: 0, g: 255, b: 255});
 * // Draw a rectangle using brush
 * graphics.drawRectangle({x: 10, y: 10, width: 100, height: 100}, brush);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfBrush = /** @class */ (function () {
    function PdfBrush(color) {
        this._color = typeof color !== 'undefined' ? color : { r: 0, g: 0, b: 0 };
    }
    return PdfBrush;
}());
export { PdfBrush };
/**
 * Represents a pen for the PDF page.
 *
 * ```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 a rectangle using pen
 * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfPen = /** @class */ (function () {
    function PdfPen(color, width, properties) {
        this._color = color;
        this._width = width;
        this._dashOffset = 0;
        this._dashPattern = [];
        this._dashStyle = PdfDashStyle.solid;
        this._miterLimit = 0;
        this._lineCap = PdfLineCap.flat;
        this._lineJoin = PdfLineJoin.miter;
        if (properties) {
            if (_isNullOrUndefined(properties.dashOffset)) {
                this._dashOffset = properties.dashOffset;
            }
            if (_isNullOrUndefined(properties.dashPattern) && Array.isArray(properties.dashPattern)) {
                this._dashPattern = properties.dashPattern;
            }
            if (_isNullOrUndefined(properties.dashStyle)) {
                this._dashStyle = properties.dashStyle;
            }
            if (_isNullOrUndefined(properties.miterLimit)) {
                this._miterLimit = properties.miterLimit;
            }
            if (_isNullOrUndefined(properties.lineCap)) {
                this._lineCap = properties.lineCap;
            }
            if (_isNullOrUndefined(properties.lineJoin)) {
                this._lineJoin = properties.lineJoin;
            }
        }
    }
    Object.defineProperty(PdfPen.prototype, "color", {
        /**
         * Gets the pen color used for drawing.
         *
         * @returns {PdfColor} The current pen color.
         * ```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}, 4, {dashOffset: 0.5, dashPattern: [4,2,1,3], dashStyle: PdfDashStyle.custom, miterLimit:2, lineCap: PdfLineCap.round, lineJoin: PdfLineJoin.bevel});
         * // Gets the pen color used for drawing
         * const color: PdfColor = pen.color;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._color;
        },
        /**
         * Sets the pen color used for drawing.
         *
         * @param {PdfColor} value - The color to use for the pen.
         * ```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}, 4);
         * // Set the pen color for drawing
         * pen.color = {r: 255, g: 0, b: 0};
         * // Draw using the pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (_isNullOrUndefined(value)) {
                this._color = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "width", {
        /**
         * Gets the width of the pen.
         *
         * @returns {number} The pen width in points.
         * ```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}, 4, {dashOffset: 0.5, dashPattern: [4,2,1,3], dashStyle: PdfDashStyle.custom, miterLimit:2, lineCap: PdfLineCap.round, lineJoin: PdfLineJoin.bevel});
         * // Gets the width of the pen used for drawing
         * const w: number = pen.width;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._width;
        },
        /**
         * Sets the width of the pen.
         *
         * @param {number} value - The pen width in points.
         * ```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);
         * // Sets the pen width for drawing
         * pen.width = 2;
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && value > 0) {
                this._width = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "dashOffset", {
        /**
         * Gets the dash phase offset that shifts where the dash pattern begins. Measured in points.
         *
         * @returns {number} The dash offset in points.
         * ```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}, 4, {dashOffset: 0.5, dashPattern: [4,2,1,3], dashStyle: PdfDashStyle.custom, miterLimit:2, lineCap: PdfLineCap.round, lineJoin: PdfLineJoin.bevel});
         * const offset = pen.dashOffset;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._dashOffset;
        },
        /**
         * Sets the dash phase offset that determines where the dash pattern begins. Measured in points.
         *
         * @param {number} value - The dash offset in points.
         * ```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}, 4);
         * //Sets the dashOffset value for drawing
         * pen.dashOffset = 0.5;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && value > 0) {
                this._dashOffset = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "dashPattern", {
        /**
         * Gets the dash pattern array specifying alternating dash and gap lengths in points.
         *
         * @returns {number[]} The dash/gap lengths array.
         * ```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}, 4, {dashOffset: 0.5, dashPattern: [4,2,1,3], dashStyle: PdfDashStyle.custom});
         * // Gets the dash pattern used for drawing
         * const pattern: number[] = pen.dashPattern;
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._dashPattern;
        },
        /**
         * Sets the dash pattern array specifying alternating dash and gap lengths in points.
         *
         * @remarks
         * The dash pattern cannot be set when the pen's `dashStyle` is `PdfDashStyle.Solid`.
         *
         * @param {number[]} value - Array of numbers representing dash and gap lengths.
         * ```typescript
         * // Create a new PDF document
         * let document: PdfDocument = new PdfDocument();
         * // Add a new page
         * let page: PdfPage = document.pages.add();
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * // Create a pen with width 2
         * let pen: PdfPen = new PdfPen({r:0, g:0, b:0}, 2);
         * //Sets the dashPattern value for drawing
         * pen.dashPattern = [3, 1, 3, 1];
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (Array.isArray(value) && value.length > 0) {
                this._dashPattern = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "dashStyle", {
        /**
         * Gets the dash style of the pen.
         *
         * @returns {PdfDashStyle} The dash style.
         * ```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}, 4, {dashOffset: 0.5, dashPattern: [4,2,1,3], dashStyle: PdfDashStyle.custom, miterLimit:2, lineCap: PdfLineCap.round, lineJoin: PdfLineJoin.bevel});
         * // Gets pen dash style used for drawing
         * const style: PdfDashStyle = pen.dashStyle;
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._dashStyle;
        },
        /**
         * Sets the dash style of the pen.
         *
         * @param {PdfDashStyle} value - The dash style to apply.
         * ```typescript
         * // Create a new PDF document
         * let document: PdfDocument = new PdfDocument();
         * // Add a new page
         * let page: PdfPage = document.pages.add();
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * // Create a pen and set a dash style
         * let pen: PdfPen = new PdfPen({r:0, g:0, b:0}, 2);
         * // Sets the dashStyle value for drawing
         * pen.dashStyle = PdfDashStyle.custom;
         * // Sets the dash pattern for custom style
         * pen.dashPattern = [4, 2, 1, 3];
         * //Sets the dashStyle value for drawing
         * // For custom style, set the pattern as well
         * pen.dashStyle = PdfDashStyle.custom;
         * pen.dashPattern = [4,2,1,3];
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && value >= PdfDashStyle.solid && value <= PdfDashStyle.custom) {
                this._dashStyle = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "miterLimit", {
        /**
         * Gets the miter limit value, used when lineJoin is Miter.
         *
         * @returns {number} The miter limit value.
         * ```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}, 4);
         * // Gets miter limit used for drawing
         * const m: number = pen.miterLimit;
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._miterLimit;
        },
        /**
         * Sets the miter limit for mitered line joins.
         *
         * @param {number} value - The miter limit value.
         * ```typescript
         * // Create a new PDF document
         * let document: PdfDocument = new PdfDocument();
         * // Add a new page
         * let page: PdfPage = document.pages.add();
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * // Create a pen and set miter limit
         * let pen: PdfPen = new PdfPen({r:0, g:0, b:0}, 2);
         * // Sets the line join type as miter.
         * pen.lineJoin = PdfLineJoin.miter;
         * // Sets the miter limit value for drawing
         * pen.miterLimit = 4;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && _isNullOrUndefined(value)) {
                this._miterLimit = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "lineCap", {
        /**
         * Gets the line cap style applied to the ends of lines.
         *
         * @returns {PdfLineCap} The line cap style.
         * ```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}, 4);
         * // Gets line cap style used for drawing
         * const cap: PdfLineCap = pen.lineCap; // PdfLineCap.flat | round | square
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._lineCap;
        },
        /**
         * Sets the line cap style applied to the ends of lines.
         *
         * @param {PdfLineCap} value - The line cap style.
         * ```typescript
         * // Create a new PDF document
         * let document: PdfDocument = new PdfDocument();
         * // Add a new page
         * let page: PdfPage = document.pages.add();
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * // Create a pen and set line cap
         * let pen: PdfPen = new PdfPen({r:0, g:0, b:0}, 2);
         * // Sets the line cap value used for drawing
         * pen.lineCap = PdfLineCap.round;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && value >= PdfLineCap.flat && value <= PdfLineCap.square) {
                this._lineCap = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfPen.prototype, "lineJoin", {
        /**
         * Gets the line join style used at intersections between line segments.
         *
         * @returns {PdfLineJoin} The line join style.
         * ```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}, 4);
         * // Gets the line join style used for drawing
         * const join: PdfLineJoin = pen.lineJoin; // PdfLineJoin.miter | round | bevel
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return this._lineJoin;
        },
        /**
         * Sets the line join style used at intersections between line segments.
         *
         * @param {PdfLineJoin} value - The line join style to set.
         * ```typescript
         * // Create a new PDF document
         * let document: PdfDocument = new PdfDocument();
         * // Add a new page
         * let page: PdfPage = document.pages.add();
         * // Gets the graphics of the PDF page
         * let graphics: PdfGraphics = page.graphics;
         * // Create a pen and set line join
         * let pen: PdfPen = new PdfPen({r:0, g:0, b:0}, 2);
         * // Sets the line join type for drawing
         * pen.lineJoin = PdfLineJoin.bevel;
         * // Draw a rectangle using pen
         * graphics.drawRectangle({x: 150, y: 50, width: 50, height: 50}, pen);
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        set: function (value) {
            if (!Number.isNaN(value) && value >= PdfLineJoin.miter && value <= PdfLineJoin.bevel) {
                this._lineJoin = value;
            }
        },
        enumerable: true,
        configurable: true
    });
    return PdfPen;
}());
export { PdfPen };
/**
 * Provides internal unit conversion between various measurement units used
 * in PDF graphics pixels, points, inches, centimeters, etc.
 *
 * @private
 */
var _PdfUnitConvertor = /** @class */ (function () {
    /**
     * Initializes a new unit converter using the default horizontal resolution.
     *
     * @private
     */
    function _PdfUnitConvertor() {
        /**
         * Horizontal pixel resolution used for unit conversions.
         *
         * @private
         */
        this._horizontalResolution = 96;
        this._proportions = this._updateProportions(this._horizontalResolution);
    }
    /**
     * Computes and returns the proportional conversion values based on the
     * specified pixel resolution.
     *
     * @param {number} pixel The horizontal pixel resolution.
     * @returns {number[]} The array of proportional constants.
     *
     * @private
     */
    _PdfUnitConvertor.prototype._updateProportions = function (pixel) {
        return [pixel / 2.54, pixel / 6.0, 1, pixel / 72.0, pixel, pixel / 300.0, pixel / 25.4];
    };
    /**
     * Converts a value from one unit type to another.
     *
     * @param {number} value The value to convert.
     * @param {_PdfGraphicsUnit} from The source unit.
     * @param {_PdfGraphicsUnit} to The destination unit.
     * @returns {number} The converted value.
     *
     * @private
     */
    _PdfUnitConvertor.prototype._convertUnits = function (value, from, to) {
        return this._convertFromPixels(this._convertToPixels(value, from), to);
    };
    /**
     * Converts a pixel value into the specified target unit.
     *
     * @param {number} value Pixel value.
     * @param {_PdfGraphicsUnit} to Target unit.
     * @returns {number} Converted value.
     *
     * @private
     */
    _PdfUnitConvertor.prototype._convertFromPixels = function (value, to) {
        var index = to;
        return (value / this._proportions[index]);
    };
    /**
     * Converts a value from the specified unit into pixels.
     *
     * @param {number} value The value to convert.
     * @param {_PdfGraphicsUnit} from The source unit.
     * @returns {number} Converted pixel value.
     *
     * @private
     */
    _PdfUnitConvertor.prototype._convertToPixels = function (value, from) {
        var index = from;
        return (value * this._proportions[index]);
    };
    return _PdfUnitConvertor;
}());
export { _PdfUnitConvertor };