UNPKG

term-kitty-img

Version:

Show images in your kitty terminal

158 lines 6.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.terminalKittyImage = exports.UnsupportedTerminalError = exports.getKittySupport = exports.drawImageFromBuffer = exports.drawImageFromUrl = exports.hasLocalSupport = exports.hasImageSupport = void 0; const node_os_1 = __importDefault(require("node:os")); const node_child_process_1 = __importDefault(require("node:child_process")); const node_fs_1 = __importDefault(require("node:fs")); const node_path_1 = __importDefault(require("node:path")); const node_readline_1 = __importDefault(require("node:readline")); const node_process_1 = require("node:process"); const jimp_1 = __importDefault(require("jimp")); const rl = node_readline_1.default.createInterface(node_process_1.stdin); const IMAGE_REGEX = /_Gi=69[;,]OK/g; const LOCAL_REGEX = /_Gi=31[;,]OK/g; async function hasImageSupport() { node_process_1.stdin.setRawMode(true); node_process_1.stdin.resume(); let data = ""; node_process_1.stdin.on("data", function (chunk) { data += chunk.toString(); }); const subprocess = node_child_process_1.default.spawn(`printf`, [`\\033_Gi=69,s=1,v=1,a=q,t=d,f=24;AAAA\\033\\\\\\033[c`], { stdio: [node_process_1.stdin, node_process_1.stdout, "pipe"], }); const all = await new Promise((resolve) => { setTimeout(() => { resolve(data); node_process_1.stdin.pause(); subprocess.kill(); }, 20); }); // clear line rl.write("", { ctrl: true, name: "u" }); return IMAGE_REGEX.test(all); } exports.hasImageSupport = hasImageSupport; async function hasLocalSupport() { // create a temp file that will hold a 1x1 image const image = new jimp_1.default(1, 1, "#00000077"); const tmpFilePath = node_path_1.default.join(node_os_1.default.tmpdir(), `.tmp.kitty.${Math.random().toString().slice(2) || "0"}`); image.write(tmpFilePath); node_process_1.stdin.setRawMode(true); node_process_1.stdin.resume(); let data = ""; node_process_1.stdin.on("data", function (chunk) { data += chunk.toString(); }); const subprocess = node_child_process_1.default.spawn(`printf`, [ `${`\\033_Gi=31,s=1,v=1,a=q,t=t;${Buffer.from(tmpFilePath).toString("base64")}\\033\\\\`}`, ], { stdio: [node_process_1.stdin, node_process_1.stdout, "pipe"], }); const all = await new Promise((resolve) => { setTimeout(() => { resolve(data); node_process_1.stdin.pause(); subprocess.kill(); }, 20); }); // clear line rl.write("", { ctrl: true, name: "u" }); return LOCAL_REGEX.test(all); } exports.hasLocalSupport = hasLocalSupport; async function drawImageFromUrl(pngBuffer) { const tmpFilePath = node_path_1.default.join(node_os_1.default.tmpdir(), `.tmp.kitty.${Math.random().toString().slice(2) || "0"}.png`); node_fs_1.default.writeFileSync(tmpFilePath, pngBuffer); const subprocess = node_child_process_1.default.spawn(`printf`, [ `\\033_Gf=100,t=t,a=T,X=4,Y=4;${Buffer.from(tmpFilePath).toString("base64")}\\033\\\\`, ], { stdio: ["pipe", "inherit", "pipe"], }); await new Promise((resolve) => { setTimeout(() => { node_child_process_1.default.spawnSync(`printf`, [`\n`], { stdio: ["pipe", "inherit", "pipe"], }); resolve(undefined); subprocess.kill(); }, 20); }); } exports.drawImageFromUrl = drawImageFromUrl; async function drawImageFromBuffer(pngBuffer) { const asBase64 = pngBuffer.toString("base64"); const chunks = []; for (let i = 0; i < asBase64.length; i += 256) { chunks.push(asBase64.slice(i, i + 256)); } for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; node_child_process_1.default.spawnSync(`printf`, [ `\\033_Gf=100,m=${i === chunks.length - 1 ? 0 : 1},a=T,X=4,Y=4;${chunk}\\033\\\\`, ], { stdio: ["pipe", "inherit", "pipe"], }); } node_child_process_1.default.spawnSync(`printf`, [`\n`], { stdio: "inherit", }); } exports.drawImageFromBuffer = drawImageFromBuffer; let kittySupport; const getKittySupport = async () => { if (kittySupport === undefined) { kittySupport = (await hasImageSupport()) ? (await hasLocalSupport()) ? "local" : "remote" : "none"; } node_process_1.stdin.destroy(); return kittySupport; }; exports.getKittySupport = getKittySupport; class UnsupportedTerminalError extends Error { constructor() { super("Terminal must support Kitty graphics protocol"); this.name = "UnsupportedTerminalError"; } } exports.UnsupportedTerminalError = UnsupportedTerminalError; function unsupported() { throw new UnsupportedTerminalError(); } const terminalKittyImage = async (image, options = {}) => { var _a, _b, _c, _d, _e; const fallback = (_a = options.fallback) !== null && _a !== void 0 ? _a : unsupported; const kittySupport = await (0, exports.getKittySupport)(); const imagePath = node_path_1.default.resolve(process.cwd(), image.toString()); let pngBuffer; if (typeof image === "string") { const image = await jimp_1.default.read(imagePath); if ((options === null || options === void 0 ? void 0 : options.preserveAspectRatio) === false) { image.resize((_b = options.width) !== null && _b !== void 0 ? _b : jimp_1.default.AUTO, (_c = options.height) !== null && _c !== void 0 ? _c : jimp_1.default.AUTO); } else { image.scaleToFit((_d = options.width) !== null && _d !== void 0 ? _d : 600, (_e = options.height) !== null && _e !== void 0 ? _e : 600); } pngBuffer = await image.getBufferAsync("image/png"); } else { pngBuffer = image; } if (kittySupport === "local" && typeof image === "string") { await drawImageFromUrl(pngBuffer); return; } else if (kittySupport !== "none") { await drawImageFromBuffer(pngBuffer); return; } return fallback(); }; exports.terminalKittyImage = terminalKittyImage; //# sourceMappingURL=index.js.map