diff --git a/Cargo.toml b/Cargo.toml index 36c7a34..eb644d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,15 @@ repository = "https://github.com/image-rs/image-tiff" exclude = ["tests/images/*", "tests/fuzz_images/*"] [dependencies] -lzw = "0.10" +weezl = "0.1.0" + [dependencies.miniz_oxide] version = "0.4.1" features = ["no_extern_crate_alloc"] + +[dev-dependencies] +criterion = "0.3.1" + +[[bench]] +name = "lzw" +harness = false diff --git a/benches/lzw.rs b/benches/lzw.rs new file mode 100644 index 0000000..96e3d70 --- /dev/null +++ b/benches/lzw.rs @@ -0,0 +1,72 @@ +extern crate criterion; +extern crate tiff; + +use criterion::{black_box, BenchmarkId, BenchmarkGroup, Criterion, Throughput, measurement::Measurement}; +use tiff::decoder::Decoder; + +fn read_image(image: &[u8]) { + let image = std::io::Cursor::new(image); + let decoder = Decoder::new(black_box(image)); + let mut reader = decoder.unwrap(); + + while { + reader.read_image().unwrap(); + reader.more_images() + } {} +} + +fn main() { + struct BenchDef { + data: &'static [u8], + id: &'static str, + sample_size: usize, + } + + fn run_bench_def(group: &mut BenchmarkGroup, def: BenchDef) { + group + .sample_size(def.sample_size) + .throughput(Throughput::Bytes(def.data.len() as u64)) + .bench_with_input( + BenchmarkId::new(def.id, def.data.len()), + def.data, + |b, input| { + b.iter(|| read_image(input)) + } + ); + }; + + let mut c = Criterion::default().configure_from_args(); + let mut group = c.benchmark_group("tiff-lzw"); + + /* + run_bench_def(&mut group, BenchDef { + data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/images/quad-lzw-compat.tiff")), + id: "quad-lzw.tif", + sample_size: 500, + }); + */ + + run_bench_def(&mut group, BenchDef { + data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/images/issue_69_lzw.tiff")), + id: "issue-69-lzw.tif", + sample_size: 500, + }); + + run_bench_def(&mut group, BenchDef { + data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/kodim02-lzw.tif")), + id: "kodim02-lzw.tif", + sample_size: 20, + }); + + run_bench_def(&mut group, BenchDef { + data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/kodim07-lzw.tif")), + id: "kodim07-lzw.tif", + sample_size: 20, + }); + + run_bench_def(&mut group, BenchDef { + data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/Transparency-lzw.tif")), + id: "Transparency-lzw.tif", + sample_size: 20, + }); +} diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 2796fe4..dbdf300 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -2,7 +2,6 @@ use crate::bytecast; use crate::error::{TiffError, TiffResult}; -use lzw; use miniz_oxide::inflate; use std::io::{self, Read, Seek}; @@ -244,12 +243,27 @@ impl LZWReader { let mut compressed = vec![0; compressed_length as usize]; reader.read_exact(&mut compressed[..])?; let mut uncompressed = Vec::with_capacity(max_uncompressed_length); - let mut decoder = lzw::DecoderEarlyChange::new(lzw::MsbReader::new(), 8); + let mut decoder = weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8); let mut bytes_read = 0; while bytes_read < compressed_length && uncompressed.len() < max_uncompressed_length { - let (len, bytes) = decoder.decode_bytes(&compressed[bytes_read..])?; - bytes_read += len; - uncompressed.extend_from_slice(bytes); + let bytes_written = uncompressed.len(); + uncompressed.reserve(1 << 12); + let buffer_space = uncompressed.capacity(); + uncompressed.resize(buffer_space, 0u8); + + let result = decoder.decode_bytes(&compressed[bytes_read..], &mut uncompressed[bytes_written..]); + bytes_read += result.consumed_in; + uncompressed.truncate(bytes_written + result.consumed_out); + + match result.status { + Ok(weezl::LzwStatus::Ok) => {}, + Ok(weezl::LzwStatus::Done) => break, + Ok(weezl::LzwStatus::NoProgress) => return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "no lzw end code found", + )), + Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidData, err)), + } } let bytes = uncompressed.len(); diff --git a/src/lib.rs b/src/lib.rs index 7bb874b..c3f80dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! # Related Links //! * - The TIFF specification -extern crate lzw; +extern crate weezl; extern crate miniz_oxide; mod bytecast; diff --git a/tests/benches/README.md b/tests/benches/README.md new file mode 100644 index 0000000..616292c --- /dev/null +++ b/tests/benches/README.md @@ -0,0 +1,4 @@ +Copyrights: + +kodim*.png: Eastman Kodak Company, released for unrestricted use +Transparency.png: Public Domain, according to Wikimedia diff --git a/tests/benches/Transparency-lzw.tif b/tests/benches/Transparency-lzw.tif new file mode 100644 index 0000000..a7a26a9 Binary files /dev/null and b/tests/benches/Transparency-lzw.tif differ diff --git a/tests/benches/kodim02-lzw.tif b/tests/benches/kodim02-lzw.tif new file mode 100644 index 0000000..a1aabfb Binary files /dev/null and b/tests/benches/kodim02-lzw.tif differ diff --git a/tests/benches/kodim07-lzw.tif b/tests/benches/kodim07-lzw.tif new file mode 100644 index 0000000..f8d543d Binary files /dev/null and b/tests/benches/kodim07-lzw.tif differ