77 lines
2.4 KiB
Python
77 lines
2.4 KiB
Python
"""Image rendering abstraction — kitty graphics, sixel, or ASCII art."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def render_image_kitty(path: str) -> str:
|
|
"""Return kitty graphics protocol escape sequence for the image."""
|
|
data = Path(path).read_bytes()
|
|
b64 = base64.standard_b64encode(data).decode()
|
|
chunks = [b64[i:i + 4096] for i in range(0, len(b64), 4096)]
|
|
escape = ""
|
|
for i, chunk in enumerate(chunks):
|
|
m = 1 if i < len(chunks) - 1 else 0
|
|
if i == 0:
|
|
escape += f"\033_Ga=T,f=100,m={m};{chunk}\033\\"
|
|
else:
|
|
escape += f"\033_Gm={m};{chunk}\033\\"
|
|
return escape
|
|
|
|
|
|
def render_image_sixel(path: str) -> str:
|
|
"""Convert image to sixel using chafa or img2sixel."""
|
|
if shutil.which("chafa"):
|
|
result = subprocess.run(
|
|
["chafa", "--format=sixel", "--size=80x40", str(path)],
|
|
capture_output=True, text=True,
|
|
)
|
|
if result.returncode == 0:
|
|
return result.stdout
|
|
if shutil.which("img2sixel"):
|
|
result = subprocess.run(
|
|
["img2sixel", "-w", "640", str(path)],
|
|
capture_output=True, text=True,
|
|
)
|
|
if result.returncode == 0:
|
|
return result.stdout
|
|
return f"[Sixel unavailable — install chafa or libsixel. Image: {path}]"
|
|
|
|
|
|
def render_image_ascii(path: str) -> str:
|
|
"""Convert image to ASCII/Unicode block art using chafa."""
|
|
if shutil.which("chafa"):
|
|
result = subprocess.run(
|
|
["chafa", "--size=60x30", str(path)],
|
|
capture_output=True, text=True,
|
|
)
|
|
if result.returncode == 0:
|
|
return result.stdout
|
|
return f"[Image: {path}]"
|
|
|
|
|
|
def render_image(path: str, protocol: str) -> str:
|
|
"""Render an image using the specified protocol. Returns terminal-ready string."""
|
|
p = Path(path)
|
|
|
|
if p.suffix.lower() == ".svg":
|
|
try:
|
|
import cairosvg
|
|
png_path = p.with_suffix(".png")
|
|
cairosvg.svg2png(url=str(p), write_to=str(png_path))
|
|
path = str(png_path)
|
|
except ImportError:
|
|
return f"[SVG display requires cairosvg: pip install cairosvg. File: {path}]"
|
|
|
|
if protocol == "kitty":
|
|
return render_image_kitty(path)
|
|
elif protocol == "sixel":
|
|
return render_image_sixel(path)
|
|
else:
|
|
return render_image_ascii(path)
|