use std::{ fs::{self, File}, io::{stdin, BufReader}, }; use image::{self, DynamicImage, GenericImageView, ImageFormat, Rgba}; // pub const OUTPUT_DIR: &str = "ch32_decoder"; pub const OUTPUT_DIR: &str = "pico_decoder/src"; pub const WIDTH: usize = 320; pub const HEIGHT: usize = 240; pub const FRAME_SIZE: usize = WIDTH * HEIGHT; pub type Frame = [[u8; HEIGHT]; WIDTH]; pub const FRAME_0: Frame = [[0; HEIGHT]; WIDTH]; pub const FRAME_1: Frame = [[1; HEIGHT]; WIDTH]; pub fn wait_for_input() { stdin().read_line(&mut String::new()).unwrap(); } fn convert_pixel(rgba: Rgba) -> u8 { (rgba.0[0] > 128) as u8 } pub fn convert_image(image: &DynamicImage) -> Frame { let mut frame = FRAME_0; for x in 0..WIDTH { for y in 0..HEIGHT { frame[x][y] = convert_pixel(image.get_pixel(x as u32, y as u32)); } } frame } pub fn get_all_frames(path: &str) -> Vec { let frame_count = fs::read_dir(path).unwrap().count(); let mut frames = Vec::new(); for i in 0..frame_count { let path = format!("{}frame_{:04}.png", path, i + 1); let file = BufReader::new(File::open(path).unwrap()); let image = image::load(file, ImageFormat::Png).unwrap(); frames.push(convert_image(&image)); } frames } pub fn frame_error(real: &Frame, decoded: &Frame) -> usize { let mut error = 0; for x in 0..WIDTH { for y in 0..HEIGHT { if real[x][y] != decoded[x][y] { error += 1; } } } error } pub fn most_common_pixel(frame: &Frame) -> u8 { let mut white_pixels = 0; let mut black_pixels = 0; for col in frame { for &p in col { let p = p as u32; white_pixels += p; black_pixels += 1 - p; } } if white_pixels > black_pixels { 1 } else { 0 } } fn render_pixel_pair(img: &Frame, x: usize, y: usize) { let char = match (img[x][y * 2], img[x][y * 2 + 1]) { (0, 0) => " ", (0, 1) => "▄", (1, 0) => "▀", (1, 1) => "█", _ => panic!("image contained nonbinary bytes"), }; print!("{}", char); } pub fn render_image(img: &Frame) { for y in 0..(HEIGHT / 2) { for x in 0..WIDTH { render_pixel_pair(img, x, y); } println!(); } } pub fn render_images(left: &Frame, right: &Frame) { for y in 0..(HEIGHT / 2) { print!("|"); for x in 0..WIDTH { render_pixel_pair(left, x, y); } print!("|"); for x in 0..WIDTH { render_pixel_pair(right, x, y); } println!("|"); } } pub fn rle_255_encode(raw: &[u8]) -> Vec { rle_encode(raw, 255) } pub fn rle_encode(raw: &[u8], max: u8) -> Vec { let mut encoded = Vec::new(); let mut last_val = 0; let mut run = 0; for &val in raw { if val != last_val || run == max { encoded.push(run); if run == max && val == last_val { encoded.push(0); } run = 1; } else { run += 1; } last_val = val; } encoded.push(run); encoded } pub fn pack_nybbles(mut nybbles: Vec) -> Vec { if nybbles.len() % 2 == 1 { nybbles.push(0); } assert!(nybbles.iter().all(|&n| n < 16)); let mut packed = Vec::with_capacity(nybbles.len() / 2); for i in 0..(nybbles.len() / 2) { let upper = nybbles[i * 2] << 4; let lower = nybbles[i * 2 + 1] & 15; let byte = upper | lower; packed.push(byte); } packed } pub fn unpack_nybbles(packed: &[u8]) -> Vec { let mut nybbles = Vec::with_capacity(packed.len() * 2); for &p in packed { nybbles.push(p >> 4); nybbles.push(p & 15); } nybbles } pub fn rle_255_decode(encoded: &[u8], max_size: usize) -> (usize, Vec) { let mut raw = Vec::new(); let mut val = 0; let mut consumed_bytes = 0; for &run in encoded { consumed_bytes += 1; for _ in 0..run { raw.push(val); } if raw.len() >= max_size { break; } val = 1 - val; } (consumed_bytes, raw) }