UNPKG

@syncfusion/ej2-pdf

Version:

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

2,336 lines 105 kB
import { _PdfArithmeticDecoder } from '../../compression/arithmaric-decoder';
import { _readInteger8, _readUnsignedInteger16, _readUnsignedInteger32, _log2, _defineLazyProperty } from '../../utils';
import { _PdfFaxDecoder } from './pdf-fax-decoder';
/**
 * Helper that reads a specified number of bits using the arithmetic decoder,
 * maintaining a rolling context state for JBIG2 procedures.
 *
 * @private
 */
var _PdfBitReader = /** @class */ (function () {
    function _PdfBitReader() {
        this.prev = 1;
    }
    /**
     * Reads `length` bits using the arithmetic decoder with the provided contexts,
     * updating the internal rolling context (`prev`) and returning the accumulated value.
     *
     * @private
     * @param {number} length The number of bits to read.
     * @param {any} decoder The arithmetic decoder supplying `_readBit(contexts, state)`.
     * @param {any} contexts The JBIG2 context states used by the decoder.
     * @returns {number} The unsigned integer composed from the read bits.
     */
    _PdfBitReader.prototype._readBits = function (length, decoder, contexts) {
        var v = 0;
        for (var i = 0; i < length; i++) {
            var bit = decoder._readBit(contexts, this.prev);
            this.prev = this.prev < 256 ? (this.prev << 1) | bit : (((this.prev << 1) | bit) & 511) | 256;
            v = (v << 1) | bit;
        }
        return v >>> 0;
    };
    return _PdfBitReader;
}());
export { _PdfBitReader };
/**
 * Caches and supplies JBIG2 context state arrays (lazily initialized),
 * keyed by a procedure or identifier.
 *
 * @private
 */
var _PdfContextCache = /** @class */ (function () {
    function _PdfContextCache() {
        this.cache = {};
    }
    _PdfContextCache.prototype.getContexts = function (id) {
        var key = id.toString();
        if (!(key in this.cache)) {
            this.cache[key] = new Int8Array(1 << 16); //eslint-disable-line
        }
        return this.cache[key]; //eslint-disable-line
    };
    return _PdfContextCache;
}());
export { _PdfContextCache };
/**
 * Holds the decoding window over the input data and lazily exposes
 * the arithmetic decoder and the shared JBIG2 context cache.
 *
 * @private
 */
