summaryrefslogtreecommitdiff
path: root/README.org
blob: 403347fcbc87c5fe4bd9461501dedcffeea9e6e2 (plain) (blame)
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
#+TITLE: kitty-graphics.el
#+AUTHOR: cashmere

Display images in terminal Emacs (~emacs -nw~) using the [[https://sw.kovidgoyal.net/kitty/graphics-protocol/][Kitty graphics protocol]].

* Foreword

I got the opportunity to subscribe to the highest Claude level. I'm allowed to use it outside of work. I was able to extend Emacs in terminal mode with the kitty protocol. Out of curiosity I wanted to know if a thought I had for months was possible or not, which was basically to extend libvterm with the kitty image protocol and then utilize vterm to display those images inside Emacs Terminal.

Besides, I don't even have the guts to release it, even though my intention of such a release would be first and foremost for the people who have been asking for such a feature specifically for years, or for other developers to use it as some kind of reference. So idk, while I totally agree that the current AI slop is getting to be exhausting, we as humans should judge projects on a project by project basis.

* Overview

~kitty-graphics.el~ renders images directly in terminal Emacs using Kitty's
graphics protocol with direct placements. Images are transmitted once to the
terminal, then positioned at overlay screen coordinates after each redisplay.
They scroll with text, survive buffer switches, and work in split windows ---
they're managed as overlays in Emacs's display engine.

Integrations are provided for:
- *org-mode* --- inline images via =C-c C-x C-v= (both =org-toggle-inline-images= and =org-link-preview= for org 10.0+)
- *image-mode* --- terminal-aware image file viewing
- *shr/eww* --- inline images in HTML rendering (eww, mu4e, gnus)
- *dired* --- image preview in side window (=P= key)
- *dirvish* --- native preview dispatcher for image files

* Requirements

- Emacs >= 27.1
- [[https://sw.kovidgoyal.net/kitty/][Kitty]] >= 0.20.0 (or WezTerm/Ghostty with direct placement support)
- ImageMagick (~magick~ / ~convert~ / ~identify~) for non-PNG formats and image sizing
- Launch Emacs with ~TERM=xterm-256color~ (Emacs often can't find the ~xterm-kitty~ terminfo)
  
  #+begin_src sh
  TERM=xterm-256color emacsclient -nw
  #+end_src

* Installation

** straight.el

#+begin_src emacs-lisp
(use-package kitty-graphics
  :straight (:local-repo "~/projects/kitty-graphics")
  :if (and (not (display-graphic-p)) (getenv "KITTY_PID"))
  :config
  (kitty-graphics-mode 1))
#+end_src

** Manual

#+begin_src emacs-lisp
(add-to-list 'load-path "~/projects/kitty-graphics")
(require 'kitty-graphics)
(when (and (not (display-graphic-p)) (getenv "KITTY_PID"))
  (kitty-graphics-mode 1))
#+end_src

* Usage

Enable the global minor mode:

#+begin_src emacs-lisp
(kitty-graphics-mode 1)
#+end_src

Then:
- In org-mode: toggle inline images with =C-c C-x C-v=
- In dired: press =P= on an image file for a side-window preview
- In dirvish: image previews work automatically (no extra config)
- Open an image file: =image-mode= displays it via Kitty
- In eww/mu4e/gnus: HTML images render inline

** Commands

| Command                 | Description                        |
|-------------------------+------------------------------------|
| ~kitty-graphics-mode~     | Toggle the global minor mode       |
| ~kitty-gfx-display-image~ | Display a single image at point    |
| ~kitty-gfx-remove-images~ | Remove images in region or buffer  |
| ~kitty-gfx-clear-all~     | Remove all images from all buffers |
| ~kitty-gfx-dired-preview~ | Preview image at point in dired    |

** Customization

| Variable               | Default | Description                          |
|------------------------+---------+--------------------------------------|
| ~kitty-gfx-max-width~    |      80 | Maximum image width in columns       |
| ~kitty-gfx-max-height~   |      24 | Maximum image height in rows         |
| ~kitty-gfx-render-delay~ |   0.016 | Debounce delay for re-rendering (s)  |
| ~kitty-gfx-debug~        |     nil | Log debug info to ~/tmp/kitty-gfx.log~ |

* How It Works

1. On startup, cell pixel size is queried via ~CSI 16 t~ (XTWINOPS) for
   accurate image scaling. Falls back to 8x16 if the query times out.
2. Image data is transmitted once via APC escape sequences (~a=t~, store only)
3. Overlays with a ~display~ property reserve blank space in Emacs buffers
4. After each redisplay, direct placements (~a=p~) are emitted via
   ~send-string-to-terminal~ at the overlay's screen coordinates
5. All placement output is wrapped in synchronized output (~BSU/ESU~,
   =DEC mode 2026=) to prevent partial rendering and flicker
6. Each placement uses a unique placement ID (~p=PID~) so re-placements
   at new positions replace the old rendering without accumulation
7. Position caching skips redundant re-placements when nothing moved
8. Placements are deleted when overlays scroll out of view

* Supported Formats

PNG is sent directly to the terminal. Other formats (JPEG, GIF, WebP, SVG,
TIFF, BMP) are converted to PNG via ImageMagick before transmission.

* Known Limitations

- No tmux support 
- Primary focus on kitty terminal. While other terminals should work too, I wont give any guarantee
- Animated GIFs display only the first frame
- Without ImageMagick, only PNG files work and image sizing falls back to a fixed default

* License

GPL-2.0-or-later