1use std::io::BufWriter;
4
5pub fn encode_png(width: u32, height: u32, rgba: &[u8]) -> Result<Vec<u8>, String> {
7 let mut out = Vec::new();
8 {
9 let mut encoder = png::Encoder::new(BufWriter::new(&mut out), width, height);
10 encoder.set_color(png::ColorType::Rgba);
11 encoder.set_depth(png::BitDepth::Eight);
12 encoder.set_compression(png::Compression::High);
13 let mut writer = encoder.write_header().map_err(|e| e.to_string())?;
14 writer.write_image_data(rgba).map_err(|e| e.to_string())?;
15 }
16 Ok(out)
17}
18
19pub fn decode_png(bytes: &[u8]) -> Result<(u32, u32, Vec<u8>), String> {
21 let mut decoder = png::Decoder::new(std::io::Cursor::new(bytes));
22 let mut wanted = png::Transformations::EXPAND;
24 wanted.insert(png::Transformations::ALPHA);
25 wanted.insert(png::Transformations::STRIP_16);
26 decoder.set_transformations(wanted);
27 let mut reader = decoder.read_info().map_err(|e| e.to_string())?;
28 let size = reader
29 .output_buffer_size()
30 .ok_or("the picture is too large to decode")?;
31 let mut buf = vec![0; size];
32 let info = reader.next_frame(&mut buf).map_err(|e| e.to_string())?;
33 buf.truncate(info.buffer_size());
34 Ok((info.width, info.height, buf))
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn png_round_trips() {
43 let rgba: Vec<u8> = (0..2 * 3 * 4)
44 .map(|i| u8::try_from(i * 10).unwrap())
45 .collect();
46 let png = encode_png(2, 3, &rgba).unwrap();
47 assert_eq!(decode_png(&png).unwrap(), (2, 3, rgba));
48 assert!(decode_png(b"nope").is_err());
49 assert!(encode_png(2, 3, &[0; 4]).is_err());
50 }
51}