var _PdfDecodingContext = /** @class */ (function () {
    function _PdfDecodingContext(data, start, end) {
        this._data = data;
        this._start = start;
        this._end = end;
    }
    Object.defineProperty(_PdfDecodingContext.prototype, "decoder", {
        get: function () {
            var decoder = new _PdfArithmeticDecoder(this._data, this._start, this._end);
            return _defineLazyProperty(this, 'decoder', decoder);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_PdfDecodingContext.prototype, "contextCache", {
        get: function () {
            var cache = new _PdfContextCache();
            return _defineLazyProperty(this, 'contextCache', cache);
        },
        enumerable: true,
        configurable: true
    });
    return _PdfDecodingContext;
}());
export { _PdfDecodingContext };
/**
 * Segment visitor that decodes JBIG2 segments generic/text/halftone/symbol tables,
 * manages symbol/pattern/table caches, and composites bitmaps into the page buffer.
 *
 * @private
 */
var _PdfSimpleSegmentVisitor = /** @class */ (function () {
    function _PdfSimpleSegmentVisitor() {
        /**
         * Cache of standard Huffman tables keyed by table id.
         *
         * @private
         */
        this._standardTablesCache = {};
        /**
         * Neighborhood coding templates for generic regions.
         *
         * @private
         */
        this._codingTemplates = [
            [
                { x: -1, y: -2 }, { x: 0, y: -2 }, { x: 1, y: -2 }, { x: -2, y: -1 }, { x: -1, y: -1 }, { x: 0, y: -1 },
                { x: 1, y: -1 }, { x: 2, y: -1 }, { x: -4, y: 0 }, { x: -3, y: 0 }, { x: -2, y: 0 }, { x: -1, y: 0 }
            ],
            [
                { x: -1, y: -2 }, { x: 0, y: -2 }, { x: 1, y: -2 }, { x: 2, y: -2 }, { x: -2, y: -1 }, { x: -1, y: -1 },
                { x: 0, y: -1 }, { x: 1, y: -1 }, { x: 2, y: -1 }, { x: -3, y: 0 }, { x: -2, y: 0 }, { x: -1, y: 0 }
            ],
            [
                { x: -1, y: -2 }, { x: 0, y: -2 }, { x: 1, y: -2 }, { x: -2, y: -1 }, { x: -1, y: -1 },
                { x: 0, y: -1 }, { x: 1, y: -1 }, { x: -2, y: 0 }, { x: -1, y: 0 }
            ],
            [
                { x: -3, y: -1 }, { x: -2, y: -1 }, { x: -1, y: -1 }, { x: 0, y: -1 }, { x: 1, y: -1 },
                { x: -4, y: 0 }, { x: -3, y: 0 }, { x: -2, y: 0 }, { x: -1, y: 0 }
            ]
        ];
        /**
         * Refinement region coding and reference templates.
         *
         * @private
         */
        this._refinementTemplates = [
            {
                coding: [
                    { x: 0, y: -1 }, { x: 1, y: -1 }, { x: -1, y: 0 }
                ],
                reference: [
                    { x: 0, y: -1 }, { x: 1, y: -1 }, { x: -1, y: 0 }, { x: 0, y: 0 }, { x: 1, y: 0 },
                    { x: -1, y: 1 }, { x: 0, y: 1 }, { x: 1, y: 1 }
                ]
            },
            {
                coding: [
                    { x: -1, y: -1 }, { x: 0, y: -1 }, { x: 1, y: -1 }, { x: -1, y: 0 }
                ],
                reference: [
                    { x: 0, y: -1 }, { x: -1, y: 0 }, { x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }
                ]
            }
        ];
        /**
         * Context states reused for generic region decoding.
         *
         * @private
         */
        this._reusedContexts = [0x9b25, 0x0795, 0x00e5, 0x0195];
        /**
         * Context states reused for refinement region decoding.
         *
         * @private
         */
        this._refinementReusedContexts = [0x0020, 0x0008];
    }
    /**
     * Initializes page-level state from the `PageInformation` segment and allocates
     * the destination bit buffer (row-major, bit-packed).
     *
     * @private
     * @param {any} info The page information array (first entry contains width/height and flags).
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onPageInformation = function (info) {
        this._currentPageInfo = info;
        var rowSize = (info[0].width + 7) >> 3;
        var buffer = new Uint8ClampedArray(rowSize * info[0].height);
        if (info.defaultPixelValue) {
            buffer.fill(0xff);
        }
        this._buffer = buffer;
    };
    /**
     * Composites a decoded bitmap into the page buffer using the specified
     * combination operator at the region position.
     *
     * @private
     * @param {any} regionInfo The region info with `x`, `y`, `width`, `height`.
     * @param {any} bitmap The 2D bitmap array (rows of 0/1) to draw.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._drawBitmap = function (regionInfo, bitmap) {
        var pageInfo = this._currentPageInfo; //eslint-disable-line
        var width = regionInfo.width;
        var height = regionInfo.height;
        var rowSize = (pageInfo[0].width + 7) >> 3;
        var combinationOperator = pageInfo[0].combinationOperatorOverride //eslint-disable-line
            ? regionInfo.combinationOperator
            : pageInfo[0].combinationOperator;
        var buffer = this._buffer; //eslint-disable-line
        var mask0 = 128 >> (regionInfo.x & 7);
        var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
        var i;
        var j;
        var mask;
        var offset;
        switch (combinationOperator) {
            case 0:
                for (i = 0; i < height; i++) {
                    mask = mask0;
                    offset = offset0;
                    for (j = 0; j < width; j++) {
                        if (bitmap[i][j]) {
                            buffer[offset] |= mask;
                        }
                        mask >>= 1;
                        if (!mask) {
                            mask = 128;
                            offset++;
                        }
                    }
                    offset0 += rowSize;
                }
                break;
            case 2:
                for (i = 0; i < height; i++) {
                    mask = mask0;
                    offset = offset0;
                    for (j = 0; j < width; j++) {
                        if (bitmap[i][j]) {
                            buffer[offset] ^= mask;
                        }
                        mask >>= 1;
                        if (!mask) {
                            mask = 128;
                            offset++;
                        }
                    }
                    offset0 += rowSize;
                }
                break;
            default:
                throw new Error("The combination operator " + combinationOperator + " is not supported");
        }
    };
    /**
     * Decodes and draws an Immediate Generic Region segment.
     *
     * @private
     * @param {any} region The parsed region descriptor.
     * @param {Uint8Array} data The segment data buffer.
     * @param {number} start The start offset within `data`.
     * @param {number} end The end offset within `data`.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onImmediateGenericRegion = function (region, data, start, end) {
        var regionInfo = region.info; //eslint-disable-line
        var decodingContext = new _PdfDecodingContext(data, start, end);
        var bitmap = this._decodeBitmap(region.mmr, regionInfo.width, regionInfo.height, region.template, //eslint-disable-line
        region.prediction, null, region.at, decodingContext);
        this._drawBitmap(regionInfo, bitmap);
    };
    /**
     * Resolves a custom Huffman table by index among the referred segments/custom tables.
     *
     * @private
     * @param {number} index The zero-based custom table index to retrieve.
     * @param {number[]} referredTo The list of referred segment numbers.
     * @param {any} customTables The dictionary of custom tables by segment id.
     * @returns {any} The matching custom Huffman table.
     */
    _PdfSimpleSegmentVisitor.prototype._getCustomHuffmanTable = function (index, referredTo, customTables) {
        var currentIndex = 0;
        for (var i = 0, ii = referredTo.length; i < ii; i++) {
            var table = customTables[referredTo[i]]; //eslint-disable-line
            if (table) {
                if (index === currentIndex) {
                    return table;
                }
                currentIndex++;
            }
        }
        throw new Error("Custom Huffman table not found in the input data."); //eslint-disable-line
    };
    /**
     * Builds all Huffman tables required for a Huffman-coded text region:
     * symbol ID table and delta tables (S/DS/DT).
     *
     * @private
     * @param {any} textRegion The text region parameters.
     * @param {any} referredTo Referred segment ids.
     * @param {any} customTables Custom Huffman tables dictionary.
     * @param {number} numberOfSymbols Total symbols available for coding.
     * @param {_PdfReader} reader The bit reader used to decode table definitions.
     * @returns {any} An object containing `symbolIDTable`, `tableFirstS`, `tableDeltaS`, `tableDeltaT`.
     */
    _PdfSimpleSegmentVisitor.prototype._getTextRegionHuffmanTables = function (textRegion, //eslint-disable-line
    referredTo, //eslint-disable-line
    customTables, //eslint-disable-line
    numberOfSymbols, reader) {
        var codes = []; //eslint-disable-line
        for (var i = 0; i <= 34; i++) {
            var codeLength = reader._readBits(4);
            codes.push(new _PdfHuffmanLine([i, codeLength, 0, 0]));
        }
        var runCodesTable = new _PdfHuffmanTable(codes, false);
        codes.length = 0;
        for (var i = 0; i < numberOfSymbols;) {
            var codeLength = runCodesTable.decode(reader);
            if (codeLength >= 32) {
                var repeatedLength = void 0;
                var numberOfRepeats = void 0;
                var j = void 0;
                switch (codeLength) {
                    case 32:
                        if (i === 0) {
                            throw new Error('No previous value found in the symbol ID table');
                        }
                        numberOfRepeats = reader._readBits(2) + 3;
                        repeatedLength = codes[i - 1].prefixLength;
                        break;
                    case 33:
                        numberOfRepeats = reader._readBits(3) + 3;
                        repeatedLength = 0;
                        break;
                    case 34:
                        numberOfRepeats = reader._readBits(7) + 11;
                        repeatedLength = 0;
                        break;
                    default:
                        throw new Error('JBIG2 decoding error: Invalid code length found in the symbol ID table');
                }
                for (j = 0; j < numberOfRepeats; j++) {
                    codes.push(new _PdfHuffmanLine([i, repeatedLength, 0, 0]));
                    i++;
                }
            }
            else {
                codes.push(new _PdfHuffmanLine([i, codeLength, 0, 0]));
                i++;
            }
        }
        reader.byteAlign();
        var symbolIDTable = new _PdfHuffmanTable(codes, false);
        var customIndex = 0;
        var tableFirstS; //eslint-disable-line
        var tableDeltaS; //eslint-disable-line
        var tableDeltaT; //eslint-disable-line
        switch (textRegion.huffmanFS) {
            case 0:
            case 1:
                tableFirstS = this._getStandardTable(textRegion.huffmanFS + 6);
                break;
            case 3:
                tableFirstS = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
                customIndex++;
                break;
            default:
                throw new Error('Invalid Huffman File Segment Selector: Selector does not match any recognized Huffman-coded segment.');
        }
        switch (textRegion.huffmanDS) {
            case 0:
            case 1:
            case 2:
                tableDeltaS = this._getStandardTable(textRegion.huffmanDS + 8);
                break;
            case 3:
                tableDeltaS = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
                customIndex++;
                break;
            default:
                throw new Error('Jbig2 decode error: Detected invalid Huffman Data Stream selector.');
        }
        switch (textRegion.huffmanDT) {
            case 0:
            case 1:
            case 2:
                tableDeltaT = this._getStandardTable(textRegion.huffmanDT + 11);
                break;
            case 3:
                tableDeltaT = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
                customIndex++;
                break;
            default:
                throw new Error('Invalid Huffman Decoding Table (DT) selector encountered.');
        }
        if (textRegion.refinement) {
            throw new Error('Refinement with Huffman encoding is not supported.');
        }
        return {
            symbolIDTable: symbolIDTable,
            tableFirstS: tableFirstS,
            tableDeltaS: tableDeltaS,
            tableDeltaT: tableDeltaT
        };
    };
    /**
     * Returns a predefined (standard) Huffman table by its B.n number, caching it for reuse.
     *
     * @private
     * @param {number} number The standard table identifier (B.1..B.15 etc.).
     * @returns {_PdfHuffmanTable} The standard Huffman table instance.
     */
    _PdfSimpleSegmentVisitor.prototype._getStandardTable = function (number) {
        var table = this._standardTablesCache[number];
        if (table) {
            return table;
        }
        var lines; // eslint-disable-line
        switch (number) {
            case 1:
                lines = [[0, 1, 4, 0x0], [16, 2, 8, 0x2], [272, 3, 16, 0x6], [65808, 3, 32, 0x7]];
                break;
            case 2:
                lines = [[0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6], [3, 4, 3, 0xe],
                    [11, 5, 6, 0x1e], [75, 6, 32, 0x3e], [6, 0x3f]];
                break;
            case 3:
                lines = [[-256, 8, 8, 0xfe], [0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6],
                    [3, 4, 3, 0xe], [11, 5, 6, 0x1e], [-257, 8, 32, 0xff, 'lower'],
                    [75, 7, 32, 0x7e], [6, 0x3e]];
                break;
            case 4:
                lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 0, 0x6], [4, 4, 3, 0xe],
                    [12, 5, 6, 0x1e], [76, 5, 32, 0x1f]];
                break;
            case 5:
                lines = [[-255, 7, 8, 0x7e], [1, 1, 0, 0x0], [2, 2, 0, 0x2],
                    [3, 3, 0, 0x6], [4, 4, 3, 0xe], [12, 5, 6, 0x1e],
                    [-256, 7, 32, 0x7f, 'lower'], [76, 6, 32, 0x3e]];
                break;
            case 6:
                lines = [[-2048, 5, 10, 0x1c], [-1024, 4, 9, 0x8], [-512, 4, 8, 0x9],
                    [-256, 4, 7, 0xa], [-128, 5, 6, 0x1d], [-64, 5, 5, 0x1e],
                    [-32, 4, 5, 0xb], [0, 2, 7, 0x0], [128, 3, 7, 0x2],
                    [256, 3, 8, 0x3], [512, 4, 9, 0xc], [1024, 4, 10, 0xd],
                    [-2049, 6, 32, 0x3e, 'lower'], [2048, 6, 32, 0x3f]];
                break;
            case 7:
                lines = [[-1024, 4, 9, 0x8], [-512, 3, 8, 0x0], [-256, 4, 7, 0x9],
                    [-128, 5, 6, 0x1a], [-64, 5, 5, 0x1b], [-32, 4, 5, 0xa],
                    [0, 4, 5, 0xb], [32, 5, 5, 0x1c], [64, 5, 6, 0x1d],
                    [128, 4, 7, 0xc], [256, 3, 8, 0x1], [512, 3, 9, 0x2],
                    [1024, 3, 10, 0x3], [-1025, 5, 32, 0x1e, 'lower'],
                    [2048, 5, 32, 0x1f]];
                break;
            case 8:
                lines = [[-15, 8, 3, 0xfc], [-7, 9, 1, 0x1fc], [-5, 8, 1, 0xfd],
                    [-3, 9, 0, 0x1fd], [-2, 7, 0, 0x7c], [-1, 4, 0, 0xa],
                    [0, 2, 1, 0x0], [2, 5, 0, 0x1a], [3, 6, 0, 0x3a],
                    [4, 3, 4, 0x4], [20, 6, 1, 0x3b], [22, 4, 4, 0xb],
                    [38, 4, 5, 0xc], [70, 5, 6, 0x1b], [134, 5, 7, 0x1c],
                    [262, 6, 7, 0x3c], [390, 7, 8, 0x7d], [646, 6, 10, 0x3d],
                    [-16, 9, 32, 0x1fe, 'lower'], [1670, 9, 32, 0x1ff]];
                break;
            case 9:
                lines = [[-31, 8, 4, 0xfc], [-15, 9, 2, 0x1fc], [-11, 8, 2, 0xfd],
                    [-7, 9, 1, 0x1fd], [-5, 7, 1, 0x7c], [-3, 4, 1, 0xa],
                    [-1, 3, 1, 0x2], [1, 3, 1, 0x3], [3, 5, 1, 0x1a],
                    [5, 6, 1, 0x3a], [7, 3, 5, 0x4], [39, 6, 2, 0x3b],
                    [43, 4, 5, 0xb], [75, 4, 6, 0xc], [139, 5, 7, 0x1b],
                    [267, 5, 8, 0x1c], [523, 6, 8, 0x3c], [779, 7, 9, 0x7d],
                    [1291, 6, 11, 0x3d], [-32, 9, 32, 0x1fe, 'lower'],
                    [3339, 9, 32, 0x1ff]];
                break;
            case 10:
                lines = [[-21, 7, 4, 0x7a], [-5, 8, 0, 0xfc], [-4, 7, 0, 0x7b],
                    [-3, 5, 0, 0x18], [-2, 2, 2, 0x0], [2, 5, 0, 0x19],
                    [3, 6, 0, 0x36], [4, 7, 0, 0x7c], [5, 8, 0, 0xfd],
                    [6, 2, 6, 0x1], [70, 5, 5, 0x1a], [102, 6, 5, 0x37],
                    [134, 6, 6, 0x38], [198, 6, 7, 0x39], [326, 6, 8, 0x3a],
                    [582, 6, 9, 0x3b], [1094, 6, 10, 0x3c], [2118, 7, 11, 0x7d],
                    [-22, 8, 32, 0xfe, 'lower'], [4166, 8, 32, 0xff]];
                break;
            case 11:
                lines = [[1, 1, 0, 0x0], [2, 2, 1, 0x2], [4, 4, 0, 0xc],
                    [5, 4, 1, 0xd], [7, 5, 1, 0x1c], [9, 5, 2, 0x1d],
                    [13, 6, 2, 0x3c], [17, 7, 2, 0x7a], [21, 7, 3, 0x7b],
                    [29, 7, 4, 0x7c], [45, 7, 5, 0x7d], [77, 7, 6, 0x7e],
                    [141, 7, 32, 0x7f]];
                break;
            case 12:
                lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 1, 0x6],
                    [5, 5, 0, 0x1c], [6, 5, 1, 0x1d], [8, 6, 1, 0x3c],
                    [10, 7, 0, 0x7a], [11, 7, 1, 0x7b], [13, 7, 2, 0x7c],
                    [17, 7, 3, 0x7d], [25, 7, 4, 0x7e], [41, 8, 5, 0xfe],
                    [73, 8, 32, 0xff]];
                break;
            case 13:
                lines = [[1, 1, 0, 0x0], [2, 3, 0, 0x4], [3, 4, 0, 0xc],
                    [4, 5, 0, 0x1c], [5, 4, 1, 0xd], [7, 3, 3, 0x5],
                    [15, 6, 1, 0x3a], [17, 6, 2, 0x3b], [21, 6, 3, 0x3c],
                    [29, 6, 4, 0x3d], [45, 6, 5, 0x3e], [77, 7, 6, 0x7e],
                    [141, 7, 32, 0x7f]];
                break;
            case 14:
                lines = [[-2, 3, 0, 0x4], [-1, 3, 0, 0x5], [0, 1, 0, 0x0],
                    [1, 3, 0, 0x6], [2, 3, 0, 0x7]];
                break;
            case 15:
                lines = [[-24, 7, 4, 0x7c], [-8, 6, 2, 0x3c], [-4, 5, 1, 0x1c],
                    [-2, 4, 0, 0xc], [-1, 3, 0, 0x4], [0, 1, 0, 0x0],
                    [1, 3, 0, 0x5], [2, 4, 0, 0xd], [3, 5, 1, 0x1d],
                    [5, 6, 2, 0x3d], [9, 7, 4, 0x7d], [-25, 7, 32, 0x7e, 'lower'],
                    [25, 7, 32, 0x7f]];
                break;
            default:
                throw new Error("Standard table B." + number + " does not exist");
        }
        for (var i = 0, ii = lines.length; i < ii; i++) {
            lines[i] = new _PdfHuffmanLine(lines[i]);
        }
        table = new _PdfHuffmanTable(lines, true);
        this._standardTablesCache[number] = table;
        return table;
    };
    /* eslint-disable */
    /**
     * Prepares Huffman tables for symbol dictionary decoding: delta height/width, bitmap size,
     * and aggregate instances, resolving from standard or custom tables.
     *
     * @private
     * @param {{huffmanDHSelector:number, huffmanDWSelector:number, bitmapSizeSelector:boolean, aggregationInstancesSelector:boolean}} dictionary The dictionary flags/selectors.
     * @param {any} referredTo Referred segment ids.
     * @param {any} customTables Custom Huffman tables dictionary.
     * @returns {{tableDeltaHeight:number, tableDeltaWidth:number, tableBitmapSize:number, tableAggregateInstances:any}} The required Huffman tables.
     */
    _PdfSimpleSegmentVisitor.prototype._getSymbolDictionaryHuffmanTables = function (dictionary, referredTo, customTables) {
        var customIndex = 0;
        var tableDeltaHeight;
        var tableDeltaWidth;
        switch (dictionary.huffmanDHSelector) {
            case 0:
            case 1:
                tableDeltaHeight = this._getStandardTable(dictionary.huffmanDHSelector + 4);
                break;
            case 3:
                tableDeltaHeight = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
                customIndex++;
                break;
            default:
                throw new Error('Invalid Huffman DH selector: the provided selector value is not recognized or supported.');
        }
        switch (dictionary.huffmanDWSelector) {
            case 0:
            case 1:
                tableDeltaWidth = this._getStandardTable(dictionary.huffmanDWSelector + 2);
                break;
            case 3:
                tableDeltaWidth = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
                customIndex++;
                break;
            default:
                throw new Error('Invalid Huffman Dictionary Word selector: failed during decoding process.');
        }
        var tableBitmapSize;
        var tableAggregateInstances;
        if (dictionary.bitmapSizeSelector) {
            tableBitmapSize = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
            customIndex++;
        }
        else {
            tableBitmapSize = this._getStandardTable(1);
        }
        if (dictionary.aggregationInstancesSelector) {
            tableAggregateInstances = this._getCustomHuffmanTable(customIndex, referredTo, customTables);
        }
        else {
            tableAggregateInstances = this._getStandardTable(1);
        }
        return {
            tableDeltaHeight: tableDeltaHeight,
            tableDeltaWidth: tableDeltaWidth,
            tableBitmapSize: tableBitmapSize,
            tableAggregateInstances: tableAggregateInstances
        };
    };
    /* eslint-enable */
    /**
     * Reads a raw (uncompressed) bitmap from the bit stream into a 2D array.
     *
     * @private
     * @param {any} reader The bit reader providing `_readBit()` and `byteAlign()`.
     * @param {number} width The bitmap width in pixels.
     * @param {number} height The bitmap height in pixels.
     * @returns {Uint8Array[]} The decoded bitmap (rows of 0/1 values).
     */
    _PdfSimpleSegmentVisitor.prototype._readUncompressedBitmap = function (reader, width, height) {
        var bitmap = [];
        for (var y = 0; y < height; y++) {
            var row = new Uint8Array(width);
            bitmap.push(row);
            for (var x = 0; x < width; x++) {
                row[x] = reader._readBit();
            }
            reader.byteAlign();
        }
        return bitmap;
    };
    /**
     * Decodes an MMR (fax) compressed bitmap into a 2D array of bits.
     *
     * @private
     * @param {any} input The input providing `readNextChar()` bytes.
     * @param {number} width The bitmap width in pixels.
     * @param {number} height The bitmap height in pixels.
     * @param {boolean} endOfBlock Whether to consume an end-of-block marker.
     * @returns {Uint8Array[]} The decoded bitmap (rows of 0/1 values).
     */
    _PdfSimpleSegmentVisitor.prototype._decodeMmrBitmap = function (input, width, height, endOfBlock) {
        var params = {
            K: -1,
            Columns: width,
            Rows: height,
            BlackIs1: true,
            EndOfBlock: endOfBlock
        };
        var decoder = new _PdfFaxDecoder(input, params);
        var bitmap = [];
        var currentByte;
        var eof = false;
        for (var y = 0; y < height; y++) {
            var row = new Uint8Array(width);
            bitmap.push(row);
            var shift = -1;
            for (var x = 0; x < width; x++) {
                if (shift < 0) {
                    currentByte = decoder.readNextChar();
                    if (currentByte === -1) {
                        currentByte = 0;
                        eof = true;
                    }
                    shift = 7;
                }
                row[x] = (currentByte >> shift) & 1;
                shift--;
            }
        }
        if (endOfBlock && !eof) {
            var lookForEOFLimit = 5;
            for (var i = 0; i < lookForEOFLimit; i++) {
                if (decoder.readNextChar() === -1) {
                    break;
                }
            }
        }
        return bitmap;
    };
    /**
     * Decodes a Symbol Dictionary segment and stores the resulting symbol bitmaps
     * keyed by the current segment id.
     *
     * @private
     * @param {any} dictionary The symbol dictionary parameters.
     * @param {any} currentSegment The current segment number.
     * @param {any} referredSegments The list of referred segment ids.
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset.
     * @param {number} end End offset.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onSymbolDictionary = function (dictionary, currentSegment, referredSegments, // eslint-disable-line
    data, start, end) {
        var huffmanTables; // eslint-disable-line
        var huffmanInput; // eslint-disable-line
        if (dictionary.huffman) {
            huffmanTables = this._getSymbolDictionaryHuffmanTables(dictionary, referredSegments, this._customTables);
            huffmanInput = new _PdfReader(data, start, end);
        }
        var symbols = this._symbols; // eslint-disable-line
        if (!symbols) {
            this._symbols = symbols = {};
        }
        var inputSymbols = []; // eslint-disable-line
        for (var _i = 0, referredSegments_1 = referredSegments; _i < referredSegments_1.length; _i++) {
            var referredSegment = referredSegments_1[_i];
            var referredSymbols = symbols[referredSegment]; // eslint-disable-line
            if (referredSymbols) {
                inputSymbols.push.apply(inputSymbols, referredSymbols);
            }
        }
        var decodingContext = new _PdfDecodingContext(data, start, end);
        symbols[currentSegment] = this._decodeSymbolDictionary(dictionary.huffman, dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols, dictionary.numberOfExportedSymbols, huffmanTables, dictionary.template, dictionary.at, dictionary.refinementTemplate, dictionary.refinementAt, decodingContext, huffmanInput);
    };
    /**
     * Decodes and draws an Immediate Text Region (optionally Huffman-coded),
     * composing the decoded symbols into the page bitmap.
     *
     * @private
     * @param {any} region The text region parameters.
     * @param {string[]} referredSegments Referred segment ids (as strings).
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset.
     * @param {number} end End offset.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onImmediateTextRegion = function (region, referredSegments, data, start, end // eslint-disable-line
    ) {
        var regionInfo = region.info; // eslint-disable-line
        var huffmanTables; //eslint-disable-line
        var huffmanInput; // eslint-disable-line
        var symbols = this._symbols; // eslint-disable-line
        var inputSymbols = []; // eslint-disable-line
        for (var _i = 0, referredSegments_2 = referredSegments; _i < referredSegments_2.length; _i++) {
            var referredSegment = referredSegments_2[_i];
            var referredSymbols = symbols[Number.parseInt(referredSegment.toString(), 10)]; //eslint-disable-line
            if (referredSymbols) {
                inputSymbols.push.apply(inputSymbols, referredSymbols);
            }
        }
        var symbolCodeLength = _log2(inputSymbols.length);
        if (region.huffman) {
            huffmanInput = new _PdfReader(data, start, end);
            huffmanTables = this._getTextRegionHuffmanTables(region, referredSegments, this._customTables, inputSymbols.length, huffmanInput);
        }
        var decodingContext = new _PdfDecodingContext(data, start, end);
        var bitmap = this._decodeTextRegion(region.huffman, region.refinement, regionInfo.width, // eslint-disable-line
        regionInfo.height, region.defaultPixelValue, region.numberOfSymbolInstances, region.stripSize, inputSymbols, symbolCodeLength, region.transposed, region.dsOffset, region.referenceCorner, region.combinationOperator, huffmanTables, region.refinementTemplate, region.refinementAt, decodingContext, region.logStripSize, huffmanInput);
        this._drawBitmap(regionInfo, bitmap);
    };
    /**
     * Decodes a Pattern Dictionary segment and stores patterns by segment id.
     *
     * @private
     * @param {any} dictionary The pattern dictionary parameters.
     * @param {string} currentSegment The current segment number.
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset.
     * @param {number} end End offset.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onPatternDictionary = function (dictionary, currentSegment, data, start, end) {
        var patterns = this._patterns; // eslint-disable-line
        if (!patterns) {
            this._patterns = patterns = {};
        }
        var decodingContext = new _PdfDecodingContext(data, start, end);
        patterns[Number.parseInt(currentSegment.toString(), 10)] = this._decodePatternDictionary(dictionary.mmr, dictionary.patternWidth, dictionary.patternHeight, dictionary.maxPatternIndex, dictionary.template, decodingContext);
    };
    /**
     * Decodes and draws an Immediate Halftone Region using previously decoded patterns.
     *
     * @private
     * @param {any} region The halftone region parameters.
     * @param {string[]} referredSegments Ids referencing the pattern dictionary.
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset.
     * @param {number} end End offset.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onImmediateHalftoneRegion = function (region, referredSegments, data, start, end) {
        var patterns = this._patterns[referredSegments[0]]; // eslint-disable-line
        var regionInfo = region.info; // eslint-disable-line
        var decodingContext = new _PdfDecodingContext(data, start, end);
        var bitmap = this._decodeHalftoneRegion(region.mmr, patterns, region.template, regionInfo.width, // eslint-disable-line
        regionInfo.height, region.defaultPixelValue, region.enableSkip, region.combinationOperator, region.gridWidth, region.gridHeight, region.gridOffsetX, region.gridOffsetY, region.gridVectorX, region.gridVectorY, decodingContext);
        this._drawBitmap(regionInfo, bitmap);
    };
    /**
     * Decodes a Tables segment and caches the resulting custom Huffman tables under the segment id.
     *
     * @private
     * @param {string} currentSegment The current segment number.
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset in `data`.
     * @param {number} end End offset in `data`.
     * @returns {void}
     */
    _PdfSimpleSegmentVisitor.prototype._onTables = function (currentSegment, data, start, end) {
        var customTables = this._customTables; // eslint-disable-line
        if (!customTables) {
            this._customTables = customTables = {};
        }
        customTables[Number.parseInt(currentSegment.toString(), 10)] = this._decodeTablesSegment(data, start, end);
    };
    /**
     * Decodes a custom Huffman table from a Tables segment payload.
     *
     * @private
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset in `data`.
     * @param {number} end End offset in `data`.
     * @returns {_PdfHuffmanTable} The constructed custom Huffman table.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeTablesSegment = function (data, start, end) {
        var flags = data[start];
        var lowestValue = _readUnsignedInteger32(data, start + 1) & 0xffffffff;
        var highestValue = _readUnsignedInteger32(data, start + 5) & 0xffffffff;
        var reader = new _PdfReader(data, start + 9, end);
        var prefixSizeBits = ((flags >> 1) & 7) + 1;
        var rangeSizeBits = ((flags >> 4) & 7) + 1;
        var lines = [];
        var prefixLength;
        var rangeLength;
        var currentRangeLow = lowestValue;
        do {
            prefixLength = reader._readBits(prefixSizeBits);
            rangeLength = reader._readBits(rangeSizeBits);
            lines.push(new _PdfHuffmanLine([currentRangeLow, prefixLength, rangeLength, 0]));
            currentRangeLow += 1 << rangeLength;
        } while (currentRangeLow < highestValue);
        prefixLength = reader._readBits(prefixSizeBits);
        lines.push(new _PdfHuffmanLine([lowestValue - 1, prefixLength, 32, 0, 'lower']));
        prefixLength = reader._readBits(prefixSizeBits);
        lines.push(new _PdfHuffmanLine([highestValue, prefixLength, 32, 0]));
        if (flags & 1) {
            prefixLength = reader._readBits(prefixSizeBits);
            lines.push(new _PdfHuffmanLine([prefixLength, 0]));
        }
        return new _PdfHuffmanTable(lines, false);
    };
    /**
     * Fast-path decoding for Generic Region template 0 with default AT positions,
     * producing a bitmap using the specified arithmetic decoder contexts.
     *
     * @private
     * @param {number} width Bitmap width in pixels.
     * @param {number} height Bitmap height in pixels.
     * @param {_PdfDecodingContext} decodingContext The decoding context providing decoder and contexts.
     * @returns {Uint8Array[]} The decoded bitmap.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeBitmapTemplate0 = function (width, height, decodingContext) {
        var decoder = decodingContext.decoder; // eslint-disable-line
        var contexts = decodingContext.contextCache.getContexts('GB'); // eslint-disable-line
        var bitmap = [];
        var contextLabel;
        var i;
        var j;
        var pixel;
        var row;
        var row1;
        var row2;
        var OLD_PIXEL_MASK = 0x7bf7;
        for (i = 0; i < height; i++) {
            row = bitmap[i] = new Uint8Array(width);
            row1 = i < 1 ? row : bitmap[i - 1];
            row2 = i < 2 ? row : bitmap[i - 2];
            contextLabel =
                (row2[0] << 13) |
                    (row2[1] << 12) |
                    (row2[2] << 11) |
                    (row1[0] << 7) |
                    (row1[1] << 6) |
                    (row1[2] << 5) |
                    (row1[3] << 4);
            for (j = 0; j < width; j++) {
                row[j] = pixel = decoder._readBit(contexts, contextLabel);
                contextLabel =
                    ((contextLabel & OLD_PIXEL_MASK) << 1) |
                        (j + 3 < width ? row2[j + 3] << 11 : 0) |
                        (j + 4 < width ? row1[j + 4] << 4 : 0) |
                        pixel;
            }
        }
        return bitmap;
    };
    /* eslint-disable */
    /**
     * Decodes a Generic Region bitmap (MMR or arithmetic-coded) with the specified template,
     * prediction mode, optional skip mask, and AT positions.
     *
     * @private
     * @param {boolean} mmr Whether the bitmap is MMR-compressed.
     * @param {number} width Bitmap width.
     * @param {number} height Bitmap height.
     * @param {number} templateIndex JBIG2 template index (0..3).
     * @param {boolean} prediction When true, uses LTP prediction.
     * @param {boolean[][]} skip Optional skip mask (true = skip decoding at pixel).
     * @param {{x:number, y:number}[]} at Additional relative AT positions.
     * @param {_PdfDecodingContext} decodingContext The decoding context.
     * @returns {Uint8Array[]} The decoded bitmap.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeBitmap = function (mmr, width, height, templateIndex, prediction, skip, at, decodingContext) {
        if (mmr) {
            var input = new _PdfReader(decodingContext._data, decodingContext._start, decodingContext._end);
            return this._decodeMmrBitmap(input, width, height, false);
        }
        if (templateIndex === 0 &&
            !skip &&
            !prediction &&
            at.length === 4 &&
            at[0].x === 3 &&
            at[0].y === -1 &&
            at[1].x === -3 &&
            at[1].y === -1 &&
            at[2].x === 2 &&
            at[2].y === -2 &&
            at[3].x === -2 &&
            at[3].y === -2) {
            return this._decodeBitmapTemplate0(width, height, decodingContext);
        }
        var useskip = !!skip;
        var template = this._codingTemplates[templateIndex].concat(at);
        template.sort(function (a, b) { return a.y - b.y || a.x - b.x; });
        var templateLength = template.length;
        var templateX = new Int8Array(templateLength);
        var templateY = new Int8Array(templateLength);
        var changingTemplateEntries = [];
        var reuseMask = 0;
        var minX = 0;
        var maxX = 0;
        var minY = 0;
        var c;
        var k;
        for (k = 0; k < templateLength; k++) {
            templateX[k] = template[k].x;
            templateY[k] = template[k].y;
            minX = Math.min(minX, template[k].x);
            maxX = Math.max(maxX, template[k].x);
            minY = Math.min(minY, template[k].y);
            if (k < templateLength - 1 &&
                template[k].y === template[k + 1].y &&
                template[k].x === template[k + 1].x - 1) {
                reuseMask |= 1 << (templateLength - 1 - k);
            }
            else {
                changingTemplateEntries.push(k);
            }
        }
        var changingEntriesLength = changingTemplateEntries.length;
        var changingTemplateX = new Int8Array(changingEntriesLength);
        var changingTemplateY = new Int8Array(changingEntriesLength);
        var changingTemplateBit = new Uint16Array(changingEntriesLength);
        for (c = 0; c < changingEntriesLength; c++) {
            k = changingTemplateEntries[c];
            changingTemplateX[c] = template[k].x;
            changingTemplateY[c] = template[k].y;
            changingTemplateBit[c] = 1 << (templateLength - 1 - k);
        }
        var sbbLeft = -minX;
        var sbbTop = -minY;
        var sbbRight = width - maxX;
        var pseudoPixelContext = this._reusedContexts[templateIndex];
        var row = new Uint8Array(width);
        var bitmap = [];
        var decoder = decodingContext.decoder;
        var contexts = decodingContext.contextCache.getContexts('GB');
        var ltp = 0;
        var j;
        var i0;
        var j0;
        var contextLabel = 0;
        var bit;
        var shift;
        for (var i = 0; i < height; i++) {
            if (prediction) {
                var sltp = decoder._readBit(contexts, pseudoPixelContext);
                ltp ^= sltp;
                if (ltp) {
                    bitmap.push(row);
                    continue;
                }
            }
            row = new Uint8Array(row);
            bitmap.push(row);
            for (j = 0; j < width; j++) {
                if (useskip && skip[i][j]) {
                    row[j] = 0;
                    continue;
                }
                if (j >= sbbLeft && j < sbbRight && i >= sbbTop) {
                    contextLabel = (contextLabel << 1) & reuseMask;
                    for (k = 0; k < changingEntriesLength; k++) {
                        i0 = i + changingTemplateY[k];
                        j0 = j + changingTemplateX[k];
                        bit = bitmap[i0][j0];
                        if (bit) {
                            bit = changingTemplateBit[k];
                            contextLabel |= bit;
                        }
                    }
                }
                else {
                    contextLabel = 0;
                    shift = templateLength - 1;
                    for (k = 0; k < templateLength; k++, shift--) {
                        j0 = j + templateX[k];
                        if (j0 >= 0 && j0 < width) {
                            i0 = i + templateY[k];
                            if (i0 >= 0) {
                                bit = bitmap[i0][j0];
                                if (bit) {
                                    contextLabel |= bit << shift;
                                }
                            }
                        }
                    }
                }
                var pixel = decoder._readBit(contexts, contextLabel);
                row[j] = pixel;
            }
        }
        return bitmap;
    };
    /* eslint-enable */
    /**
     * Decodes a Refinement Region bitmap using coding and reference templates applied
     * against a reference bitmap with given offsets.
     *
     * @private
     * @param {number} width Output width.
     * @param {number} height Output height.
     * @param {number} templateIndex Refinement template index (0/1).
     * @param {any} referenceBitmap The reference bitmap (2D 0/1).
     * @param {number} offsetX X offset into the reference.
     * @param {number} offsetY Y offset into the reference.
     * @param {any} prediction Prediction flag (unused/unsupported when true).
     * @param {any} at Additional AT positions.
     * @param {_PdfDecodingContext} decodingContext The decoding context.
     * @returns {Uint8Array[]} The decoded refinement bitmap.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeRefinement = function (width, height, templateIndex, referenceBitmap, // eslint-disable-line
    offsetX, offsetY, prediction, at, decodingContext // eslint-disable-line
    ) {
        var codingTemplate = this._refinementTemplates[templateIndex].coding;
        if (templateIndex === 0) {
            codingTemplate = codingTemplate.concat([at[0]]);
        }
        var codingTemplateLength = codingTemplate.length;
        var codingTemplateX = new Int32Array(codingTemplateLength);
        var codingTemplateY = new Int32Array(codingTemplateLength);
        for (var k = 0; k < codingTemplateLength; k++) {
            codingTemplateX[k] = codingTemplate[k].x;
            codingTemplateY[k] = codingTemplate[k].y;
        }
        var referenceTemplate = this._refinementTemplates[templateIndex].
            reference;
        if (templateIndex === 0) {
            referenceTemplate = referenceTemplate.concat([at[1]]);
        }
        var referenceTemplateLength = referenceTemplate.length;
        var referenceTemplateX = new Int32Array(referenceTemplateLength);
        var referenceTemplateY = new Int32Array(referenceTemplateLength);
        for (var k = 0; k < referenceTemplateLength; k++) {
            referenceTemplateX[k] = referenceTemplate[k].x;
            referenceTemplateY[k] = referenceTemplate[k].y;
        }
        var referenceWidth = referenceBitmap[0].length;
        var referenceHeight = referenceBitmap.length;
        var pseudoPixelContext = this._refinementReusedContexts[templateIndex];
        var bitmap = [];
        var decoder = decodingContext.decoder; // eslint-disable-line
        var contexts = decodingContext.contextCache.getContexts('GR'); // eslint-disable-line
        var ltp = 0;
        for (var i = 0; i < height; i++) {
            if (prediction) {
                var sltp = decoder._readBit(contexts, pseudoPixelContext);
                ltp ^= sltp;
                if (ltp) {
                    throw new Error('Prediction functionality is not supported.');
                }
            }
            var row = new Uint8Array(width);
            bitmap.push(row);
            for (var j = 0; j < width; j++) {
                var i0 = void 0;
                var j0 = void 0;
                var contextLabel = 0;
                for (var k = 0; k < codingTemplateLength; k++) {
                    i0 = i + codingTemplateY[k];
                    j0 = j + codingTemplateX[k];
                    if (i0 < 0 || j0 < 0 || j0 >= width) {
                        contextLabel <<= 1;
                    }
                    else {
                        contextLabel = (contextLabel << 1) | bitmap[i0][j0];
                    }
                }
                for (var k = 0; k < referenceTemplateLength; k++) {
                    i0 = i + referenceTemplateY[k] - offsetY;
                    j0 = j + referenceTemplateX[k] - offsetX;
                    if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) {
                        contextLabel <<= 1;
                    }
                    else {
                        contextLabel = (contextLabel << 1) |
                            referenceBitmap[i0][j0];
                    }
                }
                var pixel = decoder._readBit(contexts, contextLabel);
                row[j] = pixel;
            }
        }
        return bitmap;
    };
    /**
     * Decodes a Symbol Dictionary, producing and (optionally) exporting symbol bitmaps
     * using either arithmetic or Huffman coding with optional refinement.
     *
     * @private
     * @param {any} huffman Whether Huffman coding is used.
     * @param {any} refinement Whether refinement coding is used.
     * @param {any} symbols Existing input symbol bitmaps.
     * @param {number} numberOfNewSymbols Number of new symbols to decode.
     * @param {number} numberOfExportedSymbols Number of symbols to export.
     * @param {any} huffmanTables Huffman tables bundle when `huffman` is true.
     * @param {number} templateIndex Generic Region template for symbol bitmaps.
     * @param {{x:number,y:number}[]} at AT positions for generic template.
     * @param {number} refinementTemplateIndex Refinement template index.
     * @param {any} refinementAt AT positions for refinement.
     * @param {_PdfDecodingContext} decodingContext The decoding context.
     * @param {any} huffmanInput The Huffman bit reader when `huffman` is true.
     * @returns {any[]} The exported symbol bitmaps.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeSymbolDictionary = function (huffman, refinement, symbols, numberOfNewSymbols, // eslint-disable-line
    numberOfExportedSymbols, huffmanTables, templateIndex, // eslint-disable-line
    at, refinementTemplateIndex, refinementAt, // eslint-disable-line
    decodingContext, huffmanInput) {
        if (huffman && refinement) {
            throw new Error('Huffman coding with symbol refinement is not supported.');
        }
        var newSymbols = []; // eslint-disable-line
        var currentHeight = 0;
        var symbolCodeLength = _log2(symbols.length + numberOfNewSymbols);
        var decoder = decodingContext.decoder; // eslint-disable-line
        var contextCache = decodingContext.contextCache; // eslint-disable-line
        var tableB1; // eslint-disable-line
        var symbolWidths = []; // eslint-disable-line
        if (huffman) {
            tableB1 = this._getStandardTable(1);
            symbolCodeLength = Math.max(symbolCodeLength, 1);
        }
        while (newSymbols.length < numberOfNewSymbols) {
            var deltaHeight = huffman
                ? huffmanTables.tableDeltaHeight.decode(huffmanInput)
                : this._decodeInteger(contextCache, 'IADH', decoder);
            currentHeight += deltaHeight;
            var currentWidth = 0;
            var totalWidth = 0;
            var firstSymbol = huffman ? symbolWidths.length : 0;
            while (true) { // eslint-disable-line
                var deltaWidth = huffman
                    ? huffmanTables.tableDeltaWidth.decode(huffmanInput)
                    : this._decodeInteger(contextCache, 'IADW', decoder);
                if (typeof (deltaWidth) === 'undefined') {
                    break;
                }
                currentWidth += deltaWidth;
                totalWidth += currentWidth;
                var bitmap = void 0; // eslint-disable-line
                if (refinement) {
                    var numberOfInstances = this._decodeInteger(contextCache, 'IAAI', decoder);
                    if (numberOfInstances > 1) {
                        bitmap = this._decodeTextRegion(huffman, refinement, currentWidth, currentHeight, 0, numberOfInstances, 1, symbols.concat(newSymbols), symbolCodeLength, 0, 0, 1, 0, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext, 0, huffmanInput);
                    }
                    else {
                        var symbolId = this._decodeImageData(contextCache, decoder, symbolCodeLength);
                        var rdx = this._decodeInteger(contextCache, 'IARDX', decoder);
                        var rdy = this._decodeInteger(contextCache, 'IARDY', decoder);
                        var symbol = symbolId < symbols.length // eslint-disable-line
                            ? symbols[symbolId]
                            : newSymbols[symbolId - symbols.length];
                        bitmap = this._decodeRefinement(currentWidth, currentHeight, refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt, decodingContext);
                    }
                    newSymbols.push(bitmap);
                }
                else if (huffman) {
                    symbolWidths.push(currentWidth);
                }
                else {
                    bitmap = this._decodeBitmap(false, currentWidth, currentHeight, templateIndex, false, null, at, decodingContext);
                    newSymbols.push(bitmap);
                }
            }
            if (huffman && !refinement) {
                var bitmapSize = huffmanTables.tableBitmapSize.decode(huffmanInput);
                huffmanInput.byteAlign();
                var collectiveBitmap = void 0; // eslint-disable-line
                if (bitmapSize === 0) {
                    collectiveBitmap = this._readUncompressedBitmap(huffmanInput, totalWidth, currentHeight);
                }
                else {
                    var originalEnd = huffmanInput.end;
                    var bitmapEnd = huffmanInput.position + bitmapSize;
                    huffmanInput.end = bitmapEnd;
                    collectiveBitmap = this._decodeMmrBitmap(huffmanInput, totalWidth, currentHeight, false);
                    huffmanInput.end = originalEnd;
                    huffmanInput.position = bitmapEnd;
                }
                var numberOfSymbolsDecoded = symbolWidths.length;
                if (firstSymbol === numberOfSymbolsDecoded - 1) {
                    newSymbols.push(collectiveBitmap);
                }
                else {
                    var xMin = 0;
                    var xMax = void 0;
                    var bitmapWidth = void 0;
                    var symbolBitmap = void 0; // eslint-disable-line
                    for (var i_1 = firstSymbol; i_1 < numberOfSymbolsDecoded; i_1++) {
                        bitmapWidth = symbolWidths[i_1];
                        xMax = xMin + bitmapWidth;
                        symbolBitmap = [];
                        for (var y = 0; y < currentHeight; y++) {
                            symbolBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
                        }
                        newSymbols.push(symbolBitmap);
                        xMin = xMax;
                    }
                }
            }
        }
        var exportedSymbols = []; // eslint-disable-line
        var flags = [];
        var currentFlag = false;
        var i = 0;
        var totalSymbolsLength = symbols.length + numberOfNewSymbols;
        while (flags.length < totalSymbolsLength) {
            var runLength = huffman
                ? tableB1.decode(huffmanInput)
                : this._decodeInteger(contextCache, 'IAEX', decoder);
            while (runLength--) {
                flags.push(currentFlag);
            }
            currentFlag = !currentFlag;
        }
        for (var i_2 = 0; i_2 < symbols.length; i_2++) {
            if (flags[i_2]) {
                exportedSymbols.push(symbols[i_2]);
            }
        }
        for (var j = 0; j < numberOfNewSymbols; j++, i++) {
            if (flags[i]) {
                exportedSymbols.push(newSymbols[j]);
            }
        }
        return exportedSymbols;
    };
    /**
     * Decodes a signed integer using the specified JBIG2 integer procedure contexts.
     *
     * @private
     * @param {any} contextCache The context cache providing states by procedure name.
     * @param {any} procedure The procedure id/name (e.g., 'IADW', 'IADT', 'IAID').
     * @param {any} decoder The arithmetic decoder.
     * @returns {number} The decoded signed integer (32-bit range).
     */
    _PdfSimpleSegmentVisitor.prototype._decodeInteger = function (contextCache, procedure, decoder) {
        var result; // eslint-disable-line
        var contexts = contextCache.getContexts(procedure); // eslint-disable-line
        var reader = new _PdfBitReader();
        var sign = reader._readBits(1, decoder, contexts);
        var value = reader._readBits(1, decoder, contexts) ?
            (reader._readBits(1, decoder, contexts) ?
                (reader._readBits(1, decoder, contexts) ?
                    (reader._readBits(1, decoder, contexts) ?
                        (reader._readBits(1, decoder, contexts) ?
                            (reader._readBits(32, decoder, contexts) + 4436) :
                            reader._readBits(12, decoder, contexts) + 340) :
                        reader._readBits(8, decoder, contexts) + 84) :
                    reader._readBits(6, decoder, contexts) + 20) :
                reader._readBits(4, decoder, contexts) + 4) :
            reader._readBits(2, decoder, contexts);
        var signedValue;
        if (sign === 0) {
            signedValue = value;
        }
        else if (value > 0) {
            signedValue = -value;
        }
        if (signedValue >= -(Math.pow(2, 31)) && signedValue <= (Math.pow(2, 31) - 1)) {
            return signedValue;
        }
        return result;
    };
    /**
     * Decodes an unsigned integer of the given bit-length using the IAID procedure.
     *
     * @private
     * @param {any} contextCache The context cache.
     * @param {any} decoder The arithmetic decoder.
     * @param {any} codeLength The number of bits to decode.
     * @returns {number} The decoded unsigned value.
     */
    _PdfSimpleSegmentVisitor.prototype._decodeImageData = function (contextCache, decoder, codeLength) {
        var contexts = contextCache.getContexts('IAID'); // eslint-disable-line
        var prev = 1;
        for (var i = 0; i < codeLength; i++) {
            var bit = decoder._readBit(contexts, prev);
            prev = (prev << 1) | bit;
        }
        if (codeLength < 31) {
            return prev & ((1 << codeLength) - 1);
        }
        return prev & 0x7fffffff;
    };
    /**
     * Decodes a Text Region by placing symbol bitmaps (with optional refinement)
     * onto a target bitmap using the specified combination operator.
     *
     * @private
     * @param {any} huffman Whether Huffman coding is used.
     * @param {any} refinement Whether refinement coding is used.
     * @param {number} width Region width.
     * @param {number} height Region height.
     * @param {any} defaultPixelValue Initial fill value for the region rows (0/1).
     * @param {any} numberOfSymbolInstances Number of symbol placements.
     * @param {any} stripSize The strip height.
     * @param {any} inputSymbols The list of available symbol bitmaps.
     * @param {any} symbolCodeLength Bit-length for symbol ids (IAID).
     * @param {any} transposed Whether symbols are laid out transposed.
     * @param {any} dsOffset Delta-S offset.
     * @param {any} referenceCorner Reference corner selector.
     * @param {any} combinationOperator Composition operator (e.g., 0 = OR, 2 = XOR).
     * @param {any} huffmanTables Huffman tables bundle when `huffman` is true.
     * @param {any} refinementTemplateIndex Refinement template index.
     * @param {any} refinementAt AT positions for refinement.
     * @param {any} decodingContext The decoding context.
     * @param {any} logStripSize Log2 of strip size (when Huffman-coded).
     * @param {any} huffmanInput The Huffman input reader when `huffman` is true.
     * @returns {any} The decoded text region bitmap (2D array).
     */
    _PdfSimpleSegmentVisitor.prototype._decodeTextRegion = function (huffman, refinement, width, height, defaultPixelValue, // eslint-disable-line
    numberOfSymbolInstances, stripSize, inputSymbols, symbolCodeLength, // eslint-disable-line
    transposed, dsOffset, referenceCorner, combinationOperator, huffmanTables, // eslint-disable-line
    refinementTemplateIndex, refinementAt, decodingContext, logStripSize, // eslint-disable-line
    huffmanInput) {
        if (huffman && refinement) {
            throw new Error('Huffman encoding with refinement is currently not supported.');
        }
        var bitmap = [];
        for (var i_3 = 0; i_3 < height; i_3++) {
            var row = new Uint8Array(width);
            if (defaultPixelValue) {
                row.fill(defaultPixelValue);
            }
            bitmap.push(row);
        }
        var decoder = decodingContext.decoder; // eslint-disable-line
        var contextCache = decodingContext.contextCache; // eslint-disable-line
        var stripT = huffman
            ? -huffmanTables.tableDeltaT.decode(huffmanInput)
            : -this._decodeInteger(contextCache, 'IADT', decoder);
        var firstS = 0;
        var i = 0;
        while (i < numberOfSymbolInstances) {
            var deltaT = huffman // eslint-disable-line
                ? huffmanTables.tableDeltaT.decode(huffmanInput)
                : this._decodeInteger(contextCache, 'IADT', decoder);
            stripT += deltaT;
            var deltaFirstS = huffman // eslint-disable-line
                ? huffmanTables.tableFirstS.decode(huffmanInput)
                : this._decodeInteger(contextCache, 'IAFS', decoder);
            firstS += deltaFirstS;
            var currentS = firstS; // eslint-disable-line
            do {
                var currentT = 0;
                if (stripSize > 1) {
                    currentT = huffman
                        ? huffmanInput._readBits(logStripSize)
                        : this._decodeInteger(contextCache, 'IAIT', decoder);
                }
                var t = stripSize * stripT + currentT;
                var symbolId = huffman // eslint-disable-line
                    ? huffmanTables.symbolIDTable.decode(huffmanInput)
                    : this._decodeImageData(contextCache, decoder, symbolCodeLength);
                var applyRefinement = refinement && (huffman // eslint-disable-line
                    ? huffmanInput._readBit()
                    : this._decodeInteger(contextCache, 'IARI', decoder));
                var symbolBitmap = inputSymbols[symbolId]; // eslint-disable-line
                var symbolWidth = symbolBitmap[0].length;
                var symbolHeight = symbolBitmap.length;
                if (applyRefinement) {
                    var rdw = this._decodeInteger(contextCache, 'IARDW', decoder);
                    var rdh = this._decodeInteger(contextCache, 'IARDH', decoder);
                    var rdx = this._decodeInteger(contextCache, 'IARDX', decoder);
                    var rdy = this._decodeInteger(contextCache, 'IARDY', decoder);
                    symbolWidth += rdw;
                    symbolHeight += rdh;
                    symbolBitmap = this._decodeRefinement(symbolWidth, symbolHeight, refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx, (rdh >> 1) + rdy, false, refinementAt, decodingContext);
                }
                var increment = 0;
                if (!transposed) {
                    if (referenceCorner > 1) {
                        currentS += symbolWidth - 1;
                    }
                    else {
                        increment = symbolWidth - 1;
                    }
                }
                else if (!(referenceCorner & 1)) {
                    currentS += symbolHeight - 1;
                }
                else {
                    increment = symbolHeight - 1;
                }
                var offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1);
                var offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0);
                var s2 = void 0;
                var t2 = void 0;
                var symbolRow = void 0; // eslint-disable-line
                if (transposed) {
                    for (s2 = 0; s2 < symbolHeight; s2++) {
                        var row = bitmap[offsetS + s2]; // eslint-disable-line
                        if (!row) {
                            continue;
                        }
                        symbolRow = symbolBitmap[s2];
                        var maxWidth = Math.min(width - offsetT, symbolWidth);
                        switch (combinationOperator) {
                            case 0:
                                for (t2 = 0; t2 < maxWidth; t2++) {
                                    row[offsetT + t2] |= symbolRow[t2];
                                }
                                break;
                            case 2:
                                for (t2 = 0; t2 < maxWidth; t2++) {
                                    row[offsetT + t2] ^= symbolRow[t2];
                                }
                                break;
                            default:
                                throw new Error("The combination operator " + combinationOperator + " is not supported.");
                        }
                    }
                }
                else {
                    for (t2 = 0; t2 < symbolHeight; t2++) {
                        var row = bitmap[offsetT + t2]; // eslint-disable-line
                        if (!row) {
                            continue;
                        }
                        symbolRow = symbolBitmap[t2];
                        switch (combinationOperator) {
                            case 0:
                                for (s2 = 0; s2 < symbolWidth; s2++) {
                                    row[offsetS + s2] |= symbolRow[s2];
                                }
                                break;
                            case 2:
                                for (s2 = 0; s2 < symbolWidth; s2++) {
                                    row[offsetS + s2] ^= symbolRow[s2];
                                }
                                break;
                            default:
                                throw new Error("The combination operator " + combinationOperator + " is not supported.");
                        }
                    }
                }
                i++;
                var deltaS = huffman // eslint-disable-line
                    ? huffmanTables.tableDeltaS.decode(huffmanInput)
                    : this._decodeInteger(contextCache, 'IADS', decoder);
                if (deltaS === null || typeof (deltaS) === 'undefined') {
                    break;
                }
                currentS += increment + deltaS + dsOffset;
            } while (true); // eslint-disable-line
        }
        return bitmap;
    };
    /**
     * Decodes a Pattern Dictionary into an array of pattern bitmaps by slicing a collective bitmap.
     *
     * @private
     * @param {any} mmr Whether MMR compression is used.
     * @param {number} patternWidth Pattern tile width.
     * @param {number} patternHeight Pattern tile height.
     * @param {any} maxPatternIndex Maximum pattern index (inclusive).
     * @param {any} template Generic Region template index.
     * @param {any} decodingContext The decoding context.
     * @returns {any} An array of pattern bitmaps (2D arrays).
     */
    _PdfSimpleSegmentVisitor.prototype._decodePatternDictionary = function (mmr, patternWidth, patternHeight, maxPatternIndex, // eslint-disable-line
    template, decodingContext) {
        var at = []; // eslint-disable-line
        if (!mmr) {
            at.push({
                x: -patternWidth,
                y: 0
            });
            if (template === 0) {
                at.push({ x: -3, y: -1 }, { x: 2, y: -2 }, { x: -2, y: -2 });
            }
        }
        var collectiveWidth = (maxPatternIndex + 1) * patternWidth;
        var collectiveBitmap = this._decodeBitmap(mmr, collectiveWidth, patternHeight, // eslint-disable-line
        template, false, null, at, decodingContext);
        var patterns = []; // eslint-disable-line
        for (var i = 0; i <= maxPatternIndex; i++) {
            var patternBitmap = []; // eslint-disable-line
            var xMin = patternWidth * i;
            var xMax = xMin + patternWidth;
            for (var y = 0; y < patternHeight; y++) {
                patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
            }
            patterns.push(patternBitmap);
        }
        return patterns;
    };
    /**
     * Decodes a Halftone Region by assembling patterns based on gray-scale bit planes
     * and placing them onto the target bitmap using the specified grid.
     *
     * @private
     * @param {any} mmr Whether bit planes are MMR-compressed.
     * @param {any} patterns The pattern dictionary (array of bitmaps).
     * @param {any} template Generic Region template index for bit planes.
     * @param {any} regionWidth Region width.
     * @param {any} regionHeight Region height.
     * @param {any} defaultPixelValue Initial row fill value (0/1).
     * @param {any} enableSkip Whether skip is enabled (unsupported here).
     * @param {any} combinationOperator Composition operator (0 = OR required).
     * @param {number} gridWidth Grid width in cells.
     * @param {number} gridHeight Grid height in cells.
     * @param {number} gridOffsetX Fixed-point X offset (8.8).
     * @param {number} gridOffsetY Fixed-point Y offset (8.8).
     * @param {number} gridVectorX Fixed-point X vector (8.8).
     * @param {any} gridVectorY Fixed-point Y vector (8.8).
     * @param {any} decodingContext The decoding context.
     * @returns {any} The decoded halftone region bitmap (2D array).
     */
    _PdfSimpleSegmentVisitor.prototype._decodeHalftoneRegion = function (mmr, patterns, template, regionWidth, regionHeight, // eslint-disable-line
    defaultPixelValue, enableSkip, combinationOperator, gridWidth, // eslint-disable-line
    gridHeight, gridOffsetX, gridOffsetY, gridVectorX, gridVectorY, decodingContext) {
        var skip = null; // eslint-disable-line
        if (enableSkip) {
            throw new Error('Operation failed: skip is not implemented or allowed here.');
        }
        if (combinationOperator !== 0) {
            throw new Error("The operator '" + combinationOperator + "' is not supported in halftone region");
        }
        var regionBitmap = []; // eslint-disable-line
        for (var i = 0; i < regionHeight; i++) {
            var row = new Uint8Array(regionWidth);
            if (defaultPixelValue) {
                row.fill(defaultPixelValue);
            }
            regionBitmap.push(row);
        }
        var numberOfPatterns = patterns.length;
        var pattern0 = patterns[0]; // eslint-disable-line
        var patternWidth = pattern0[0].length;
        var patternHeight = pattern0.length;
        var bitsPerValue = _log2(numberOfPatterns);
        var at = []; // eslint-disable-line
        if (!mmr) {
            at.push({
                x: template <= 1 ? 3 : 2,
                y: -1
            });
            if (template === 0) {
                at.push({ x: -3, y: -1 }, { x: 2, y: -2 }, { x: -2, y: -2 });
            }
        }
        var grayScaleBitPlanes = []; // eslint-disable-line
        var mmrInput; //eslint-disable-line
        var bitmap; //eslint-disable-line
        if (mmr) {
            mmrInput = new _PdfReader(decodingContext.data, decodingContext.start, decodingContext.end);
        }
        for (var i = bitsPerValue - 1; i >= 0; i--) {
            if (mmr) {
                bitmap = this._decodeMmrBitmap(mmrInput, gridWidth, gridHeight, true);
            }
            else {
                bitmap = this._decodeBitmap(false, gridWidth, gridHeight, template, false, skip, at, decodingContext);
            }
            grayScaleBitPlanes[i] = bitmap;
        }
        for (var mg = 0; mg < gridHeight; mg++) {
            for (var ng = 0; ng < gridWidth; ng++) {
                var bit = 0;
                var patternIndex = 0;
                for (var j = bitsPerValue - 1; j >= 0; j--) {
                    bit ^= grayScaleBitPlanes[j][mg][ng];
                    patternIndex |= bit << j;
                }
                var patternBitmap = patterns[patternIndex]; // eslint-disable-line
                var x = (gridOffsetX + mg * gridVectorY + ng * gridVectorX) >> 8;
                var y = (gridOffsetY + mg * gridVectorX - ng * gridVectorY) >> 8;
                if (x >= 0 &&
                    x + patternWidth <= regionWidth &&
                    y >= 0 &&
                    y + patternHeight <= regionHeight) {
                    for (var i = 0; i < patternHeight; i++) {
                        var regionRow = regionBitmap[y + i]; // eslint-disable-line
                        var patternRow = patternBitmap[i]; // eslint-disable-line
                        for (var j = 0; j < patternWidth; j++) {
                            regionRow[x + j] |= patternRow[j];
                        }
                    }
                }
                else {
                    var regionX = void 0;
                    var regionY = void 0;
                    for (var i = 0; i < patternHeight; i++) {
                        regionY = y + i;
                        if (regionY < 0 || regionY >= regionHeight) {
                            continue;
                        }
                        var regionRow = regionBitmap[regionY]; // eslint-disable-line
                        var patternRow = patternBitmap[i]; // eslint-disable-line
                        for (var j = 0; j < patternWidth; j++) {
                            regionX = x + j;
                            if (regionX >= 0 && regionX < regionWidth) {
                                regionRow[regionX] |= patternRow[j];
                            }
                        }
                    }
                }
            }
        }
        return regionBitmap;
    };
    return _PdfSimpleSegmentVisitor;
}());
export { _PdfSimpleSegmentVisitor };
/**
 * Represents a single Huffman table entry, including range bounds,
 * prefix length/code, and flags.
 *
 * @private
 */
