1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::io::{Read, Write};
use png;
use super::{Bitmap, Gray, RGB};

pub trait PngColorType {
    type PngPixelType;
    const PNG_COLOR_TYPE: png::ColorType;
}

impl<T> PngColorType for Gray<T> {
    type PngPixelType = Gray<u8>;
    const PNG_COLOR_TYPE: png::ColorType = png::ColorType::Grayscale;
}

impl<T> PngColorType for RGB<T> {
    type PngPixelType = RGB<u8>;
    const PNG_COLOR_TYPE: png::ColorType = png::ColorType::RGB;
}

impl<T> Bitmap<T>
where
    T: PngColorType + Copy,
    T::PngPixelType: From<T>,
{
    /// Save bitmap as png
    pub fn write_png(&self, writer: impl Write) -> Result<(), png::EncodingError> {
        let mut encoder = png::Encoder::new(
            writer, self.width(), self.height(),
        );

        encoder.set_color(T::PNG_COLOR_TYPE);
        encoder.set_depth(png::BitDepth::Eight);

        let mut writer = encoder.write_header()?;
        let bitmap = Bitmap::<T::PngPixelType>::from(self);

        writer.write_image_data(bitmap.raw_pixels())
    }
}

impl<T> Bitmap<T>
where
    T: PngColorType,
    T: From<<T as PngColorType>::PngPixelType>,
    T::PngPixelType: Copy,
{
    /// Load bitmap from png
    pub fn read_png(reader: impl Read) -> Result<Bitmap<T>, png::DecodingError> {
        let decoder = png::Decoder::new(reader);
        let (info, mut reader) = decoder.read_info()?;

        if info.bit_depth != png::BitDepth::Eight {
            return Err(png::DecodingError::Other("Bit depth should be 8".into()));
        }

        if info.color_type != T::PNG_COLOR_TYPE {
            return Err(png::DecodingError::Other("Color type mismatch".into()));
        }

        let mut bitmap = Bitmap::<T::PngPixelType>::new(info.width, info.height);

        reader.next_frame(bitmap.raw_pixels_mut())?;

        Ok(Bitmap::<T>::from(&bitmap))
    }
}