1use std::path::Path;
21use std::fs::{read, read_to_string};
22use std::slice::Iter;
23
24use cgmath::{Vector3,vec3};
25use simple_canvas::Canvas;
26
27use crate::utils::complete_path;
28
29#[derive(Debug)]
30pub enum PpmReaderError{
31 ImageHeaderCouldNotBeRead,
32 ImageDoesNotExistAtPath
33}
34
35impl std::error::Error for PpmReaderError{}
36impl std::fmt::Display for PpmReaderError{
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "There was an error when trying to read an image file.")
39 }
40}
41
42pub fn read_ppm(directory: &Path, file_name: &str) -> Result<Canvas<Vector3<u8>>, Box<dyn std::error::Error>> {
49 let full_path = complete_path(directory, file_name);
50
51 if full_path.try_exists()? {
52 let file = read(&full_path)?;
53 let mut file_iter: Iter<'_, u8> = file.iter();
54 let mut header: String = "".to_string();
55 header.push(*file_iter.next().unwrap() as char);
56 header.push(*file_iter.next().unwrap() as char);
57 file_iter.next(); if header.eq("P6") {
59 return Ok(read_binary_image(&mut file_iter));
60 }
61 else if header.eq("P3") {
62 return Ok(read_string_image(&full_path));
63 } else {
64 Err(Box::new(PpmReaderError::ImageHeaderCouldNotBeRead))
65 }
66 } else {
67 Err(Box::new(PpmReaderError::ImageDoesNotExistAtPath))
68 }
69}
70
71fn read_string_image(path: &Path) -> Canvas<Vector3<u8>> {
73 let file = read_to_string(path).unwrap();
74 let mut file_iter = file.split([' ', '\n']);
75 file_iter.next(); let width: usize = file_iter.next().unwrap().parse::<usize>().unwrap();
77 let height: usize = file_iter.next().unwrap().parse::<usize>().unwrap();
78 let _color_code = file_iter.next(); let size = file_iter.size_hint().0;
80 if size != width * height && size % 3 != 0 {
81 println!("Actual size: {} * {} = {}", width, height, width * height);
82 println!("Iter size: {}", size);
83 panic!("Some pixel data seems to be missing or the file might be corrupted.")
84 };
85 let mut canvas: Canvas<Vector3<u8>> = Canvas::new(width, height, vec3(0,0,0));
86 for pixel in canvas.iter_mut() {
87 *pixel = vec3(file_iter.next().unwrap().parse::<u8>().unwrap(),
88 file_iter.next().unwrap().parse::<u8>().unwrap(),
89 file_iter.next().unwrap().parse::<u8>().unwrap()
90 )
91 }
92 canvas
93
94}
95
96fn read_binary_image(file_iter: &mut Iter<'_, u8>) -> Canvas<Vector3<u8>> {
98 let width_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
99 let mut width_str: String = "".to_string();
100 width_iter.for_each(|e| width_str.push(e as char));
101
102 let height_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
103 let mut height_str: String = "".to_string();
104 height_iter.for_each(|e| height_str.push(e as char));
105
106 let color_code_iter = file_iter.cloned().take_while(|e| (*e <= 57 && *e >= 48));
107 let mut color_code_str: String = "".to_string();
108 color_code_iter.for_each(|e| color_code_str.push(e as char));
109
110 let width = width_str.parse::<usize>().expect("Could not parse");
111 let height = height_str.parse::<usize>().expect("Could not parse");
112
113 let size = file_iter.size_hint().0;
114 if size != width * height && size % 3 != 0 {
115 println!("Actual size: {} * {} = {}", width, height, width * height);
116 println!("Iter size: {}", size);
117 panic!("Size issue")
118 }
119 let mut canvas: Canvas<Vector3<u8>> = Canvas::new(width, height, vec3(0,0,0));
120 for pixel in canvas.iter_mut() {
121 *pixel = vec3(*file_iter.next().unwrap(), *file_iter.next().unwrap(), *file_iter.next().unwrap());
122 }
123 canvas
124}