game_toolkit_dosvideo/
png.rs1fn crc32(data: &[u8], mut crc: u32) -> u32 {
4 for &b in data {
5 crc ^= b as u32;
6 for _ in 0..8 {
7 crc = if crc & 1 != 0 {
8 0xEDB8_8320 ^ (crc >> 1)
9 } else {
10 crc >> 1
11 };
12 }
13 }
14 crc
15}
16
17fn chunk(out: &mut Vec<u8>, kind: &[u8; 4], data: &[u8]) {
18 out.extend_from_slice(&(data.len() as u32).to_be_bytes());
19 out.extend_from_slice(kind);
20 out.extend_from_slice(data);
21 let c = crc32(data, crc32(kind, 0xFFFF_FFFF)) ^ 0xFFFF_FFFF;
22 out.extend_from_slice(&c.to_be_bytes());
23}
24
25pub fn encode_rgba(width: u32, height: u32, rgba: &[u8]) -> Vec<u8> {
27 let mut raw = Vec::with_capacity((width as usize * 4 + 1) * height as usize);
28 for row in rgba.chunks_exact(width as usize * 4).take(height as usize) {
29 raw.push(0);
30 raw.extend_from_slice(row);
31 }
32 let mut z = vec![0x78, 0x01];
33 let mut blocks = raw.chunks(65535).peekable();
34 if blocks.peek().is_none() {
35 z.extend_from_slice(&[1, 0, 0, 0xFF, 0xFF]);
36 }
37 while let Some(b) = blocks.next() {
38 z.push(u8::from(blocks.peek().is_none()));
39 let n = b.len() as u16;
40 z.extend_from_slice(&n.to_le_bytes());
41 z.extend_from_slice(&(!n).to_le_bytes());
42 z.extend_from_slice(b);
43 }
44 let (mut a, mut bb) = (1u32, 0u32);
45 for &x in &raw {
46 a = (a + x as u32) % 65521;
47 bb = (bb + a) % 65521;
48 }
49 z.extend_from_slice(&((bb << 16) | a).to_be_bytes());
50 let mut out = b"\x89PNG\r\n\x1a\n".to_vec();
51 let mut ihdr = Vec::with_capacity(13);
52 ihdr.extend_from_slice(&width.to_be_bytes());
53 ihdr.extend_from_slice(&height.to_be_bytes());
54 ihdr.extend_from_slice(&[8, 6, 0, 0, 0]);
55 chunk(&mut out, b"IHDR", &ihdr);
56 chunk(&mut out, b"IDAT", &z);
57 chunk(&mut out, b"IEND", &[]);
58 out
59}
60
61impl crate::crt::FrameView<'_> {
62 pub fn to_png(&self) -> Vec<u8> {
64 encode_rgba(self.width, self.height, self.rgba)
65 }
66}