use byteorder::WriteBytesExt;
use std::io::Write;
pub fn write_noncompressed_png(w: &mut impl Write, size: u32, idat_bytes: usize) {
write_png_sig(w);
write_rgba8_ihdr_with_width(w, size);
write_rgba8_idats(w, size, idat_bytes);
write_iend(w);
}
pub fn write_png_sig(w: &mut impl Write) {
const SIG: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];
w.write_all(&SIG).unwrap();
}
pub fn write_chunk(w: &mut impl Write, chunk_type: &[u8], data: &[u8]) {
assert_eq!(chunk_type.len(), 4);
let crc = {
let input = chunk_type
.iter()
.copied()
.chain(data.iter().copied())
.collect::<Vec<_>>();
crc32fast::hash(input.as_slice())
};
w.write_u32::<byteorder::BigEndian>(data.len() as u32)
.unwrap();
w.write_all(chunk_type).unwrap();
w.write_all(data).unwrap();
w.write_u32::<byteorder::BigEndian>(crc).unwrap();
}
pub fn write_rgba8_ihdr_with_width(w: &mut impl Write, width: u32) {
let mut data = Vec::new();
data.write_u32::<byteorder::BigEndian>(width).unwrap();
data.write_u32::<byteorder::BigEndian>(width).unwrap(); data.write_u8(8).unwrap(); data.write_u8(6).unwrap(); data.write_u8(0).unwrap(); data.write_u8(0).unwrap(); data.write_u8(0).unwrap(); write_chunk(w, b"IHDR", &data);
}
pub fn generate_rgba8_with_width_and_height(width: u32, height: u32) -> Vec<u8> {
let image_pixels = {
let mut row = Vec::new();
row.write_u8(0).unwrap();
let row_pixels = (0..width).flat_map(|i| {
let color: u8 = (i * 255 / width) as u8;
let alpha: u8 = 0xff;
[color, 255 - color, color / 2, alpha]
});
row.extend(row_pixels);
std::iter::repeat(row)
.take(height as usize)
.flatten()
.collect::<Vec<_>>()
};
let mut zlib_data = Vec::new();
let mut store_only_compressor =
fdeflate::StoredOnlyCompressor::new(std::io::Cursor::new(&mut zlib_data)).unwrap();
store_only_compressor.write_data(&image_pixels).unwrap();
store_only_compressor.finish().unwrap();
zlib_data
}
pub fn write_rgba8_idats(w: &mut impl Write, size: u32, idat_bytes: usize) {
let data = generate_rgba8_with_width_and_height(size, size);
for chunk in data.chunks(idat_bytes) {
write_chunk(w, b"IDAT", chunk);
}
}
pub fn write_iend(w: &mut impl Write) {
write_chunk(w, b"IEND", &[]);
}