term-kitty-img
Version:
Show images in your kitty terminal
158 lines • 6.42 kB
JavaScript
;
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