From 6fdb5619052ff68face6ad06b4423776ce8bd4f2 Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 5 Sep 2023 22:37:10 -0400 Subject: rename to minipng --- Cargo.toml | 7 ++++++- README.md | 17 ++++++++++------- benches/bench.rs | 12 ++++++------ check-size.sh | 4 ++-- examples/example.rs | 4 ++-- examples/profile.rs | 4 ++-- examples/wasm-minipng/.cargo/config.toml | 2 ++ examples/wasm-minipng/Cargo.toml | 14 ++++++++++++++ examples/wasm-minipng/src/lib.rs | 15 +++++++++++++++ examples/wasm-tiny-png/.cargo/config.toml | 2 -- examples/wasm-tiny-png/Cargo.toml | 14 -------------- examples/wasm-tiny-png/src/lib.rs | 15 --------------- src/test.rs | 10 +++++----- 13 files changed, 64 insertions(+), 56 deletions(-) create mode 100644 examples/wasm-minipng/.cargo/config.toml create mode 100644 examples/wasm-minipng/Cargo.toml create mode 100644 examples/wasm-minipng/src/lib.rs delete mode 100644 examples/wasm-tiny-png/.cargo/config.toml delete mode 100644 examples/wasm-tiny-png/Cargo.toml delete mode 100644 examples/wasm-tiny-png/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index add0d26..44f6234 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,10 @@ [package] -name = "tiny-png" +name = "minipng" +description = "Tiny PNG decoder with no dependencies" +repository = "https://github.com/pommicket/minipng" +categories = ["encoding", "graphics", "multimedia::images", "no-std::no-alloc"] +keywords = ["png", "decoder", "image", "no_std", "no_alloc"] +license = "0BSD" version = "0.1.0" edition = "2021" diff --git a/README.md b/README.md index d4bb721..65c28ea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -## tiny-png +## minipng + +[crates.io page](https://crates.io/crates/minipng) · [repository](https://github.com/pommicket/minipng) Tiny Rust PNG decoder with no dependencies (not even `std` or `alloc`) and tiny code size (e.g. >8 times smaller `.wasm.gz` size compared to the `png` crate — see `check-size.sh`). @@ -15,11 +17,12 @@ and tiny code size (e.g. >8 times smaller `.wasm.gz` size compared to the `pn ## Non-goals - Adam7 interlacing (increases code complexity and interlaced PNGs are rare anyways) -- Significantly sacrificing code size/complexity for speed -- Checking block CRCs (increases code complexity +- significantly sacrificing code size/complexity for speed +- checking block CRCs (increases code complexity and there’s already Adler32 checksums for IDAT chunks) - ancillary chunks (tEXt, iCCP, etc.) - correctly handling non-indexed image with tRNS chunk (who uses this?) +- animated PNGs ## Example usage @@ -28,7 +31,7 @@ Basic usage: ```rust let mut buffer = vec![0; 1 << 20]; // hope this is big enough! let png = &include_bytes!("../examples/image.png")[..]; -let image = tiny_png::decode_png(png, &mut buffer).expect("bad PNG"); +let image = minipng::decode_png(png, &mut buffer).expect("bad PNG"); println!("{}×{} image", image.width(), image.height()); let pixels = image.pixels(); println!("top-left pixel is #{:02x}{:02x}{:02x}", pixels[0], pixels[1], pixels[2]); @@ -39,9 +42,9 @@ More complex example that allocates the right number of bytes and handles all co ```rust let png = &include_bytes!("../examples/image.png")[..]; -let header = tiny_png::decode_png_header(png).expect("bad PNG"); +let header = minipng::decode_png_header(png).expect("bad PNG"); let mut buffer = vec![0; header.required_bytes_rgba8bpc()]; -let mut image = tiny_png::decode_png(png, &mut buffer).expect("bad PNG"); +let mut image = minipng::decode_png(png, &mut buffer).expect("bad PNG"); image.convert_to_rgba8bpc(); println!("{}×{} image", image.width(), image.height()); let pixels = image.pixels(); @@ -69,7 +72,7 @@ tests and no way of enabling `--nocapture` by default *grumble grumble*). ## Performance -Benchmarks (see `cargo bench`) show that `tiny-png` is about 50% slower than the `png` crate +Benchmarks (see `cargo bench`) show that `minipng` is about 50% slower than the `png` crate for large images, but faster than `png` for small images. ## License diff --git a/benches/bench.rs b/benches/bench.rs index cb3f4d9..a41f600 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -8,12 +8,12 @@ fn run_benches(c: &mut Criterion) { let mut group = c.benchmark_group("large-image"); group.sample_size(50); - group.bench_function("tiny-png", |b| { + group.bench_function("minipng", |b| { b.iter(|| { let png = &large_image[..]; - let header = tiny_png::decode_png_header(png).unwrap(); + let header = minipng::decode_png_header(png).unwrap(); let mut buf = vec![0; header.required_bytes()]; - let data = tiny_png::decode_png(png, &mut buf).unwrap(); + let data = minipng::decode_png(png, &mut buf).unwrap(); std::hint::black_box(data); }) }); @@ -32,12 +32,12 @@ fn run_benches(c: &mut Criterion) { let mut group = c.benchmark_group("small-image"); group.sample_size(1000); - group.bench_function("tiny-png", |b| { + group.bench_function("minipng", |b| { b.iter(|| { let png = &small_image[..]; - let header = tiny_png::decode_png_header(png).unwrap(); + let header = minipng::decode_png_header(png).unwrap(); let mut buf = vec![0; header.required_bytes()]; - let data = tiny_png::decode_png(png, &mut buf).unwrap(); + let data = minipng::decode_png(png, &mut buf).unwrap(); std::hint::black_box(data); }) }); diff --git a/check-size.sh b/check-size.sh index 618eb5b..b0de7cc 100755 --- a/check-size.sh +++ b/check-size.sh @@ -1,6 +1,6 @@ #!/bin/sh -cd examples/wasm-tiny-png && cargo b --release && cd ../.. && wasm-opt --strip-debug -Oz examples/wasm-tiny-png/target/wasm32-unknown-unknown/release/wasm_tiny_png.wasm -o target/tiny_png.wasm && gzip -k -f target/tiny_png.wasm || exit 1 +cd examples/wasm-minipng && cargo b --release && cd ../.. && wasm-opt --strip-debug -Oz examples/wasm-minipng/target/wasm32-unknown-unknown/release/wasm_minipng.wasm -o target/minipng.wasm && gzip -k -f target/minipng.wasm || exit 1 cd examples/wasm-png && cargo b --release && cd ../.. && wasm-opt --strip-debug -Oz examples/wasm-png/target/wasm32-unknown-unknown/release/wasm_png.wasm -o target/png.wasm && gzip -k -f target/png.wasm || exit 1 -wc -c target/png.wasm.gz target/tiny_png.wasm.gz | head -n2 +wc -c target/png.wasm.gz target/minipng.wasm.gz | head -n2 diff --git a/examples/example.rs b/examples/example.rs index dda0a79..c26b484 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,9 +1,9 @@ fn main() { let png = &include_bytes!("image.png")[..]; - let header = tiny_png::decode_png_header(png).expect("bad PNG"); + let header = minipng::decode_png_header(png).expect("bad PNG"); println!("need {} bytes of memory", header.required_bytes()); let mut buffer = vec![0; header.required_bytes()]; - let image = tiny_png::decode_png(png, &mut buffer).expect("bad PNG"); + let image = minipng::decode_png(png, &mut buffer).expect("bad PNG"); println!("{}×{} image", image.width(), image.height()); let pixels = image.pixels(); println!( diff --git a/examples/profile.rs b/examples/profile.rs index fb8110a..9833c32 100644 --- a/examples/profile.rs +++ b/examples/profile.rs @@ -11,9 +11,9 @@ fn main() { for _ in 0..100 { let png = &large_image[..]; - let header = tiny_png::decode_png_header(png).unwrap(); + let header = minipng::decode_png_header(png).unwrap(); let mut buf = vec![0; header.required_bytes()]; - let data = tiny_png::decode_png(png, &mut buf).unwrap(); + let data = minipng::decode_png(png, &mut buf).unwrap(); std::hint::black_box(data); } } diff --git a/examples/wasm-minipng/.cargo/config.toml b/examples/wasm-minipng/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/examples/wasm-minipng/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/examples/wasm-minipng/Cargo.toml b/examples/wasm-minipng/Cargo.toml new file mode 100644 index 0000000..ac51c8b --- /dev/null +++ b/examples/wasm-minipng/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "wasm-minipng" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +minipng = { path = "../.." } + +[profile.release] +opt-level = "z" +lto = true diff --git a/examples/wasm-minipng/src/lib.rs b/examples/wasm-minipng/src/lib.rs new file mode 100644 index 0000000..aebf88b --- /dev/null +++ b/examples/wasm-minipng/src/lib.rs @@ -0,0 +1,15 @@ +#[no_mangle] +pub unsafe fn decode_png(input: *const u8, input_len: usize, output: *mut u8, output_len: usize) -> usize { + let input = core::slice::from_raw_parts(input, input_len); + let output = core::slice::from_raw_parts_mut(output, output_len); + let Ok(header) = minipng::decode_png_header(input) else { + return 0; + }; + let required_bytes = header.required_bytes(); + if output_len >= required_bytes { + if minipng::decode_png(input, output).is_err() { + return 0; + } + } + required_bytes +} diff --git a/examples/wasm-tiny-png/.cargo/config.toml b/examples/wasm-tiny-png/.cargo/config.toml deleted file mode 100644 index f4e8c00..0000000 --- a/examples/wasm-tiny-png/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-unknown-unknown" diff --git a/examples/wasm-tiny-png/Cargo.toml b/examples/wasm-tiny-png/Cargo.toml deleted file mode 100644 index 5c8dae5..0000000 --- a/examples/wasm-tiny-png/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "wasm-tiny-png" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -tiny-png = { path = "../.." } - -[profile.release] -opt-level = "z" -lto = true diff --git a/examples/wasm-tiny-png/src/lib.rs b/examples/wasm-tiny-png/src/lib.rs deleted file mode 100644 index 449b67d..0000000 --- a/examples/wasm-tiny-png/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[no_mangle] -pub unsafe fn decode_png(input: *const u8, input_len: usize, output: *mut u8, output_len: usize) -> usize { - let input = core::slice::from_raw_parts(input, input_len); - let output = core::slice::from_raw_parts_mut(output, output_len); - let Ok(header) = tiny_png::decode_png_header(input) else { - return 0; - }; - let required_bytes = header.required_bytes(); - if output_len >= required_bytes { - if tiny_png::decode_png(input, output).is_err() { - return 0; - } - } - required_bytes -} diff --git a/src/test.rs b/src/test.rs index df9f7d0..06a634d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -29,16 +29,16 @@ fn test_bytes(bytes: &[u8]) -> Result<(), Flaw> { if let Ok(png_header) = reader.next_frame(&mut png_buf) { let png_bytes = &png_buf[..png_header.buffer_size()]; - let tiny_header = match decode_png_header(bytes) { + let mini_header = match decode_png_header(bytes) { Ok(h) => h, Err(Error::UnsupportedInterlace) => return Ok(()), Err(_) => return Err(Flaw::ErrorFromValidPNG), }; - let mut tiny_buf = vec![0; tiny_header.required_bytes_rgba8bpc()]; + let mut mini_buf = vec![0; mini_header.required_bytes_rgba8bpc()]; let mut image = - decode_png(bytes, &mut tiny_buf).map_err(|_| Flaw::ErrorFromValidPNG)?; - let tiny_bytes = image.pixels(); - if png_bytes != tiny_bytes { + decode_png(bytes, &mut mini_buf).map_err(|_| Flaw::ErrorFromValidPNG)?; + let mini_bytes = image.pixels(); + if png_bytes != mini_bytes { return Err(Flaw::DecodedMismatch); } let (_, mut data) = png_decoder::decode(bytes).unwrap(); -- cgit v1.2.3