var _PdfHuffmanLine = /** @class */ (function () {
    function _PdfHuffmanLine(lineData) {
        if (lineData.length === 2) {
            this.isoob = true;
            this.rangeLow = 0;
            this.prefixLength = lineData[0];
            this.rangeLength = 0;
            this.prefixCode = lineData[1];
            this.isLowerRange = false;
        }
        else {
            this.isoob = false;
            this.rangeLow = lineData[0];
            this.prefixLength = lineData[1];
            this.rangeLength = lineData[2];
            this.prefixCode = lineData[3];
            this.isLowerRange = lineData[4] === 'lower';
        }
    }
    return _PdfHuffmanLine;
}());
export { _PdfHuffmanLine };
/**
 * Node in a Huffman decoding tree that can be extended from prefix codes
 * and used to decode values from a bit reader.
 *
 * @private
 */
var _PdfHuffmanTreeNode = /** @class */ (function () {
    function _PdfHuffmanTreeNode(line) {
        this.children = [];
        if (line) {
            this.isLeaf = true;
            this.rangeLength = line.rangeLength;
            this.rangeLow = line.rangeLow;
            this.isLowerRange = line.isLowerRange;
            this.isoob = line.isoob;
        }
        else {
            this.isLeaf = false;
        }
    }
    /**
     * Inserts a Huffman line into the decoding tree according to its prefix code.
     *
     * @private
     * @param {_PdfHuffmanLine} line The Huffman line defining a code range or OOB.
     * @param {number} shift The remaining bit shift (prefixLength - 1 .. 0).
     * @returns {void}
     */
    _PdfHuffmanTreeNode.prototype._buildTree = function (line, shift) {
        var bit = (line.prefixCode >> shift) & 1;
        if (shift <= 0) {
            this.children[bit] = new _PdfHuffmanTreeNode(line);
        }
        else {
            var node = this.children[bit]; // eslint-disable-line
            if (!node) {
                this.children[bit] = node = new _PdfHuffmanTreeNode(null);
            }
            node._buildTree(line, shift - 1);
        }
    };
    /**
     * Decodes a value  by traversing the tree using bits from the reader,
     * and applies the range adjustment when needed.
     *
     * @private
     * @param {any} reader The reader exposing `_readBit()` / `_readBits(n)`.
     * @returns {number | null} The decoded value, or `null` if OOB was reached.
     */
    _PdfHuffmanTreeNode.prototype._decodeNode = function (reader) {
        if (this.isLeaf) {
            if (this.isoob) {
                return null;
            }
            var htOffset = reader._readBits(this.rangeLength);
            return this.rangeLow + (this.isLowerRange ? -htOffset : htOffset);
        }
        var node = this.children[reader._readBit()]; // eslint-disable-line
        if (!node) {
            throw new Error('Failed to decode: Huffman data is invalid or corrupted.');
        }
        return node._decodeNode(reader);
    };
    return _PdfHuffmanTreeNode;
}());
export { _PdfHuffmanTreeNode };
/**
 * Canonical Huffman table that assigns prefix codes to lines, builds a decode tree,
 * and provides value decoding against a bit reader.
 *
 * @private
 */
