UNPKG

@syncfusion/ej2-pdf

Version:

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

2,290 lines 101 kB
import { PdfPage } from './../pdf-page';
import { _PdfStreamWriter } from './pdf-stream-writer';
import { _PdfBaseStream } from './../base-stream';
import { _floatToString, _addProcSet, _reverseMapBlendMode, _mapBlendMode, _getNewGuidString, _getBezierArc, _numberToString, _bytesToString, _stringToUnicodeArray } from './../utils';
import { _PdfDictionary, _PdfReference, _PdfName } from './../pdf-primitives';
import { 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 } from './../enumerator';
import { PdfStringFormat, PdfVerticalAlignment } from './../fonts/pdf-string-format';
import { PdfTemplate } from './pdf-template';
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';
/**
 * 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([0, 0, 0], 1);
 * //Draw line on the page graphics.
 * graphics.drawLine(pen, 10, 10, 100, 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 {number[]} 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) {
        this._pendingResource = []; // eslint-disable-line
        this._isItalic = 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);
            }
            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, "clientSize", {
        /**
         * Gets the size of the canvas reduced by margins and page templates (Read only).
         *
         * @returns {number[]} 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: number[] = page.graphics.clientSize;
         * // Save the document
         * document.save('output.pdf');
         * // Destroy the document
         * document.destroy();
         * ```
         */
        get: function () {
            return [this._clipBounds[2], this._clipBounds[3]];
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfGraphics.prototype, "_matrix", {
        get: function () {
            if (typeof this._m === 'undefined') {
                this._m = new _PdfTransformationMatrix();
            }
            return this._m;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PdfGraphics.prototype, "_resources", {
        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
    });
    /**
     * Save the current graphics state.
     *
     * @returns {PdfGraphicsState} 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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // Save the graphics
     * let state: PdfGraphicsState = graphics.save();
     * //Set graphics translate transform.
     * graphics.translateTransform(100, 100);
     * //Draws the String.
     * graphics.drawString("Hello world!", font, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * //Restore the graphics.
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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.
     *
     * @param {PdfGraphicsState} state graphics state.
     * @returns {void} restore of 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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // Save the graphics
     * let state: PdfGraphicsState = graphics.save();
     * //Set graphics translate transform.
     * graphics.translateTransform(100, 100);
     * //Draws the String.
     * graphics.drawString("Hello world!", font, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * //Restore the graphics.
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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;
                        }
                    }
                }
            }
        }
    };
    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.drawRectangle = function (x, y, width, height, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._sw._appendRectangle(x, y, width, 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.
     *
     * @param {number} startX The x-coordinate of the starting point of the Bezier curve.
     * @param {number} startY The y-coordinate of the starting point of the Bezier curve.
     * @param {number} firstX The x-coordinate of the first control point of the Bezier curve.
     * @param {number} firstY The y-coordinate of the first control point of the Bezier curve.
     * @param {number} secondX The x-coordinate of the second control point of the Bezier curve.
     * @param {number} secondY The y-coordinate of the second control point of the Bezier curve.
     * @param {number} endX The x-coordinate of the ending point of the Bezier curve.
     * @param {number} endY The y-coordinate 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
     *
     * ```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([0, 0, 0], 1);
     * // Draw a Bezier curve on the page graphics
     * graphics.drawBezier(50, 100, 200, 50, 100, 150, 150, 100, pen);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.drawBezier = function (startX, startY, firstX, firstY, secondX, secondY, endX, endY, pen) {
        this._beginMarkContent();
        this._stateControl(pen, null, null);
        this._sw._beginPath(startX, startY);
        this._sw._appendBezierSegment(firstX, firstY, secondX, secondY, endX, endY);
        this._drawGraphicsPath(pen);
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawPie = function (x, y, width, height, startAngle, sweepAngle, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._constructPiePath(x, y, x + width, y + height, startAngle, sweepAngle);
        this._sw._appendLineSegment(x + width / 2, y + 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][0], points[0][1]);
            points.forEach(function (point, index) {
                if (index > 0) {
                    _this._sw._appendLineSegment(point[0], point[1]);
                }
            });
            this._drawGraphicsPath(result.pen, result.brush, PdfFillMode.winding, true);
        }
        this._endMarkContent();
    };
    PdfGraphics.prototype.drawEllipse = function (x, y, width, height, first, second) {
        this._beginMarkContent();
        var result = this._setPenBrush(first, second);
        this._constructArcPath(x, y, x + width, y + height, 0, 360);
        this._drawGraphicsPath(result.pen, result.brush, PdfFillMode.winding, true);
        this._endMarkContent();
    };
    /**
     * Draw arc on the page graphics.
     *
     * @param {number} x The x-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the arc shape comes.
     * @param {number} y The y-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the arc shape comes.
     * @param {number} width Width of the bounding rectangle that defines the ellipse from which the arc shape comes.
     * @param {number} height Height of 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.
     *
     * ```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([0, 0, 0], 1);
     * // Draw an arc on the page graphics
     * graphics.drawArc(10, 20, 100, 200, 20, 30, pen);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.drawArc = function (x, y, width, height, startAngle, sweepAngle, pen) {
        if (sweepAngle !== 0) {
            this._beginMarkContent();
            this._stateControl(pen);
            this._constructArcPath(x, y, x + width, y + height, startAngle, sweepAngle);
            this._drawGraphicsPath(pen, null, PdfFillMode.winding, false);
            this._endMarkContent();
        }
    };
    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');
            }
        }
    };
    PdfGraphics.prototype.drawImage = function (arg1, arg2, arg3, arg4, arg5) {
        this._beginMarkContent();
        if (typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'undefined') {
            var size = arg1.physicalDimension;
            this.drawImage(arg1, arg2, arg3, size[0], size[1]);
        }
        else {
            arg1._save();
            var matrix = new _PdfTransformationMatrix();
            this._getTranslateTransform(arg2, (arg3 + arg5), matrix);
            this._getScaleTransform(arg4, arg5, 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);
        }
        this._endMarkContent();
    };
    /**
     * Draws a PDF template onto the page graphics.
     *
     * @param {PdfTemplate} template The PDF template to be drawn.
     * @param {{x: number, y: number, width: number, height: number}} bounds The bounds of the template.
     * @param {number} bounds.x The x-coordinate of the upper-left corner where the template will be drawn.
     * @param {number} bounds.y The y-coordinate of the upper-left corner where the template will be drawn.
     * @param {number} bounds.width The width of the area where the template will be drawn.
     * @param {number} bounds.height The height of the area where the template will be drawn.
     * @returns {void} Nothing.
     *
     * ```typescript
     * // Load an existing PDF document
     * let document: PdfDocument = new PdfDocument(data, password);
     * // Access the first page
     * let page: PdfPage = document.getPage(0);
     * // Get the first annotation of the page
     * let annotation: PdfRubberStampAnnotation = page.annotations.at(0) as PdfRubberStampAnnotation;
     * // Get the appearance template of the annotation
     * let template: PdfTemplate = annotation.createTemplate();
     * // Get 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[0], height: template.size[1] });
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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 = (template && template._size[0] > 0) ? bounds.width / template._size[0] : 1;
            var scaleY = (template && template._size[1] > 0) ? bounds.height / template._size[1] : 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(cropBox[0], -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);
                matrix._translate(bounds.x, -(bounds.y + ((this._page._origin[0] >= 0 || needTransform) ? bounds.height : 0)));
            }
            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[0] &&
                            templateBox[3] === template._size[1] && 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[1]);
                            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._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 = [];
        }
    };
    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;
    };
    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);
            }
        }
    };
    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.
     *
     * @param {number} x The x-coordinate of the upper-left corner of the rounded rectangle.
     * @param {number} y The y-coordinate of the upper-left corner of the rounded rectangle.
     * @param {number} width The width of the rounded rectangle.
     * @param {number} height The height 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.
     *
     * ```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([0, 0, 0], 1);
     * // Create a new brush
     * let brush: PdfBrush = new PdfBrush([0, 0, 255]);
     * // Draw a rounded rectangle on the page graphics
     * graphics.drawRoundedRectangle(10, 20, 100, 200, 5, pen, brush);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.drawRoundedRectangle = function (x, y, width, height, radius, pen, brush) {
        if (pen === null) {
            throw new Error('pen');
        }
        if (brush === null) {
            throw new Error('brush');
        }
        var bounds = [x, y, width, height];
        var diameter = radius * 2;
        var size = [diameter, diameter];
        var arc = [bounds[0], bounds[1], size[0], size[1]];
        var path = new PdfPath();
        if (radius === 0) {
            path.addRectangle(bounds[0], bounds[1], bounds[2], bounds[3]);
            this.drawPath(path, pen, brush);
        }
        else {
            path._isRoundedRectangle = true;
            path.addArc(arc[0], arc[1], arc[2], arc[3], 180, 90);
            arc[0] = (bounds[0] + bounds[2]) - diameter;
            path.addArc(arc[0], arc[1], arc[2], arc[3], 270, 90);
            arc[1] = (bounds[1] + bounds[3]) - diameter;
            path.addArc(arc[0], arc[1], arc[2], arc[3], 0, 90);
            arc[0] = bounds[0];
            path.addArc(arc[0], arc[1], arc[2], arc[3], 90, 90);
            path.closeFigure();
            this.drawPath(path, pen, brush);
        }
    };
    PdfGraphics.prototype._constructArcPath = function (x1, y1, x2, y2, start, sweep) {
        var points = _getBezierArc(x1, y1, x2, y2, start, sweep);
        if (points.length === 8) {
            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]);
        }
    };
    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]);
            }
        }
    };
    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, true);
    };
    /**
     * Draw text on the page graphics.
     *
     * @param {string} value The string to be drawn.
     * @param {PdfFont} font The font used to draw the string.
     * @param {number[]} bounds An array specifying the bounds [x, y, width, height] where the string will be drawn.
     * @param {PdfPen} pen The pen that determines the stroke color, width, and style of the string.
     * @param {PdfBrush} brush The brush that determines the fill color and texture of the string.
     * @param {PdfStringFormat} format The format that specifies text layout information such as alignment, line spacing, and trimming.
     * @returns {void} Nothing.
     *
     * ```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([0, 0, 0], 1);
     * // Create a new font
     * let font: PdfStandardFont = new PdfStandardFont(PdfFontFamily.helvetica, 12);
     * // Create a new string format
     * let format: PdfStringFormat = new PdfStringFormat();
     * format.alignment = PdfTextAlignment.center;
     * // Draw text on the page graphics
     * graphics.drawString('Hello World', font, [10, 20, 100, 200], pen, new PdfBrush([0, 0, 255]), format);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.drawString = function (value, font, bounds, pen, brush, format) {
        this._beginMarkContent();
        var layouter = new _PdfStringLayouter();
        if (!format) {
            format = new PdfStringFormat();
        }
        if (value) {
            value = this._normalizeText(font, value);
        }
        var result = layouter._layout(value, font, format, [bounds[2], bounds[3]]);
        if (!result._empty) {
            var rect = this._checkCorrectLayoutRectangle(result._actualSize, bounds[0], bounds[1], format);
            if (bounds[2] <= 0) {
                bounds[0] = rect[0];
                bounds[2] = rect[2];
            }
            if (bounds[3] <= 0) {
                bounds[1] = rect[1];
                bounds[3] = rect[3];
            }
            this._drawStringLayoutResult(result, font, pen, brush, bounds, format);
        }
        _addProcSet('Text', this._resourceObject);
        this._endMarkContent();
    };
    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;
    };
    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[0], point[1]);
                    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[0], point[1], first[0], first[1], second[0], second[1]);
                    break;
                case PathPointType.line:
                    this._sw._appendLineSegment(point[0], point[1]);
                    break;
                default:
                    throw new Error('Incorrect path formation.');
            }
            type = types[Number.parseInt(i.toString(), 10)];
            if ((type & PathPointType.closePath) === PathPointType.closePath) {
                this._sw._closePath();
            }
        }
    };
    PdfGraphics.prototype._getBezierPoint = function (points, types, index) {
        if (types[index] !== PathPointType.bezier) {
            throw new Error('Malforming path.');
        }
        index++;
        return { 'index': index, 'point': points[index] };
    };
    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[0], this._size[1]];
        this._colorSpaceInitialized = false;
        this._startCutIndex = -1;
    };
    PdfGraphics.prototype._initializeCurrentColorSpace = function () {
        if (!this._colorSpaceInitialized) {
            this._sw._setColorSpace('DeviceRGB', true);
            this._sw._setColorSpace('DeviceRGB', false);
            this._colorSpaceInitialized = true;
        }
    };
    PdfGraphics.prototype._brushControl = function (brush) {
        this._sw._setColor(brush._color, false);
        this._currentBrush = brush;
    };
    PdfGraphics.prototype._penControl = function (pen) {
        this._currentPen = pen;
        this._writePen(pen);
        this._currentPen = pen;
    };
    PdfGraphics.prototype._fontControl = function (font, format) {
        var _this = this;
        var size = font._metrics._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))) {
                                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);
    };
    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 };
    };
    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);
        }
    };
    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[0], result._actualSize[1]];
                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(clipBounds);
            }
            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[1], layoutRectangle[3], format);
            var height = (typeof format === 'undefined' || format === null || format.lineSpacing === 0) ?
                font._metrics._getHeight(format) :
                format.lineSpacing + font._metrics._getHeight(format);
            var script = (format !== null && typeof format !== 'undefined' &&
                format.subSuperScript === PdfSubSuperScript.subScript);
            var shift = 0;
            shift = (script) ? height - (font.height + font._metrics._getDescent(format)) : (height - font._metrics._getAscent(format));
            if (format && format.lineAlignment === PdfVerticalAlignment.bottom) {
                var layoutStr = _numberToString(layoutRectangle[3]);
                var fontHeightStr = _numberToString(font._metrics._getHeight(format));
                if (layoutRectangle[3] - result._actualSize[1] !== 0 &&
                    (layoutRectangle[3] - result._actualSize[1]) < (font._metrics._size / 2) - 1) {
                    var layoutNum = +layoutStr;
                    var fontHeightNum = +fontHeightStr;
                    if (layoutNum <= fontHeightNum) {
                        shift = -(height / font._metrics._size);
                    }
                }
            }
            var matrix = new _PdfTransformationMatrix();
            if (this._isItalic) {
                this.translateTransform(layoutRectangle[0] + font.size / 5, layoutRectangle[1] - shift + verticalAlignShift);
                this._skewTransform(0, -11);
            }
            else {
                matrix._translate(layoutRectangle[0], (-(layoutRectangle[1] + font._metrics._getHeight(format)) -
                    (font._metrics._getDescent(format) > 0 ? -font._metrics._getDescent(format) : font._metrics._getDescent(format))) -
                    verticalAlignShift);
                this._sw._modifyTM(matrix);
            }
            if (layoutRectangle[3] < font._metrics._size) {
                if ((result._actualSize[1] - layoutRectangle[3]) < (font._metrics._size / 2) - 1) {
                    verticalAlignShift = 0;
                }
            }
            if (verticalAlignShift !== 0) {
                if (format !== null && format.lineAlignment === PdfVerticalAlignment.bottom) {
                    if (layoutRectangle[3] - result._actualSize[1] !== 0 &&
                        (layoutRectangle[3] - result._actualSize[1]) > (font._metrics._size / 2) - 1) {
                        verticalAlignShift -= (shift - (height - font._metrics._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);
            }
        }
    };
    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;
    };
    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);
        }
    };
    PdfGraphics.prototype._drawLayoutResult = function (result, font, format, layoutRectangle) {
        var height = (typeof format === 'undefined' || format === null || format.lineSpacing === 0) ?
            font._metrics._getHeight(format) :
            format.lineSpacing + font._metrics._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 (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[1], layoutRectangle[3], format);
                var matrix = new _PdfTransformationMatrix();
                var baseline = ((-(layoutRectangle[1] + font._metrics._getHeight(format)) -
                    font._metrics._getDescent(format)) -
                    vAlignShift) -
                    (height * (i + 1));
                matrix._translate(layoutRectangle[0], baseline);
                this._sw._modifyTM(matrix);
            }
        }
    };
    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);
            }
        }
    };
    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)[0];
                        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;
                }
            }
        }
    };
    PdfGraphics.prototype._breakUnicodeLine = function (line, ttfFont, words) {
        var _this = this;
        var tokens = [];
        if (line !== null && typeof line !== 'undefined' && line.length > 0) {
            words = line.split(null);
            words.forEach(function (word) {
                var token = _this._convertToUnicode(word, ttfFont);
                tokens.push(token);
            });
        }
        return { tokens: tokens, words: words };
    };
    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;
    };
    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;
    };
    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;
    };
    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;
    };
    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) {
            Array.from(lineInfo._text).forEach(function (char) {
                if (char === '(') {
                    value += '\\(';
                }
                else if (char === ')') {
                    value += '\\)';
                }
                else {
                    value += char;
                }
            });
        }
        if (value === '') {
            value = lineInfo._text;
        }
        this._sw._showNextLineText('(' + value + ')');
    };
    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;
    };
    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);
    };
    PdfGraphics.prototype._underlineStrikeoutText = function (brush, result, font, layoutRectangle, format) {
        var _this = this;
        if (font.isUnderline || font.isStrikeout) {
            var linePen_1 = this._createUnderlineStrikeoutPen(brush, font);
            if (typeof linePen_1 !== 'undefined' && linePen_1 !== null) {
                var shift = this._getTextVerticalAlignShift(result._actualSize[1], layoutRectangle[3], format);
                var underlineYOffset_1 = layoutRectangle[1] + shift + font._metrics._getAscent(format) + 1.5 * linePen_1._width;
                var strikeoutYOffset_1 = layoutRectangle[1] + shift + font._metrics._getHeight(format) / 2 + 1.5 * linePen_1._width;
                var lines = result._lines;
                lines.forEach(function (lineInfo, 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_1, x1, underlineYOffset_1, x2, underlineYOffset_1);
                        underlineYOffset_1 += result._lineHeight;
                    }
                    if (font.isStrikeout) {
                        _this.drawLine(linePen_1, x1, strikeoutYOffset_1, x2, strikeoutYOffset_1);
                        strikeoutYOffset_1 += result._lineHeight;
                    }
                });
            }
        }
    };
    /**
     * Draws a line on the page graphics.
     *
     * @param {PdfPen} pen The pen that determines the stroke color, width, and style of the line.
     * @param {number} x1 The x-coordinate of the starting point of the line.
     * @param {number} y1 The y-coordinate of the starting point of the line.
     * @param {number} x2 The x-coordinate of the ending point of the line.
     * @param {number} y2 The y-coordinate of the ending point of the line.
     * @returns {void} Nothing.
     *
     * ```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([0, 0, 0], 1);
     * // Draw a line on the page graphics
     * graphics.drawLine(pen, 10, 10, 100, 100);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.drawLine = function (pen, x1, y1, x2, y2) {
        this._beginMarkContent();
        this._stateControl(pen);
        this._sw._beginPath(x1, y1);
        this._sw._appendLineSegment(x2, y2);
        this._sw._strokePath();
        _addProcSet('PDF', this._resourceObject);
        this._endMarkContent();
    };
    PdfGraphics.prototype._createUnderlineStrikeoutPen = function (brush, font) {
        return new PdfPen(brush._color, font._metrics._size / 20);
    };
    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;
    };
    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);
            }
        }
    };
    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(cbox[0], -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(this._cropBox[0], -this._cropBox[3]);
                    }
                    else {
                        if (-(page._origin[1]) < this._mediaBoxUpperRightBound || this._mediaBoxUpperRightBound === 0) {
                            this.translateTransform(0, -this._size[1]);
                        }
                        else {
                            this.translateTransform(0, -this._mediaBoxUpperRightBound);
                        }
                    }
                }
            }
        }
        else {
            this._sw._writeComment('Change co-ordinate system to left/top.');
            if (this._mediaBoxUpperRightBound !== (-this._size[1])) {
                if (this._cropBox) {
                    cbox = this._cropBox;
                    if (cbox[0] > 0 || cbox[1] > 0 || this._size[0] === cbox[2] || this._size[1] === cbox[3]) {
                        this.translateTransform(cbox[0], -cbox[3]);
                    }
                    else {
                        if (this._mediaBoxUpperRightBound === this._size[1] || this._mediaBoxUpperRightBound === 0) {
                            this.translateTransform(0, -this._size[1]);
                        }
                        else {
                            this.translateTransform(0, -this._mediaBoxUpperRightBound);
                        }
                    }
                }
                else {
                    if (this._mediaBoxUpperRightBound === this._size[1] || this._mediaBoxUpperRightBound === 0) {
                        this.translateTransform(0, -this._size[1]);
                    }
                    else {
                        this.translateTransform(0, -this._mediaBoxUpperRightBound);
                    }
                }
            }
        }
    };
    /**
     * Represents a scale transform of the graphics.
     *
     * @param {number} scaleX Scale factor in the x direction.
     * @param {number} scaleY Scale factor in the y direction.
     * @returns {void} Nothing.
     *
     * ```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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // 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, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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.
     *
     * @param {number} x x-coordinate of the translation.
     * @param {number} y y-coordinate of the translation.
     * @returns {void} Nothing.
     *
     * ```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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // Save the current graphics state
     * let state: PdfGraphicsState = graphics.save();
     * // Apply translate transform
     * graphics.translateTransform(100, 100);
     * // Draw a string with the translation applied
     * graphics.drawString("Hello world!", font, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.translateTransform = function (x, y) {
        var matrix = new _PdfTransformationMatrix();
        matrix._translate(x, -y);
        this._sw._modifyCtm(matrix);
        this._matrix._multiply(matrix);
    };
    /**
     * Represents a rotate transform of the graphics.
     *
     * @param {number} angle Angle of rotation in degrees.
     * @returns {void} Nothing.
     *
     * ```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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // 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, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * // Restore the graphics to its previous state
     * graphics.restore(state);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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.
     *
     * @param {number[]} bounds Rectangle structure that represents the new clip region, specified as [x, y, width, height].
     * @param {PdfFillMode} mode Member of the PdfFillMode enumeration that specifies the filling operation to use.
     * @returns {void} Nothing.
     *
     * ```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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // Set clipping region
     * graphics.setClip([0, 0, 50, 12], PdfFillMode.alternate);
     * // Draw a string within the clipping region
     * graphics.drawString("Hello world!", font, [0, 0, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    PdfGraphics.prototype.setClip = function (bounds, mode) {
        if (typeof mode === 'undefined') {
            mode = PdfFillMode.winding;
        }
        this._sw._appendRectangle(bounds[0], bounds[1], bounds[2], bounds[3]);
        this._sw._clipPath(mode === PdfFillMode.alternate);
    };
    /**
     * Sets the transparency for the graphics.
     *
     * @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.
     *
     * ```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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
     * // Set transparency
     * graphics.setTransparency(0.5, 0.5, PdfBlendMode.multiply);
     * // Draw the string
     * graphics.drawString("Hello world!", font, [0, 0, 100, 200], undefined, new PdfBrush([0, 0, 255]));
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    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);
    };
    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);
    };
    PdfGraphics.prototype._getTranslateTransform = function (x, y, input) {
        input._translate(x, -y);
        return input;
    };
    PdfGraphics.prototype._getScaleTransform = function (x, y, input) {
        if (input === null || typeof input === 'undefined') {
            input = new _PdfTransformationMatrix();
        }
        input._scale(x, y);
        return input;
    };
    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(clipBounds[0], clipBounds[1]);
    };
    PdfGraphics.prototype._skewTransform = function (angleX, angleY) {
        var matrix = new _PdfTransformationMatrix();
        this._getSkewTransform(angleX, angleY, matrix);
        this._sw._modifyCtm(matrix);
        matrix._multiply(matrix);
    };
    PdfGraphics.prototype._getSkewTransform = function (angleX, angleY, input) {
        input._skew(-angleX, -angleY);
        return input;
    };
    return PdfGraphics;
}());
export { PdfGraphics };
var _PdfTransformationMatrix = /** @class */ (function () {
    function _PdfTransformationMatrix() {
        this._matrix = new _Matrix(1, 0, 0, 1, 0, 0);
    }
    _PdfTransformationMatrix.prototype._translate = function (x, y) {
        this._matrix._translate(x, y);
    };
    _PdfTransformationMatrix.prototype._scale = function (x, y) {
        this._matrix._elements[0] = x;
        this._matrix._elements[3] = y;
    };
    _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);
    };
    _PdfTransformationMatrix.prototype._multiply = function (matrix) {
        this._matrix._multiply(matrix._matrix);
    };
    _PdfTransformationMatrix.prototype._toString = function () {
        var builder = '';
        this._matrix._elements.forEach(function (element) {
            builder += _floatToString(element) + ' ';
        });
        return builder;
    };
    _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);
    };
    _PdfTransformationMatrix.prototype._degreeToRadians = function (degreesX) {
        var degreeRadFactor = Math.PI / 180;
        return degreeRadFactor * degreesX;
    };
    return _PdfTransformationMatrix;
}());
export { _PdfTransformationMatrix };
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", {
        get: function () {
            return this._elements[4];
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_Matrix.prototype, "_offsetY", {
        get: function () {
            return this._elements[5];
        },
        enumerable: true,
        configurable: true
    });
    _Matrix.prototype._clone = function () {
        return new _Matrix(this._elements.slice());
    };
    _Matrix.prototype._translate = function (x, y) {
        this._elements[4] = x;
        this._elements[5] = y;
    };
    _Matrix.prototype._transform = function (points) {
        var x = points[0];
        var y = points[1];
        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 [x2, y2];
    };
    _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 = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
 * // Save the graphics state
 * let state: PdfGraphicsState = graphics.save();
 * // Set graphics translate transform
 * graphics.translateTransform(100, 100);
 * // Draw the string
 * graphics.drawString("Hello world!", font, [10, 20, 100, 200], undefined, new PdfBrush([0, 0, 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 };
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([0, 255, 255]);
 * // Draw a rectangle using brush
 * graphics.drawRectangle(10, 10, 100, 100, brush);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfBrush = /** @class */ (function () {
    /**
     * Initializes a new instance of the `PdfBrush` class.
     *
     * @param {number[]} color 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 brush
     * let brush: PdfBrush = new PdfBrush([0, 255, 255]);
     * // Draw a rectangle using brush
     * graphics.drawRectangle(10, 10, 100, 100, brush);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    function PdfBrush(color) {
        this._color = typeof color !== 'undefined' ? color : [0, 0, 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([0, 0, 0], 1);
 * // Draw a rectangle using pen
 * graphics.drawRectangle(150, 50, 50, 50, pen);
 * // Save the document
 * document.save('output.pdf');
 * // Destroy the document
 * document.destroy();
 * ```
 */
var PdfPen = /** @class */ (function () {
    /**
     * Initializes a new instance of the `PdfPen` class.
     *
     * @param {number[]} color Color.
     * @param {number} width Width.
     *
     * ```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([0, 0, 0], 1);
     * // Draw a rectangle using pen
     * graphics.drawRectangle(150, 50, 50, 50, pen);
     * // Save the document
     * document.save('output.pdf');
     * // Destroy the document
     * document.destroy();
     * ```
     */
    function PdfPen(color, width) {
        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;
    }
    return PdfPen;
}());
export { PdfPen };
var _PdfUnitConvertor = /** @class */ (function () {
    function _PdfUnitConvertor() {
        this._horizontalResolution = 96;
        this._proportions = this._updateProportions(this._horizontalResolution);
    }
    _PdfUnitConvertor.prototype._updateProportions = function (pixel) {
        return [pixel / 2.54, pixel / 6.0, 1, pixel / 72.0, pixel, pixel / 300.0, pixel / 25.4];
    };
    _PdfUnitConvertor.prototype._convertUnits = function (value, from, to) {
        return this._convertFromPixels(this._convertToPixels(value, from), to);
    };
    _PdfUnitConvertor.prototype._convertFromPixels = function (value, to) {
        var index = to;
        return (value / this._proportions[index]);
    };
    _PdfUnitConvertor.prototype._convertToPixels = function (value, from) {
        var index = from;
        return (value * this._proportions[index]);
    };
    return _PdfUnitConvertor;
}());
export { _PdfUnitConvertor };