Liking cljdoc? Tell your friends :D

com.blockether.vis.ext.channel-tui.terminal-image

Inline terminal image rendering — Kitty graphics protocol / iTerm2 inline images.

The pixel-free logic (capability detection, intrinsic dimension sniffing, cell-box sizing, escape encoding, base64/PNG transcoding) now lives in the lanterna fork's Java class com.googlecode.lanterna.terminal.image.TerminalImage. This namespace is the thin Clojure adapter that keeps vis's map-shaped API ({:images …}, {:w :h}, {:cols :rows}) plus the attachment-aware paste probe, which reaches back into vis internals and so stays here.

The escape strings are emitted DIRECTLY to the tty AFTER Lanterna's delta refresh (the screen loop owns that), placed over rows the renderer reserved as blanks. Lanterna never sees the graphics bytes, so its cell diff stays intact and the image survives subsequent delta frames.

Inline terminal image rendering — Kitty graphics protocol / iTerm2 inline
images.

The pixel-free logic (capability detection, intrinsic dimension sniffing,
cell-box sizing, escape encoding, base64/PNG transcoding) now lives in the
lanterna fork's Java class
`com.googlecode.lanterna.terminal.image.TerminalImage`. This namespace is the
thin Clojure adapter that keeps vis's map-shaped API (`{:images …}`,
`{:w :h}`, `{:cols :rows}`) plus the attachment-aware paste probe, which
reaches back into vis internals and so stays here.

The escape strings are emitted DIRECTLY to the tty AFTER Lanterna's delta
refresh (the screen loop owns that), placed over rows the renderer
reserved as blanks. Lanterna never sees the graphics bytes, so its cell
diff stays intact and the image survives subsequent delta frames.
raw docstring

attachment-cache-dirclj

(attachment-cache-dir)

Durable cache dir (~/.vis/cache/tui-attachments) for persisted image attachments, so a re-rendered history image survives its original (often OS-temp) source path vanishing. Created on demand.

Durable cache dir (`~/.vis/cache/tui-attachments`) for persisted image
attachments, so a re-rendered history image survives its original (often
OS-temp) source path vanishing. Created on demand.
sourceraw docstring

box-pixelsclj

(box-pixels cols rows)

Long-edge PIXEL ceiling of a cols×rows cell box — what to ask a decoder for when the result will be drawn into that box.

Decoding 1080p for an 80-column window produces about six times the pixels the cells can show: seconds of extra decode and tens of megabytes of extra escape bytes, all of it thrown away by the terminal's own downscale. The fork reads its LIVE cell metrics, so a HiDPI cell asks for a proportionally sharper picture.

Long-edge PIXEL ceiling of a `cols`×`rows` cell box — what to ask a decoder
for when the result will be drawn into that box.

Decoding 1080p for an 80-column window produces about six times the pixels
the cells can show: seconds of extra decode and tens of megabytes of extra
escape bytes, all of it thrown away by the terminal's own downscale. The fork
reads its LIVE cell metrics, so a HiDPI cell asks for a proportionally
sharper picture.
sourceraw docstring

cell-pixelsclj

(cell-pixels)

The terminal's current CELL size in pixels, {:w :h}.

The terminal's current CELL size in pixels, `{:w :h}`.
sourceraw docstring

cell-sizeclj

(cell-size {:keys [w h]} max-cols max-rows)

Fit an image of {:w :h} px into max-cols × max-rows cells, aspect-preserving. Returns {:cols :rows} (>= 1).

Fit an image of `{:w :h}` px into `max-cols` × `max-rows` cells,
aspect-preserving. Returns `{:cols :rows}` (>= 1).
sourceraw docstring

detect-capabilitiesclj

(detect-capabilities)
(detect-capabilities env)

Sniff which inline-image protocol the host terminal speaks from env (defaults to the process environment). Returns {:images :kitty|:iterm2|nil}. tmux and screen report nil — they don't reliably forward graphics.

Sniff which inline-image protocol the host terminal speaks from `env`
(defaults to the process environment). Returns `{:images :kitty|:iterm2|nil}`.
tmux and screen report `nil` — they don't reliably forward graphics.
sourceraw docstring

encode-iterm2clj

(encode-iterm2 data {:keys [cols]})