var _PdfHuffmanTable = /** @class */ (function () {
    function _PdfHuffmanTable(lines, prefixCodesDone) {
        if (!prefixCodesDone) {
            this.assignPrefixCodes(lines);
        }
        this.rootNode = new _PdfHuffmanTreeNode(null);
        for (var i = 0, ii = lines.length; i < ii; i++) {
            var line = lines[i]; // eslint-disable-line
            if (line.prefixLength > 0) {
                this.rootNode._buildTree(line, line.prefixLength - 1);
            }
        }
    }
    _PdfHuffmanTable.prototype.decode = function (reader) {
        return this.rootNode._decodeNode(reader);
    };
    _PdfHuffmanTable.prototype.assignPrefixCodes = function (lines) {
        var linesLength = lines.length;
        var prefixLengthMax = 0;
        for (var i = 0; i < linesLength; i++) {
            prefixLengthMax = Math.max(prefixLengthMax, lines[i].prefixLength);
        }
        var histogram = new Uint32Array(prefixLengthMax + 1);
        for (var i = 0; i < linesLength; i++) {
            histogram[lines[i].prefixLength]++;
        }
        var currentLength = 1;
        var firstCode = 0;
        var currentCode;
        var currentTemp;
        var line;
        histogram[0] = 0;
        while (currentLength <= prefixLengthMax) {
            firstCode = (firstCode + histogram[currentLength - 1]) << 1;
            currentCode = firstCode;
            currentTemp = 0;
            while (currentTemp < linesLength) {
                line = lines[currentTemp];
                if (line.prefixLength === currentLength) {
                    line.prefixCode = currentCode;
                    currentCode++;
                }
                currentTemp++;
            }
            currentLength++;
        }
    };
    return _PdfHuffmanTable;
}());
export { _PdfHuffmanTable };
/**
 * MSB first bit reader over a byte array for Huffman/bit level parsing,
 * with byte alignment support.
 *
 * @private
 */
