Arreglar el preview de imágenes en ranger: kitty (PNG/JPG) y SVG
Arreglar el preview de imágenes en ranger: kitty (PNG/JPG) y SVG
En ranger el panel de previsualización se quedó en blanco al seleccionar imágenes. Al investigarlo resultaron ser dos problemas independientes que conviene separar:
- Las imágenes raster (PNG, JPG, WebP…) no se veían por una incompatibilidad entre ranger 1.9.4 y kitty ≥ 0.40.
- Los SVG tampoco se veían, pero por otra razón:
scope.shlos trae con la rama de conversión comentada y acaban en manos de PIL, que no sabe leer SVG.
El caso original está reportado en ranger/ranger#3193.
Nota: el preview de texto y el de directorios seguían funcionando. El fallo afecta solo a imágenes.
Parte 1 — PNG/JPG: EINVAL: temporary file not named correctly
El síntoma
Al pasar por encima de un PNG/JPG, ranger mostraba el error:
ranger.ext.img_display.ImgDisplayUnsupportedException:
kitty replied "b'\x1b_Gi=...;EINVAL: temporary file not named correctly\x1b\\'"
La causa
No es mala configuración de ranger ni de kitty. Es una incompatibilidad fija entre la versión 1.9.4 de ranger y kitty moderno.
ranger 1.9.4 envía la imagen ya escalada como archivo temporal (t=t)
creado así:
NamedTemporaryFile(prefix='ranger_thumb_', suffix='.png')
Es decir, su ruta es algo como $TMPDIR/ranger_thumb_XXXX.png.
Desde kitty 0.40, el protocolo gráfico solo acepta t=t (y t=f) cuando
la ruta completa contiene la cadena tty-graphics-protocol y está en un
directorio temporal conocido. Si no, kitty responde
EINVAL: temporary file not named correctly y no dibuja nada.
Se puede comprobar interceptando lo que manda kitten icat, que sí pasa el
parámetro correcto:
a=q,f=24,t=t,s=1,v=1,S=47,i=2 payload=/dev/shm/kitty-tty-graphics-protocol-<pid>
ranger 1.9.4, en cambio, manda:
a=T,i=1,t=t,f=100 payload=/tmp/ranger_thumb_XXXX.png # ← sin tty-graphics-protocol
Solución 1 (recomendada): ranger master
Ya está corregido en master: ranger/ext/img_display.py crea y usa un
directorio con el nombre exigido:
self.temp_file_dir = os.path.join(gettempdir(), "tty-graphics-protocol")
os.mkdir(self.temp_file_dir)
# ...
NamedTemporaryFile(prefix='ranger_thumb_', suffix='.png',
dir=self.temp_file_dir, delete=False)
En Arch/CachyOS basta con el paquete git:
$ paru -S ranger-git
O desde el propio repositorio con pipx:
$ pipx install --force 'git+https://github.com/ranger/ranger.git'
Esto además trae el código nuevo de kitty (consulta DA1, passthrough de tmux y soporte de Ghostty).
Solución 2: wrapper, sin tocar ranger
Si quieres mantener el paquete 1.9.4, apunta TMPDIR a un directorio que
contenga tty-graphics-protocol, solo durante la ejecución de ranger. No
necesita root y no modifica nada del paquete.
bash/zsh (~/.bashrc o ~/.zshrc):
ranger() {
local d="${XDG_RUNTIME_DIR:-/tmp}/tty-graphics-protocol"
mkdir -p "$d"
TMPDIR="$d" command ranger "$@"
}
fish (~/.config/fish/functions/ranger.fish):
function ranger
set -l base $XDG_RUNTIME_DIR
test -z "$base" -o ! -d "$base"; and set base /tmp
set -l d $base/tty-graphics-protocol
mkdir -p -- $d
TMPDIR=$d command ranger $argv
end
Con esto ranger pasa a mandar:
a=T,i=1,t=t,f=100 payload=$TMPDIR/tty-graphics-protocol/ranger_thumb_XXXX.png
que kitty acepta.
Caso especial: EBADF (ssh / sin filesystem compartido)
Si en lugar de EINVAL kitty responde EBADF, ranger ya cae en el modo
streaming (t=d, píxeles en línea), así que ese supuesto no necesita nada.
Parte 2 — SVG: la rama de scope.sh está comentada
El síntoma
Los .svg tampoco se veían, aunque aquí el error es distinto: silencio y panel
vacío, sin mensaje de kitty.
La causa
El scope.sh de serie trae la conversión de SVG comentada:
## SVG
# image/svg+xml|image/svg)
# convert -- "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6
# exit 1;;
Sin esa rama, un SVG cae en la regla image/* y sale con exit 7 (imagen
directa). Ranger le entrega el .svg a PIL, y PIL no soporta SVG:
PIL.UnidentifiedImageError: cannot identify image file '.../test.svg'
La solución
Activa la rama en ~/.config/ranger/scope.sh y usa rsvg-convert como primera
opción (tienes librsvg; ImageMagick queda de respaldo):
## SVG
image/svg+xml|image/svg)
rsvg-convert -o "${IMAGE_CACHE_PATH}" -- "${FILE_PATH}" && exit 6
magick -- "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6
convert -- "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6
exit 1;;
exit 6 significa «imagen convertida en $IMAGE_CACHE_PATH», que es justo lo
que se necesita: se rasteriza el SVG a PNG y ranger lo pinta con el mismo
mecanismo que un PNG normal.
Comprobación
$ ./scope.sh /tmp/test.svg 80 40 /tmp/cache_svg.png True ; echo "exit=$?"
exit=6
$ file /tmp/cache_svg.png
PNG image data, 100 x 80, 8-bit/color RGB, non-interlaced
Resumen
| Tipo de archivo | Antes | Ahora |
|---|---|---|
| Texto | ✅ exit 5 |
✅ exit 5 |
| PNG / JPG | ❌ kitty rechaza el temporal | ✅ con ranger-git o el wrapper TMPDIR |
| SVG | ❌ PIL no sabe leerlo | ✅ rsvg-convert → PNG (exit 6) |
| Directorios | ✅ | ✅ |
Las dos correcciones son complementarias: el arreglo del TMPDIR (o
ranger-git) hace que kitty acepte las imágenes raster (incluido el PNG que
resulta de convertir un SVG), y la rama de scope.sh hace que los SVG se
conviertan antes de llegar a kitty.
Referencias
- Issue: ranger/ranger#3193 — Cannot get image previews to work on Omarchy (Arch) and Ghostty
- Protocolo gráfico de kitty: https://sw.kovidgoyal.net/kitty/graphics-protocol/
scope.shde ranger:~/.config/ranger/scope.sh