@fx-/chat-ink 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ //#region src/kitty/jpeg.d.ts
2
+ interface JpegDecoderOptions {
3
+ /** Largest width and height in pixels after downscaling (default 1600 × 1600). */
4
+ maxWidth?: number;
5
+ maxHeight?: number;
6
+ /** Refuse images above this many megapixels before decoding (default 50). */
7
+ maxMegapixels?: number;
8
+ }
9
+ /** Whether bytes start with the JPEG signature. */
10
+ declare function isJpeg(bytes: Uint8Array): boolean;
11
+ /** The size that fits `width` × `height` into the bounds, keeping aspect, never upscaling. */
12
+ declare function fitSize(width: number, height: number, maxWidth: number, maxHeight: number): {
13
+ width: number;
14
+ height: number;
15
+ };
16
+ /** Downscale RGBA pixels by averaging the source area under each target pixel. */
17
+ declare function downscale(data: Uint8Array, width: number, height: number, toWidth: number, toHeight: number): Uint8Array;
18
+ /**
19
+ * A decoder for `createKittyProvider({ decode })`: JPEG bytes become a
20
+ * downscaled PNG; anything else is declined (`undefined`), as is a JPEG that
21
+ * fails to decode or is too large.
22
+ */
23
+ declare function createJpegDecoder(options?: JpegDecoderOptions): (bytes: Uint8Array, _mediaType: string) => Promise<Uint8Array | undefined>;
24
+
25
+ //#endregion
26
+ export { JpegDecoderOptions, createJpegDecoder, downscale, fitSize, isJpeg };
@@ -0,0 +1,84 @@
1
+ import { encode } from "fast-png";
2
+ import { decode } from "jpeg-js";
3
+
4
+ //#region src/kitty/jpeg.ts
5
+ /** Whether bytes start with the JPEG signature. */
6
+ function isJpeg(bytes) {
7
+ return bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255;
8
+ }
9
+ /** The size that fits `width` × `height` into the bounds, keeping aspect, never upscaling. */
10
+ function fitSize(width, height, maxWidth, maxHeight) {
11
+ const scale = Math.min(1, maxWidth / width, maxHeight / height);
12
+ return {
13
+ width: Math.max(1, Math.round(width * scale)),
14
+ height: Math.max(1, Math.round(height * scale))
15
+ };
16
+ }
17
+ /** Downscale RGBA pixels by averaging the source area under each target pixel. */
18
+ function downscale(data, width, height, toWidth, toHeight) {
19
+ if (toWidth === width && toHeight === height) return data;
20
+ const out = new Uint8Array(toWidth * toHeight * 4);
21
+ const sx = width / toWidth;
22
+ const sy = height / toHeight;
23
+ for (let y = 0; y < toHeight; y++) {
24
+ const y0 = Math.floor(y * sy);
25
+ const y1 = Math.max(y0 + 1, Math.floor((y + 1) * sy));
26
+ for (let x = 0; x < toWidth; x++) {
27
+ const x0 = Math.floor(x * sx);
28
+ const x1 = Math.max(x0 + 1, Math.floor((x + 1) * sx));
29
+ const sum = [
30
+ 0,
31
+ 0,
32
+ 0,
33
+ 0
34
+ ];
35
+ for (let yy = y0; yy < y1; yy++) for (let xx = x0; xx < x1; xx++) {
36
+ const i = (yy * width + xx) * 4;
37
+ for (let c = 0; c < 4; c++) sum[c] = sum[c] + data[i + c];
38
+ }
39
+ const n = (y1 - y0) * (x1 - x0);
40
+ const o = (y * toWidth + x) * 4;
41
+ for (let c = 0; c < 4; c++) out[o + c] = Math.round(sum[c] / n);
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * A decoder for `createKittyProvider({ decode })`: JPEG bytes become a
48
+ * downscaled PNG; anything else is declined (`undefined`), as is a JPEG that
49
+ * fails to decode or is too large.
50
+ */
51
+ function createJpegDecoder(options = {}) {
52
+ const { maxWidth = 1600, maxHeight = 1600, maxMegapixels = 50 } = options;
53
+ for (const [name, value] of Object.entries({
54
+ maxWidth,
55
+ maxHeight,
56
+ maxMegapixels
57
+ })) if (!(value > 0 && Number.isFinite(value))) throw new RangeError(`${name} must be a positive finite number, got ${value}`);
58
+ return async (bytes, _mediaType) => {
59
+ if (!isJpeg(bytes)) return void 0;
60
+ let image;
61
+ try {
62
+ image = decode(bytes, {
63
+ useTArray: true,
64
+ formatAsRGBA: true,
65
+ maxResolutionInMP: maxMegapixels,
66
+ maxMemoryUsageInMB: 1024
67
+ });
68
+ } catch {
69
+ return void 0;
70
+ }
71
+ const size = fitSize(image.width, image.height, maxWidth, maxHeight);
72
+ const data = downscale(image.data, image.width, image.height, size.width, size.height);
73
+ return encode({
74
+ width: size.width,
75
+ height: size.height,
76
+ data,
77
+ channels: 4,
78
+ depth: 8
79
+ });
80
+ };
81
+ }
82
+
83
+ //#endregion
84
+ export { createJpegDecoder, downscale, fitSize, isJpeg };
@@ -0,0 +1,86 @@
1
+ import { CellBox, ImageProvider } from "./images.d-KUBzdbd9.js";
2
+
3
+ //#region src/kitty/diacritics.d.ts
4
+ /**
5
+ * Row/column combining diacritics for kitty Unicode placeholders, in order:
6
+ * the n-th code point encodes the number n. From the kitty graphics
7
+ * protocol's published list (`gen/rowcolumn-diacritics.txt`, 297 entries).
8
+ */
9
+ declare const DIACRITICS: readonly number[];
10
+
11
+ //#endregion
12
+ //#region src/kitty/provider.d.ts
13
+ /** Ids available to images (the 256-colour foreground carries the id). */
14
+ declare const MAX_IMAGES = 255;
15
+ /** The largest width or height in pixels a terminal accepts (kitty's and ghostty's limit). */
16
+ declare const MAX_IMAGE_SIDE = 10000;
17
+ /** The largest grid in cells: one combining diacritic per row and per column number. */
18
+ declare const MAX_CELLS: number;
19
+ /** Whether the terminal speaks the kitty graphics protocol (and is not behind a multiplexer). */
20
+ declare function detectKitty(env?: Record<string, string | undefined>): boolean;
21
+ declare function isPng(bytes: Uint8Array): boolean;
22
+ /**
23
+ * A PNG's pixel size from its header: undefined unless the signature is
24
+ * followed by a complete IHDR chunk (length, type, data, CRC) whose CRC
25
+ * matches and whose fields are legal. The image data is not decoded here.
26
+ */
27
+ declare function pngSize(bytes: Uint8Array): {
28
+ width: number;
29
+ height: number;
30
+ } | undefined;
31
+ /**
32
+ * The cells an image of `px` pixels takes in `box`, keeping its aspect and
33
+ * never upscaling. The box is first capped to `MAX_CELLS` each way, the most
34
+ * rows and columns placeholders can number.
35
+ */
36
+ declare function fitCells(px: {
37
+ width: number;
38
+ height: number;
39
+ }, within: CellBox, cell: {
40
+ width: number;
41
+ height: number;
42
+ }): CellBox;
43
+ /** Placeholder text for an image: one string per cell row, at most `MAX_CELLS` each way. */
44
+ declare function placeholderRows(columns: number, rows: number): string[];
45
+ /** Transmit PNG bytes quietly under `id`, in protocol-sized chunks. */
46
+ declare function transmit(id: number, png: Uint8Array): string;
47
+ /** One virtual placement for `id`, sized to a cell box (replacing the previous one). */
48
+ declare function place(id: number, box: CellBox): string;
49
+ /** Forget an image and its placements. */
50
+ declare function forget(id: number): string;
51
+ /** Ask the terminal for its cell size in pixels. */
52
+ declare const CELL_SIZE_QUERY: string;
53
+ interface KittyOptions {
54
+ /** Writes escapes to the terminal (before the frame showing the placeholders). */
55
+ write: (data: string) => void;
56
+ fetch?: typeof fetch;
57
+ /** Turns other formats into PNG bytes; without it they stay captions. */
58
+ decode?: (bytes: Uint8Array, mediaType: string) => Promise<Uint8Array | undefined>;
59
+ /** Sources loaded without a click (default: `data:` URLs only). */
60
+ autoFetch?: (src: string) => boolean;
61
+ /** Per fetch, in ms (default 15 s). */
62
+ timeoutMs?: number;
63
+ /** Largest image in bytes, fetched or decoded (default 20 MB). */
64
+ maxBytes?: number;
65
+ /**
66
+ * Largest image in megapixels, PNG or decoded (default 50); each side is
67
+ * also held to `MAX_IMAGE_SIDE`. The terminal inflates what it is sent, so
68
+ * a small, highly compressed PNG is bounded by its pixels, not its bytes.
69
+ */
70
+ maxMegapixels?: number;
71
+ }
72
+ interface KittyProvider extends ImageProvider {
73
+ /** The cell-size query (the viewport writes it once). */
74
+ readonly query: string;
75
+ /** The current cell size in pixels (9×18 until the terminal answers). */
76
+ readonly cellSize: {
77
+ width: number;
78
+ height: number;
79
+ };
80
+ /** Recognise a cell-size reply; returns whether `input` was one. */
81
+ takeReply(input: string): boolean;
82
+ }
83
+ declare function createKittyProvider(options: KittyOptions): KittyProvider;
84
+
85
+ //#endregion
86
+ export { CELL_SIZE_QUERY, DIACRITICS, KittyOptions, KittyProvider, MAX_CELLS, MAX_IMAGES, MAX_IMAGE_SIDE, createKittyProvider, detectKitty, fitCells, forget, isPng, place, placeholderRows, pngSize, transmit };