var _PdfReader = /** @class */ (function () {
    function _PdfReader(data, start, end) {
        this.data = data;
        this.start = start;
        this.end = end;
        this.position = start;
        this.shift = -1;
        this.currentByte = 0;
    }
    /**
     * Reads a single bit from the underlying byte stream, refilling as needed.
     *
     * @private
     * @returns {number} The next bit (0 or 1).
     * @throws {Error} If the end of input is reached prematurely.
     */
    _PdfReader.prototype._readBit = function () {
        if (this.shift < 0) {
            if (this.position >= this.end) {
                throw new Error('Unexpected end of input: No more data available while attempting to read a bit.');
            }
            this.currentByte = this.data[this.position++];
            this.shift = 7;
        }
        var bit = (this.currentByte >> this.shift) & 1;
        this.shift--;
        return bit;
    };
    /**
     * Reads `numBits` bits MSB-first and returns the aggregated value.
     *
     * @private
     * @param {number} numBits The number of bits to read.
     * @returns {number} The unsigned integer composed from the read bits.
     */
    _PdfReader.prototype._readBits = function (numBits) {
        var result = 0;
        for (var i = numBits - 1; i >= 0; i--) {
            result |= this._readBit() << i;
        }
        return result;
    };
    _PdfReader.prototype.byteAlign = function () {
        this.shift = -1;
    };
    _PdfReader.prototype.next = function () {
        if (this.position >= this.end) {
            return -1;
        }
        return this.data[this.position++];
    };
    return _PdfReader;
}());
export { _PdfReader };
/**
 * JBIG2 image parser that reads headers and segments, dispatches work to the visitor,
 * and produces unpacked image data.
 *
 * @private
 */
