import { _convertToRGBA, imageKind, maximumCount } from './image-utils';
import { _isLittleEndian } from '@syncfusion/ej2-pdf';
var _PdfImageResizer = /** @class */ (function () {
    function _PdfImageResizer(imgData, isMask) {
        this.minimumImageDimension = 2048;
        this.maximumImageDimension = 65537;
        this.error = 128;
        this.goodSquareLength = 2048;
        this.isImageDecoderSupported = false; //FeatureTest.isImageDecoderSupported;
        this._hasMaxArea = false;
        if (typeof (imgData) !== 'undefined' && typeof (isMask) !== 'undefined') {
            this._imgData = imgData;
            this._isMask = isMask;
        }
    }
    Object.defineProperty(_PdfImageResizer.prototype, "canUseImageDecoder", {
        get: function () {
            return this.isImageDecoderSupported ? Promise.resolve(false) : Promise.resolve(false);
        },
        enumerable: true,
        configurable: true
    });
    _PdfImageResizer.prototype._needsToBeResized = function (width, height) {
        if (width <= this.goodSquareLength && height <= this.goodSquareLength) {
            return false;
        }
        var _maximumDim = this._maximumDim;
        if (width > _maximumDim || height > _maximumDim) {
            return true;
        }
        var area = width * height;
        if (this._hasMaxArea) {
            return area > this._maximumArea;
        }
        if (area < Math.pow(this.goodSquareLength, 2)) {
            return false;
        }
        if (this._areGoodDims(width, height)) {
            this.goodSquareLength = Math.max(this.goodSquareLength, Math.floor(Math.sqrt(width * height)));
            return false;
        }
        this.goodSquareLength = this._guessMax(this.goodSquareLength, _maximumDim, this.error, 0);
        var maxArea = (this._maximumArea = Math.pow(this.goodSquareLength, 2));
        return area > maxArea;
    };
    _PdfImageResizer.prototype._getReducePowerForJPX = function (width, height, componentsCount) {
        var area = width * height;
        var maxJPXArea = Math.pow(2, 30) / (componentsCount * 4);
        if (!this._needsToBeResized(width, height)) {
            if (area > maxJPXArea) {
                return Math.ceil(Math.log2(area / maxJPXArea));
            }
            return 0;
        }
        var _a = this, _maximumDim = _a._maximumDim, _maximumArea = _a._maximumArea;
        var minFactor = Math.max(width / _maximumDim, height / _maximumDim, Math.sqrt(area / Math.min(maxJPXArea, _maximumArea)));
        return Math.ceil(Math.log2(minFactor));
    };
    Object.defineProperty(_PdfImageResizer.prototype, "_maximumDim", {
        get: function () {
            return this._guessMax(this.maximumImageDimension, this.maximumImageDimension, 0, 1);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_PdfImageResizer.prototype, "_maximumArea", {
        get: function () {
            this._hasMaxArea = true;
            return Math.pow(this._guessMax(this.goodSquareLength, this._maximumDim, this.error, 0), 2);
        },
        set: function (area) {
            if (area >= 0) {
                this._hasMaxArea = true;
            }
        },
        enumerable: true,
        configurable: true
    });
    _PdfImageResizer.prototype._setOptions = function (_a) {
        var _b = _a.canvasMaxAreaInBytes, canvasMaxAreaInBytes = _b === void 0 ? -1 : _b, _c = _a.isImageDecoderSupported, isImageDecoderSupported = _c === void 0 ? false : _c;
        if (!this._hasMaxArea) {
            this._maximumArea = canvasMaxAreaInBytes >> 2;
        }
        this.isImageDecoderSupported = isImageDecoderSupported;
    };
    _PdfImageResizer.prototype._areGoodDims = function (width, height) {
        try {
            var canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext('2d');
            ctx.fillRect(0, 0, 1, 1);
            var opacity = ctx.getImageData(0, 0, 1, 1).data[3]; // eslint-disable-line
            canvas.width = canvas.height = 1;
            return opacity !== 0;
        }
        catch (_a) {
            return false;
        }
    };
    _PdfImageResizer.prototype._guessMax = function (start, end, tolerance, defaultHeight) {
        while (start + tolerance + 1 < end) {
            var middle = Math.floor((start + end) / 2);
            var height = defaultHeight || middle;
            if (this._areGoodDims(middle, height)) {
                start = middle;
            }
            else {
                end = middle;
            }
        }
        return start;
    };
    _PdfImageResizer.prototype._createImageData = function (imgData, isMask) {
        if (isMask === void 0) { isMask = false; }
        return new _PdfImageResizer(imgData, isMask)._createImage();
    };
    _PdfImageResizer.prototype._createImage = function () {
        var imgData = this._imgData;
        var width = imgData.width, height = imgData.height;
        if (width * height * 4 > maximumCount) {
            var result_1 = this._rescaleImageData(); // eslint-disable-line
            if (result_1) {
                return result_1;
            }
        }
        var data = this._encodeBMP(); // eslint-disable-line
        var imagePromise; // eslint-disable-line
        var _a = this, _maximumArea = _a._maximumArea, _maximumDim = _a._maximumDim;
        var minFactor = Math.max(width / _maximumDim, height / _maximumDim, Math.sqrt((width * height) / _maximumArea));
        var firstFactor = Math.max(minFactor, 2);
        var factor = Math.round(10 * (minFactor + 1.25)) / 10 / firstFactor;
        var n = Math.floor(Math.log2(factor));
        var steps = new Array(n + 2).fill(2); // eslint-disable-line
        steps[0] = firstFactor;
        steps.splice(-1, 1, factor / (1 << n));
        var newWidth = width;
        var newHeight = height;
        var result = imagePromise; // eslint-disable-line
        var bitmap = result.image || result; // eslint-disable-line
        for (var _i = 0, steps_1 = steps; _i < steps_1.length; _i++) {
            var step = steps_1[_i];
            var prevWidth = newWidth;
            var prevHeight = newHeight;
            newWidth = Math.floor(newWidth / step) - 1;
            newHeight = Math.floor(newHeight / step) - 1;
            var canvas = document.createElement('canvas');
            canvas.width = newWidth;
            canvas.height = newHeight;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
            bitmap.close();
        }
        imgData.data = null;
        imgData.bitmap = bitmap;
        imgData.width = newWidth;
        imgData.height = newHeight;
        return imgData;
    };
    _PdfImageResizer.prototype._rescaleImageData = function () {
        var imgData = this._imgData;
        var data = imgData.data, width = imgData.width, height = imgData.height, kind = imgData.kind;
        var rgbaSize = width * height * 4;
        var k = Math.ceil(Math.log2(rgbaSize / maximumCount));
        var newWidth = width >> k;
        var newHeight = height >> k;
        var rgbaData = null;
        var maxHeight = height;
        try {
            rgbaData = new Uint8Array(rgbaSize);
        }
        catch (_a) {
            var n = Math.floor(Math.log2(rgbaSize + 1));
            while (true) { // eslint-disable-line
                try {
                    rgbaData = new Uint8Array(Math.pow(2, n) - 1);
                    break;
                }
                catch (_b) {
                    n -= 1;
                }
            }
            maxHeight = Math.floor((Math.pow(2, n) - 1) / (width * 4));
            var newSize = width * maxHeight * 4;
            if (newSize < rgbaData.length) {
                rgbaData = new Uint8Array(newSize);
            }
        }
        if (rgbaData === null) {
            return null;
        }
        var src32 = new Uint32Array(rgbaData.buffer);
        var dest32 = new Uint32Array(newWidth * newHeight);
        var newIndex = 0;
        var step = Math.ceil(height / maxHeight);
        var remainder = height % maxHeight === 0 ? height : height % maxHeight;
        for (var k_1 = 0; k_1 < step; k_1++) {
            var h = k_1 < step - 1 ? maxHeight : remainder;
            _convertToRGBA(kind, data, src32, width, h, this._isMask);
            for (var i = 0, ii = h >> k_1; i < ii; i++) {
                var buf = src32.subarray((i << k_1) * width);
                for (var j = 0; j < newWidth; j++) {
                    dest32[newIndex++] = buf[j << k_1];
                }
            }
        }
        if (this._needsToBeResized(newWidth, newHeight)) {
            imgData.data = dest32;
            imgData.width = newWidth;
            imgData.height = newHeight;
            imgData.kind = imageKind.rgba32BPP;
            return null;
        }
        var canvas = document.createElement('canvas');
        canvas.width = newWidth;
        canvas.height = newHeight;
        var ctx = canvas.getContext('2d');
        ctx.putImageData(new ImageData(new Uint8ClampedArray(dest32.buffer), newWidth, newHeight), 0, 0);
        imgData.data = null;
        //imgData.bitmap = canvas.transferToImageBitmap();
        imgData.width = newWidth;
        imgData.height = newHeight;
        return imgData;
    };
    _PdfImageResizer.prototype._encodeBMP = function () {
        var _a = this._imgData, width = _a.width, height = _a.height, kind = _a.kind;
        var data = this._imgData.data; // eslint-disable-line
        var bitPerPixel;
        var view;
        var colorTable = new Uint8Array(0);
        var maskTable = colorTable;
        var compression = 0;
        switch (kind) {
            case imageKind.grayScale1Bpp: {
                bitPerPixel = 1;
                colorTable = new Uint8Array(this._isMask ? [255, 255, 255, 255, 0, 0, 0, 0] : [0, 0, 0, 0, 255, 255, 255, 255]);
                var rowLen = (width + 7) >> 3;
                var rowSize = (rowLen + 3) & -4;
                if (rowLen !== rowSize) {
                    var newData = new Uint8Array(rowSize * height);
                    var k = 0;
                    for (var i_1 = 0, ii = height * rowLen; i_1 < ii; i_1 += rowLen, k += rowSize) {
                        newData.set(data.subarray(i_1, i_1 + rowLen), k);
                    }
                    data = newData;
                }
                break;
            }
            case imageKind.rgb24BPP: {
                bitPerPixel = 24;
                if (width & 3) {
                    var rowLen = 3 * width;
                    var rowSize = (rowLen + 3) & -4;
                    var extraLen = rowSize - rowLen;
                    var newData = new Uint8Array(rowSize * height);
                    var k = 0;
                    for (var i_2 = 0, ii = height * rowLen; i_2 < ii; i_2 += rowLen) {
                        var row = data.subarray(i_2, i_2 + rowLen); // eslint-disable-line
                        for (var j = 0; j < rowLen; j += 3) {
                            newData[k++] = row[j + 2];
                            newData[k++] = row[j + 1];
                            newData[k++] = row[j];
                        }
                        k += extraLen;
                    }
                    data = newData;
                }
                else {
                    for (var i_3 = 0, ii = data.length; i_3 < ii; i_3 += 3) {
                        var tmp = data[i_3]; // eslint-disable-line
                        data[i_3] = data[i_3 + 2];
                        data[i_3 + 2] = tmp;
                    }
                }
                break;
            }
            case imageKind.rgba32BPP:
                bitPerPixel = 32;
                compression = 3;
                maskTable = new Uint8Array(4 + 4 + 4 + 4 + 52);
                view = new DataView(maskTable.buffer);
                if (_isLittleEndian()) {
                    view.setUint32(0, 0x000000ff, true);
                    view.setUint32(4, 0x0000ff00, true);
                    view.setUint32(8, 0x00ff0000, true);
                    view.setUint32(12, 0xff000000, true);
                }
                else {
                    view.setUint32(0, 0xff000000, true);
                    view.setUint32(4, 0x00ff0000, true);
                    view.setUint32(8, 0x0000ff00, true);
                    view.setUint32(12, 0x000000ff, true);
                }
                break;
            default:
                throw new Error('invalid format');
        }
        var i = 0;
        var headerLength = 40 + maskTable.length;
        var fileLength = 14 + headerLength + colorTable.length + data.length;
        var bmpData = new Uint8Array(fileLength);
        view = new DataView(bmpData.buffer);
        view.setUint16(i, 0x4d42, true);
        i += 2;
        view.setUint32(i, fileLength, true);
        i += 4;
        view.setUint32(i, 0, true);
        i += 4;
        view.setUint32(i, 14 + headerLength + colorTable.length, true);
        i += 4;
        view.setUint32(i, headerLength, true);
        i += 4;
        view.setInt32(i, width, true);
        i += 4;
        view.setInt32(i, -height, true);
        i += 4;
        view.setUint16(i, 1, true);
        i += 2;
        view.setUint16(i, bitPerPixel, true);
        i += 2;
        view.setUint32(i, compression, true);
        i += 4;
        view.setUint32(i, 0, true);
        i += 4;
        view.setInt32(i, 0, true);
        i += 4;
        view.setInt32(i, 0, true);
        i += 4;
        view.setUint32(i, colorTable.length / 4, true);
        i += 4;
        view.setUint32(i, 0, true);
        i += 4;
        bmpData.set(maskTable, i);
        i += maskTable.length;
        bmpData.set(colorTable, i);
        i += colorTable.length;
        bmpData.set(data, i);
        return bmpData;
    };
    return _PdfImageResizer;
}());
export { _PdfImageResizer };
