Skip to main content

tess/
image_export.rs

1//! Serialize a rendered ASCII-art cell grid to a writer: ANSI-colored rows by
2//! default, or plain text when color is off.
3
4use crate::ansi::Color;
5use crate::render::Cell;
6use std::io::{self, Write};
7
8/// Write `grid` to `out`. When `color` is true, emit truecolor SGR for fg (and
9/// bg, for half-block cells); otherwise emit just the characters. One line per
10/// row, reset (`\x1b[0m`) before each newline when colored.
11pub fn write_grid<W: Write>(out: &mut W, grid: &[Vec<Cell>], color: bool) -> io::Result<()> {
12    for row in grid {
13        for cell in row {
14            match cell {
15                Cell::Char { ch, style, .. } => {
16                    if color {
17                        if let Some(Color::Rgb(r, g, b)) = style.fg {
18                            write!(out, "\x1b[38;2;{r};{g};{b}m")?;
19                        }
20                        if let Some(Color::Rgb(r, g, b)) = style.bg {
21                            write!(out, "\x1b[48;2;{r};{g};{b}m")?;
22                        }
23                    }
24                    write!(out, "{ch}")?;
25                }
26                Cell::Continuation => {}
27                Cell::Empty => write!(out, " ")?,
28            }
29        }
30        if color { write!(out, "\x1b[0m")?; }
31        writeln!(out)?;
32    }
33    Ok(())
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::ansi::Style;
40
41    fn ch(c: char, fg: Option<Color>) -> Cell {
42        Cell::Char { ch: c, width: 1, style: Style { fg, bg: None, ..Default::default() }, hyperlink: None }
43    }
44
45    #[test]
46    fn plain_writes_chars_only() {
47        let grid = vec![vec![ch('@', Some(Color::Rgb(1, 2, 3))), ch('.', None)]];
48        let mut buf = Vec::new();
49        write_grid(&mut buf, &grid, false).unwrap();
50        assert_eq!(String::from_utf8(buf).unwrap(), "@.\n");
51    }
52
53    #[test]
54    fn color_emits_truecolor_sgr_and_reset() {
55        let grid = vec![vec![ch('@', Some(Color::Rgb(10, 20, 30)))]];
56        let mut buf = Vec::new();
57        write_grid(&mut buf, &grid, true).unwrap();
58        assert_eq!(String::from_utf8(buf).unwrap(), "\x1b[38;2;10;20;30m@\x1b[0m\n");
59    }
60}