var _PdfJbig2Image = /** @class */ (function () {
    function _PdfJbig2Image() {
        /**
         * Field length of the region segment information.
         *
         * @private
         */
        this._regionSegmentInformationFieldLength = 17;
        /**
         * Lookup of segment type names by id.
         *
         * @private
         */
        this._segmentTypes = [
            'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null, 'ImmediateTextRegion', 'ImmediateLosslessTextRegion',
            null, null, null, null, null, null, null, null, 'PatternDictionary', null, null, null, 'IntermediateHalftoneRegion',
            null, 'ImmediateHalftoneRegion', 'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null, null, null,
            null, null, null, 'IntermediateGenericRegion', null, 'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
            'IntermediateGenericRefinementRegion', null, 'ImmediateGenericRefinementRegion', 'ImmediateLosslessGenericRefinementRegion', null,
            null, null, null, 'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles', 'Tables', null,
            null, null, null, null, null, null, null, 'Extension'
        ];
    }
    /**
     * Parses a sequence of JBIG2 chunks and returns the bit-packed page buffer.
     *
     * @private
     * @param {any} chunks The array of chunk objects containing `data`, `start`, and `end`.
     * @returns {any} The bit-packed image buffer of the last processed page.
     */
    _PdfJbig2Image.prototype._parseChunks = function (chunks) {
        return this._parseJbig2Chunks(chunks);
    };
    /**
     * Parses a complete JBIG2 stream and returns the unpacked 8-bit grayscale image data.
     *
     * @private
     * @param {any} data The input JBIG2 byte array.
     * @returns {any} The unpacked image data buffer.
     */
    _PdfJbig2Image.prototype._parse = function (data) {
        var _a = this._parseJbig2(data), imgData = _a.imgData, width = _a.width, height = _a.height;
        this.width = width;
        this.height = height;
        return imgData;
    };
    /* eslint-disable */
    /**
     * Processes a list of segments by dispatching each to the segment visitor.
     *
     * @private
     * @param {any} segments The parsed JBIG2 segments.
     * @param {_PdfSimpleSegmentVisitor} visitor The visitor handling segment types.
     * @returns {any} as process segment.
     */
    _PdfJbig2Image.prototype._processSegments = function (segments, visitor) {
        for (var i = 0, ii = segments.length; i < ii; i++) {
            this._processSegment(segments[i], visitor);
        }
    };
    /* eslint-enable */
    /**
     * Parses an entire JBIG2 file/stream (with header), processes segments, and
     * converts the bit-packed page buffer to 8-bit grayscale image data.
     *
     * @private
     * @param {Uint8Array} data The full JBIG2 data.
     * @returns {{imgData: Uint8ClampedArray, width: number, height: number}} Decoded image buffer and dimensions.
     */
    _PdfJbig2Image.prototype._parseJbig2 = function (data) {
        var end = data.length;
        var position = 0;
        if (data[position] !== 0x97 || data[position + 1] !== 0x4a || data[position + 2] !== 0x42 ||
            data[position + 3] !== 0x32 || data[position + 4] !== 0x0d || data[position + 5] !== 0x0a ||
            data[position + 6] !== 0x1a || data[position + 7] !== 0x0a) {
            throw new Error('JBIG2 parsing error: The image header is invalid or malformed.');
        }
        var header = Object.create(null);
        position += 8;
        var flags = data[position++];
        header.randomAccess = !(flags & 1);
        if (!(flags & 2)) {
            header.numberOfPages = _readUnsignedInteger32(data, position);
            position += 4;
        }
        var segments = this._readSegments(header, data, position, end); // eslint-disable-line
        var visitor = new _PdfSimpleSegmentVisitor();
        this._processSegments(segments, visitor);
        var _a = visitor._currentPageInfo, width = _a.width, height = _a.height;
        var bitPacked = visitor._buffer; // eslint-disable-line
        var imgData = new Uint8ClampedArray(width * height);
        var q = 0;
        var k = 0;
        for (var i = 0; i < height; i++) {
            var mask = 0;
            var buffer = void 0;
            for (var j = 0; j < width; j++) {
                if (!mask) {
                    mask = 128;
                    buffer = bitPacked[k++];
                }
                imgData[q++] = buffer & mask ? 0 : 255;
                mask >>= 1;
            }
        }
        return { imgData: imgData, width: width, height: height };
    };
    /**
     * Parses and processes JBIG2 segments from chunked inputs (e.g., inline images),
     * returning the bit-packed page buffer.
     *
     * @private
     * @param {any} chunks The chunk array with `data`, `start`, and `end`.
     * @returns {any} The bit-packed image buffer.
     */
    _PdfJbig2Image.prototype._parseJbig2Chunks = function (chunks) {
        var visitor = new _PdfSimpleSegmentVisitor();
        for (var i = 0, ii = chunks.length; i < ii; i++) {
            var chunk = chunks[i]; // eslint-disable-line
            var segments = this._readSegments({}, chunk.data, chunk.start, chunk.end); // eslint-disable-line
            this._processSegments(segments, visitor);
        }
        return visitor._buffer;
    };
    /* eslint-disable */
    /**
     * Reads a segment header starting at `start`, validating type, extracting flags,
     * referred-to segments, page association, and length.
     *
     * @private
     * @param {Uint8Array} data The data buffer.
     * @param {number} start The start offset of the header.
     * @returns {{number:number, type:number, typeName:string|null, deferredNonRetain:boolean, retainBits:number[], pageAssociation:number, length:number, referredTo:number[], headerEnd:number}} The parsed header structure.
     */
    _PdfJbig2Image.prototype._readSegmentHeader = function (data, start) {
        var segmentHeader = {
            number: _readUnsignedInteger32(data, start), type: 0, typeName: null, deferredNonRetain: false, retainBits: [],
            pageAssociation: 0, length: 0, referredTo: [], headerEnd: start
        };
        var flags = data[start + 4];
        var segmentType = flags & 0x3f;
        if (!this._segmentTypes[segmentType]) {
            throw new Error('JBIG2 decoding error: Encountered an unknown or unsupported segment type' + segmentType);
        }
        segmentHeader.type = segmentType;
        segmentHeader.typeName = this._segmentTypes[segmentType];
        segmentHeader.deferredNonRetain = !!(flags & 0x80);
        var pageAssociationFieldSize = !!(flags & 0x40);
        var referredFlags = data[start + 5];
        var referredToCount = (referredFlags >> 5) & 7;
        var retainBits = [referredFlags & 31];
        var position = start + 6;
        if (referredFlags === 7) {
            referredToCount = _readUnsignedInteger32(data, position - 1) & 0x1fffffff;
            position += 3;
            var bytes = (referredToCount + 7) >> 3;
            retainBits[0] = data[position++];
            while (--bytes > 0) {
                retainBits.push(data[position++]);
            }
        }
        else if (referredFlags === 5 || referredFlags === 6) {
            throw new Error('JBIG2 decoding error: Encountered invalid or malformed referred-to flags in the segment header.');
        }
        segmentHeader.retainBits = retainBits;
        var referredToSegmentNumberSize = 4;
        if (segmentHeader.number <= 256) {
            referredToSegmentNumberSize = 1;
        }
        else if (segmentHeader.number <= 65536) {
            referredToSegmentNumberSize = 2;
        }
        var referredTo = [];
        for (var i = 0; i < referredToCount; i++) {
            var number = void 0;
            if (referredToSegmentNumberSize === 1) {
                number = data[position];
            }
            else if (referredToSegmentNumberSize === 2) {
                number = _readUnsignedInteger16(data, position);
            }
            else {
                number = _readUnsignedInteger32(data, position);
            }
            referredTo.push(number);
            position += referredToSegmentNumberSize;
        }
        segmentHeader.referredTo = referredTo;
        if (!pageAssociationFieldSize) {
            segmentHeader.pageAssociation = data[position++];
        }
        else {
            segmentHeader.pageAssociation = _readUnsignedInteger32(data, position);
            position += 4;
        }
        segmentHeader.length = _readUnsignedInteger32(data, position);
        position += 4;
        if (segmentHeader.length === 0xffffffff) {
            if (segmentType === 38) {
                var genericRegionInfo = this._readRegionSegmentInformation(data, position);
                var genericRegionSegmentFlags = data[position + this._regionSegmentInformationFieldLength];
                var genericRegionMmr = !!(genericRegionSegmentFlags & 1);
                var searchPatternLength = 6;
                var searchPattern = new Uint8Array(searchPatternLength);
                if (!genericRegionMmr) {
                    searchPattern[0] = 0xff;
                    searchPattern[1] = 0xac;
                }
                searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xff;
                searchPattern[3] = (genericRegionInfo.height >> 16) & 0xff;
                searchPattern[4] = (genericRegionInfo.height >> 8) & 0xff;
                searchPattern[5] = genericRegionInfo.height & 0xff;
                for (var i = position, ii = data.length; i < ii; i++) {
                    var j = 0;
                    while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
                        j++;
                    }
                    if (j === searchPatternLength) {
                        segmentHeader.length = i + searchPatternLength;
                        break;
                    }
                }
                if (segmentHeader.length === 0xffffffff) {
                    throw new Error('Decoding error: Unable to find the end of the segment');
                }
            }
            else {
                throw new Error('Segment length is unknown or invalid');
            }
        }
        segmentHeader.headerEnd = position;
        return segmentHeader;
    };
    /* eslint-enable */
    /**
     * Iterates the stream to collect segments  until EOF or EndOfFile segment.
     *
     * @private
     * @param {any} header The file header (randomAccess/numberOfPages).
     * @param {any} data The data buffer.
     * @param {number} start Start offset.
     * @param {number} end End offset.
     * @returns {any} The list of segments with parsed headers and data ranges.
     */
    _PdfJbig2Image.prototype._readSegments = function (header, data, start, end) {
        var segments = []; // eslint-disable-line
        var position = start;
        while (position < end) {
            var segmentHeader = this._readSegmentHeader(data, position); // eslint-disable-line
            position = segmentHeader.headerEnd;
            var segment = {
                header: segmentHeader,
                data: data
            };
            if (!header.randomAccess) {
                segment.start = position;
                position += segmentHeader.length;
                segment.end = position;
            }
            segments.push(segment);
            if (segmentHeader.type === 51) {
                break;
            }
        }
        if (header.randomAccess) {
            for (var i = 0, ii = segments.length; i < ii; i++) {
                segments[i].start = position;
                position += segments[i].header.length;
                segments[i].end = position;
            }
        }
        return segments;
    };
    /* eslint-disable */
    /**
     * Dispatches a single segment to the appropriate visitor callback based on its type,
     * parsing type-specific payload arguments beforehand.
     *
     * @private
     * @param {{header:{type:number, number:number, referredTo:number}, data:Uint8Array, start:number, end:number}} segment The segment to process. // eslint-disable-line
     * @param {any} visitor The segment visitor instance.
     * @returns {void}
     */
    _PdfJbig2Image.prototype._processSegment = function (segment, visitor) {
        var header = segment.header;
        var data = segment.data;
        var end = segment.end;
        var position = segment.start;
        var dictionary;
        var dictionaryFlags;
        var textRegion;
        var patternDictionary;
        var patternDictionaryFlags;
        var halftoneRegion;
        var halftoneRegionFlags;
        var genericRegion;
        var genericRegionSegmentFlags;
        var pageInfo;
        var pageSegmentFlags;
        var textRegionSegmentFlags;
        var args, at, i, atLength;
        switch (header.type) {
            case 0:
                dictionary = {};
                dictionaryFlags = _readUnsignedInteger16(data, position);
                dictionary.huffman = !!(dictionaryFlags & 1);
                dictionary.refinement = !!(dictionaryFlags & 2);
                dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
                dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
                dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
                dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
                dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
                dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
                dictionary.template = (dictionaryFlags >> 10) & 3;
                dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
                position += 2;
                if (!dictionary.huffman) {
                    atLength = dictionary.template === 0 ? 4 : 1;
                    at = [];
                    for (i = 0; i < atLength; i++) {
                        at.push({
                            x: _readInteger8(data, position),
                            y: _readInteger8(data, position + 1)
                        });
                        position += 2;
                    }
                    dictionary.at = at;
                }
                if (dictionary.refinement && !dictionary.refinementTemplate) {
                    at = [];
                    for (i = 0; i < 2; i++) {
                        at.push({
                            x: _readInteger8(data, position),
                            y: _readInteger8(data, position + 1)
                        });
                        position += 2;
                    }
                    dictionary.refinementAt = at;
                }
                dictionary.numberOfExportedSymbols = _readUnsignedInteger32(data, position);
                position += 4;
                dictionary.numberOfNewSymbols = _readUnsignedInteger32(data, position);
                position += 4;
                args = [dictionary, header.number, header.referredTo, data, position, end];
                break;
            case 6:
            case 7:
                textRegion = {};
                textRegion.info = this._readRegionSegmentInformation(data, position);
                position += this._regionSegmentInformationFieldLength;
                textRegionSegmentFlags = _readUnsignedInteger16(data, position);
                position += 2;
                textRegion.huffman = !!(textRegionSegmentFlags & 1);
                textRegion.refinement = !!(textRegionSegmentFlags & 2);
                textRegion.logStripSize = (textRegionSegmentFlags >> 2) & 3;
                textRegion.stripSize = 1 << textRegion.logStripSize;
                textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
                textRegion.transposed = !!(textRegionSegmentFlags & 64);
                textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
                textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
                textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
                textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
                if (textRegion.huffman) {
                    var textRegionHuffmanFlags = _readUnsignedInteger16(data, position);
                    position += 2;
                    textRegion.huffmanFS = textRegionHuffmanFlags & 3;
                    textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
                    textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
                    textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
                    textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
                    textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
                    textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
                    textRegion.huffmanRefinementSizeSelector = !!(textRegionHuffmanFlags & 0x4000);
                }
                if (textRegion.refinement && !textRegion.refinementTemplate) {
                    at = [];
                    for (i = 0; i < 2; i++) {
                        at.push({
                            x: _readInteger8(data, position),
                            y: _readInteger8(data, position + 1)
                        });
                        position += 2;
                    }
                    textRegion.refinementAt = at;
                }
                textRegion.numberOfSymbolInstances = _readUnsignedInteger32(data, position);
                position += 4;
                args = [textRegion, header.referredTo, data, position, end];
                break;
            case 16:
                patternDictionary = {};
                patternDictionaryFlags = data[position++];
                patternDictionary.mmr = !!(patternDictionaryFlags & 1);
                patternDictionary.template = (patternDictionaryFlags >> 1) & 3;
                patternDictionary.patternWidth = data[position++];
                patternDictionary.patternHeight = data[position++];
                patternDictionary.maxPatternIndex = _readUnsignedInteger32(data, position);
                position += 4;
                args = [patternDictionary, header.number, data, position, end];
                break;
            case 22:
            case 23:
                halftoneRegion = {};
                halftoneRegion.info = this._readRegionSegmentInformation(data, position);
                position += this._regionSegmentInformationFieldLength;
                halftoneRegionFlags = data[position++];
                halftoneRegion.mmr = !!(halftoneRegionFlags & 1);
                halftoneRegion.template = (halftoneRegionFlags >> 1) & 3;
                halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8);
                halftoneRegion.combinationOperator = (halftoneRegionFlags >> 4) & 7;
                halftoneRegion.defaultPixelValue = (halftoneRegionFlags >> 7) & 1;
                halftoneRegion.gridWidth = _readUnsignedInteger32(data, position);
                position += 4;
                halftoneRegion.gridHeight = _readUnsignedInteger32(data, position);
                position += 4;
                halftoneRegion.gridOffsetX = _readUnsignedInteger32(data, position) & 0xffffffff;
                position += 4;
                halftoneRegion.gridOffsetY = _readUnsignedInteger32(data, position) & 0xffffffff;
                position += 4;
                halftoneRegion.gridVectorX = _readUnsignedInteger16(data, position);
                position += 2;
                halftoneRegion.gridVectorY = _readUnsignedInteger16(data, position);
                position += 2;
                args = [halftoneRegion, header.referredTo, data, position, end];
                break;
            case 38:
            case 39:
                genericRegion = {};
                genericRegion.info = this._readRegionSegmentInformation(data, position);
                position += this._regionSegmentInformationFieldLength;
                genericRegionSegmentFlags = data[position++];
                genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
                genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
                genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
                if (!genericRegion.mmr) {
                    atLength = genericRegion.template === 0 ? 4 : 1;
                    at = [];
                    for (i = 0; i < atLength; i++) {
                        at.push({
                            x: _readInteger8(data, position),
                            y: _readInteger8(data, position + 1)
                        });
                        position += 2;
                    }
                    genericRegion.at = at;
                }
                args = [genericRegion, data, position, end];
                break;
            case 48:
                pageInfo = {
                    width: _readUnsignedInteger32(data, position),
                    height: _readUnsignedInteger32(data, position + 4),
                    resolutionX: _readUnsignedInteger32(data, position + 8),
                    resolutionY: _readUnsignedInteger32(data, position + 12)
                };
                if (pageInfo.height === 0xffffffff) {
                    delete pageInfo.height;
                }
                pageSegmentFlags = data[position + 16];
                _readUnsignedInteger16(data, position + 17);
                pageInfo.lossless = !!(pageSegmentFlags & 1);
                pageInfo.refinement = !!(pageSegmentFlags & 2);
                pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
                pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
                pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
                pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
                args = [pageInfo];
                break;
            case 49:
                break;
            case 50:
                break;
            case 51:
                break;
            case 53:
                args = [header.number, data, position, end];
                break;
            case 62:
                break;
            default:
                throw new Error("Segment type " + header.typeName + "(" + header.type + ") is not implemented");
        }
        var callbackName = '_on' + header.typeName;
        if (callbackName === '_onImmediateLosslessGenericRegion') {
            visitor._onImmediateGenericRegion(args[0], args[1], args[2], args[3], args[4]);
        }
        else if (callbackName === '_onImmediateLosslessTextRegion') {
            visitor._onImmediateTextRegion(args[0], args[1], args[2], args[3], args[4]);
        }
        else if (callbackName === '_onImmediateLosslessHalftoneRegion') {
            visitor._onImmediateHalftoneRegion(args[0], args[1], args[2], args[3], args[4]);
        }
        else if (callbackName === '_onPageInformation') {
            visitor._onPageInformation(args);
        }
        else if (callbackName === '_onSymbolDictionary') {
            visitor._onSymbolDictionary(args[0], args[1], args[2], args[3], args[4], args[5]);
        }
    };
    /* eslint-enable */
    /**
     * Reads a `RegionSegmentInformation` structure (width, height, position, operator).
     *
     * @private
     * @param {Uint8Array} data The data buffer.
     * @param {number} start Start offset of the structure.
     * @returns {{width:number, height:number, x:number, y:number, combinationOperator:number}} The parsed region information.
     */
    _PdfJbig2Image.prototype._readRegionSegmentInformation = function (data, start) {
        return {
            width: _readUnsignedInteger32(data, start), height: _readUnsignedInteger32(data, start + 4),
            x: _readUnsignedInteger32(data, start + 8), y: _readUnsignedInteger32(data, start + 12),
            combinationOperator: data[start + 16] & 7
        };
    };
    return _PdfJbig2Image;
}());
export { _PdfJbig2Image };