Minimal PNG encoder (no external dependency). Matches the macOS implementation byte-for-byte so screenshots are identical across platforms.
(width: u32, height: u32, rgba: &[u8])
| 2840 | /// implementation byte-for-byte so screenshots are identical across |
| 2841 | /// platforms. |
| 2842 | fn encode_png(width: u32, height: u32, rgba: &[u8]) -> Option<Vec<u8>> { |
| 2843 | use std::io::Write; |
| 2844 | |
| 2845 | let mut png = Vec::new(); |
| 2846 | png.write_all(&[137, 80, 78, 71, 13, 10, 26, 10]).ok()?; |
| 2847 | |
| 2848 | let mut ihdr = Vec::new(); |
| 2849 | ihdr.extend_from_slice(&width.to_be_bytes()); |
| 2850 | ihdr.extend_from_slice(&height.to_be_bytes()); |
| 2851 | ihdr.push(8); |
| 2852 | ihdr.push(6); |
| 2853 | ihdr.push(0); |
| 2854 | ihdr.push(0); |
| 2855 | ihdr.push(0); |
| 2856 | write_png_chunk(&mut png, b"IHDR", &ihdr); |
| 2857 | |
| 2858 | let row_bytes = (width * 4) as usize; |
| 2859 | let mut raw = Vec::with_capacity((row_bytes + 1) * height as usize); |
| 2860 | for y in 0..height as usize { |
| 2861 | raw.push(0); |
| 2862 | let start = y * row_bytes; |
| 2863 | for x in 0..width as usize { |
| 2864 | let idx = start + x * 4; |
| 2865 | // wgpu Bgra8UnormSrgb: byte order is B, G, R, A |
| 2866 | raw.push(rgba[idx + 2]); |
| 2867 | raw.push(rgba[idx + 1]); |
| 2868 | raw.push(rgba[idx + 0]); |
| 2869 | raw.push(255); |
| 2870 | } |
| 2871 | } |
| 2872 | |
| 2873 | let deflated = deflate_store(&raw); |
| 2874 | write_png_chunk(&mut png, b"IDAT", &deflated); |
| 2875 | write_png_chunk(&mut png, b"IEND", &[]); |
| 2876 | Some(png) |
| 2877 | } |
| 2878 | |
| 2879 | fn write_png_chunk(out: &mut Vec<u8>, chunk_type: &[u8; 4], data: &[u8]) { |
| 2880 | let len = data.len() as u32; |
no test coverage detected