/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../../../unisharp/Utils");
const Stream = require("./../../../unisharp/Stream");
const MemoryStream = require("./../../../unisharp/MemoryStream");

const PngWrapper = require("./../misc/PngWrapper");
const PdfObject = require("./PdfObject");
const PdfStringValue = require("./PdfStringValue");
const PdfRect = require("./PdfRect");
const PdfRealValue = require("./PdfRealValue");
const PdfIntValue = require("./PdfIntValue");
const PdfName = require("./PdfName");
const IPdfDictionaryWrapper = require("./IPdfDictionaryWrapper");
const TiffHelperCCITT_Types = require("./../misc/TiffHelperCCITT_Types");
const PdfArray = require("./PdfArray");
const PdfDictionary = require("./PdfDictionary");
const TiffHelper = require("./../misc/TiffHelper");

class PdfImage extends PdfRect {
    
    constructor(xobj, smask = false, fillcol = null, nocontent = false) {
        super();
        this.m_Smask = null;
        this._dic = null;
        this.content = null;
        this.imageWidth = 0;
        this.imageHeight = 0;
        this.dic = xobj;
        xobj.obj = this;
        let wi = xobj.getObject("Width", false);
        if (wi !== null) 
            this.imageWidth = Math.floor(wi.getDouble());
        let hi = xobj.getObject("Height", false);
        if (hi !== null) 
            this.imageHeight = Math.floor(hi.getDouble());
        if (nocontent) 
            return;
        let sub = Utils.as(xobj.getObject("Filter", false), PdfName);
        let data = xobj.getData();
        if (sub === null) {
            let aaa = Utils.as(xobj.getObject("Filter", false), PdfArray);
            if (aaa !== null && aaa.itemsCount === 1) 
                sub = Utils.as(aaa.getItem(0, false), PdfName);
            else if ((aaa !== null && aaa.itemsCount === 2 && (aaa.getItem(0, false) instanceof PdfName)) && aaa.getItem(0, false).name === "FlateDecode") {
                data = xobj.extractData();
                sub = Utils.as(aaa.getItem(1, false), PdfName);
            }
        }
        if (sub !== null && sub.name === "DCTDecode") {
            this.content = data;
            return;
        }
        if (sub !== null && sub.name === "JPXDecode") {
            this.content = data;
            return;
        }
        let mask = null;
        let matte = null;
        let mdic = this.dic.getDictionary("SMask", null);
        if (mdic !== null && matte === null) {
            let mmm = new PdfImage(mdic, true);
            if (mmm.imageHeight === this.imageHeight && mmm.imageWidth === this.imageWidth) {
                mask = mmm;
                matte = Utils.as(mdic.getObject("Matte", false), PdfArray);
            }
        }
        if (sub !== null && sub.name === "CCITTFaxDecode") {
            let parms = xobj.getDictionary("DecodeParms", null);
            if (parms !== null) {
                let k = parms.getIntItem("K");
                let _width = parms.getIntItem("Columns");
                if (_width < 10) 
                    _width = xobj.getIntItem("Width");
                let _height = parms.getIntItem("Rows");
                if (_height < 10) 
                    _height = xobj.getIntItem("Height");
                let invert = false;
                let str = parms.getStringItem("BlackIs1");
                if (str === null) 
                    str = xobj.getStringItem("ImageMask");
                if (str !== null) {
                    if (str === "true") 
                        invert = true;
                }
                if (_width > 0 && _height > 0) {
                    let mem = new MemoryStream(); 
                    try {
                        let tif = new TiffHelper.Tiff(null);
                        tif.writeTiff(mem, _width, _height, (k < 0 ? TiffHelperCCITT_Types.G4 : (k === 0 ? TiffHelperCCITT_Types.G3_2D : TiffHelperCCITT_Types.G3_1D)), 300, 300, invert, data);
                        this.content = mem.toByteArray();
                    }
                    finally {
                        mem.close();
                    }
                }
            }
            return;
        }
        if (((sub === null || ((sub.name === "FlateDecode" || sub.name === "LZWDecode")))) && this.imageWidth > 0 && this.imageHeight > 0) {
            data = xobj.extractData();
            let bpi = xobj.getObject("BitsPerComponent", false);
            let dparms = xobj.getDictionary("DecodeParms", null);
            let predict = 0;
            if (dparms !== null) {
                let pred = Utils.as(dparms.getObject("Predictor", false), PdfIntValue);
                if (pred !== null && pred.val > 1) {
                    predict = pred.val;
                    if (predict >= 10 && (predict < 15)) {
                    }
                }
            }
            let colorsp = xobj.getObject("ColorSpace", false);
            let colorMap = null;
            if (bpi !== null && ((bpi.getDouble() === 8 || bpi.getDouble() === 4 || bpi.getDouble() === 1)) && colorsp !== null) {
                let colorTyp = null;
                let bpiVal = Math.floor(bpi.getDouble());
                let isIccBased = false;
                if (colorsp instanceof PdfName) 
                    colorTyp = colorsp.name;
                else if (colorsp instanceof PdfArray) {
                    let arr = Utils.as(colorsp, PdfArray);
                    let it0 = Utils.as(arr.getItem(0, false), PdfName);
                    if (it0 !== null && it0.name === "ICCBased") 
                        isIccBased = true;
                    if (it0 !== null && it0.name === "Indexed") {
                        let sss = Utils.as(arr.getItem(3, false), PdfStringValue);
                        if (sss !== null) 
                            colorMap = sss.val;
                        else {
                            let ddd = Utils.as(arr.getItem(3, false), PdfDictionary);
                            if (ddd !== null) 
                                colorMap = ddd.extractData();
                        }
                    }
                    let dii = Utils.as(arr.getItem(3, false), PdfDictionary);
                    if (dii === null && arr.itemsCount === 2) {
                        dii = Utils.as(arr.getItem(1, false), PdfDictionary);
                        let ddd = Utils.as(arr.getItem(1, false), PdfDictionary);
                        if (ddd !== null && (ddd.getObject("Alternate", false) instanceof PdfName)) 
                            colorTyp = ddd.getObject("Alternate", false).name;
                    }
                    if (arr.itemsCount > 2 && (arr.getItem(1, false) instanceof PdfArray)) {
                        arr = Utils.as(arr.getItem(1, false), PdfArray);
                        if (arr.itemsCount === 2) {
                            let ddd = Utils.as(arr.getItem(1, false), PdfDictionary);
                            if (ddd !== null && (ddd.getObject("Alternate", false) instanceof PdfName)) 
                                colorTyp = ddd.getObject("Alternate", false).name;
                        }
                    }
                    else if (arr.itemsCount === 4 && (arr.getItem(1, false) instanceof PdfName)) 
                        colorTyp = arr.getItem(1, false).name;
                }
                if (colorTyp === "DeviceRGB" || colorTyp === "DeviceGray" || colorTyp === "DeviceCMYK") {
                    if (data !== null) {
                        let rowWidth = Utils.intDiv(data.length, this.imageHeight);
                        let mmm = data.length % this.imageHeight;
                        let nn = Utils.intDiv(rowWidth, this.imageWidth);
                        if (mmm !== 0) {
                        }
                        if (nn === 0 && (bpiVal < 8)) 
                            nn = 1;
                        let isGray = colorTyp === "DeviceGray";
                        let isCmyk = colorTyp === "DeviceCMYK";
                        if ((nn === 3 || ((nn === 4 && isCmyk)) || ((isCmyk && colorMap !== null))) || bpiVal === 4 || (((nn === 1 && ((colorMap !== null || colorTyp === "DeviceGray"))) || ((bpiVal === 1 && colorMap !== null))))) {
                            if (colorTyp === "DeviceGray") {
                            }
                            if (colorTyp === "DeviceRGB" && colorMap !== null && ((colorMap.length % 3)) === 0) {
                            }
                            if (isCmyk && colorMap !== null) {
                                let rgb = new Uint8Array(((Utils.intDiv(colorMap.length, 4))) * 3);
                                let j = 0;
                                for (let i = 0; (i + 3) < colorMap.length; i += 4) {
                                    rgb[j] = PdfImage._corrCMYK(colorMap[i], colorMap[i + 3]);
                                    rgb[j + 1] = PdfImage._corrCMYK(colorMap[i + 1], colorMap[i + 3]);
                                    rgb[j + 2] = PdfImage._corrCMYK(colorMap[i + 2], colorMap[i + 3]);
                                    j += 3;
                                }
                                colorMap = rgb;
                            }
                            let img = new PngWrapper(this.imageWidth, this.imageHeight, isGray, colorMap, smask);
                            for (let row = 0; row < this.imageHeight; row++) {
                                let pp = row * rowWidth;
                                if (img !== null) 
                                    img.beginRow();
                                if (bpiVal === 1) {
                                    for (let ii = 0; ii < rowWidth; ii++) {
                                        if ((pp + ii) >= data.length) 
                                            break;
                                        let b = data[pp + ii];
                                        for (let jj = 7; jj >= 0; jj--) {
                                            if (img !== null) 
                                                img.addPixelIndex(((((b) >>> jj)) & 1));
                                        }
                                    }
                                }
                                else 
                                    for (let w = 0; w < this.imageWidth; w++) {
                                        if (nn === 3) {
                                            if ((pp + 2) >= data.length) 
                                                break;
                                            let r = data[pp + 0];
                                            let g = data[pp + 1];
                                            let b = data[pp + 2];
                                            if (mask !== null && mask.m_Smask !== null) {
                                                let alpha = mask.m_Smask.getPixelGray(w, row);
                                                fillcol = null;
                                                let m0 = null;
                                                let m1 = null;
                                                let m2 = null;
                                                if (matte !== null && matte.itemsCount === 3) {
                                                    m0 = matte.getItem(0, false);
                                                    m1 = matte.getItem(1, false);
                                                    m2 = matte.getItem(2, false);
                                                }
                                                r = PdfImage._corrSMask(r, alpha, m0, (fillcol === null ? 0 : fillcol.R));
                                                g = PdfImage._corrSMask(g, alpha, m1, (fillcol === null ? 0 : fillcol.G));
                                                b = PdfImage._corrSMask(b, alpha, m2, (fillcol === null ? 0 : fillcol.B));
                                                if ((alpha === (0) && r === (0) && g === (0)) && b === (0)) 
                                                    r = (g = (b = 0xFF));
                                            }
                                            img.addPixelRgb(r, g, b);
                                            pp += 3;
                                        }
                                        else if (nn === 4) {
                                            if ((pp + 3) >= data.length) 
                                                break;
                                            let r = PdfImage._corrCMYK(data[pp], data[pp + 3]);
                                            let g = PdfImage._corrCMYK(data[pp + 1], data[pp + 3]);
                                            let b = PdfImage._corrCMYK(data[pp + 2], data[pp + 3]);
                                            img.addPixelRgb(b, r, g);
                                            pp += 4;
                                        }
                                        else if (colorTyp === "DeviceGray" && colorMap === null) {
                                            if (pp < data.length) {
                                                let bb = data[pp];
                                                img.addPixelGray(bb);
                                                pp += 1;
                                            }
                                        }
                                        else if (pp < data.length) {
                                            let b1 = data[pp];
                                            if (bpiVal === 4) {
                                                if (colorMap !== null) {
                                                    img.addPixelIndex((((b1 >> 4)) & 0xF));
                                                    img.addPixelIndex((b1 & 0xF));
                                                    pp++;
                                                }
                                                else if ((pp + 2) < data.length) {
                                                    let b2 = data[pp + 1];
                                                    let b3 = data[pp + 2];
                                                    img.addPixelRgb(b3, b1, b2);
                                                    img.addPixelRgb(b3, b1, b2);
                                                    pp += 3;
                                                }
                                            }
                                            else {
                                                img.addPixelIndex(b1);
                                                pp += 1;
                                            }
                                        }
                                    }
                                img.endRow();
                            }
                            if (smask) 
                                this.m_Smask = img;
                            else {
                                img.commit();
                                this.content = img.getBytes();
                            }
                            return;
                        }
                    }
                }
            }
        }
    }
    
