var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
import { _grayToRgba, _readUnsignedInteger16, BaseException } from '@syncfusion/ej2-pdf';
import { _PdfDeviceCmykCS } from './colorspace';
import { _PdfColorSpaceUtils } from './colorspace-utils';
var _PdfDoNotLoadMarkerError = /** @class */ (function (_super) {
    __extends(_PdfDoNotLoadMarkerError, _super);
    function _PdfDoNotLoadMarkerError(message, scanLines) {
        var _this = _super.call(this, message, 'PDF do not load marker error') || this;
        _this.scanLines = scanLines;
        return _this;
    }
    return _PdfDoNotLoadMarkerError;
}(BaseException));
var _PdfEndOfImageMarkerError = /** @class */ (function (_super) {
    __extends(_PdfEndOfImageMarkerError, _super);
    function _PdfEndOfImageMarkerError(msg) {
        return _super.call(this, msg, 'PDF end of image error') || this;
    }
    return _PdfEndOfImageMarkerError;
}(BaseException));
var _PdfJpegImage = /** @class */ (function () {
    function _PdfJpegImage() {
        this._dctZigZag = new Uint8Array([
            0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41,
            34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44,
            51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
        ]);
        this._dctCos1 = 4017;
        this._dctSin1 = 799;
        this._dctCos3 = 3406;
        this._dctSin3 = 2276;
        this._dctCos6 = 1567;
        this._dctSin6 = 3784;
        this._dctSqrt2 = 5793;
        this._dctSqrt = 2896;
        this._eobrun = 0;
        this._successiveACState = 0;
        this._successiveACNextValue = 0;
        this._blockRow = 0;
        this._bitsCount = 0;
        this._colorSpace = new _PdfColorSpaceUtils();
        this._colorTransform = -1;
        this._width = 0;
        this._height = 0;
        this._jfif = null;
        this._adobe = null;
        this._components = [];
        this._numComponents = 0;
    }
    _PdfJpegImage.prototype._canUseImageDecoder = function (data, colorTransform) {
        if (colorTransform === void 0) { colorTransform = -1; }
        var exifOffsets; // eslint-disable-line
        var offset = 0;
        var numComponents = null;
        var fileMarker = _readUnsignedInteger16(data, offset);
        offset += 2;
        if (fileMarker !== 0xffd8) {
            throw new Error('JPEG decoding error: Start Of Image (SOI) marker not found.');
        }
        fileMarker = _readUnsignedInteger16(data, offset);
        offset += 2;
        while (fileMarker !== 0xffd9) {
            switch (fileMarker) {
                case 0xffe1:
                    {
                        var _a = this._readDataBlock(data, offset), appData = _a.appData, oldOffset = _a.oldOffset, newOffset = _a.newOffset;
                        offset = newOffset;
                        if (appData[0] === 0x45 && appData[1] === 0x78 && appData[2] === 0x69 && appData[3] === 0x66 &&
                            appData[4] === 0 && appData[5] === 0) {
                            if (exifOffsets) {
                                throw new Error('The JPEG image contains duplicate EXIF metadata blocks, which is invalid.');
                            }
                            exifOffsets = { exifStart: oldOffset + 6, exifEnd: newOffset };
                        }
                        fileMarker = _readUnsignedInteger16(data, offset);
                        offset += 2;
                        continue;
                    }
                case 0xffc0:
                case 0xffc1:
                case 0xffc2:
                    numComponents = data[offset + (2 + 1 + 2 + 2)];
                    return;
                case 0xffff:
                    if (data[offset] !== 0xff) {
                        offset--;
                    }
                    break;
            }
            offset = this._skipData(data, offset);
            fileMarker = _readUnsignedInteger16(data, offset);
            offset += 2;
        }
        if (numComponents === 4) {
            return null;
        }
        if (numComponents === 3 && colorTransform === 0) {
            return null;
        }
        return exifOffsets || {};
    };
    _PdfJpegImage.prototype.parse = function (data, dnlScanLines) {
        var offset = 0;
        var jfif; // eslint-disable-line
        var adobe; // eslint-disable-line
        var frame; // eslint-disable-line
        var resetInterval;
        var numSOSMarkers = 0;
        var quantizationTables = [];
        var huffmanTablesAC = []; // eslint-disable-line
        var huffmanTablesDC = []; // eslint-disable-line
        var parseMarker;
        var selectorsCount;
        var components = []; // eslint-disable-line
        var spectralStart;
        var spectralEnd;
        var successiveApproximation;
        var fileMarker = _readUnsignedInteger16(data, offset);
        var sofScanLines;
        var componentsCount;
        offset += 2;
        if (fileMarker !== 0xffd8) {
            throw new Error('JPEG Start Of Image (SOI) marker not found in input data.');
        }
        fileMarker = _readUnsignedInteger16(data, offset);
        offset += 2;
        var maxH;
        var maxV;
        while (fileMarker !== 0xffd9) {
            switch (fileMarker) {
                case 0xffe0:
                case 0xffe1:
                case 0xffe2:
                case 0xffe3:
                case 0xffe4:
                case 0xffe5:
                case 0xffe6:
                case 0xffe7:
                case 0xffe8:
                case 0xffe9:
                case 0xffea:
                case 0xffeb:
                case 0xffec:
                case 0xffed:
                case 0xffee:
                case 0xffef:
                case 0xfffe:
                    {
                        var _a = this._readDataBlock(data, offset), appData = _a.appData, newOffset = _a.newOffset;
                        offset = newOffset;
                        if (fileMarker === 0xffe0) {
                            if (appData[0] === 0x4a && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 &&
                                appData[4] === 0) {
                                jfif = {
                                    version: { major: appData[5], minor: appData[6] },
                                    densityUnits: appData[7],
                                    xDensity: (appData[8] << 8) | appData[9],
                                    yDensity: (appData[10] << 8) | appData[11],
                                    thumbWidth: appData[12],
                                    thumbHeight: appData[13],
                                    thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
                                };
                            }
                        }
                        if (fileMarker === 0xffee) {
                            if (appData[0] === 0x41 &&
                                appData[1] === 0x64 &&
                                appData[2] === 0x6f &&
                                appData[3] === 0x62 &&
                                appData[4] === 0x65) {
                                adobe = {
                                    version: (appData[5] << 8) | appData[6],
                                    flags0: (appData[7] << 8) | appData[8],
                                    flags1: (appData[9] << 8) | appData[10],
                                    transformCode: appData[11]
                                };
                            }
                        }
                    }
                    break;
                case 0xffdb:
                    {
                        var quantizationTablesLength = _readUnsignedInteger16(data, offset);
                        offset += 2;
                        var quantizationTablesEnd = quantizationTablesLength + offset - 2;
                        var z = void 0;
                        while (offset < quantizationTablesEnd) {
                            var quantizationTableSpec = data[offset++];
                            var tableData = new Uint16Array(64);
                            if (quantizationTableSpec >> 4 === 0) {
                                for (var j = 0; j < 64; j++) {
                                    z = this._dctZigZag[j];
                                    tableData[z] = data[offset++];
                                }
                            }
                            else if (quantizationTableSpec >> 4 === 1) {
                                for (var j = 0; j < 64; j++) {
                                    z = this._dctZigZag[j];
                                    tableData[z] = _readUnsignedInteger16(data, offset);
                                    offset += 2;
                                }
                            }
                            else {
                                throw new Error('DQT Error: The provided JPEG quantization table specification is invalid or incomplete.');
                            }
                            quantizationTables[quantizationTableSpec & 15] = tableData;
                        }
                    }
                    break;
                case 0xffc0:
                case 0xffc1:
                case 0xffc2:
                    if (frame) {
                        throw new Error('Only single-frame JPEG images are supported. ');
                    }
                    offset += 2;
                    frame = {};
                    frame.extended = fileMarker === 0xffc1;
                    frame.progressive = fileMarker === 0xffc2;
                    frame.precision = data[offset++];
                    sofScanLines = _readUnsignedInteger16(data, offset);
                    offset += 2;
                    frame.scanLines = dnlScanLines || sofScanLines;
                    frame.samplesPerLine = _readUnsignedInteger16(data, offset);
                    offset += 2;
                    frame.components = [];
                    frame.componentIds = {};
                    componentsCount = data[offset++];
                    maxH = 0;
                    maxV = 0;
                    for (var i = 0; i < componentsCount; i++) {
                        var componentId = data[offset];
                        var h = data[offset + 1] >> 4;
                        var v = data[offset + 1] & 15;
                        if (maxH < h) {
                            maxH = h;
                        }
                        if (maxV < v) {
                            maxV = v;
                        }
                        var qId = data[offset + 2];
                        var l = frame.components.push({
                            h: h,
                            v: v,
                            quantizationId: qId,
                            quantizationTable: null
                        });
                        frame.componentIds[componentId] = l - 1;
                        offset += 3;
                    }
                    frame.maxH = maxH;
                    frame.maxV = maxV;
                    this._prepareComponents(frame);
                    break;
                case 0xffc4:
                    {
                        var huffmanLength = _readUnsignedInteger16(data, offset);
                        offset += 2;
                        for (var i = 2; i < huffmanLength;) {
                            var huffmanTableSpec = data[offset++];
                            var codeLengths = []; // eslint-disable-line
                            var codeLengthSum = 0;
                            for (var j = 0; j < 16; j++, offset++) {
                                codeLengthSum += codeLengths[j] = data[offset];
                            }
                            var huffmanValues = []; // eslint-disable-line
                            for (var j = 0; j < codeLengthSum; j++, offset++) {
                                huffmanValues[j] = data[offset];
                            }
                            i += 17 + codeLengthSum;
                            (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = this._buildHuffmanTable(codeLengths, huffmanValues);
                        }
                    }
                    break;
                case 0xffdd:
                    offset += 2;
                    resetInterval = _readUnsignedInteger16(data, offset);
                    offset += 2;
                    break;
                case 0xffda:
                    parseMarker = ++numSOSMarkers === 1 && !dnlScanLines;
                    offset += 2;
                    selectorsCount = data[offset++];
                    components = [];
                    for (var i = 0; i < selectorsCount; i++) {
                        var index = data[offset++];
                        var componentIndex = frame.componentIds[index];
                        var component = frame.components[componentIndex]; // eslint-disable-line
                        component.index = index;
                        var tableSpec = data[offset++];
                        component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
                        component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
                        components.push(component);
                    }
                    spectralStart = data[offset++];
                    spectralEnd = data[offset++];
                    successiveApproximation = data[offset++];
                    try {
                        var processed = this._decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15, parseMarker);
                        offset += processed;
                    }
                    catch (ex) {
                        if (ex instanceof _PdfDoNotLoadMarkerError) {
                            return this.parse(data, ex.scanLines);
                        }
                        else if (ex instanceof _PdfEndOfImageMarkerError) {
                            return;
                        }
                        throw ex;
                    }
                    break;
                case 0xffdc:
                    offset += 4;
                    break;
                case 0xffff:
                    if (data[offset] !== 0xff) {
                        offset--;
                    }
                    break;
                default:
                    var nextFileMarker = this._findNextFileMarker(// eslint-disable-line
                    data, offset - 2, offset - 3);
                    if (nextFileMarker && nextFileMarker.invalid) {
                        offset = nextFileMarker.offset;
                        break;
                    }
                    if (!nextFileMarker || offset >= data.length - 1) {
                        return;
                    }
                    throw new Error('JpegImage.parse - unknown JPEG marker encountered:' + fileMarker.toString(16));
            }
            fileMarker = _readUnsignedInteger16(data, offset);
            offset += 2;
        }
        if (!frame) {
            throw new Error('JpegImage.parse - JPEG parse error: No frame data found in image stream.');
        }
        this._width = frame.samplesPerLine;
        this._height = frame.scanLines;
        this._jfif = jfif;
        this._adobe = adobe;
        this._components = [];
        for (var _i = 0, _b = frame.components; _i < _b.length; _i++) {
            var component = _b[_i];
            var quantizationTable = quantizationTables[component.quantizationId];
            if (quantizationTable) {
                component.quantizationTable = quantizationTable;
            }
            this._components.push({
                index: component.index,
                output: this._buildComponentData(frame, component),
                scaleX: component.h / frame.maxH,
                scaleY: component.v / frame.maxV,
                blocksPerLine: component.blocksPerLine,
                blocksPerColumn: component.blocksPerColumn
            });
        }
        this._numComponents = this._components.length;
    };
    _PdfJpegImage.prototype._getLinearizedBlockData = function (width, height, isSourcePdf) {
        if (isSourcePdf === void 0) { isSourcePdf = false; }
        var scaleX = this._width / width;
        var scaleY = this._height / height;
        var component; // eslint-disable-line
        var componentScaleX;
        var componentScaleY;
        var blocksPerScanline;
        var x;
        var y;
        var i;
        var j;
        var k;
        var index;
        var offset = 0;
        var output; // eslint-disable-line
        var numComponents = this._components.length;
        var dataLength = width * height * numComponents;
        var data = new Uint8ClampedArray(dataLength);
        var xScaleBlockOffset = new Uint32Array(width);
        var mask3LSB = 0xfffffff8;
        var lastComponentScaleX;
        for (i = 0; i < numComponents; i++) {
            component = this._components[i];
            componentScaleX = component.scaleX * scaleX;
            componentScaleY = component.scaleY * scaleY;
            offset = i;
            output = component.output;
            blocksPerScanline = (component.blocksPerLine + 1) << 3;
            if (componentScaleX !== lastComponentScaleX) {
                for (x = 0; x < width; x++) {
                    j = 0 | (x * componentScaleX);
                    xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
                }
                lastComponentScaleX = componentScaleX;
            }
            for (y = 0; y < height; y++) {
                j = 0 | (y * componentScaleY);
                index = (blocksPerScanline * (j & mask3LSB)) | ((j & 7) << 3);
                for (x = 0; x < width; x++) {
                    data[offset] = output[index + xScaleBlockOffset[x]];
                    offset += numComponents;
                }
            }
        }
        var transform = this._decodeTransform; // eslint-disable-line
        if (!isSourcePdf && numComponents === 4 && !transform) {
            transform = new Int32Array([-256, 255, -256, 255, -256, 255, -256, 255]);
        }
        if (transform) {
            for (i = 0; i < dataLength;) {
                for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
                    data[i] = ((data[i] *
                        transform[k]) >> 8) + transform[k + 1];
                }
            }
        }
        return data;
    };
    Object.defineProperty(_PdfJpegImage.prototype, "_isColorConversionNeeded", {
        get: function () {
            if (this._adobe) {
                return !!this._adobe.transformCode;
            }
            if (this._numComponents === 3) {
                if (this._colorTransform === 0) {
                    return false;
                }
                else if (this._components[0].index === 0x52 &&
                    this._components[1].index === 0x47 &&
                    this._components[2].index === 0x42) {
                    return false;
                }
                return true;
            }
            if (this._colorTransform === 1) {
                return true;
            }
            return false;
        },
        enumerable: true,
        configurable: true
    });
    _PdfJpegImage.prototype._convertYccToRgb = function (data) {
        var Y;
        var Cb;
        var Cr;
        for (var i = 0, length_1 = data.length; i < length_1; i += 3) {
            Y = data[i];
            Cb = data[i + 1];
            Cr = data[i + 2];
            data[i] = Y - 179.456 + 1.402 * Cr;
            data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr;
            data[i + 2] = Y - 226.816 + 1.772 * Cb;
        }
        return data;
    };
    _PdfJpegImage.prototype._convertYccToRgba = function (data, out) {
        for (var i = 0, j = 0, length_2 = data.length; i < length_2; i += 3, j += 4) {
            var Y = data[i];
            var Cb = data[i + 1];
            var Cr = data[i + 2];
            out[j] = Y - 179.456 + 1.402 * Cr;
            out[j + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr;
            out[j + 2] = Y - 226.816 + 1.772 * Cb;
            out[j + 3] = 255;
        }
        return out;
    };
    _PdfJpegImage.prototype._convertYcckToRgb = function (data) {
        this._convertYcckToCmyk(data);
        return this._convertCmykToRgb(data);
    };
    _PdfJpegImage.prototype._convertYcckToRgba = function (data) {
        this._convertYcckToCmyk(data);
        return this._convertCmykToRgba(data);
    };
    _PdfJpegImage.prototype._convertYcckToCmyk = function (data) {
        var Y;
        var Cb;
        var Cr;
        for (var i = 0, length_3 = data.length; i < length_3; i += 4) {
            Y = data[i];
            Cb = data[i + 1];
            Cr = data[i + 2];
            data[i] = 434.456 - Y - 1.402 * Cr;
            data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr;
            data[i + 2] = 481.816 - Y - 1.772 * Cb;
        }
        return data;
    };
    _PdfJpegImage.prototype._convertCmykToRgb = function (data) {
        var count = data.length / 4;
        this._colorSpace.cmyk._getRgbBuffer(data, 0, count, data, 0, 8, 0);
        return data.subarray(0, count * 3);
    };
    _PdfJpegImage.prototype._convertCmykToRgba = function (data) {
        this._colorSpace.cmyk._getRgbBuffer(data, 0, data.length / 4, data, 0, 8, 1);
        if (this._colorSpace.cmyk instanceof _PdfDeviceCmykCS) {
            for (var i = 3, ii = data.length; i < ii; i += 4) {
                data[i] = 255;
            }
        }
        return data;
    };
    _PdfJpegImage.prototype._buildHuffmanTable = function (codeLengths, values) {
        var k = 0;
        var i;
        var j;
        var length = 16;
        while (length > 0 && !codeLengths[length - 1]) {
            length--;
        }
        var code = [{ children: [], index: 0 }]; // eslint-disable-line
        var p = code[0]; // eslint-disable-line
        var q; // eslint-disable-line
        for (i = 0; i < length; i++) {
            for (j = 0; j < codeLengths[i]; j++) {
                p = code.pop();
                p.children[p.index] = values[k];
                while (p.index > 0) {
                    p = code.pop();
                }
                p.index++;
                code.push(p);
                while (code.length <= i) {
                    code.push((q = { children: [], index: 0 }));
                    p.children[p.index] = q.children;
                    p = q;
                }
                k++;
            }
            if (i + 1 < length) {
                code.push((q = { children: [], index: 0 }));
                p.children[p.index] = q.children;
                p = q;
            }
        }
        return code[0].children;
    };
    _PdfJpegImage.prototype._getBlockBufferOffset = function (component, row, col) {
        return 64 * ((component.blocksPerLine + 1) * row + col);
    };
    _PdfJpegImage.prototype._quantizeAndInverse = function (component, blockBufferOffset, p) {
        var qt = component.quantizationTable;
        var blockData = component.blockData;
        var v0;
        var v1;
        var v2;
        var v3;
        var v4;
        var v5;
        var v6;
        var v7;
        var p0;
        var p1;
        var p2;
        var p3;
        var p4;
        var p5;
        var p6;
        var p7;
        var t;
        if (!qt) {
            throw new Error('Required quantization table is missing');
        }
        for (var row = 0; row < 64; row += 8) {
            p0 = blockData[blockBufferOffset + row];
            p1 = blockData[blockBufferOffset + row + 1];
            p2 = blockData[blockBufferOffset + row + 2];
            p3 = blockData[blockBufferOffset + row + 3];
            p4 = blockData[blockBufferOffset + row + 4];
            p5 = blockData[blockBufferOffset + row + 5];
            p6 = blockData[blockBufferOffset + row + 6];
            p7 = blockData[blockBufferOffset + row + 7];
            p0 *= qt[row];
            if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
                t = (this._dctSqrt2 * p0 + 512) >> 10;
                p[row] = t;
                p[row + 1] = t;
                p[row + 2] = t;
                p[row + 3] = t;
                p[row + 4] = t;
                p[row + 5] = t;
                p[row + 6] = t;
                p[row + 7] = t;
                continue;
            }
            p1 *= qt[row + 1];
            p2 *= qt[row + 2];
            p3 *= qt[row + 3];
            p4 *= qt[row + 4];
            p5 *= qt[row + 5];
            p6 *= qt[row + 6];
            p7 *= qt[row + 7];
            v0 = (this._dctSqrt2 * p0 + 128) >> 8;
            v1 = (this._dctSqrt2 * p4 + 128) >> 8;
            v2 = p2;
            v3 = p6;
            v4 = (this._dctSqrt * (p1 - p7) + 128) >> 8;
            v7 = (this._dctSqrt * (p1 + p7) + 128) >> 8;
            v5 = p3 << 4;
            v6 = p5 << 4;
            v0 = (v0 + v1 + 1) >> 1;
            v1 = v0 - v1;
            t = (v2 * this._dctSin6 + v3 * this._dctCos6 + 128) >> 8;
            v2 = (v2 * this._dctCos6 - v3 * this._dctSin6 + 128) >> 8;
            v3 = t;
            v4 = (v4 + v6 + 1) >> 1;
            v6 = v4 - v6;
            v7 = (v7 + v5 + 1) >> 1;
            v5 = v7 - v5;
            v0 = (v0 + v3 + 1) >> 1;
            v3 = v0 - v3;
            v1 = (v1 + v2 + 1) >> 1;
            v2 = v1 - v2;
            t = (v4 * this._dctSin3 + v7 * this._dctCos3 + 2048) >> 12;
            v4 = (v4 * this._dctCos3 - v7 * this._dctSin3 + 2048) >> 12;
            v7 = t;
            t = (v5 * this._dctSin1 + v6 * this._dctCos1 + 2048) >> 12;
            v5 = (v5 * this._dctCos1 - v6 * this._dctSin1 + 2048) >> 12;
            v6 = t;
            p[row] = v0 + v7;
            p[row + 7] = v0 - v7;
            p[row + 1] = v1 + v6;
            p[row + 6] = v1 - v6;
            p[row + 2] = v2 + v5;
            p[row + 5] = v2 - v5;
            p[row + 3] = v3 + v4;
            p[row + 4] = v3 - v4;
        }
        for (var col = 0; col < 8; ++col) {
            p0 = p[col];
            p1 = p[col + 8];
            p2 = p[col + 16];
            p3 = p[col + 24];
            p4 = p[col + 32];
            p5 = p[col + 40];
            p6 = p[col + 48];
            p7 = p[col + 56];
            if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
                t = (this._dctSqrt2 * p0 + 8192) >> 14;
                if (t < -2040) {
                    t = 0;
                }
                else if (t >= 2024) {
                    t = 255;
                }
                else {
                    t = (t + 2056) >> 4;
                }
                blockData[blockBufferOffset + col] = t;
                blockData[blockBufferOffset + col + 8] = t;
                blockData[blockBufferOffset + col + 16] = t;
                blockData[blockBufferOffset + col + 24] = t;
                blockData[blockBufferOffset + col + 32] = t;
                blockData[blockBufferOffset + col + 40] = t;
                blockData[blockBufferOffset + col + 48] = t;
                blockData[blockBufferOffset + col + 56] = t;
                continue;
            }
            v0 = (this._dctSqrt2 * p0 + 2048) >> 12;
            v1 = (this._dctSqrt2 * p4 + 2048) >> 12;
            v2 = p2;
            v3 = p6;
            v4 = (this._dctSqrt * (p1 - p7) + 2048) >> 12;
            v7 = (this._dctSqrt * (p1 + p7) + 2048) >> 12;
            v5 = p3;
            v6 = p5;
            v0 = ((v0 + v1 + 1) >> 1) + 4112;
            v1 = v0 - v1;
            t = (v2 * this._dctSin6 + v3 * this._dctCos6 + 2048) >> 12;
            v2 = (v2 * this._dctCos6 - v3 * this._dctSin6 + 2048) >> 12;
            v3 = t;
            v4 = (v4 + v6 + 1) >> 1;
            v6 = v4 - v6;
            v7 = (v7 + v5 + 1) >> 1;
            v5 = v7 - v5;
            v0 = (v0 + v3 + 1) >> 1;
            v3 = v0 - v3;
            v1 = (v1 + v2 + 1) >> 1;
            v2 = v1 - v2;
            t = (v4 * this._dctSin3 + v7 * this._dctCos3 + 2048) >> 12;
            v4 = (v4 * this._dctCos3 - v7 * this._dctSin3 + 2048) >> 12;
            v7 = t;
            t = (v5 * this._dctSin1 + v6 * this._dctCos1 + 2048) >> 12;
            v5 = (v5 * this._dctCos1 - v6 * this._dctSin1 + 2048) >> 12;
            v6 = t;
            p0 = v0 + v7;
            p7 = v0 - v7;
            p1 = v1 + v6;
            p6 = v1 - v6;
            p2 = v2 + v5;
            p5 = v2 - v5;
            p3 = v3 + v4;
            p4 = v3 - v4;
            if (p0 < 16) {
                p0 = 0;
            }
            else if (p0 >= 4080) {
                p0 = 255;
            }
            else {
                p0 >>= 4;
            }
            if (p1 < 16) {
                p1 = 0;
            }
            else if (p1 >= 4080) {
                p1 = 255;
            }
            else {
                p1 >>= 4;
            }
            if (p2 < 16) {
                p2 = 0;
            }
            else if (p2 >= 4080) {
                p2 = 255;
            }
            else {
                p2 >>= 4;
            }
            if (p3 < 16) {
                p3 = 0;
            }
            else if (p3 >= 4080) {
                p3 = 255;
            }
            else {
                p3 >>= 4;
            }
            if (p4 < 16) {
                p4 = 0;
            }
            else if (p4 >= 4080) {
                p4 = 255;
            }
            else {
                p4 >>= 4;
            }
            if (p5 < 16) {
                p5 = 0;
            }
            else if (p5 >= 4080) {
                p5 = 255;
            }
            else {
                p5 >>= 4;
            }
            if (p6 < 16) {
                p6 = 0;
            }
            else if (p6 >= 4080) {
                p6 = 255;
            }
            else {
                p6 >>= 4;
            }
            if (p7 < 16) {
                p7 = 0;
            }
            else if (p7 >= 4080) {
                p7 = 255;
            }
            else {
                p7 >>= 4;
            }
            blockData[blockBufferOffset + col] = p0;
            blockData[blockBufferOffset + col + 8] = p1;
            blockData[blockBufferOffset + col + 16] = p2;
            blockData[blockBufferOffset + col + 24] = p3;
            blockData[blockBufferOffset + col + 32] = p4;
            blockData[blockBufferOffset + col + 40] = p5;
            blockData[blockBufferOffset + col + 48] = p6;
            blockData[blockBufferOffset + col + 56] = p7;
        }
    };
    _PdfJpegImage.prototype._buildComponentData = function (frame, component) {
        var blocksPerLine = component.blocksPerLine;
        var blocksPerColumn = component.blocksPerColumn;
        var computationBuffer = new Int16Array(64);
        for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
            for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
                var offset = this._getBlockBufferOffset(component, blockRow, blockCol);
                this._quantizeAndInverse(component, offset, computationBuffer);
            }
        }
        return component.blockData;
    };
    _PdfJpegImage.prototype._findNextFileMarker = function (data, currentPos, startPos) {
        if (startPos === void 0) { startPos = currentPos; }
        var maxPos = data.length - 1;
        var newPos = startPos < currentPos ? startPos : currentPos;
        if (currentPos >= maxPos) {
            return null;
        }
        var currentMarker = _readUnsignedInteger16(data, currentPos);
        if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) {
            return { invalid: null, marker: currentMarker, offset: currentPos };
        }
        var newMarker = _readUnsignedInteger16(data, newPos);
        while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) {
            if (++newPos >= maxPos) {
                return null;
            }
            newMarker = _readUnsignedInteger16(data, newPos);
        }
        return { invalid: currentMarker.toString(16), marker: newMarker, offset: newPos };
    };
    _PdfJpegImage.prototype._prepareComponents = function (frame) {
        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
        for (var _i = 0, _a = frame.components; _i < _a.length; _i++) {
            var component = _a[_i];
            var blocksPerLine = Math.ceil((Math.ceil(frame.samplesPerLine / 8) * component.h) / frame.maxH);
            var blocksPerColumn = Math.ceil((Math.ceil(frame.scanLines / 8) * component.v) / frame.maxV);
            var blocksPerLineForMcu = mcusPerLine * component.h;
            var blocksPerColumnForMcu = mcusPerColumn * component.v;
            var blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
            component.blockData = new Int16Array(blocksBufferSize);
            component.blocksPerLine = blocksPerLine;
            component.blocksPerColumn = blocksPerColumn;
        }
        frame.mcusPerLine = mcusPerLine;
        frame.mcusPerColumn = mcusPerColumn;
    };
    _PdfJpegImage.prototype._readDataBlock = function (data, offset) {
        var length = _readUnsignedInteger16(data, offset);
        offset += 2;
        var endOffset = offset + length - 2;
        var fileMarker = this._findNextFileMarker(data, endOffset, offset); // eslint-disable-line
        if (fileMarker && fileMarker.invalid) {
            endOffset = fileMarker.offset;
        }
        var array = data.subarray(offset, endOffset);
        return { appData: array, oldOffset: offset, newOffset: offset + array.length };
    };
    _PdfJpegImage.prototype._skipData = function (data, offset) {
        var length = _readUnsignedInteger16(data, offset);
        offset += 2;
        var endOffset = offset + length - 2;
        var fileMarker = this._findNextFileMarker(data, endOffset, offset); // eslint-disable-line       
        if (fileMarker && fileMarker.invalid) {
            return fileMarker.offset;
        }
        return endOffset;
    };
    _PdfJpegImage.prototype._getData = function (width, height, forceRgba, forceRgb, isSourcePdf) {
        if (this._numComponents > 4) {
            throw new Error('JPEG decoding error: Encountered an unsupported color mode in the image.');
        }
        var data = this._getLinearizedBlockData(width, height, isSourcePdf); // eslint-disable-line
        if (this._numComponents === 1 && (forceRgba || forceRgb)) {
            var len = data.length * (forceRgba ? 4 : 3);
            var rgbaData = new Uint8ClampedArray(len);
            var offset = 0;
            if (forceRgba) {
                _grayToRgba(data, new Uint32Array(rgbaData.buffer));
            }
            else {
                for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
                    var grayColor = data_1[_i];
                    rgbaData[offset++] = grayColor;
                    rgbaData[offset++] = grayColor;
                    rgbaData[offset++] = grayColor;
                }
            }
            return rgbaData;
        }
        else if (this._numComponents === 3 && this._isColorConversionNeeded) {
            if (forceRgba) {
                var rgbaData = new Uint8ClampedArray((data.length / 3) * 4);
                return this._convertYccToRgba(data, rgbaData);
            }
            return this._convertYccToRgb(data);
        }
        else if (this._numComponents === 4) {
            if (this._isColorConversionNeeded) {
                if (forceRgba) {
                    return this._convertYcckToRgba(data);
                }
                if (forceRgb) {
                    return this._convertYcckToRgb(data);
                }
                return this._convertYcckToCmyk(data);
            }
            else if (forceRgba) {
                return this._convertCmykToRgba(data);
            }
            else if (forceRgb) {
                return this._convertCmykToRgb(data);
            }
        }
        return data;
    };
    _PdfJpegImage.prototype._decodeHuffman = function (tree) {
        var node = tree; // eslint-disable-line
        while (true) { // eslint-disable-line
            node = node[this._readBit()];
            switch (typeof node) {
                case 'number':
                    return node;
                case 'object':
                    continue;
            }
            throw new Error('JPEG decoding error: The image contains an invalid Huffman sequence.');
        }
    };
    _PdfJpegImage.prototype._receive = function (length) {
        var n = 0;
        while (length > 0) {
            n = (n << 1) | this._readBit();
            length--;
        }
        return n;
    };
    _PdfJpegImage.prototype._receiveAndExtend = function (length) {
        if (length === 1) {
            return this._readBit() === 1 ? 1 : -1;
        }
        var n = this._receive(length);
        if (n >= 1 << (length - 1)) {
            return n;
        }
        return n + (-1 << length) + 1;
    };
    _PdfJpegImage.prototype._decodeBaseline = function (component, blockOffset) {
        var t = this._decodeHuffman(component.huffmanTableDC);
        var diff = t === 0 ? 0 : this._receiveAndExtend(t);
        component.blockData[blockOffset] = component.pred += diff;
        var k = 1;
        while (k < 64) {
            var rs = this._decodeHuffman(component.huffmanTableAC);
            var s = rs & 15;
            var r = rs >> 4;
            if (s === 0) {
                if (r < 15) {
                    break;
                }
                k += 16;
                continue;
            }
            k += r;
            var z = this._dctZigZag[k];
            component.blockData[blockOffset + z] = this._receiveAndExtend(s);
            k++;
        }
    };
    _PdfJpegImage.prototype._decodeDCFirst = function (component, blockOffset, successive) {
        var t = this._decodeHuffman(component.huffmanTableDC);
        var diff = t === 0 ? 0 : this._receiveAndExtend(t) << successive;
        component.blockData[blockOffset] = component.pred += diff;
    };
    _PdfJpegImage.prototype._decodeDCSuccessive = function (component, blockOffset, successive) {
        component.blockData[blockOffset] |= this._readBit() << successive;
    };
    _PdfJpegImage.prototype._decodeACFirst = function (component, blockOffset, successive) {
        if (this._eobrun > 0) {
            this._eobrun--;
            return;
        }
        var k = this._spectralStart;
        var e = this._spectralEnd;
        while (k <= e) {
            var rs = this._decodeHuffman(component.huffmanTableAC);
            var s = rs & 15;
            var r = rs >> 4;
            if (s === 0) {
                if (r < 15) {
                    this._eobrun = this._receive(r) + (1 << r) - 1;
                    break;
                }
                k += 16;
                continue;
            }
            k += r;
            var z = this._dctZigZag[k];
            component.blockData[blockOffset + z] = this._receiveAndExtend(s) * (1 << successive);
            k++;
        }
    };
    _PdfJpegImage.prototype._decodeMcu = function (component, decode, mcu, row, col, mcusPerLine) {
        var mcuRow = (mcu / mcusPerLine) | 0;
        var mcuCol = mcu % mcusPerLine;
        this._blockRow = mcuRow * component.v + row;
        var blockCol = mcuCol * component.h + col;
        var blockOffset = this._getBlockBufferOffset(component, this._blockRow, blockCol);
        decode(component, blockOffset);
    };
    _PdfJpegImage.prototype._decodeBlock = function (component, _decode, mcu) {
        this._blockRow = (mcu / component.blocksPerLine) | 0;
        var blockCol = mcu % component.blocksPerLine;
        var blockOffset = this._getBlockBufferOffset(component, this._blockRow, blockCol);
        _decode(component, blockOffset);
    };
    _PdfJpegImage.prototype._decodeACSuccessive = function (component, blockOffset, successive) {
        var k = this._spectralStart;
        var e = this._spectralEnd;
        var r = 0;
        var s;
        var rs;
        while (k <= e) {
            var offsetZ = blockOffset + this._dctZigZag[k];
            var sign = component.blockData[offsetZ] < 0 ? -1 : 1;
            switch (this._successiveACState) {
                case 0:
                    rs = this._decodeHuffman(component.huffmanTableAC);
                    s = rs & 15;
                    r = rs >> 4;
                    if (s === 0) {
                        if (r < 15) {
                            this._eobrun = this._receive(r) + (1 << r);
                            this._successiveACState = 4;
                        }
                        else {
                            r = 16;
                            this._successiveACState = 1;
                        }
                    }
                    else {
                        if (s !== 1) {
                            throw new Error('Invalid ACn encoding: expected valid ACn data format but received unsupported input.');
                        }
                        this._successiveACNextValue = this._receiveAndExtend(s);
                        this._successiveACState = r ? 2 : 3;
                    }
                    continue;
                case 1:
                case 2:
                    if (component.blockData[offsetZ]) {
                        component.blockData[offsetZ] += sign * (this._readBit() << successive);
                    }
                    else {
                        r--;
                        if (r === 0) {
                            this._successiveACState = this._successiveACState === 2 ? 3 : 0;
                        }
                    }
                    break;
                case 3:
                    if (component.blockData[this._offset]) {
                        component.blockData[this._offset] += sign * (this._readBit() << successive);
                    }
                    else {
                        component.blockData[this._offset] = this._successiveACNextValue << successive;
                        this._successiveACState = 0;
                    }
                    break;
                case 4:
                    if (component.blockData[this._offset]) {
                        component.blockData[this._offset] += sign * (this._readBit() << successive);
                    }
                    break;
            }
            k++;
        }
        if (this._successiveACState === 4) {
            this._eobrun--;
            if (this._eobrun === 0) {
                this._successiveACState = 0;
            }
        }
    };
    _PdfJpegImage.prototype._decodeScan = function (data, offset, frame, components, resetInterval, // eslint-disable-line
    spectralStart, spectralEnd, successivePrev, successive, // eslint-disable-line
    parseMarker) {
        var _this = this;
        if (parseMarker === void 0) { parseMarker = false; }
        var mcusPerLine = frame.mcusPerLine;
        var progressive = frame.progressive;
        var startOffset = offset;
        this._bitsData = 0;
        var componentsLength = components.length;
        var component; // eslint-disable-line
        var i;
        var j;
        var k;
        var n;
        this._data = data;
        this._offset = offset;
        this._frame = frame;
        this._bitsCount = 0;
        this._parseMarker = parseMarker;
        this._spectralStart = spectralStart;
        this._spectralEnd = spectralEnd;
        this._blockOffset = 0;
        var decodeFn; // eslint-disable-line
        if (progressive) {
            if (spectralStart === 0) {
                decodeFn = function (component, blockOffset) {
                    return successivePrev === 0
                        ? _this._decodeDCFirst(component, blockOffset, successive)
                        : _this._decodeDCSuccessive(component, blockOffset, successive);
                };
            }
            else {
                decodeFn = function (component, blockOffset) {
                    return successivePrev === 0
                        ? _this._decodeACFirst(component, blockOffset, successive)
                        : _this._decodeACSuccessive(component, blockOffset, successive);
                };
            }
        }
        else {
            decodeFn = function (component, blockOffset) {
                return _this._decodeBaseline(component, blockOffset);
            };
        }
        var mcu = 0;
        var fileMarker; // eslint-disable-line
        var mcuExpected = componentsLength === 1
            ? components[0].blocksPerLine * components[0].blocksPerColumn
            : mcusPerLine * frame.mcusPerColumn;
        var h;
        var v;
        while (mcu <= mcuExpected) {
            // reset interval stuff
            var mcuToRead = resetInterval
                ? Math.min(mcuExpected - mcu, resetInterval)
                : mcuExpected;
            if (mcuToRead > 0) {
                for (i = 0; i < componentsLength; i++) {
                    components[i].pred = 0;
                }
                this._eobrun = 0;
                if (componentsLength === 1) {
                    component = components[0];
                    for (n = 0; n < mcuToRead; n++) {
                        this._decodeBlock(component, decodeFn, mcu);
                        mcu++;
                    }
                }
                else {
                    for (n = 0; n < mcuToRead; n++) {
                        for (i = 0; i < componentsLength; i++) {
                            component = components[i];
                            h = component.h;
                            v = component.v;
                            for (j = 0; j < v; j++) {
                                for (k = 0; k < h; k++) {
                                    this._decodeMcu(component, decodeFn, mcu, j, k, mcusPerLine);
                                }
                            }
                        }
                        mcu++;
                    }
                }
            }
            this._bitsCount = 0;
            fileMarker = this._findNextFileMarker(data, this._offset);
            if (!fileMarker) {
                break;
            }
            if (fileMarker.invalid) {
                this._offset = fileMarker.offset;
            }
            if (fileMarker.marker >= 0xffd0 && fileMarker.marker <= 0xffd7) {
                this._offset += 2;
            }
            else {
                break;
            }
        }
        return this._offset - startOffset;
    };
    _PdfJpegImage.prototype._readBit = function () {
        if (this._bitsCount > 0) {
            this._bitsCount--;
            return (this._bitsData >> this._bitsCount) & 1;
        }
        this._bitsData = this._data[this._offset++];
        if (this._bitsData === 0xff) {
            var nextByte = this._data[this._offset++];
            if (nextByte) {
                if (nextByte === 0xdc && this._parseMarker) {
                    this._offset += 2;
                    var scanLines = _readUnsignedInteger16(this._data, this._offset);
                    this._offset += 2;
                    if (scanLines > 0 && scanLines !== this._frame.scanLines) {
                        throw new _PdfDoNotLoadMarkerError('Found DNL marker (0xFFDC) while parsing scan data', scanLines);
                    }
                }
                else if (nextByte === 0xd9) {
                    if (this._parseMarker) {
                        var maybeScanLines = this._blockRow * (this._frame.precision === 8 ? 8 : 0);
                        if (maybeScanLines > 0 &&
                            Math.round(this._frame.scanLines / maybeScanLines) >= 5) {
                            throw new _PdfDoNotLoadMarkerError('Found EOI marker (0xFFD9) while parsing scan data, ' +
                                'possibly caused by incorrect `scanLines` parameter', maybeScanLines);
                        }
                    }
                    throw new _PdfEndOfImageMarkerError('Found EOI marker (0xFFD9) while parsing scan data');
                }
                throw new Error("Unexpected marker encountered: " + ((this._bitsData << 8) | nextByte).toString(16));
            }
        }
        this._bitsCount = 7;
        return this._bitsData >>> 7;
    };
    return _PdfJpegImage;
}());
export { _PdfJpegImage };
