27个版本 (6个稳定版)
1.0.5 | 2024年7月20日 |
---|---|
1.0.1 | 2024年6月1日 |
1.0.0 | 2024年3月31日 |
0.10.0 | 2024年3月31日 |
0.4.3 | 2023年11月24日 |
#16 在 图形API 中
4,478 每月下载量
在 16 个crates中(14个直接使用) 使用
86KB
2K SLoC
Ratatui-image
展示
为ratatui提供具有多个图形协议后端的图像小部件
ratatui是一个即时模式的TUI库。ratatui-image在即时模式的TUI中渲染图像时解决了3个一般问题
-
查询终端可用的图形协议。某些终端可能实现了一个或多个图形协议,例如Sixels,或iTerm2或Kitty图形协议。通过环境变量猜测。如果失败,使用一些控制序列查询终端。回退到使用一些带前景色和背景色的unicode半块字符的“半块”。
-
查询终端的像素字体大小。如果确实有图形协议可用,需要知道字体大小才能将图像像素映射到字符单元格区域。图像可以调整大小、适应或裁剪到某个区域。查询终端的窗口和列/行大小,并推导出字体大小。
-
通过猜测的协议渲染图像。某些协议,如Sixels,本质上属于“即时模式”,但我们仍然需要避免TUI覆盖图像区域,即使是空白字符。其他协议,如Kitty,本质上是有状态的,但至少提供了一种重新渲染已加载图像的方法,位置可以是不同的或相同的。
快速开始
use ratatui::{backend::TestBackend, Terminal, terminal::Frame};
use ratatui_image::{picker::Picker, StatefulImage, protocol::StatefulProtocol};
struct App {
// We need to hold the render state.
image: Box<dyn StatefulProtocol>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let backend = TestBackend::new(80, 30);
let mut terminal = Terminal::new(backend)?;
// Should use Picker::from_termios(), to get the font size,
// but we can't put that here because that would break doctests!
let mut picker = Picker::new((8, 12));
// Guess the protocol.
picker.guess_protocol();
// Load an image with the image crate.
let dyn_img = image::io::Reader::open("./assets/Ada.png")?.decode()?;
// Create the Protocol which will be used by the widget.
let image = picker.new_resize_protocol(dyn_img);
let mut app = App { image };
// This would be your typical `loop {` in a real app:
terminal.draw(|f| ui(f, &mut app))?;
Ok(())
}
fn ui(f: &mut Frame<'_>, app: &mut App) {
// The image widget.
let image = StatefulImage::new(None);
// Render with the protocol state.
f.render_stateful_widget(image, f.size(), &mut app.image);
}
picker::Picker 辅助工具用于执行所有这些字体大小和图形协议猜测,并且还可以将字符单元格大小映射到像素大小,这样我们就可以例如“适应”图像到所需的列+行边界内,等等。
小部件选择
- 图片小部件不能适应渲染区域(如果空间不足则完全不绘制),可能更容易出现一些错误(过度绘制或伪影),并且与一些协议(例如状态性的Kitty图形协议)不太兼容。它最大的优点是它是无状态的(在ratatui中即即时模式),因此永远不会阻塞渲染线程/任务。许多ratatui应用程序只使用无状态小部件。
- 有状态的图片小部件适应其渲染区域,对过度绘制错误和伪影更健壮,并且与一些图形协议更兼容。默认情况下,调整大小和编码是阻塞的,但可以将这些操作卸载到另一个线程或异步任务(请参阅
examples/async.rs
)。必须使用render_stateful_widget
(即带有一些可变状态)进行渲染。
示例
examples/demo.rs
是一个完整的演示。examples/async.rs
展示了如何将调整大小和编码卸载到另一个线程,以避免阻塞UI线程。
库还包含一个二进制文件,用于渲染图像文件,但它主要关注测试。
功能
rustix
(默认)通过rustix::termios::tcgetattr
启用了对图形协议的更好猜测。crossterm
或termion
应与您的ratatui后端相匹配。termwiz
可用,但与ratatu-image不正确工作。serde
用于picker::ProtocolType上的#[derive]
,以方便使用,因为它可能有助于将其保存到某些用户配置中。image-defaults
(默认)仅启用image/defaults
(image
有default-features = false
)。为了仅支持一组图像格式并减少依赖项,请禁用此功能,将image
添加到您的crate中,并根据需要启用其功能/格式。请参阅https://doc.rust-lang.net.cn/cargo/reference/features.html#feature-unification。
兼容性矩阵
兼容性和QA
终端 | 协议 | 已修复 | 调整大小 | 备注 |
---|---|---|---|---|
Xterm | Sixel |
✔️ | ✔️ | 使用-ti 340 运行以确保启用Sixel支持。 |
页脚 | Sixel |
✔️ | ✔️ | Wayland。 |
kitty | Kitty |
✔️ | ✔️ | |
Wezterm | iTerm2 |
✔️ | ✔️ | 也支持Sixel 和Kitty ,但只有iTerm2 真正无错误工作。 |
Alacritty | Sixel |
❌ | ❌ | 存在一个Sixel分支,但它已过时且不清除图形。 |
iTerm2 | iTerm2 |
❔ | ❔ | 未测试(需要苹果硬件),但应与WezTerm相同。 |
konsole | Sixel |
❌ | ❌ | 不会修复:不清除图形,其他伪影。 |
Contour | Sixel |
❌ | ❌ | 不清除图形。 |
ctx | Sixel |
❌ | ❌ | 有错误。 |
Blackbox | Sixel |
❔ | ❔ | 未测试。 |
在此,“已修复”是指Image
小部件,“调整大小”是指StatefulWidget
。
使用xterm在Xvfb上运行了一个基本的截图测试(在CI中或cargo make screenshot-xvfb && cargo make screenshot-diff
)。
半块应该在所有终端中工作。
使用ratatui-image的项目
- iamb 一个具有vim快捷键的矩阵客户端。
- joshuto 一个可以预览图片的终端文件管理器。
- Aerostream 使用EventStream的Bluesky客户端。
比较
- viuer 在不同的终端/协议中渲染图形,但“丢弃”图像,这使得TUI程序难以工作。终端协议猜测代码已适配到rustix,因此viuer的作者被包括在版权声明中。
- yazi 不是一个库,而是一个实现了许多图形协议的终端文件管理器,允许你在文件系统中预览图片。
- Überzug++ 一个CLI实用程序,通过使用X11/wayland子窗口、sixels、kitty和/或iterm2协议(任何必要的手段)在终端上绘制图像。存在几个包装器或绑定crates。经过更多实战测试,但本质上是有状态的,这使得与即时模式一起使用变得困难。
许可证:MIT
依赖项
~9–22MB
~330K SLoC