var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
import { _PdfImageResizer } from './image-resizer';
import { _PdfJpxImage } from '../jpx-image';
import { _PdfImageProcessor } from '../import/decode-image';
import { ImageFormat } from '../enum';
import { _convertBlackAndWhiteToRGBA, _convertToRGBA, imageKind } from './image-utils';
import { _isLittleEndian, _mathClamp, _PdfBaseStream, _PdfDecodeStream, _PdfFlateStream, _PdfJpegStream, _PdfJpxStream, _PdfName, _PdfReference, FormatError, PdfRotationAngle } from '@syncfusion/ej2-pdf';
import { _PdfColorSpaceUtils } from './colorspace-utils';
import { _PdfColorPalette } from './colorspace';
import { _base64ToUint8Array } from '../utils';
import { _PdfJpegImage } from './jpeg-image';
var _PdfImage = /** @class */ (function () {
    function _PdfImage() {
        this.imageResizer = new _PdfImageResizer();
    }
    _PdfImage.prototype._initializeFromImage = function (xref, image, isInline, callBack, // eslint-disable-line 
    smask, mask, isMask) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, dict, filter, filterName, filterZero, jpx, reducePower, factor, width, height, validWidth, validHeight, bitsPerComponent, colorSpace, hasColorSpace, color, _b, max, isIndexed, i, j, dmin, dmax, _c, maskDict, imageMask, _d;
            return __generator(this, function (_e) {
                switch (_e.label) {
                    case 0:
                        if (!image) return [3 /*break*/, 8];
                        this.image = image;
                        dict = image.dictionary;
                        filter = dict.get('F', 'Filter');
                        filterName = void 0;
                        if (filter instanceof _PdfName) {
                            filterName = filter.name;
                        }
                        else if (Array.isArray(filter)) {
                            filterZero = void 0;
                            if (filter[0] instanceof _PdfReference) {
                                filterZero = xref._fetch(filter[0]);
                            }
                            else {
                                filterZero = filter[0];
                            }
                            if (filterZero instanceof _PdfName) {
                                filterName = filterZero.name;
                            }
                        }
                        jpx = void 0;
                        reducePower = void 0;
                        switch (filterName) {
                            case 'JPXDecode':
                                jpx = new _PdfJpxImage();
                                (_a = jpx._parseImageProperties(image.stream), image.width = _a.width, image.height = _a.height, image.numComps = _a.componentsCount, image.bitsPerComponent = _a.bitsPerComponent);
                                image.stream.reset();
                                reducePower = this.imageResizer._getReducePowerForJPX(image.width, image.height, image.numComps);
                                this.jpxDecoderOptions = { numComponents: 0, isIndexedColormap: false, smaskInData: dict.has('SMaskInData'), reducePower: reducePower };
                                if (reducePower) {
                                    factor = Math.pow(2, reducePower);
                                    image.width = Math.ceil(image.width / factor);
                                    image.height = Math.ceil(image.height / factor);
                                }
                                break;
                            case 'JBIG2Decode':
                                image.bitsPerComponent = 1;
                                image.numComps = 1;
                                break;
                        }
                        width = dict.get('W', 'Width');
                        height = dict.get('H', 'Height');
                        if (Number.isInteger(image.width) && image.width > 0 && Number.isInteger(image.height) && image.height > 0 &&
                            (image.width !== width || image.height !== height)) {
                            width = image.width;
                            height = image.height;
                        }
                        else {
                            validWidth = typeof width === 'number' && width > 0;
                            validHeight = typeof height === 'number' && height > 0;
                            if (!validWidth || !validHeight) {
                                if (!image.fallbackDims) {
                                    throw new FormatError("Invalid image width: " + width + " or height: " + height);
                                }
                                if (!validWidth) {
                                    width = image.fallbackDims.width;
                                }
                                if (!validHeight) {
                                    height = image.fallbackDims.height;
                                }
                            }
                        }
                        this.width = width;
                        this.height = height;
                        this.interpolate = dict.get('I', 'Interpolate');
                        this.imageMask = dict.get('IM', 'ImageMask') || false;
                        this.matte = dict.get('Matte') || false;
                        bitsPerComponent = image.bitsPerComponent;
                        if (!bitsPerComponent) {
                            bitsPerComponent = dict.get('BPC', 'BitsPerComponent');
                            if (!bitsPerComponent) {
                                if (this.imageMask) {
                                    bitsPerComponent = 1;
                                }
                                else {
                                    throw new FormatError("Bits per component missing in image: " + this.imageMask);
                                }
                            }
                        }
                        this.bpc = bitsPerComponent;
                        if (!!this.imageMask) return [3 /*break*/, 2];
                        colorSpace = dict.getRaw('CS') || dict.getRaw('ColorSpace');
                        hasColorSpace = colorSpace !== undefined;
                        if (!hasColorSpace) {
                            if (this.jpxDecoderOptions) {
                                colorSpace = _PdfName.get('DeviceRGBA');
                            }
                            else {
                                switch (image.numComps) {
                                    case 1:
                                        colorSpace = _PdfName.get('DeviceGray');
                                        break;
                                    case 3:
                                        colorSpace = _PdfName.get('DeviceRGB');
                                        break;
                                    case 4:
                                        colorSpace = _PdfName.get('DeviceCMYK');
                                        break;
                                    default:
                                        throw new Error("Images with " + image.numComps + " color components not supported.");
                                }
                            }
                        }
                        else if (this.jpxDecoderOptions && this.jpxDecoderOptions.smaskInData) {
                            colorSpace = _PdfName.get('DeviceRGBA');
                        }
                        color = new _PdfColorSpaceUtils(callBack);
                        _b = this;
                        return [4 /*yield*/, color._parse(colorSpace, xref, null, null, null, false, null)];
                    case 1:
                        _b.colorSpace = _e.sent();
                        this.numComps = this.colorSpace.numComps;
                        if (this.jpxDecoderOptions) {
                            this.jpxDecoderOptions.numComponents = hasColorSpace
                                ? this.numComps
                                : 0;
                            this.jpxDecoderOptions.isIndexedColormap =
                                this.colorSpace.name === 'Indexed';
                        }
                        _e.label = 2;
                    case 2:
                        this.decode = dict.getArray('D', 'Decode') || null;
                        this.needsDecode = false;
                        if (this.decode && ((this.colorSpace && !this.colorSpace._isDefaultDecode(this.decode, bitsPerComponent)) || (isMask && !this._isDefaultDecode()))) {
                            this.needsDecode = true;
                            max = (1 << bitsPerComponent) - 1;
                            this.decodeCoefficients = [];
                            this.decodeAddends = [];
                            isIndexed = this.colorSpace && this.colorSpace.name === 'Indexed';
                            for (i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
                                dmin = this.decode[i];
                                dmax = this.decode[i + 1];
                                this.decodeCoefficients[j] = isIndexed
                                    ? (dmax - dmin) / max
                                    : dmax - dmin;
                                this.decodeAddends[j] = isIndexed ? dmin : max * dmin;
                            }
                        }
                        if (!smask) return [3 /*break*/, 4];
                        if (smask.fallbackDims === null) {
                            smask.fallbackDims = { width: width, height: height };
                        }
                        _c = this;
                        return [4 /*yield*/, new _PdfImage()._initializeFromImage(xref, smask, isInline, callBack, null, null, false)];
                    case 3:
                        _c.smask = _e.sent();
                        return [3 /*break*/, 8];
                    case 4:
                        if (!mask) return [3 /*break*/, 8];
                        if (!(mask instanceof _PdfBaseStream)) return [3 /*break*/, 7];
                        maskDict = mask.dictionary;
                        imageMask = maskDict.get('IM', 'ImageMask');
                        if (!imageMask) return [3 /*break*/, 6];
                        _d = this;
                        return [4 /*yield*/, new _PdfImage()._initializeFromImage(xref, mask, isInline, callBack, null, null, true)];
                    case 5:
                        _d.mask = _e.sent();
                        _e.label = 6;
                    case 6: return [3 /*break*/, 8];
                    case 7:
                        this.mask = mask;
                        _e.label = 8;
                    case 8: return [2 /*return*/, this];
                }
            });
        });
    };
    _PdfImage.prototype._resizeImageMask = function (src, bpc, w1, h1, w2, h2) {
        var length = w2 * h2;
        var dest;
        if (bpc <= 8) {
            dest = new Uint8Array(length);
        }
        else if (bpc <= 16) {
            dest = new Uint16Array(length);
        }
        else {
            dest = new Uint32Array(length);
        }
        var xRatio = w1 / w2;
        var yRatio = h1 / h2;
        var i;
        var j;
        var py;
        var newIndex = 0;
        var oldIndex;
        var xScaled = new Uint16Array(w2);
        var w1Scanline = w1;
        for (i = 0; i < w2; i++) {
            xScaled[i] = Math.floor(i * xRatio);
        }
        for (i = 0; i < h2; i++) {
            py = Math.floor(i * yRatio) * w1Scanline;
            for (j = 0; j < w2; j++) {
                oldIndex = py + xScaled[j];
                dest[newIndex] = src[oldIndex];
                newIndex++;
            }
        }
        return dest;
    };
    _PdfImage.prototype._isDefaultDecode = function () {
        if (typeof (this.colorSpace) === 'undefined') {
            var colorPalette = new _PdfColorPalette('ColorSpace', undefined);
            return colorPalette._isDefaultDecode(this.decode, 1);
        }
        return false;
    };
    _PdfImage.prototype._getImageData = function (length, decoderOptions) {
        var stream = decoderOptions.image; // eslint-disable-line
        if (stream instanceof _PdfJpegStream) {
            var values = decoderOptions.image.getBytes(length, decoderOptions); // eslint-disable-line
            var jpegImage = new _PdfJpegImage();
            jpegImage.parse(values);
            var data_1 = jpegImage._getData(this.drawWidth, this.drawHeight, this.forceRgba, this.forceRgb, // eslint-disable-line 
            true);
            decoderOptions.image.buffer = data_1;
            decoderOptions.bufferLength = data_1.length;
            return data_1;
        }
        if (!(stream instanceof _PdfFlateStream)) {
            if (stream instanceof _PdfJpxStream) {
                return decoderOptions.image.decodeImage(null, decoderOptions);
            }
            return decoderOptions.image.getBytes(length, decoderOptions);
        }
        var data = decoderOptions.image.getBytes(length, decoderOptions); // eslint-disable-line
        if (stream instanceof _PdfFlateStream) {
            return data;
        }
        return decoderOptions.image.decodeImage(data, decoderOptions);
    };
    _PdfImage.prototype._createImageData = function (forceRGBA, isOffscreenCanvasSupported) {
        if (forceRGBA === void 0) { forceRGBA = false; }
        if (isOffscreenCanvasSupported === void 0) { isOffscreenCanvasSupported = false; }
        return __awaiter(this, void 0, void 0, function () {
            var drawWidth, drawHeight, imgData, numComps, originalWidth, originalHeight, bpc, rowBytes, mustBeResized, imgArray_1, _a, kind, image, data_2, buffer, i, ii, imgArray, actualHeight, comps, alpha01, maybeUndoPreblend, data, canvasImgData, ctx, canvas, arr, format, buffer, base64, bytes;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        drawWidth = this.drawWidth;
                        drawHeight = this.drawHeight;
                        imgData = { width: drawWidth, height: drawHeight, interpolate: this.interpolate, kind: 0,
                            data: null };
                        numComps = this.numComps;
                        originalWidth = this.width;
                        originalHeight = this.height;
                        bpc = this.bpc;
                        rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
                        mustBeResized = isOffscreenCanvasSupported &&
                            this.imageResizer._needsToBeResized(drawWidth, drawHeight);
                        if (!(!this.smask && !this.mask && this.colorSpace.name === 'DeviceRGBA')) return [3 /*break*/, 6];
                        imgData.kind = imageKind.rgba32BPP;
                        _a = imgData;
                        return [4 /*yield*/, this._getImageBytes(originalHeight * originalWidth * 4, {})];
                    case 1:
                        imgArray_1 = (_a.data = _b.sent());
                        if (!isOffscreenCanvasSupported) return [3 /*break*/, 5];
                        if (!!mustBeResized) return [3 /*break*/, 3];
                        return [4 /*yield*/, this._createBitmap(imageKind.rgba32BPP, drawWidth, drawHeight, imgArray_1)];
                    case 2: return [2 /*return*/, _b.sent()];
                    case 3: return [4 /*yield*/, this.imageResizer._createImageData(imgData, false)];
                    case 4: return [2 /*return*/, _b.sent()];
                    case 5: return [2 /*return*/, imgData];
                    case 6:
                        if (!!forceRGBA) return [3 /*break*/, 10];
                        kind = void 0;
                        if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
                            kind = imageKind.grayScale1Bpp;
                        }
                        else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 && !this.needsDecode) {
                            kind = imageKind.rgb24BPP;
                        }
                        if (!(kind && !this.smask && !this.mask && drawWidth === originalWidth && drawHeight === originalHeight)) return [3 /*break*/, 10];
                        image = this._getImage(originalWidth, originalHeight);
                        if (image) {
                            return [2 /*return*/, image];
                        }
                        return [4 /*yield*/, this._getImageBytes(originalHeight * rowBytes, {})];
                    case 7:
                        data_2 = _b.sent();
                        if (!isOffscreenCanvasSupported) return [3 /*break*/, 9];
                        if (mustBeResized) {
                            return [2 /*return*/, this.imageResizer._createImageData({ data: data_2, kind: kind, width: drawWidth, height: drawHeight, interpolate: this.interpolate }, this.needsDecode)];
                        }
                        return [4 /*yield*/, this._createBitmap(kind, originalWidth, originalHeight, data_2)];
                    case 8: return [2 /*return*/, _b.sent()];
                    case 9:
                        imgData.kind = kind;
                        imgData.data = data_2;
                        if (this.needsDecode) {
                            buffer = imgData.data;
                            for (i = 0, ii = buffer.length; i < ii; i++) {
                                buffer[i] ^= 0xff;
                            }
                        }
                        return [2 /*return*/, imgData];
                    case 10: return [4 /*yield*/, this._getImageBytes(originalHeight * rowBytes, { internal: true })];
                    case 11:
                        imgArray = _b.sent();
                        actualHeight = 0 | (((imgArray.length / rowBytes) * drawHeight) / originalHeight);
                        comps = this._getComponents(imgArray);
                        if (isOffscreenCanvasSupported && !mustBeResized) {
                            canvas = document.createElement('canvas');
                            canvas.width = drawWidth;
                            canvas.height = drawHeight;
                            ctx = canvas.getContext('2d');
                            canvasImgData = ctx.createImageData(drawWidth, drawHeight);
                            data = canvasImgData.data;
                        }
                        imgData.kind = imageKind.rgba32BPP;
                        if (!(!forceRGBA && !this.smask && !this.mask)) return [3 /*break*/, 12];
                        if (!isOffscreenCanvasSupported || mustBeResized) {
                            imgData.kind = imageKind.rgb24BPP;
                            data = new Uint8ClampedArray(drawWidth * drawHeight * 3);
                            alpha01 = 0;
                        }
                        else {
                            arr = new Uint32Array(data.buffer);
                            arr.fill(_isLittleEndian() ? 0xff000000 : 0x000000ff);
                            alpha01 = 1;
                        }
                        maybeUndoPreblend = false;
                        return [3 /*break*/, 14];
                    case 12:
                        if (!isOffscreenCanvasSupported || mustBeResized) {
                            data = new Uint8ClampedArray(drawWidth * drawHeight * 4);
                        }
                        alpha01 = 1;
                        maybeUndoPreblend = true;
                        return [4 /*yield*/, this._fillOpacity(data, drawWidth, drawHeight, actualHeight, comps)];
                    case 13:
                        _b.sent();
                        _b.label = 14;
                    case 14:
                        if (this.needsDecode) {
                            this._decodeBuffer(comps);
                        }
                        return [4 /*yield*/, this.colorSpace._fillRgb(data, originalWidth, originalHeight, drawWidth, drawHeight, actualHeight, bpc, comps, alpha01)];
                    case 15:
                        _b.sent();
                        if (maybeUndoPreblend) {
                            this._undoPreblend(data, drawWidth, actualHeight);
                        }
                        if (isOffscreenCanvasSupported && !mustBeResized) {
                            if (typeof (this._options) !== 'undefined') {
                                this._processImageRedaction(canvasImgData);
                            }
                            ctx.putImageData(canvasImgData, 0, 0);
                            format = this._findImageFormat(this._imageFormat);
                            buffer = canvas.toDataURL(format);
                            base64 = buffer.split(',')[1];
                            bytes = _base64ToUint8Array(base64);
                            return [2 /*return*/, bytes];
                        }
                        imgData.data = data;
                        if (mustBeResized) {
                            return [2 /*return*/, this.imageResizer._createImageData(imgData)];
                        }
                        return [2 /*return*/, imgData];
                }
            });
        });
    };
    _PdfImage.prototype._findImageFormat = function (format) {
        if (ImageFormat.png === format) {
            return 'image/png';
        }
        else {
            return 'image/jpeg';
        }
    };
    _PdfImage.prototype._buildImage = function (xref, image, isInline, callBack) {
        return __awaiter(this, void 0, void 0, function () {
            var imageData, smaskData, maskData, smask, mask;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        imageData = image;
                        smaskData = null;
                        maskData = null;
                        smask = image.dictionary.get('SMask');
                        mask = image.dictionary.get('Mask');
                        if (smask) {
                            if (smask instanceof _PdfBaseStream) {
                                smaskData = smask;
                            }
                        }
                        else if (mask) {
                            if (mask instanceof _PdfBaseStream || Array.isArray(mask)) {
                                maskData = mask;
                            }
                        }
                        return [4 /*yield*/, new _PdfImage()._initializeFromImage(xref, imageData, isInline, callBack, smaskData, maskData)];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    _PdfImage.prototype._createMask = function (image, isOffscreenCanvasSupported) {
        var dict = image.dictionary;
        var width = dict.get('W', 'Width');
        var height = dict.get('H', 'Height');
        var interpolate = dict.get('I', 'Interpolate'); // eslint-disable-line
        var decode = dict.getArray('D', 'Decode');
        var inverseDecode = decode && decode[0] > 0;
        var computedLength = ((width + 7) >> 3) * height;
        var imgArray = image.getBytes(computedLength); // eslint-disable-line
        var isSingleOpaquePixel = width === 1 && height === 1 &&
            inverseDecode === (imgArray.length === 0 || !!(imgArray[0] & 128));
        if (isSingleOpaquePixel) {
            return { isSingleOpaquePixel: isSingleOpaquePixel };
        }
        if (isOffscreenCanvasSupported) {
            if (this.imageResizer._needsToBeResized(width, height)) {
                var data_3 = new Uint8ClampedArray(width * height * 4);
                _convertBlackAndWhiteToRGBA(imgArray, 0, data_3, width, height, 0, inverseDecode);
                return this.imageResizer._createImageData({ kind: imageKind.rgba32BPP, data: data_3, width: width, height: height, interpolate: interpolate });
            }
            var canvas = void 0; // eslint-disable-line
            if (this._canvasRenderCallback) {
                canvas = this._canvasRenderCallback.canvas;
            }
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext('2d');
            var imgData = ctx.createImageData(width, height); // eslint-disable-line
            _convertBlackAndWhiteToRGBA(imgArray, 0, imgData.data, width, height, 0, inverseDecode);
            if (typeof (this._options) !== 'undefined') {
                this._processImageRedaction(imgData);
            }
            ctx.putImageData(imgData, 0, 0);
            var format = this._findImageFormat(this._imageFormat);
            var buffer = canvas.toDataURL(format);
            var base64 = buffer.split(',')[1];
            var bytes = _base64ToUint8Array(base64);
            return bytes;
        }
        var actualLength = imgArray.byteLength;
        var haveFullData = computedLength === actualLength;
        var data;
        if (image instanceof _PdfDecodeStream && (!inverseDecode || haveFullData)) {
            data = imgArray;
        }
        else if (!inverseDecode) {
            data = new Uint8Array(imgArray);
        }
        else {
            data = new Uint8Array(computedLength);
            data.set(imgArray);
            data.fill(0xff, actualLength);
        }
        if (inverseDecode) {
            for (var i = 0; i < actualLength; i++) {
                data[i] ^= 0xff;
            }
        }
        return data;
    };
    Object.defineProperty(_PdfImage.prototype, "drawWidth", {
        get: function () {
            return Math.max(this.width, this.smask && this.smask.width || 0, this.mask && this.mask.width || 0);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_PdfImage.prototype, "drawHeight", {
        get: function () {
            return Math.max(this.height, this.smask && this.smask.height || 0, this.mask && this.mask.height || 0);
        },
        enumerable: true,
        configurable: true
    });
    _PdfImage.prototype._decodeBuffer = function (buffer) {
        var bpc = this.bpc;
        var numComps = this.numComps;
        var decodeAddends = this.decodeAddends;
        var decodeCoefficients = this.decodeCoefficients;
        var max = (1 << bpc) - 1;
        var i;
        var ii;
        if (bpc === 1) {
            for (i = 0, ii = buffer.length; i < ii; i++) {
                buffer[i] = +!buffer[i];
            }
            return;
        }
        var index = 0;
        for (i = 0, ii = this.width * this.height; i < ii; i++) {
            for (var j = 0; j < numComps; j++) {
                buffer[index] = _mathClamp(decodeAddends[j] + buffer[index] *
                    decodeCoefficients[j], 0, max);
                index++;
            }
        }
    };
    _PdfImage.prototype._getComponents = function (buffer) {
        var bpc = this.bpc;
        if (bpc === 8) {
            return buffer;
        }
        var width = this.width;
        var height = this.height;
        var numComps = this.numComps;
        var length = width * height * numComps;
        var bufferPos = 0;
        var output; // eslint-disable-line
        if (bpc <= 8) {
            output = new Uint8Array(length);
        }
        else if (bpc <= 16) {
            output = new Uint16Array(length);
        }
        else {
            output = new Uint32Array(length);
        }
        var rowComps = width * numComps;
        var max = (1 << bpc) - 1;
        var i = 0;
        var ii;
        var buf; // eslint-disable-line
        if (bpc === 1) {
            var mask = void 0; // eslint-disable-line
            var loop1End = void 0;
            var loop2End = void 0;
            for (var j = 0; j < height; j++) {
                loop1End = i + (rowComps & ~7);
                loop2End = i + rowComps;
                while (i < loop1End) {
                    buf = buffer[bufferPos++];
                    output[i] = (buf >> 7) & 1;
                    output[i + 1] = (buf >> 6) & 1;
                    output[i + 2] = (buf >> 5) & 1;
                    output[i + 3] = (buf >> 4) & 1;
                    output[i + 4] = (buf >> 3) & 1;
                    output[i + 5] = (buf >> 2) & 1;
                    output[i + 6] = (buf >> 1) & 1;
                    output[i + 7] = buf & 1;
                    i += 8;
                }
                if (i < loop2End) {
                    buf = buffer[bufferPos++];
                    mask = 128;
                    while (i < loop2End) {
                        output[i++] = +!!(buf & mask);
                        mask >>= 1;
                    }
                }
            }
        }
        else {
            var bits = 0;
            buf = 0;
            for (i = 0, ii = length; i < ii; ++i) {
                if (i % rowComps === 0) {
                    buf = 0;
                    bits = 0;
                }
                while (bits < bpc) {
                    buf = (buf << 8) | buffer[bufferPos++];
                    bits += 8;
                }
                var remainingBits = bits - bpc;
                var value = buf >> remainingBits;
                if (value < 0) {
                    value = 0;
                }
                else if (value > max) {
                    value = max;
                }
                output[i] = value;
                buf &= (1 << remainingBits) - 1;
                bits = remainingBits;
            }
        }
        return output;
    };
    _PdfImage.prototype._fillOpacity = function (rgbaBuf, width, height, actualHeight, image) {
        return __awaiter(this, void 0, void 0, function () {
            var smask, mask, alphaBuf, sw, sh, i, ii, j, numComps, opacity, imageOffset, color, maskOffset;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        smask = this.smask;
                        mask = this.mask;
                        if (!smask) return [3 /*break*/, 2];
                        sw = smask.width;
                        sh = smask.height;
                        alphaBuf = new Uint8ClampedArray(sw * sh);
                        return [4 /*yield*/, smask._fillGrayBuffer(alphaBuf)];
                    case 1:
                        _a.sent();
                        if (sw !== width || sh !== height) {
                            alphaBuf = this._resizeImageMask(alphaBuf, smask.bpc, sw, sh, width, height);
                        }
                        return [3 /*break*/, 3];
                    case 2:
                        if (mask) {
                            if (mask instanceof _PdfImage) {
                                sw = mask.width;
                                sh = mask.height;
                                alphaBuf = new Uint8ClampedArray(sw * sh);
                                mask.numComps = 1;
                                mask._fillGrayBuffer(alphaBuf);
                                for (i = 0, ii = sw * sh; i < ii; ++i) {
                                    alphaBuf[i] = 255 - alphaBuf[i];
                                }
                                if (sw !== width || sh !== height) {
                                    alphaBuf = this._resizeImageMask(alphaBuf, mask.bpc, sw, sh, width, height);
                                }
                            }
                            else if (Array.isArray(mask)) {
                                alphaBuf = new Uint8ClampedArray(width * height);
                                numComps = this.numComps;
                                for (i = 0, ii = width * height; i < ii; ++i) {
                                    opacity = 0;
                                    imageOffset = i * numComps;
                                    for (j = 0; j < numComps; ++j) {
                                        color = image[imageOffset + j];
                                        maskOffset = j * 2;
                                        if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
                                            opacity = 255;
                                            break;
                                        }
                                    }
                                    alphaBuf[i] = opacity;
                                }
                            }
                            else {
                                throw new FormatError('Unknown mask format.');
                            }
                        }
                        _a.label = 3;
                    case 3:
                        if (alphaBuf) {
                            for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
                                rgbaBuf[j] = alphaBuf[i];
                            }
                        }
                        else {
                            for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
                                rgbaBuf[j] = 255;
                            }
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    _PdfImage.prototype._undoPreblend = function (buffer, width, height) {
        var matte = this.smask && this.smask.matte; // eslint-disable-line
        if (!matte) {
            return;
        }
        var matteRgb = this.colorSpace._getRgb(matte, 0); // eslint-disable-line
        var matteR = matteRgb[0];
        var matteG = matteRgb[1];
        var matteB = matteRgb[2];
        var length = width * height * 4;
        for (var i = 0; i < length; i += 4) {
            var alpha = buffer[i + 3];
            if (alpha === 0) {
                buffer[i] = 255;
                buffer[i + 1] = 255;
                buffer[i + 2] = 255;
                continue;
            }
            var k = 255 / alpha;
            buffer[i] = (buffer[i] - matteR) * k + matteR;
            buffer[i + 1] = (buffer[i + 1] - matteG) * k + matteG;
            buffer[i + 2] = (buffer[i + 2] - matteB) * k + matteB;
        }
    };
    _PdfImage.prototype._fillGrayBuffer = function (buffer) {
        return __awaiter(this, void 0, void 0, function () {
            var numComps, width, height, bpc, rowBytes, imgArray, comps, i, length, scale;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        numComps = this.numComps;
                        if (numComps !== 1) {
                            throw new FormatError("Reading gray scale from a color image: " + numComps);
                        }
                        width = this.width;
                        height = this.height;
                        bpc = this.bpc;
                        rowBytes = (width * numComps * bpc + 7) >> 3;
                        return [4 /*yield*/, this._getImageBytes(height * rowBytes, { internal: true })];
                    case 1:
                        imgArray = _a.sent();
                        comps = this._getComponents(imgArray);
                        if (bpc === 1) {
                            length = width * height;
                            if (this.needsDecode) {
                                for (i = 0; i < length; ++i) {
                                    buffer[i] = (comps[i] - 1) & 255;
                                }
                            }
                            else {
                                for (i = 0; i < length; ++i) {
                                    buffer[i] = -comps[i] & 255;
                                }
                            }
                            return [2 /*return*/];
                        }
                        if (this.needsDecode) {
                            this._decodeBuffer(comps);
                        }
                        length = width * height;
                        scale = 255 / ((1 << bpc) - 1);
                        for (i = 0; i < length; ++i) {
                            buffer[i] = scale * comps[i];
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    _PdfImage.prototype._createBitmap = function (kind, width, height, src) {
        return __awaiter(this, void 0, void 0, function () {
            var imgData, canvas, ctx, format, buffer, base64, bytes;
            return __generator(this, function (_a) {
                if (this._canvasRenderCallback) {
                    canvas = this._canvasRenderCallback.canvas;
                }
                else {
                    throw new Error('canvas is not defined');
                }
                canvas.width = width;
                canvas.height = height;
                ctx = canvas.getContext('2d');
                if (kind === imageKind.rgba32BPP) {
                    imgData = new ImageData(src, width, height);
                }
                else {
                    imgData = ctx.createImageData(width, height);
                    _convertToRGBA(kind, src, new Uint32Array(imgData.data.buffer), width, height, this.needsDecode);
                }
                if (typeof (this._options) !== 'undefined') {
                    this._processImageRedaction(imgData);
                }
                ctx.putImageData(imgData, 0, 0);
                format = this._findImageFormat(this._imageFormat);
                buffer = canvas.toDataURL(format);
                base64 = buffer.split(',')[1];
                bytes = _base64ToUint8Array(base64);
                return [2 /*return*/, bytes];
            });
        });
    };
    _PdfImage.prototype._getTransferableImage = function () {
        return null;
    };
    _PdfImage.prototype._getImage = function (width, height) {
        var bitmap = this._getTransferableImage(); // eslint-disable-line 
        if (!bitmap) {
            return null;
        }
        return {
            data: null,
            width: width,
            height: height,
            bitmap: bitmap,
            interpolate: this.interpolate
        };
    };
    _PdfImage.prototype._getImageBytes = function (length, _a) {
        var drawWidth = _a.drawWidth, drawHeight = _a.drawHeight, _b = _a.forceRGBA, forceRGBA = _b === void 0 ? false : _b, _c = _a.forceRGB, forceRGB = _c === void 0 ? false : _c, _d = _a.internal, internal = _d === void 0 ? false : _d;
        return __awaiter(this, void 0, void 0, function () {
            var data, imageBytes, platform, imagedata;
            return __generator(this, function (_e) {
                switch (_e.label) {
                    case 0:
                        this.image.reset();
                        this.image.drawWidth = drawWidth || this.width;
                        this.image.drawHeight = drawHeight || this.height;
                        this.image.forceRGBA = !!forceRGBA;
                        this.image.forceRGB = !!forceRGB;
                        imageBytes = this._getImageData(length, this);
                        if (!(this.image instanceof _PdfJpxStream)) return [3 /*break*/, 2];
                        platform = void 0;
                        if (this._canvasRenderCallback) {
                            platform = this._canvasRenderCallback.applicationPlatform;
                        }
                        imagedata = new _PdfImageProcessor();
                        return [4 /*yield*/, imagedata._decodeImage(imageBytes, this.image, platform)];
                    case 1:
                        data = _e.sent();
                        return [2 /*return*/, data];
                    case 2:
                        if (internal || this.image instanceof _PdfDecodeStream) {
                            return [2 /*return*/, imageBytes];
                        }
                        return [2 /*return*/, new Uint8Array(imageBytes)];
                }
            });
        });
    };
    _PdfImage.prototype._processImageRedaction = function (canvasImgData) {
        var pt = 1.3333;
        var bounds = this._bounds;
        var options = this._options;
        var page = this._page;
        var imageBoundInPx = { x: bounds[0], y: bounds[1], width: bounds[2], height: bounds[3] };
        imageBoundInPx.x *= pt;
        imageBoundInPx.y *= pt;
        imageBoundInPx.width *= pt;
        imageBoundInPx.height *= pt;
        var isIntersect = false;
        var rotation = page.rotation;
        var rect;
        for (var i = 0; i < options.length; i++) {
            var redactionBounds = options[i].bounds;
            var intersectBounds = this._intersect({ x: redactionBounds.x * pt, y: redactionBounds.y * pt,
                width: redactionBounds.width * pt, height: redactionBounds.height * pt }, imageBoundInPx);
            if (intersectBounds !== null && imageBoundInPx.height > 0) {
                isIntersect = true;
                this._isIntersect = isIntersect;
                if (rotation !== PdfRotationAngle.angle0 && page.cropBox === page.mediaBox) {
                    switch (rotation) {
                        case PdfRotationAngle.angle180:
                            {
                                intersectBounds = ({ x: (page.size.width * pt) - intersectBounds.x - intersectBounds.width,
                                    y: (page.size.height * pt) - intersectBounds.y - intersectBounds.height,
                                    width: intersectBounds.width, height: intersectBounds.height });
                                var mapX = (page.size.width - (bounds[2] + bounds[0]) - bounds[0]) * pt;
                                var mapY = (page.size.height - (bounds[3] + bounds[1]) - bounds[1]) * pt;
                                rect = ({ x: (intersectBounds.x - (imageBoundInPx.x + mapX)) * canvasImgData.Width / imageBoundInPx.width,
                                    y: (intersectBounds.y - (imageBoundInPx.y + mapY)) * canvasImgData.Height / imageBoundInPx.height,
                                    width: intersectBounds.width * canvasImgData.Width / imageBoundInPx.width,
                                    height: intersectBounds.height * canvasImgData.Height / imageBoundInPx.height });
                            }
                            break;
                        case PdfRotationAngle.angle270:
                            {
                                intersectBounds = ({ x: ((page.size.width * pt) - intersectBounds.y - intersectBounds.height),
                                    y: intersectBounds.x, width: intersectBounds.height,
                                    height: intersectBounds.width });
                                var mappingX = (((page.size.width - (bounds[1] + bounds[2])) - bounds[0]) * pt);
                                rect = ({ x: (intersectBounds.x - (imageBoundInPx.x + mappingX)) * canvasImgData.width / imageBoundInPx.height,
                                    y: ((intersectBounds.y - (imageBoundInPx.x)) * canvasImgData.Height / imageBoundInPx.width),
                                    width: intersectBounds.width * canvasImgData.Width / imageBoundInPx.height,
                                    height: intersectBounds.height * canvasImgData.height / imageBoundInPx.width });
                            }
                            break;
                        case PdfRotationAngle.angle90:
                            {
                                intersectBounds = ({ x: intersectBounds.y, y: ((page.size.height * pt) - intersectBounds.x -
                                        intersectBounds.width), width: intersectBounds.height, height: intersectBounds.width });
                                var mappingY = (((page.size.height - (bounds[0] + bounds[2])) - bounds[1]) * pt);
                                rect = ({ x: (intersectBounds.x - imageBoundInPx.y) * canvasImgData.Width / imageBoundInPx.height,
                                    y: ((intersectBounds.y - (imageBoundInPx.y + mappingY)) * canvasImgData.Height / imageBoundInPx.width),
                                    width: intersectBounds.width * canvasImgData.Width / imageBoundInPx.height, height: intersectBounds.
                                        height * canvasImgData.Height / imageBoundInPx.width });
                            }
                            break;
                        default:
                            rect = ({ x: (intersectBounds.x - imageBoundInPx.x) * canvasImgData.width / imageBoundInPx.width,
                                y: (intersectBounds.y - imageBoundInPx.y) * canvasImgData.height / imageBoundInPx.height,
                                width: intersectBounds.width * canvasImgData.Width / imageBoundInPx.width,
                                height: intersectBounds.height * canvasImgData.Height / imageBoundInPx.height });
                            break;
                    }
                }
                else {
                    rect = ({ x: (intersectBounds.x - imageBoundInPx.x) * canvasImgData.width / imageBoundInPx.width,
                        y: (intersectBounds.y - imageBoundInPx.y) * canvasImgData.height / imageBoundInPx.height,
                        width: intersectBounds.width * canvasImgData.width / imageBoundInPx.width,
                        height: intersectBounds.height * canvasImgData.height / imageBoundInPx.height });
                }
                this._applyRedaction(canvasImgData, rect.x, rect.y, rect.width, rect.height);
            }
        }
    };
    _PdfImage.prototype._intersect = function (a, b) {
        var x1 = Math.max(a.x, b.x);
        var x2 = Math.min(a.x + a.width, b.x + b.width);
        var y1 = Math.max(a.y, b.y);
        var y2 = Math.min(a.y + a.height, b.y + b.height);
        if (x2 >= x1 && y2 >= y1) {
            return { x: x1, y: y1, width: x2 - x1, height: y2 - y1 };
        }
        return null;
    };
    _PdfImage.prototype._applyRedaction = function (imageData, x, y, w, h) {
        var width = imageData.width, height = imageData.height, data = imageData.data;
        var x0 = Math.max(0, Math.floor(x));
        var y0 = Math.max(0, Math.floor(y));
        var x1 = Math.min(width, Math.ceil(x + w));
        var y1 = Math.min(height, Math.ceil(y + h));
        for (var row = y0; row < y1; row++) {
            var i = (row * width + x0) * 4;
            for (var col = x0; col < x1; col++) {
                data[i] = 255;
                data[i + 1] = 255;
                data[i + 2] = 255;
                data[i + 3] = 255;
                i += 4;
            }
        }
    };
    return _PdfImage;
}());
export { _PdfImage };
/**
 * Represents the application platform type.
 *
 * ```typescript
 * // Load an existing PDF document
 * let document: PdfDocument = new PdfDocument(data);
 * // Define a canvas render callback that returns a canvas element and the application platform.
 * const canvasRenderCallback = (): {canvas: any, applicationPlatform: ApplicationPlatform} => {
 *     const canvas = document.createElement('canvas');
 *     return { canvas: canvas, applicationPlatform: ApplicationPlatform.vue };
 * };
 * // Initialize a new instance of the `PdfDataExtractor` class
 * let extractor: PdfDataExtractor = new PdfDataExtractor(document, callBack: canvasRenderCallback);
 * // Extract collection of `PdfEmbeddedImage` from the PDF document.
 * let imageInfoCollection: PdfEmbeddedImage[] = extractor.extractImages({ startPageIndex: 0, endPageIndex: document.pageCount - 1});
 * let imageInfo: PdfEmbeddedImage = imageInfoCollection[0];
 * let data: Uint8Array = imageInfo.data;
 * // Destroy the documents
 * document.destroy();
 */
export var ApplicationPlatform;
(function (ApplicationPlatform) {
    /**
     * Specifies the `typeScript` platform.
     */
    ApplicationPlatform["typescript"] = "typescript";
    /**
     * Specifies the `javascript` platform.
     */
    ApplicationPlatform["javascript"] = "javascript";
    /**
     * Specifies the `angular` platform.
     */
    ApplicationPlatform["angular"] = "angular";
    /**
     * Specifies the `react` platform.
     */
    ApplicationPlatform["react"] = "react";
    /**
     * Specifies the `vue` platform.
     */
    ApplicationPlatform["vue"] = "vue";
    /**
     * Specifies the `aspnetcore` platform.
     */
    ApplicationPlatform["aspnetcore"] = "aspnetcore";
    /**
     * Specifies the `aspnetmvc` platform.
     */
    ApplicationPlatform["aspnetmvc"] = "aspnetmvc";
})(ApplicationPlatform || (ApplicationPlatform = {}));
