|  | @@ -3,7 +3,9 @@ use std::fs::File;
 | 
	
		
			
				|  |  |  use clap::Parser;
 | 
	
		
			
				|  |  |  use serde::Deserialize;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type Pixel = (u8, u8, u8);
 | 
	
		
			
				|  |  | +mod image;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +use crate::image::{Image, Pixel};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Deserialize, Debug)]
 | 
	
		
			
				|  |  |  struct ColorEntry {
 | 
	
	
		
			
				|  | @@ -28,78 +30,6 @@ impl Mapping {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -struct Image {
 | 
	
		
			
				|  |  | -    width: u32,
 | 
	
		
			
				|  |  | -    height: u32,
 | 
	
		
			
				|  |  | -    data: Vec<Pixel>,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl Image {
 | 
	
		
			
				|  |  | -    fn load(path: impl AsRef<std::path::Path>) -> Result<Image, Box<dyn std::error::Error>> {
 | 
	
		
			
				|  |  | -        let decoder = png::Decoder::new(File::open(path)?);
 | 
	
		
			
				|  |  | -        let mut reader = decoder.read_info()?;
 | 
	
		
			
				|  |  | -        let mut buf = vec![0u8; reader.output_buffer_size()];
 | 
	
		
			
				|  |  | -        let info = reader.next_frame(buf.as_mut_slice())?;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let mut data = Vec::new();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let skip = match info.color_type {
 | 
	
		
			
				|  |  | -            png::ColorType::Rgb => 3,
 | 
	
		
			
				|  |  | -            png::ColorType::Rgba => 4,
 | 
	
		
			
				|  |  | -            other => panic!("Unhandled color type: {:?}", other),
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let rs = buf.iter().step_by(skip);
 | 
	
		
			
				|  |  | -        let gs = buf.iter().skip(1).step_by(skip);
 | 
	
		
			
				|  |  | -        let bs = buf.iter().skip(2).step_by(skip);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        for ((r, g), b) in rs.zip(gs).zip(bs) {
 | 
	
		
			
				|  |  | -            data.push((*r, *g, *b))
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        Ok(Image {
 | 
	
		
			
				|  |  | -            width: info.width,
 | 
	
		
			
				|  |  | -            height: info.height,
 | 
	
		
			
				|  |  | -            data,
 | 
	
		
			
				|  |  | -        })
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fn iter(&self) -> ImageIterator {
 | 
	
		
			
				|  |  | -        ImageIterator {
 | 
	
		
			
				|  |  | -            width: self.width,
 | 
	
		
			
				|  |  | -            x: 0,
 | 
	
		
			
				|  |  | -            y: 0,
 | 
	
		
			
				|  |  | -            values: self.data.iter(),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -struct ImageIterator<'a> {
 | 
	
		
			
				|  |  | -    width: u32,
 | 
	
		
			
				|  |  | -    x: u32,
 | 
	
		
			
				|  |  | -    y: u32,
 | 
	
		
			
				|  |  | -    values: std::slice::Iter<'a, Pixel>,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl<'a> Iterator for ImageIterator<'a> {
 | 
	
		
			
				|  |  | -    type Item = ((u32, u32), Pixel);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fn next(&mut self) -> Option<Self::Item> {
 | 
	
		
			
				|  |  | -        let px = self.values.next();
 | 
	
		
			
				|  |  | -        if let Some(px) = px {
 | 
	
		
			
				|  |  | -            let ret = ((self.x, self.y), *px);
 | 
	
		
			
				|  |  | -            self.x += 1;
 | 
	
		
			
				|  |  | -            if self.x == self.width {
 | 
	
		
			
				|  |  | -                self.x = 0;
 | 
	
		
			
				|  |  | -                self.y += 1;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            Some(ret)
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            None
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #[derive(Deserialize)]
 | 
	
		
			
				|  |  |  struct Config {
 | 
	
		
			
				|  |  |      grid_every: u32,
 |