Skip to main content

icns/
pngio.rs

1use super::image::{Image, PixelFormat};
2use std::io::{self, BufRead, Seek, Write};
3
4impl Image {
5    /// Reads an image from a PNG file.
6    pub fn read_png<R: BufRead + Seek>(input: R) -> io::Result<Image> {
7        let mut decoder = png::Decoder::new(input);
8        decoder.set_transformations(
9            png::Transformations::STRIP_16 | png::Transformations::EXPAND,
10        );
11        let info = decoder.read_header_info()?;
12        let (width, height) = (info.width, info.height);
13        let mut reader = decoder.read_info()?;
14
15        let (color_type, bit_depth) = reader.output_color_type();
16        assert!(bit_depth == png::BitDepth::Eight);
17        let pixel_format = match color_type {
18            png::ColorType::Rgba => PixelFormat::RGBA,
19            png::ColorType::Rgb => PixelFormat::RGB,
20            png::ColorType::GrayscaleAlpha => PixelFormat::GrayAlpha,
21            png::ColorType::Grayscale => PixelFormat::Gray,
22            _ => unreachable!(), // EXPAND prevents paletted output
23        };
24
25        let mut image = Image::new(pixel_format, width, height);
26        assert_eq!(Some(image.data().len()), reader.output_buffer_size());
27        reader.next_frame(image.data_mut())?;
28        reader.finish()?;
29        Ok(image)
30    }
31
32    /// Writes the image to a PNG file.
33    pub fn write_png<W: Write>(&self, output: W) -> io::Result<()> {
34        let color_type = match self.format {
35            PixelFormat::RGBA => png::ColorType::Rgba,
36            PixelFormat::RGB => png::ColorType::Rgb,
37            PixelFormat::GrayAlpha => png::ColorType::GrayscaleAlpha,
38            PixelFormat::Gray => png::ColorType::Grayscale,
39            PixelFormat::Alpha => {
40                return self
41                    .convert_to(PixelFormat::GrayAlpha)
42                    .write_png(output);
43            }
44        };
45        let mut encoder = png::Encoder::new(output, self.width, self.height);
46        encoder.set_color(color_type);
47        encoder.set_depth(png::BitDepth::Eight);
48
49        let mut writer = encoder.write_header()?;
50        writer.write_image_data(&self.data)?;
51        Ok(())
52    }
53}