iTerm2 \x1b]1337;File= inline-image sequence for data (base64 String or RAW image bytes, base64'd into the escape without an intermediate String).

iTerm2 `\x1b]1337;File=` inline-image sequence for `data` (base64 String or
RAW image bytes, base64'd into the escape without an intermediate String).
sourceraw docstring

encode-kittyclj

(encode-kitty data {:keys [cols rows crop-top crop-bottom img-w img-h]})

Kitty graphics \x1b_G transmit+display sequence for data, sized to cols×rows cells. C=1 keeps the cursor put after placement. When crop-top/crop-bottom (cell rows scrolled past the band's top/bottom edge) are positive, only the visible vertical slice is shown at native scale via the Kitty source rectangle, sized from the transmitted image's img-w×img-h pixel dimensions.

data is a base64 String OR the RAW PNG bytes. Raw bytes are base64'd one chunk at a time straight into the escape by the fork, so the 1.33x base64 String never exists — the per-frame path for video playback, where the payload changes every frame and nothing can be cached.

Kitty graphics `\x1b_G` transmit+display sequence for `data`, sized to
`cols`×`rows` cells. `C=1` keeps the cursor put after placement. When
`crop-top`/`crop-bottom` (cell rows scrolled past the band's top/bottom edge)
are positive, only the visible vertical slice is shown at native scale via the
Kitty source rectangle, sized from the transmitted image's `img-w`×`img-h`
pixel dimensions.

`data` is a base64 String OR the RAW PNG bytes. Raw bytes are base64'd one
chunk at a time straight into the escape by the fork, so the 1.33x base64
String never exists — the per-frame path for video playback, where the
payload changes every frame and nothing can be cached.
sourceraw docstring

graphical-terminal?clj

(graphical-terminal?)
(graphical-terminal? env)

Whether we're in a GRAPHICAL terminal — one that speaks an inline-image protocol (kitty/Ghostty/WezTerm/Warp → Kitty, iTerm2 → iTerm2) — as opposed to a plain/non-graphical terminal (or tmux/screen, which mangle graphics pass-through). Callers branch on this to draw an inline image vs. a text-card fallback. The 0-arity reuses the memoized capability detection; pass env to probe an explicit environment (delegates to TerminalImage/isGraphicalTerminal).

Whether we're in a GRAPHICAL terminal — one that speaks an inline-image
protocol (kitty/Ghostty/WezTerm/Warp → Kitty, iTerm2 → iTerm2) — as opposed
to a plain/non-graphical terminal (or tmux/screen, which mangle graphics
pass-through). Callers branch on this to draw an inline image vs. a text-card
fallback. The 0-arity reuses the memoized capability detection; pass `env` to
probe an explicit environment (delegates to `TerminalImage/isGraphicalTerminal`).
sourceraw docstring

image-dimensionsclj

(image-dimensions b mime)

Intrinsic {:w :h} pixel size from the leading bytes of an image, or nil.

Intrinsic `{:w :h}` pixel size from the leading bytes of an image, or nil.
sourceraw docstring

images-protocolclj

(images-protocol)

:kitty, :iterm2, or nil for the current terminal.

`:kitty`, `:iterm2`, or nil for the current terminal.
sourceraw docstring

kitty-delete-placementclj

(kitty-delete-placement id)

Kitty sequence removing image id's placement while KEEPING its uploaded data, so an image scrolled off screen leaves no ghost yet needs no re-upload if it scrolls back into view.

Kitty sequence removing image `id`'s placement while KEEPING its uploaded data,
so an image scrolled off screen leaves no ghost yet needs no re-upload if it
scrolls back into view.
sourceraw docstring

kitty-free-imageclj

(kitty-free-image id)

Kitty sequence deleting image id AND freeing its uploaded data — used when the transmit cache evicts a long-off-screen image to bound terminal-side memory.

Kitty sequence deleting image `id` AND freeing its uploaded data — used when the
transmit cache evicts a long-off-screen image to bound terminal-side memory.
sourceraw docstring

kitty-placeclj

(kitty-place {:keys [id cols rows crop-top crop-bottom img-w img-h]})

Kitty a=p placement sequence for an ALREADY-transmitted image id at the cursor: draw it into a cols×rows cell box, optionally cropped to the visible vertical slice (crop-top/crop-bottom cell rows over an img-w×img-h px image) via the protocol's source rectangle — the SAME x/y/w/h math the fork's crop encodeKitty uses, because it is the same code. Reusing placement id p=1 REPLACES the prior placement, so a scroll moves the picture atomically: no delete-all, no re-upload, no flash.

Kitty `a=p` placement sequence for an ALREADY-transmitted image `id` at the
cursor: draw it into a `cols`×`rows` cell box, optionally cropped to the visible
vertical slice (`crop-top`/`crop-bottom` cell rows over an `img-w`×`img-h` px
image) via the protocol's source rectangle — the SAME `x/y/w/h` math the fork's
crop `encodeKitty` uses, because it is the same code. Reusing placement id `p=1`
REPLACES the prior placement, so a scroll moves the picture atomically: no
delete-all, no re-upload, no flash.
sourceraw docstring

kitty-pngclj

(kitty-png path mime {:keys [width height] :as box})

PNG payload + transmitted pixel dims {:data :w :h} for the Kitty wire. A PNG file rides through verbatim — transmitted at its intrinsic width×height (and works in the native image too); anything else is decoded and re-encoded as a box-fitted PNG via com.blockether.imaging, and a VIDEO becomes its poster frame.

:data is base64 text for the verbatim path (the fork caches that read) and RAW PNG bytes for a transcode; every encoder here takes either.

PNG payload + transmitted pixel dims `{:data :w :h}` for the Kitty wire. A PNG
file rides through verbatim — transmitted at its intrinsic `width`×`height`
(and works in the native image too); anything else is decoded and re-encoded
as a box-fitted PNG via `com.blockether.imaging`, and a VIDEO becomes its
poster frame.

`:data` is base64 text for the verbatim path (the fork caches that read) and
RAW PNG bytes for a transcode; every encoder here takes either.
sourceraw docstring

kitty-transmitclj

(kitty-transmit data id)

Kitty a=t transmit-ONLY sequence: upload PNG data (base64 String or RAW bytes) under client image id id WITHOUT displaying it, chunked into m=1m=0 pieces by the fork's own encoder. A later kitty-place draws it with NO re-upload — the key to flicker-free scrolling (transmit once, then re-place cheaply).

Kitty `a=t` transmit-ONLY sequence: upload PNG `data` (base64 String or RAW
bytes) under client image id `id` WITHOUT displaying it, chunked into
`m=1`…`m=0` pieces by the fork's own encoder. A later `kitty-place` draws it
with NO re-upload — the key to flicker-free scrolling (transmit once, then
re-place cheaply).
sourceraw docstring

materialize-attachmentclj

(materialize-attachment att)

Decode ONE persisted user image attachment (canonical wire map, STRING keys id/base64/media_type/filename) into a STABLE cache file keyed by its row id and return the descriptor a vis-image fence needs - {:path :mime :filename :size :size-label :width :height} - or nil when it is neither a usable still nor a decodable clip. Idempotent: an already-written cache file is reused, never rewritten, so a resumed session re-renders the picture from DB-owned bytes even after the original source path is gone. Never throws.

Decode ONE persisted user image attachment (canonical wire map, STRING keys
`id`/`base64`/`media_type`/`filename`) into a STABLE cache file keyed by its
row id and return the descriptor a `vis-image` fence needs -
`{:path :mime :filename :size :size-label :width :height}` - or nil when it is
neither a usable still nor a decodable clip. Idempotent: an already-written
cache file is reused,
never rewritten, so a resumed session re-renders the picture from DB-owned
bytes even after the original source path is gone. Never throws.
sourceraw docstring

parse-cell-size-reportclj

(parse-cell-size-report s)

Parse a terminal window-report reply into {:w :h} CELL pixel dimensions, or nil. The fork recognises the CSI 16 t cell-size reply ESC[6;<h>;<w>t directly, and otherwise derives the cell from a CSI 14 t text-area-pixels reply ESC[4;<hpx>;<wpx>t paired with a CSI 18 t text-area-cells reply ESC[8;<rows>;<cols>t (cell = px / cells) — tolerant of the replies arriving concatenated in any order and interleaved with whatever else the tty had queued.

Parse a terminal window-report reply into `{:w :h}` CELL pixel dimensions, or
nil. The fork recognises the `CSI 16 t` cell-size reply `ESC[6;<h>;<w>t`
directly, and otherwise derives the cell from a `CSI 14 t` text-area-pixels
reply `ESC[4;<hpx>;<wpx>t` paired with a `CSI 18 t` text-area-cells reply
`ESC[8;<rows>;<cols>t` (cell = px / cells) — tolerant of the replies arriving
concatenated in any order and interleaved with whatever else the tty had
queued.
sourceraw docstring

probe-dimensionsclj

(probe-dimensions path mime)

Read path's head and sniff its {:w :h} pixel dimensions. nil on failure. A VIDEO is answered by the fork from the MP4 track header (no decode, no native imaging library), and only then by the imaging index — so a clip can size its cell box without touching a single picture.

Read `path`'s head and sniff its `{:w :h}` pixel dimensions. nil on failure.
A VIDEO is answered by the fork from the MP4 track header (no decode, no
native imaging library), and only then by the imaging index — so a clip can
size its cell box without touching a single picture.
sourceraw docstring

probe-paste-imageclj

(probe-paste-image text {:keys [workspace-root]})

Detect the FIRST image the pasted text points at (a dropped file path). Returns {:path :mime :filename :size :size-label :width :height} or nil. A dropped MP4/M4V/MOV resolves too — it renders as its poster frame. workspace-root anchors relative candidates. Never throws.

Detect the FIRST image the pasted `text` points at (a dropped file path).
Returns `{:path :mime :filename :size :size-label :width :height}` or nil.
A dropped MP4/M4V/MOV resolves too — it renders as its poster frame.
`workspace-root` anchors relative candidates. Never throws.
sourceraw docstring

read-base64clj

(read-base64 path)

Read path and base64-encode its bytes, or nil on failure. Cached by path + mtime + size so an unchanged file is encoded at most once.

Read `path` and base64-encode its bytes, or nil on failure. Cached by
path + mtime + size so an unchanged file is encoded at most once.
sourceraw docstring

render-sequenceclj

(render-sequence path mime box)

Full escape sequence that draws the image at path (mime) into a cols×rows cell box for the current terminal, or nil when the terminal can't render inline images / the file can't be decoded. box may carry :crop-top/:crop-bottom (cell rows scrolled past the band edge) plus the image's intrinsic :width/:height, so a partly-scrolled Kitty image renders its visible slice at native scale instead of vanishing.

Full escape sequence that draws the image at `path` (`mime`) into a
`cols`×`rows` cell box for the current terminal, or nil when the terminal
can't render inline images / the file can't be decoded. `box` may carry
`:crop-top`/`:crop-bottom` (cell rows scrolled past the band edge) plus the
image's intrinsic `:width`/`:height`, so a partly-scrolled Kitty image renders
its visible slice at native scale instead of vanishing.
sourceraw docstring

set-cell-dimensions!clj

(set-cell-dimensions! w h)
source

transcode->png-base64clj

(transcode->png-base64 path box)

Decode path (any format com.blockether.imaging reads) and re-encode it as a PNG base64 string, downscaled so it fits the cols×rows cell box in pixels. The Kitty protocol's f=100 only accepts PNG, so a JPEG/GIF/BMP drop must pass through here first. Pure FFM (no java.desktop, works in the native image); returns nil on any failure so callers fall back to a text card.

Prefer [[transcode->png]] and hand its raw :data to the escape encoders: this arity exists for callers that genuinely need the base64 text.

Decode `path` (any format `com.blockether.imaging` reads) and re-encode it as a
PNG base64 string, downscaled so it fits the `cols`×`rows` cell box in pixels.
The Kitty protocol's `f=100` only accepts PNG, so a JPEG/GIF/BMP drop must
pass through here first. Pure FFM (no java.desktop, works in the native
image); returns nil on any failure so callers fall back to a text card.

Prefer [[transcode->png]] and hand its raw `:data` to the escape encoders:
this arity exists for callers that genuinely need the base64 text.
sourceraw docstring

video-mime?clj

(video-mime? mime)

True for a media type the fork sizes and posters as a clip.

True for a media type the fork sizes and posters as a clip.
sourceraw docstring

video-source?clj

(video-source? path mime)

True when path is a clip this namespace can draw — by media type when the caller knows one, else by sniffing the file's head (a dropped path carries no mime). Both halves live in the fork; 12 bytes are read, never a decode, so it is cheap enough to sit on the still-image transcode path.

True when `path` is a clip this namespace can draw — by media type when the
caller knows one, else by sniffing the file's head (a dropped path carries no
mime). Both halves live in the fork; 12 bytes are read, never a decode, so it
is cheap enough to sit on the still-image transcode path.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close