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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use image::{Image, PixelFormat};
use png;
use std::io::{self, Read, Write};
impl Image {
pub fn read_png<R: Read>(mut input: R) -> io::Result<Image> {
let mut v = Vec::new();
input.read_to_end(&mut v)?;
let image = Image::decode_from_png(v.as_slice())?;
Ok(Image {
format: PixelFormat::PNG,
width: image.width,
height: image.height,
data: v.into_boxed_slice(),
})
}
pub fn decode_from_png<R: Read>(input: R) -> io::Result<Image> {
let decoder = png::Decoder::new(input);
let mut reader = decoder.read_info()?;
let info = reader.info();
let pixel_format = match info.color_type {
png::ColorType::Rgba => PixelFormat::RGBA,
png::ColorType::Rgb => PixelFormat::RGB,
png::ColorType::GrayscaleAlpha => PixelFormat::GrayAlpha,
png::ColorType::Grayscale => PixelFormat::Gray,
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"unsupported PNG color \
type: {:?}",
info.color_type
),
));
}
};
if info.bit_depth != png::BitDepth::Eight {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"unsupported PNG bit depth: \
{:?}",
info.bit_depth
),
));
}
let mut image = Image::new(pixel_format, info.width, info.height);
assert_eq!(image.data().len(), reader.output_buffer_size());
reader.next_frame(image.data_mut())?;
Ok(image)
}
pub fn write_png<W: Write>(&self, mut output: W) -> io::Result<()> {
let color_type = match self.format {
PixelFormat::RGBA => png::ColorType::Rgba,
PixelFormat::RGB => png::ColorType::Rgb,
PixelFormat::GrayAlpha => png::ColorType::GrayscaleAlpha,
PixelFormat::Gray => png::ColorType::Grayscale,
PixelFormat::Alpha => {
return self.convert_to(PixelFormat::GrayAlpha).write_png(output);
}
PixelFormat::PNG => {
return output.write(&self.data).map(|_| ());
}
};
let mut encoder = png::Encoder::new(output, self.width, self.height);
encoder.set_color(color_type);
encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header()?;
writer
.write_image_data(&self.data)
.map_err(|err| match err {
png::EncodingError::IoError(err) => err,
png::EncodingError::Format(err) => {
io::Error::new(io::ErrorKind::InvalidData, err.to_string())
}
png::EncodingError::Parameter(err) => {
io::Error::new(io::ErrorKind::InvalidInput, err.to_string())
}
png::EncodingError::LimitsExceeded => {
io::Error::new(io::ErrorKind::Other, err.to_string())
}
})
}
}