use gifed::{writer::ImageBuilder, Gif, StandardGif}; #[rustfmt::skip] pub const DARK_PALETTE: &[u8] = &[ 0, 0, 0, // Background - Black 192, 192, 192, // Graphline - Mostly White 64, 64, 64, // Gridlines - Dark gray 32, 32, 32, // Minor Gridlines - Darker gray 144, 144, 255, // Primary 2 Colour - Blue 48, 192, 48, // Secondary 2 Colour - Green 96, 96, 224, // Primary Underfill - Light Blue 48, 128, 48, // Secondary Underfill - Lesser Green ]; const BACKGROUND: u8 = 0; const LINE: u8 = 1; const GRIDLINE: u8 = 2; const MINOR_GRIDLINE: u8 = 3; const LINE1: u8 = 4; const LINE2: u8 = 5; const LINE1_FILL: u8 = 6; const LINE2_FILL: u8 = 7; const WIDTH: usize = 256; const HEIGHT: usize = 160; const SIZE: usize = WIDTH * HEIGHT; pub fn make_1line(min: usize, max: usize, values: &[usize]) -> Gif { let range = max - min; // this assumes a range of values that is >1 per pixel let vpp = range / HEIGHT; let mut raster = vec![0; SIZE]; draw_grid(&mut raster); draw_line(&mut raster, values, vpp, LINE); let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16); standard.set_palette(Some(DARK_PALETTE[0..12].try_into().unwrap())); standard.push( ImageBuilder::new(WIDTH as u16, HEIGHT as u16) .build(raster) .unwrap(), ); standard } pub fn make_2line(min: usize, max: usize, values1: &[usize], values2: &[usize]) -> Gif { let range = max - min; // this assumes a range of values that is >1 per pixel let vpp = range / HEIGHT; let mut raster = vec![0; SIZE]; draw_grid(&mut raster); draw_line_underfill(&mut raster, values1, vpp, LINE1, LINE1_FILL); draw_line_underfill(&mut raster, values2, vpp, LINE2, LINE2_FILL); let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16); standard.set_palette(Some(DARK_PALETTE.try_into().unwrap())); standard.push( ImageBuilder::new(WIDTH as u16, HEIGHT as u16) .build(raster) .unwrap(), ); standard } fn draw_grid(raster: &mut [u8]) { // Draw Divisions // we want a gridline every 16 pixels, but not the bottom // or top, so only 8. for div in 1..=9 { let y_val = div * 16; let grid = if div % 2 == 0 { GRIDLINE } else { MINOR_GRIDLINE }; for x in 0..WIDTH { raster[y_val * WIDTH + x] = grid; } } } fn draw_line(raster: &mut [u8], values: &[usize], vpp: usize, colour: u8) { // Draw Line // this will be discontinuous and i think that's okay. we // could make it a proper line by keeping track what value // was last and drawing the whole vertical there for (x, value) in values.iter().enumerate() { let value_height = value / vpp; if value_height > (HEIGHT - 1) { continue; } let y_val = (HEIGHT - 1) - value_height; raster[y_val * WIDTH + x] = colour; } } fn draw_line_underfill( raster: &mut [u8], values: &[usize], vpp: usize, colour: u8, colour_fill: u8, ) { for (x, value) in values.iter().enumerate() { let value_height = value / vpp; if value_height > (HEIGHT - 1) { continue; } let y_val = (HEIGHT - 1) - value_height; for y in y_val + 1..HEIGHT { raster[y * WIDTH + x] = colour_fill; } raster[y_val * WIDTH + x] = colour; } }