2个版本 (1个稳定版)
1.0.0 | 2023年9月17日 |
---|---|
0.1.1 | 2023年8月28日 |
#17 in #sixel
56KB
1.5K SLoC
⚠️ 此crate/repository已重命名
ratatu-image -> ratatui-image
新链接
lib.rs
:
为 Ratatui 的图像小部件
⚠️ 该crate是实验性的
使用 Ratatui 在终端中用图形协议渲染图像。
struct App {
image: Box<dyn FixedBackend>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let font_size = (7, 16); // Or use Picker::from_termios, or let user provide it.
let mut picker = Picker::new(
font_size,
BackendType::Sixel,
None,
)?;
let dyn_img = image::io::Reader::open("./assets/Ada.png")?.decode()?;
let image = picker.new_static_fit(dyn_img, Rect::new(0, 0, 30, 20), Resize::Fit)?;
let mut app = App { image };
let backend = TestBackend::new(80, 30);
let mut terminal = Terminal::new(backend)?;
// loop:
terminal.draw(|f| ui(f, &mut app))?;
Ok(())
}
fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
let image = FixedImage::new(app.image.as_ref());
f.render_widget(image, f.size());
}
用户界面
用户界面应用程序围绕文本的列和行自然旋转,无需任何像素大小概念。 Ratatui 基于“即时渲染与中间缓冲区”。
在每一帧,小部件被构建并渲染到某个字符缓冲区,然后与上一帧相比的任何更改都会进行diff并写入终端屏幕。
终端图形协议
某些协议允许向支持它的终端输出图像数据。
在简单的情况下,Sixel协议机制就是打印一个转义序列。图像将被“转储”在光标位置,实现可能添加足够的换行符以滚动输出。
问题
简单地将图像“转储”到 Ratatui 缓冲区是不够的。在最坏的情况下,缓冲区diff可能不会覆盖图像覆盖的某些字符,但由于屏幕/区域大小调整或简单地其他小部件的内容更改,diff可能会随时更改。然后图形会被底层的字符数据立即覆盖。
解决方案
首先需要抑制被覆盖的字符单元格的渲染,这已在 Ratatui PR for cell skipping 中解决。
其次,还需要获取图像的列和行大小,这通过查询终端的像素大小并除以列/行来获取字体大小来实现。目前这是通过 rustix::termios
实现的,但这可能会根据 Ratatui PR for getting window size 进行更改。
实现
图像始终被调整大小,以适应其最近的列/行矩形。这样做是为了确保图像将与周围所有文本在同一“渲染过程”中绘制,并且图像区域下的单元格在ratatui缓冲区级别上跳过绘制,因此无法“清除”之前绘制的文本。这会导致图像的右下角出现残影。
示例
请参阅crate::picker::Picker辅助程序和examples/demo
。
依赖项
~17–30MB
~302K SLoC