use std::path::Path;
use std::fs::{read, read_to_string};
use std::slice::Iter;
use cgmath::vec3;
use crate::canvas::*;
#[derive(Debug)]
pub enum PpmReaderError{
ImageHeaderCouldNotBeRead,
ImageDoesNotExistAtPath
}
impl std::error::Error for PpmReaderError{}
impl std::fmt::Display for PpmReaderError{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "There was an error when trying to read an image file.")
}
}
pub fn read_ppm(path: &Path) -> Result<Canvas, Box<dyn std::error::Error>> {
if path.try_exists()? {
let mut file_name = path.file_name().unwrap().to_str().unwrap().to_string();
file_name.truncate(file_name.len()-4);
let file = read(path)?;
let mut file_iter: Iter<'_, u8> = file.iter();
let mut header: String = "".to_string();
header.push(*file_iter.next().unwrap() as char);
header.push(*file_iter.next().unwrap() as char);
file_iter.next(); if header.eq("P6") {
return Ok(read_binary_image(file_name, &mut file_iter));
}
else if header.eq("P3") {
return Ok(read_string_image(file_name, path));
} else {
Err(Box::new(PpmReaderError::ImageHeaderCouldNotBeRead))
}
} else {
Err(Box::new(PpmReaderError::ImageDoesNotExistAtPath))
}
}
fn read_string_image(file_name: String,path: &Path) -> Canvas {
let file = read_to_string(path).unwrap();
let mut file_iter = file.split([' ', '\n']);
file_iter.next(); let width: usize = file_iter.next().unwrap().parse::<usize>().unwrap();
let height: usize = file_iter.next().unwrap().parse::<usize>().unwrap();
let _color_code = file_iter.next(); let size = file_iter.size_hint().0;
if size != width * height && size % 3 != 0 {
println!("Actual size: {} * {} = {}", width, height, width * height);
println!("Iter size: {}", size);
panic!("Some pixel data seems to be missing or the file might be corrupted.")
};
let mut canvas = Canvas::new(&file_name, width, height);
for pixel in canvas.iter_mut() {
*pixel = vec3(file_iter.next().unwrap().parse::<u8>().unwrap(),
file_iter.next().unwrap().parse::<u8>().unwrap(),
file_iter.next().unwrap().parse::<u8>().unwrap()
)
}
canvas
}
fn read_binary_image(file_name: String, file_iter: &mut Iter<'_, u8>) -> Canvas {
let width_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
let mut width_str: String = "".to_string();
width_iter.for_each(|e| width_str.push(e as char));
let height_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
let mut height_str: String = "".to_string();
height_iter.for_each(|e| height_str.push(e as char));
let color_code_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
let mut color_code_str: String = "".to_string();
color_code_iter.for_each(|e| color_code_str.push(e as char));
let width = width_str.parse::<usize>().expect("Could not parse");
let height = height_str.parse::<usize>().expect("Could not parse");
let size = file_iter.size_hint().0;
if size != width * height && size % 3 != 0 {
println!("Actual size: {} * {} = {}", width, height, width * height);
println!("Iter size: {}", size);
panic!("Size issue")
}
let mut canvas = Canvas::new(&file_name, width, height);
for pixel in canvas.iter_mut() {
*pixel = vec3(*file_iter.next().unwrap(), *file_iter.next().unwrap(), *file_iter.next().unwrap());
}
canvas
}