Skip to content

Commit

Permalink
New PNG inputs for benchmarking non-compressed, non-filtered data.
Browse files Browse the repository at this point in the history
  • Loading branch information
anforowicz committed Oct 31, 2023
1 parent f10238a commit e70e93c
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 9 deletions.
4 changes: 3 additions & 1 deletion benches/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ criterion_main!(benches);

fn bench_file(c: &mut Criterion, data: Vec<u8>, name: String) {
let mut group = c.benchmark_group("decode");
group.sample_size(20);
if data.len() > 100000 {
group.sample_size(20);
}

let decoder = Decoder::new(&*data);
let mut reader = decoder.read_info().unwrap();
Expand Down
Binary file added tests/benches/128x128-noncompressed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/benches/8x8-noncompressed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 20 additions & 8 deletions tests/benches/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
Copyrights:

Lohengrin_-_Illustrated_Sporting_and_Dramatic_News.png: Public Domain, according to Wikimedia
kodim*.png: Eastman Kodak Company, released for unrestricted use
Transparency.png: Public Domain, according to Wikimedia
* `Lohengrin_-_Illustrated_Sporting_and_Dramatic_News.png`: Public Domain, according to Wikimedia
* `kodim*.png`: Eastman Kodak Company, released for unrestricted use
* `Transparency.png`: Public Domain, according to Wikimedia
* `8x8-noncompressed.png` and `128x128-noncompressed.png`: Created using the
ad-hoc tool that can be found in the `noncompressed` folder.

The images use different filtering:
Lohengrin: no filtering
kodim02: mixed
kodim07: mainly paeth
kodim17: mainly sub
kodim23: mixed

* Lohengrin: no filtering
* kodim02: mixed
* kodim07: mainly paeth
* kodim17: mainly sub
* kodim23: mixed

The `noncompressed` images use no filtering, and `00` compression mode (i.e.
`BTYPE` = `00` = no compression; see
https://datatracker.ietf.org/doc/html/rfc1951#section-3.2.3 for more details).
These images are somewhat artificial, but may be useful for benchmarking
performance of parts outside of `fdeflate` crate and/or the `unfilter` function
(e.g. these images were originally used to evaluate changes to minimize copying
of image pixels between various buffers - see [this discussion](TODO) for more
details).
11 changes: 11 additions & 0 deletions tests/benches/noncompressed/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "pnggen"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
adler32 = "1.2.0"
byteorder = "1.5.0"
crc32fast = "1.3.2"
108 changes: 108 additions & 0 deletions tests/benches/noncompressed/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use byteorder::WriteBytesExt;
use std::fs::File;
use std::io::Write;

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();
}

fn write_chunk(w: &mut impl Write, chunk_type: &[u8], data: &[u8]) {
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();
}

fn write_ihdr(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(); // height
data.write_u8(8).unwrap(); // bit depth = always 8-bits per channel
data.write_u8(6).unwrap(); // color type = color + alpha
data.write_u8(0).unwrap(); // compression method (0 is the only allowed value)
data.write_u8(0).unwrap(); // filter method (0 is the only allowed value)
data.write_u8(0).unwrap(); // interlace method = no interlacing
//
write_chunk(w, b"IHDR", &data);
}

fn write_noncompressed_deflate_block(w: &mut impl Write, data: &[u8], last: bool) {
if last {
w.write_u8(1).unwrap();
} else {
w.write_u8(0).unwrap();
}

assert!(data.len() < 65535);
let len = data.len() as u16;
w.write_u16::<byteorder::LittleEndian>(len).unwrap();
w.write_u16::<byteorder::LittleEndian>(!len).unwrap();

w.write_all(data).unwrap();
}

fn write_idat(w: &mut impl Write, width: u32) {
// Generate arbitrary test pixels.
let image_pixels = {
let mut row = Vec::new();
row.write_u8(0).unwrap(); // filter = no filter

let row_pixels = (0..width)
.map(|i| {
let color: u8 = (i * 255 / width) as u8;
let alpha: u8 = 0xff;
[color, 255 - color, color / 2, alpha]
})
.flatten();
row.extend(row_pixels);

std::iter::repeat(row)
.take(width as usize)
.flatten()
.collect::<Vec<_>>()
};

let mut zlib_data = Vec::new();
zlib_data.write_u8(0x78).unwrap(); // CM + CINFO
zlib_data.write_u8(0x01).unwrap(); // FLG

let mut chunks = image_pixels.as_slice().chunks_exact(8192);
while let Some(chunk) = chunks.next() {
write_noncompressed_deflate_block(&mut zlib_data, chunk, false);
}
write_noncompressed_deflate_block(&mut zlib_data, chunks.remainder(), true);

let adler = adler32::adler32(image_pixels.as_slice()).unwrap();
zlib_data.write_u32::<byteorder::BigEndian>(adler).unwrap();

write_chunk(w, b"IDAT", &zlib_data);
}

fn write_iend(w: &mut impl Write) {
write_chunk(w, b"IEND", &[]);
}

fn write_png_file(w: &mut impl Write, width: u32) {
write_png_sig(w);
write_ihdr(w, width);
write_idat(w, width);
write_iend(w);
}

fn main() {
let mut f = File::create("8x8-noncompressed.png").unwrap();
write_png_file(&mut f, 8);

let mut f = File::create("128x128-noncompressed.png").unwrap();
write_png_file(&mut f, 128);
}

0 comments on commit e70e93c

Please sign in to comment.