From 5444ff9c45d4870d4a6da9553a6d123a873248f5 Mon Sep 17 00:00:00 2001 From: Stefan Schake Date: Thu, 19 Dec 2024 19:01:42 +0100 Subject: [PATCH] Support the ZSTD compression method for reading ZSTD is generally recognized as superior to LZW in size and speed, particularly for decompression. We use the self-assigned tag first defined by libtiff and also used by GDAL and others. --- Cargo.toml | 1 + src/decoder/image.rs | 5 ++++- src/tags.rs | 3 +++ tests/decode_images.rs | 6 ++++++ tests/images/int16_zstd.tif | Bin 0 -> 7835 bytes 5 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/images/int16_zstd.tif diff --git a/Cargo.toml b/Cargo.toml index baf432fd..be4f4dd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"] weezl = "0.1.0" jpeg = { package = "jpeg-decoder", version = "0.3.0", default-features = false } flate2 = "1.0.20" +zstd = "0.13" [dev-dependencies] criterion = "0.3.1" diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 1a616401..07ef34e1 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -378,7 +378,10 @@ impl Image { CompressionMethod::None => Box::new(reader), CompressionMethod::LZW => { Box::new(LZWReader::new(reader, usize::try_from(compressed_length)?)) - } + }, + CompressionMethod::ZSTD => { + Box::new(zstd::Decoder::new(reader)?) + }, CompressionMethod::PackBits => Box::new(PackBitsReader::new(reader, compressed_length)), CompressionMethod::Deflate | CompressionMethod::OldDeflate => { Box::new(DeflateReader::new(reader)) diff --git a/src/tags.rs b/src/tags.rs index 6c18fa52..81169ca3 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -184,6 +184,9 @@ pub enum CompressionMethod(u16) unknown("A custom compression method") { Deflate = 8, OldDeflate = 0x80B2, PackBits = 0x8005, + + // Self-assigned by libtiff + ZSTD = 0xC350, } } diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 1c769d06..f037ca38 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -515,3 +515,9 @@ fn test_predictor_3_rgb_f32() { fn test_predictor_3_gray_f32() { test_image_sum_f32("predictor-3-gray-f32.tif", ColorType::Gray(32), 20008.275); } + +#[test] +fn test_zstd_compression() { + // gdal_translate -co COMPRESS=ZSTD -co ZSTD_LEVEL=20 int16.tif int16_zstd.tif + test_image_sum_i16("int16_zstd.tif", ColorType::Gray(16), 354396); +} diff --git a/tests/images/int16_zstd.tif b/tests/images/int16_zstd.tif new file mode 100644 index 0000000000000000000000000000000000000000..c1093e478eb70afee346a00389b8e6fefa18f0aa GIT binary patch literal 7835 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 literal 0 HcmV?d00001