From 7786aa99a1d4caf3ab207e247910fe00afa3f735 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Thu, 24 Jun 2021 16:40:33 -0700 Subject: [PATCH] canvas: enable saving to PNG. --- rtchallenge/src/canvas.rs | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/rtchallenge/src/canvas.rs b/rtchallenge/src/canvas.rs index df282a7..cffe1f8 100644 --- a/rtchallenge/src/canvas.rs +++ b/rtchallenge/src/canvas.rs @@ -1,12 +1,26 @@ +use std::fs::File; +use std::io::BufWriter; +use std::path::Path; + +use png; +use thiserror::Error; + use crate::tuples::{color, Color}; +#[derive(Error, Debug)] +pub enum CanvasError { + #[error("faile to write canvas")] + IOError(#[from] std::io::Error), + #[error("faile to encode canvas to png")] + EncodingError(#[from] png::EncodingError), +} pub struct Canvas { pub height: usize, pub width: usize, pub pixels: Vec, } -fn canvas(width: usize, height: usize) -> Canvas { +pub fn canvas(width: usize, height: usize) -> Canvas { let pixels = vec![color(0., 0., 0.); width * height]; Canvas { width, @@ -17,11 +31,44 @@ fn canvas(width: usize, height: usize) -> Canvas { impl Canvas { pub fn set(&mut self, x: usize, y: usize, c: Color) { + if x > self.width { + return; + } + if y > self.height { + return; + } self.pixels[x + y * self.width] = c; } pub fn get(&mut self, x: usize, y: usize) -> Color { self.pixels[x + y * self.width] } + pub fn write_to_file

(&self, path: P) -> Result<(), CanvasError> + where + P: AsRef, + { + let path = Path::new(path.as_ref()); + let file = File::create(path)?; + let ref mut w = BufWriter::new(file); + + let mut encoder = png::Encoder::new(w, self.width as u32, self.height as u32); + encoder.set_color(png::ColorType::RGB); + encoder.set_depth(png::BitDepth::Eight); + let mut writer = encoder.write_header()?; + + let data: Vec = self + .pixels + .iter() + .flat_map(|p| { + vec![ + (p.red.clamp(0., 1.) * 255.) as u8, + (p.green.clamp(0., 1.) * 255.) as u8, + (p.blue.clamp(0., 1.) * 255.) as u8, + ] + }) + .collect(); + writer.write_image_data(&data)?; + Ok(()) + } } #[cfg(test)] mod tests {