renderer.rs

3.1 kB · rust · 103 lines

1use super::Cell2d;2use crate::core::cell::mapping;3use crate::core::enums::Mode;4use crate::core::errors::Result;5use crate::math::dim::push_glyph;6use std::collections::HashMap;78fn painted(cell: &Cell2d) -> Vec<[u8; 4]> {9    match &cell.cell.colors {10        Some(colors) => colors.clone(),11        None => {12            let fresh = cell.clone().paint(&mapping(), Mode::Type);13            fresh.cell.colors.unwrap()14        }15    }16}1718/// Renders the cell as rows of glyphs, or of digits where no glyph is mapped.19///20/// ```21/// let cell = mrlyrs::math::two::carpet(3, 1).unwrap();22/// assert_eq!(mrlyrs::math::two::text(&cell, None), vec!["111", "101", "111"]);23/// ```24pub fn text(cell: &Cell2d, glyphs: Option<&HashMap<u8, char>>) -> Vec<String> {25    let (h, w) = (cell.height(), cell.width());26    let mut rows = Vec::with_capacity(h);27    for y in 0..h {28        let mut row = String::with_capacity(w);29        for x in 0..w {30            let v = cell.types().get(&[y, x]);31            push_glyph(&mut row, v, glyphs);32        }33        rows.push(row);34    }35    rows36}3738/// Renders the cell to PNG bytes at the given pixel scale, painting it by type when unpainted.39pub fn png(cell: &Cell2d, scale: usize) -> Result<Vec<u8>> {40    let colors = painted(cell);41    crate::core::png(&colors, cell.width(), cell.height(), scale)42}4344#[cfg(test)]45mod tests {46    use super::*;47    use crate::math::two::designs;48    #[test]49    fn text_digits_and_glyphs() {50        let c = designs::carpet(3, 1).unwrap();51        let t = text(&c, None);52        assert_eq!(t, vec!["111", "101", "111"]);53        let glyphs = HashMap::from([(0, ' '), (1, '#')]);54        assert_eq!(text(&c, Some(&glyphs)), vec!["###", "# #", "###"]);55    }56    #[test]57    fn png_signature_and_size() {58        let c = designs::carpet(3, 2).unwrap();59        let bytes = png(&c, 4).unwrap();60        assert_eq!(&bytes[0..8], &[137, 80, 78, 71, 13, 10, 26, 10]);61        assert!(bytes.len() > 100);62    }63}6465#[cfg(test)]66mod golden {67    use super::*;68    use crate::math::two::designs;69    #[test]70    fn png_pixels_stay_pinned() {71        let black = [0, 0, 0, 255];72        let white = [255, 255, 255, 255];73        let cases = [74            (75                png(&designs::carpet(3, 2).unwrap(), 4).unwrap(),76                36,77                1024,78                white,79            ),80            (81                png(&designs::htree(5, 1).unwrap(), 1).unwrap(),82                5,83                15,84                black,85            ),86            (87                png(&designs::vtree(7, 1).unwrap(), 3).unwrap(),88                21,89                252,90                white,91            ),92        ];93        for (bytes, side, inked, centre) in &cases {94            let (w, h, pixels) = crate::core::unpng(bytes).unwrap();95            assert_eq!((w, h), (*side, *side));96            assert!(pixels.iter().all(|p| *p == black || *p == white));97            assert_eq!(pixels.iter().filter(|p| **p == black).count(), *inked);98            assert_eq!(pixels[0], black);99            assert_eq!(pixels[(side / 2) * side + side / 2], *centre);100            assert_eq!(pixels[side * side - 1], black);101        }102    }103}