From 19f2fdc726c531d5bbc05fbd0ea1445f61208ffb Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 5 Sep 2023 13:15:32 -0400 Subject: fix conversion bugs --- README.md | 4 ++-- check-size.sh | 4 ++-- src/lib.rs | 24 +++++++++++++++++++----- test/tiny-1bpp-gray.png | Bin 0 -> 327 bytes test/tiny-2bpp.png | Bin 0 -> 95 bytes test/tinyplte-8bpp.png | Bin 0 -> 158 bytes 6 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 test/tiny-1bpp-gray.png create mode 100644 test/tiny-2bpp.png create mode 100644 test/tinyplte-8bpp.png diff --git a/README.md b/README.md index c3e7e62..5011829 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Tiny Rust PNG decoder. This decoder can be used without `std` or `alloc` by disabling the `std` feature (enabled by default). -Also it has tiny code size (e.g. 5x smaller `.wasm.gz` size compared to the `png` crate — see `check-size.sh`). +Also it has tiny code size (e.g. >8x smaller `.wasm.gz` size compared to the `png` crate — see `check-size.sh`). ## Goals @@ -18,7 +18,7 @@ Also it has tiny code size (e.g. 5x smaller `.wasm.gz` size compared to the `png ## Non-goals - Adam7 interlacing (increases code complexity and interlaced PNGs are rare anyways) -- Significantly sacrificing code size for speed (except maybe with a feature enabled) +- Significantly sacrificing code size/complexity for speed - Checking block CRCs (increases code complexity and there’s already Adler32 checksums for IDAT chunks) diff --git a/check-size.sh b/check-size.sh index 6f12db0..618eb5b 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 -Oz examples/wasm-tiny-png/target/wasm32-unknown-unknown/release/wasm_tiny_png.wasm -o target/tiny_png.wasm && gzip -f target/tiny_png.wasm || exit 1 -cd examples/wasm-png && cargo b --release && cd ../.. && wasm-opt -Oz examples/wasm-png/target/wasm32-unknown-unknown/release/wasm_png.wasm -o target/png.wasm && gzip -f target/png.wasm || exit 1 +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-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 diff --git a/src/lib.rs b/src/lib.rs index 5c5121e..eb41034 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -772,7 +772,7 @@ impl ImageData<'_> { let mut dest = 4 * area; let mut src = area; for _ in 0..area { - let index: usize = buffer[src].into(); + let index: usize = buffer[src - 1].into(); buffer[dest - 4..dest].copy_from_slice(&palette[index]); dest -= 4; src -= 1; @@ -794,8 +794,10 @@ impl ImageData<'_> { src_bit = 8; } src_bit -= bit_depth; - let index: usize = - ((buffer[src] >> src_bit) & ((1 << bit_depth) - 1)).into(); + // NOTE: PNG uses most-significant-bit first, unlike everyone else in the world. + let index: usize = ((buffer[src] >> (8 - bit_depth - src_bit)) + & ((1 << bit_depth) - 1)) + .into(); buffer[dest - 4..dest].copy_from_slice(&palette[index]); dest -= 4; } @@ -1265,7 +1267,7 @@ fn read_non_idat_chunks( } // checksum reader.skip_bytes(4)?; - } else if chunk_type[0].is_ascii_lowercase() || &chunk_type == b"PLTE" { + } else if (chunk_type[0] & 0x20) != 0 || &chunk_type == b"PLTE" { // non-essential chunk reader.skip_bytes(chunk_len + 4)?; } else { @@ -1296,7 +1298,7 @@ pub fn read_png<'a, R: Read>( return Err(Error::BufferTooSmall); } let mut writer = DecompressedDataWriter::from(buf); - let mut palette = [[0, 0, 0, 0]; 256]; + let mut palette = [[0, 0, 0, 255]; 256]; let Some(idat_len) = read_non_idat_chunks(reader, &header, &mut palette)? else { return Err(Error::NoIdat); }; @@ -1420,6 +1422,18 @@ mod tests { test_both!("test/small_rgb.png"); } #[test] + fn test_tiny1bpp_gray() { + test_both!("test/tiny-1bpp-gray.png"); + } + #[test] + fn test_tiny2bpp() { + test_both!("test/tiny-2bpp.png"); + } + #[test] + fn test_tiny_plte8bpp() { + test_both!("test/tinyplte-8bpp.png"); + } + #[test] fn test_gray_alpha() { test_both!("test/gray_alpha.png"); } diff --git a/test/tiny-1bpp-gray.png b/test/tiny-1bpp-gray.png new file mode 100644 index 0000000..bcbe525 Binary files /dev/null and b/test/tiny-1bpp-gray.png differ diff --git a/test/tiny-2bpp.png b/test/tiny-2bpp.png new file mode 100644 index 0000000..9e3a49b Binary files /dev/null and b/test/tiny-2bpp.png differ diff --git a/test/tinyplte-8bpp.png b/test/tinyplte-8bpp.png new file mode 100644 index 0000000..1fcd988 Binary files /dev/null and b/test/tinyplte-8bpp.png differ -- cgit v1.2.3