1mod zlib;
2
3use crc::{crc32, Hasher32};
4use std::io;
5use zlib::compress;
6
7pub struct Image<'a> {
8 pub width: u32,
9 pub height: u32,
10 data: &'a [u8],
11}
12
13impl<'a> Image<'a> {
14 pub fn new(data: &'a [u8], width: u32, height: u32) -> Image<'a> {
15 Image {
16 data,
17 width,
18 height,
19 }
20 }
21
22 pub fn encode_into<W: io::Write>(&self, buffer: &mut W) -> io::Result<()> {
23 write_header(buffer)?;
24 write_chunks(buffer, self.data, self.width, self.height)
25 }
26}
27
28pub fn write_header<W: io::Write>(buffer: &mut W) -> io::Result<()> {
29 buffer.write_all(b"\x89PNG\r\n\x1A\n")
30}
31
32pub fn write_chunks<W: io::Write>(
33 buffer: &mut W,
34 screen_data: &[u8],
35 width: u32,
36 height: u32,
37) -> io::Result<()> {
38 write_ihdr(buffer, width, height, 8u8, 6u8, 0u8, 0u8, 0u8)?;
39 write_idat(buffer, screen_data, width, height)?;
40 write_iend(buffer)?;
41
42 Ok(())
43}
44
45fn write_ihdr<W: io::Write>(
46 buffer: &mut W,
47 width: u32,
48 height: u32,
49 bit_depth: u8,
50 color_type: u8,
51 compression_method: u8,
52 filter_method: u8,
53 interlace_method: u8,
54) -> io::Result<()> {
55 let wb = width.to_be_bytes();
56 let hb = height.to_be_bytes();
57 let mut data = [
58 wb[0],
59 wb[1],
60 wb[2],
61 wb[3],
62 hb[0],
63 hb[1],
64 hb[2],
65 hb[3],
66 bit_depth,
67 color_type,
68 compression_method,
69 filter_method,
70 interlace_method,
71 ];
72 write_chunk(buffer, b"IHDR", &mut data)
73}
74
75fn write_idat<W: io::Write>(
76 buffer: &mut W,
77 screen_data: &[u8],
78 width: u32,
79 height: u32,
80) -> io::Result<()> {
81 let mut filtered = vec![];
82 for y in 0..height {
83 let start = (y * width * 4) as usize;
84 let end = start + (width as usize) * 4;
85 filtered.push(0);
86 let data = &screen_data[start..end];
87 filtered.extend_from_slice(data);
88 }
89 let compressed = compress(&filtered);
90
91 write_chunk(buffer, b"IDAT", &compressed)
92}
93
94fn write_iend<W: io::Write>(buffer: &mut W) -> io::Result<()> {
95 write_chunk(buffer, b"IEND", &[])
96}
97
98fn write_chunk<W: io::Write>(buffer: &mut W, kind: &[u8; 4], data: &[u8]) -> io::Result<()> {
99 buffer.write_all(&(data.len() as u32).to_be_bytes())?;
100 buffer.write_all(kind)?;
101 buffer.write_all(data)?;
102
103 let mut digest = crc32::Digest::new(crc32::IEEE);
104 digest.write(kind);
105 digest.write(data);
106 buffer.write_all(&digest.sum32().to_be_bytes())?;
107
108 Ok(())
109}