|
@@ -3,7 +3,9 @@ use std::fs::File;
|
|
use clap::Parser;
|
|
use clap::Parser;
|
|
use serde::Deserialize;
|
|
use serde::Deserialize;
|
|
|
|
|
|
-type Pixel = (u8, u8, u8);
|
|
|
|
|
|
+mod image;
|
|
|
|
+
|
|
|
|
+use crate::image::{Image, Pixel};
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
#[derive(Deserialize, Debug)]
|
|
struct ColorEntry {
|
|
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)]
|
|
#[derive(Deserialize)]
|
|
struct Config {
|
|
struct Config {
|
|
grid_every: u32,
|
|
grid_every: u32,
|