benjajaja / ratatui-image

Ratatui widget for rendering image graphics in terminals that support it
https://crates.io/crates/ratatui-image
MIT License
108 stars 16 forks source link

Buffer area to the right of Image doesn't retain the applied style #42

Open Chiffario opened 1 week ago

Chiffario commented 1 week ago

Sorry for a slightly confusing phrasing, but here's the issue I've found

If you change the background color of an area within a buffer, then render an Image widget within the same buffer, the entire area to the right of the image won't retain the style. On top of that, trying to reapply the same style to the remaining area doesn't do anything, yet applying a new background color actually affects it properly

Minimally reproducible version:

use std::io;

use ratatui::{
    crossterm::event::{self, KeyCode, KeyEventKind},
    layout::Rect,
    style::{Style, Stylize},
    DefaultTerminal,
};

use ratatui_image::protocol::Protocol;
use ratatui_image::{picker::Picker, Resize};

fn main() -> io::Result<()> {
    let mut terminal = ratatui::init();
    terminal.clear()?;
    let app_result = run(terminal);
    ratatui::restore();
    app_result
}

fn run(mut terminal: DefaultTerminal) -> io::Result<()> {
    let style = Style::default().black().on_white();
    loop {
        terminal.draw(|frame| {
            let buf = frame.buffer_mut();
            let area = Rect {
                x: 5,
                y: 5,
                width: buf.area.width - 5,
                height: 10,
            };

            let image = image::ImageReader::open("image.png")
                .unwrap()
                .decode()
                .unwrap();

            buf.set_style(area, style);

            let mut picker = Picker::from_termios().unwrap();
            picker.guess_protocol();

            let img_area = Rect {
                x: area.x + 1,
                y: area.y + 1,
                width: 20,
                height: 20,
            };
            let img = picker.new_protocol(image, img_area, Resize::Fit(None)).ok();

            if let Some(img_inner) = img {
                img_inner.render(img_area, buf);
                // Manually reapplying the style doesn't work either
                let remaining_area = Rect {
                    x: img_area.x + img_area.width,
                    y: img_area.y,
                    width: area.width - img_inner.rect().width,
                    height: img_inner.rect().height,
                };
                // Doesn't do anything
                // buf.set_style(remaining_area, style);
                // Actually affects things
                // buf.set_style(remaining_area, style.on_red());
            }
        })?;

        if let event::Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
                return Ok(());
            }
        }
    }
}

Results

  1. Without trying to recolor the empty area image
  2. Reusing the previously used style (via buf.set_style(remaining_area, style); image
  3. Changing the background color for the remaining area (via buf.set_style(remaining_area, style.on_red()); image

Terminal used: kitty, can't test on other image backends at the moment unfortunately

Note: Making a new style with the same background color doesn't work either


If possible, I'd like to help but I probably need some direction for that

benjajaja commented 5 days ago

Partially fixed: previously all styles were reset after displaying a kitty image, now only the foreground is reset. That is, the issue persists for foreground color styles only, in the same as it way as reported for background color.