1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
* Changelog
** kitty-graphics 0.5.0
A feature-heavy follow-up to =0.4.0=: typst inline equations, a much
more robust Sixel encoder pipeline, Sixel inside tmux, and inline mpv
video playback. =0.4.0= already shipped the Sixel backend and the
text-sizing protocol; =0.5.0= builds on that foundation.
*** Features
**** Typst inline equation preview
New autoloaded commands =kitty-gfx-typst-preview= and
=kitty-gfx-typst-clear-preview= scan the current buffer (or active
region) for ~$...$~ math fragments, compile each one via the =typst=
CLI, and replace it with a rendered PNG using the existing
kitty-graphics overlay pipeline. Works on both the Kitty and Sixel
backends. Customs: =kitty-gfx-typst-command=, =kitty-gfx-typst-ppi=,
=kitty-gfx-typst-text-size=, =kitty-gfx-typst-preamble=. Default
preamble auto-converts the current Emacs foreground colour to the hex
form typst's =rgb()= requires. Cached PNGs land under
=/tmp/kitty-gfx-typst/= keyed by SHA-1 of the source. Closes #5.
**** Configurable Sixel encoder + per-invocation timeout
The Sixel encoder pipeline used to be hard-wired to ImageMagick with
no timeout, so a malformed image or a hung encoder could freeze
Emacs. Three new customs and two helpers fix that:
- =kitty-gfx-sixel-encoder-program= (nil = auto-detect). Auto-detect
order: =img2sixel= (libsixel) > =magick= (ImageMagick 7) > =convert=
(ImageMagick 6, deprecated). Set to a string to pin a specific
binary.
- =kitty-gfx-sixel-encoder-args= -- extra arguments slotted before
the per-invocation size flags.
- =kitty-gfx-sixel-encoder-timeout= -- float seconds, default =5.0=,
=nil= for no timeout.
Internally =kitty-gfx--sixel-resolve-encoder= returns a
=(KIND . PATH)= cons so the encode pipeline can build the right
argv (=-w/-h <px>= for img2sixel, =-geometry WxH sixel:-= for
ImageMagick), and =kitty-gfx--sixel-run-encoder= drives the child via
=make-process= with a separate stderr buffer and a =run-at-time=
watchdog that kills the process on timeout. Failures and timeouts
surface as a logged =nil= instead of a frozen Emacs.
#+begin_QUOTE
*Bench*: =tests/test-image.png= encoded at 20×10 cells (160×160 px) on
my workstation -- =img2sixel= produced =2631=-byte payloads in
~5 ms, =magick= produced =5831=-byte payloads in ~58 ms. About =2.2x=
smaller payload and =~10x= faster. This matters most inside tmux,
where every refresh re-emits the full DCS payload.
#+end_QUOTE
Pattern adapted from [[https://github.com/timfel/sixel-graphics.el][@timfel's =sixel-graphics.el= fork]]; co-authored
on the commit. Refs #4.
**** Sixel inside tmux >= 3.4
The Sixel detector used to hard-disable the moment =$TMUX= was set --
that comment in the code predated tmux =3.4= (released =2024-02-13=),
which ships native Sixel rendering. Drop the hard guard, gate on a
parsed =tmux -V=, and let users opt out via
=kitty-gfx-tmux-allow-sixel= (default =t=). New helpers
=kitty-gfx--tmux-version= (cached) and
=kitty-gfx--tmux-sixel-supported-p= centralise the in-tmux + opt-in +
version-check logic. The =sixel-detect= debug log gained =tmux-ver==
and =tmux-ok== fields.
Caveat: tmux's cell buffer is not pixel-aware, so images may stick to
their old position after scrolling until the affected cells are
overwritten. That's an upstream tmux limitation, not something this
package can fix. The Kitty graphics protocol still does not work
inside tmux because we do not yet wrap APC sequences with the
=\ePtmux;...\e\\= passthrough envelope -- separate piece of work.
Refs #2.
**** Inline mpv video playback (Kitty backend)
The Kitty backend grew video support via mpv IPC. New commands:
=kitty-gfx-play-video=, =kitty-gfx-stop-video=,
=kitty-gfx-toggle-video=, =kitty-gfx-seek-video=. Limited to the
Kitty backend (Sixel re-emit cost makes video impractical there).
**** Loud warning on missing Sixel encoder
When the Sixel backend is selected but no encoder is on =PATH=, the
mode-enable now fires a =display-warning= pointing at
img2sixel/ImageMagick instead of silently dropping every image.
**** Windows Terminal detection + GIF routing
Windows Terminal does not advertise a stable =TERM= value, so the old
detector missed it. Accept the =WT_SESSION=, =WT_PROFILE_ID= and
=WT_WINDOWID= environment markers it injects and the Sixel backend
engages correctly. =gif= is also now routed through the image
pipeline (still first-frame only -- no animation support in the
terminal -- but no longer silently dropped). Closes #6.
Thanks again to [[https://github.com/timfel][Tim Felgentreff]] for the patch and the Windows-side
testing.
*** Fixes
- ECH-erase + pre-erase pattern for cleaner column clearing. Credit
to [[https://github.com/mdfried][mdfried]] for the approach.
- Skip heading rendering when folded to the same visual line.
- Sixel backend parity with the Kitty backend across the refresh
cycle.
- Text sizing rendering: column guard, CPU optimisation, preview-mode
behaviour.
*** Tooling
- New top-level =justfile= task runner with byte-compile, load, and
per-feature interactive recipes (=test-org=, =test-typst=,
=test-image=, =test-sixel-image=, =test-sixel-tmux=, ...) plus
headless probes (=sixel-encoder=, =sixel-encode [ENCODER]=,
=sixel-timeout-test=, =typst-render=).
*** Documentation
- =README.org= and =AGENTS.md= now hard-state img2sixel as the
recommended Sixel encoder, with the bench numbers above and a
pointer to =just sixel-encoder= as the first step when diagnosing
Sixel rendering bugs.
*** Credits
Thanks to [[https://github.com/timfel][Tim Felgentreff]] for the encoder + timeout pattern and the
ongoing collaboration on the Sixel side via his fork.
** kitty-graphics 0.4.0 - HUGE updates
*** Features
- Full sixel support
- Abstracted the library to support =kitty-gfx-protocol= and =sixel=
- Support for agent-shell
Thanks to [[https://github.com/Lenbok][Lenbok]]
- First implementation of the text sizing protocol
**** Sixel support!
Yes, you are reading it right! The library now supports displaying images in Terminals also to those, who support sixel, which opens up the support for almost the rest of the up to date terminals.
Tested and confirmed working in =foot=, =xterm=, =Konsole=, =mlterm=, and =mintty=. Auto-detection probes for Sixel support via DA1 query. If your terminal supports it, kitty-graphics will use it automatically.
#+begin_WARNING
Performance wise, the kitty image protocol is superior in terms of speed and actual image quality (truecolor vs 256 colors). If your terminal supports it, prefer the kitty protocol.
#+end_WARNING
***** Showcase
[[file:foot.gif]]
**** Text sizing protocol
Yes, we do even now support the text sizing protocol inside Emacs terminal mode! Nonetheless, take that feature with a grain of salt. This protocol is rather new compared to the others, and there are not many references which implement it.
After many attempts, I was able to add something genuinely useful. Org Mode remains my highest priority, of course.
We can render org headings at scaled sizes (=* Heading= at 2x, =** Sub= at 1.5x, =*** Deep= at 1.2x). A preview mode temporarily disables conflicting packages (org-modern, org-appear, olivetti, etc.) for clean rendering. Toggling images does also work, though currently not while the text protocol is active at the same time.
I will keep on improving this feature. I think it is actually great eyecandy, and something I had never seen before and had not even known about until somebody mentioned it under one of my threads on Reddit. If you, /anon/, feel mentioned, a big thanks to you!
*Requires Kitty >= 0.40.0* (the only terminal currently implementing OSC 66 with scale support).
***** Showcase
[[file:kitty.gif]]
*** Bug fixes & polish
- Text sizing: added column guard to prevent out-of-bounds rendering, CPU optimization (reduced redundant redraws), improved preview mode stability
- Sixel backend parity improvements: better interop with the kitty protocol path
- Heading rendering: skip overlay emission when a heading is folded to the same visual line (prevents ghost glyphs)
- Erase strategy: switched to ECH erase + pre-erase pattern (credit: mdfried) for cleaner column clearing
*** What comes next?
**** tmux support
tmux support is in progress. The Sixel side is unlocked in =0.5.0= --
see the entry above. Native Kitty graphics passthrough inside tmux is
still pending: we do not yet wrap APC sequences with the
=\ePtmux;...\e\\= envelope, and there's also an in-progress branch
adding [[https://github.com/tmux/tmux/tree/ta/kitty-img][native Kitty image protocol support to tmux]]. Until either
lands, if you already use Kitty directly I would stick with it --
the Kitty protocol gives you stateful image management, truecolor
rendering, and a smoother overall experience.
**** Package renaming?
I was thinking about renaming the project into something like =terminal-gfx= as we do now cover not only one way of displaying images, but also take an approach to stabilize the =text-protocol=. This is my first project with people actually using and/or are interested in what I do =:D=. So if you have suggestions or feedback, I would love to hear your opinion!
/In terms of actually renaming the package, I will do it in such a manner, that your current and future configurations are not going to break. Shoutouts to neovim and its stable ecosystem *hust hust*./
|