    get dic() {
        return this._dic;
    }
    set dic(value) {
        this._dic = value;
        return this._dic;
    }
    
    static _corrCMYK(b1, b2) {
        let i = b1;
        i += (b2);
        if (i >= 256) 
            i = 256;
        return (256 - i);
    }
    
    static _corrSMask(c, a, mat, def) {
        let m = 0;
        if (mat instanceof PdfIntValue) 
            m = mat.val * 256;
        else if (mat instanceof PdfRealValue) 
            m = Math.floor((mat.getDouble() * (256)));
        if (m === 0) 
            m = def;
        let res = (c) - m;
        res *= (a);
        res = Utils.intDiv(res, 256);
        res += m;
        let cres = (res & 0xFF);
        return cres;
    }
    
    toString() {
        return (super.toString() + ": Image " + (this.content === null ? "?" : this.content.length.toString()) + " bytes");
    }
    
    static setNewImageContent(__dic, _width, _height, data) {
        let filt = Utils.as(__dic.getObject("Filter", false), PdfName);
        if (filt !== null) 
            filt.name = "DCTDecode";
        else 
            __dic.addObject("Filter", PdfName._new228("DCTDecode"));
        __dic.setData(data);
        let wi = Utils.as(__dic.getObject("Width", false), PdfIntValue);
        if (wi !== null) 
            wi.val = _width;
        else 
            __dic.addObject("Width", PdfIntValue._new229(_width));
        let hi = Utils.as(__dic.getObject("Height", false), PdfIntValue);
        if (hi !== null) 
            hi.val = _height;
        else 
            __dic.addObject("Height", PdfIntValue._new229(_height));
        __dic.addObject("SMask", null);
        let col = __dic.getObject("ColorSpace", false);
        if (col !== null && (col instanceof PdfName)) 
            col.name = "DeviceRGB";
        else 
            __dic.addObject("ColorSpace", PdfName._new228("DeviceRGB"));
    }
}


module.exports = PdfImage