libtif/
image.rs

1use crate::pixel::PixelColor;
2use std::{fmt, io::Read};
3const TIF_HEADER: [u8;5] = [46, 84, 73, 70, 32];
4
5#[derive(Debug)]
6pub enum TifImageError {
7    InvalidHeader
8}
9
10impl fmt::Display for TifImageError {
11    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12        write!(f, "{:?}", self)
13    }
14}
15
16impl std::error::Error for TifImageError{}
17
18#[derive(Clone, Debug)]
19pub struct TifImage {
20   pub height: u64, //we dont really care about the type, height isnt defined inside of a tif file itself
21   pub width: u8,
22   pub pixels: Vec<Vec<PixelColor>>
23}
24
25impl TifImage {
26    pub fn parse_from_file(filename: String) -> Result<Self, Box<dyn std::error::Error>> {
27        let mut file = std::fs::File::open(filename)?;
28        let mut buf: Vec<u8> = Vec::with_capacity(1024);
29        file.read_to_end(&mut buf)?;
30        Self::parse_from_bytes(buf)
31    }
32
33    pub fn parse_from_bytes(bytes: Vec<u8>) -> Result<Self, Box<dyn std::error::Error>> {
34        if bytes[0..5] != TIF_HEADER {
35            return Err(Box::new(TifImageError::InvalidHeader));
36        }
37        //width is defined inside the tif file
38        let width: u8 = bytes[5];
39
40
41        let mut raw_pixels: Vec<PixelColor> = vec![];
42
43        for byte in bytes[6..].chunks(2) {
44            if byte[1] == 0 { continue; }
45            for _ in 0..byte[1] {
46                raw_pixels.push(PixelColor::from(byte[0]));
47            }
48        }
49
50        //now we'll convert the raw pixels to the actual struct TifImage
51        let height = (raw_pixels.len() as u64) / (width as u64);
52
53        let pixels: Vec<Vec<PixelColor>> = raw_pixels.chunks(width as usize).map(|pixel| {
54            pixel.to_vec()
55        }).collect::<Vec<Vec<PixelColor>>>();
56
57        Ok(Self {
58            height,
59            width,
60            pixels
61        })
62    }
63
64    pub fn save(&self) -> Vec<u8> {
65        let mut buf: Vec<u8> = vec![];
66        buf.extend(TIF_HEADER.iter());
67        buf.push(self.width);
68        let mut current_color = PixelColor::Black;
69        let mut pixels: u8 = 0;
70
71        for i in &self.pixels {
72            for px in i {
73
74
75                if *px == current_color {
76                    pixels += 1;
77                    if pixels >= 255 {
78                        buf.push((*px).into());
79                        buf.push(pixels);
80                        pixels = 0;
81                    }
82                }else {
83                    if pixels > 0 {
84                        buf.push(current_color.into());
85                        buf.push(pixels);
86                    }
87                    current_color = *px;
88                    pixels = 1;
89                }
90            }
91        }
92
93        if pixels > 0 {
94            buf.push(current_color.into());
95            buf.push(pixels);
96        }
97
98        buf
99    }
100
101}