Skip to content

Commit 5363c9a

Browse files
sunipkm197g
authored andcommitted
Tiff crate internal compression types hidden in public interface
1 parent ece042d commit 5363c9a

File tree

2 files changed

+77
-14
lines changed

2 files changed

+77
-14
lines changed

src/codecs/tiff.rs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::marker::PhantomData;
1010
use std::mem;
1111

1212
use tiff::decoder::{Decoder, DecodingResult};
13-
use tiff::encoder::Compression;
13+
use tiff::encoder::{Compression, DeflateLevel};
1414
use tiff::tags::Tag;
1515

1616
use crate::color::{ColorType, ExtendedColorType};
@@ -367,6 +367,60 @@ pub struct TiffEncoder<W> {
367367
comp: Compression,
368368
}
369369

370+
/// Compression types supported by the TIFF format
371+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
372+
pub enum CompressionType {
373+
/// No compression
374+
Uncompressed,
375+
/// LZW compression
376+
Lzw,
377+
/// Deflate compression
378+
Deflate(TiffDeflateLevel),
379+
/// Bit packing compression
380+
Packbits,
381+
}
382+
383+
impl Default for CompressionType {
384+
fn default() -> Self {
385+
CompressionType::Deflate(Default::default())
386+
}
387+
}
388+
389+
/// The level of compression used by the Deflate algorithm.
390+
/// It allows trading compression ratio for compression speed.
391+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
392+
#[non_exhaustive]
393+
pub enum TiffDeflateLevel {
394+
/// The fastest possible compression mode.
395+
Fast = 1,
396+
/// The conserative choice between speed and ratio.
397+
#[default]
398+
Balanced = 6,
399+
/// The best compression available with Deflate.
400+
Best = 9,
401+
}
402+
403+
impl TiffDeflateLevel {
404+
fn into_tiff(self: TiffDeflateLevel) -> DeflateLevel {
405+
match self {
406+
TiffDeflateLevel::Fast => DeflateLevel::Fast,
407+
TiffDeflateLevel::Balanced => DeflateLevel::Balanced,
408+
TiffDeflateLevel::Best => DeflateLevel::Best,
409+
}
410+
}
411+
}
412+
413+
impl CompressionType {
414+
fn into_tiff(self: CompressionType) -> Compression {
415+
match self {
416+
CompressionType::Uncompressed => Compression::Uncompressed,
417+
CompressionType::Lzw => Compression::Lzw,
418+
CompressionType::Deflate(lvl) => Compression::Deflate(lvl.into_tiff()),
419+
CompressionType::Packbits => Compression::Packbits,
420+
}
421+
}
422+
}
423+
370424
fn cmyk_to_rgb(cmyk: &[u8]) -> [u8; 3] {
371425
let c = f32::from(cmyk[0]);
372426
let m = f32::from(cmyk[1]);
@@ -410,18 +464,24 @@ fn u8_slice_as_pod<P: bytemuck::Pod>(buf: &[u8]) -> ImageResult<std::borrow::Cow
410464
impl<W: Write + Seek> TiffEncoder<W> {
411465
/// Create a new encoder that writes its output to `w`
412466
pub fn new(w: W) -> TiffEncoder<W> {
467+
let comp = CompressionType::default().into_tiff();
468+
TiffEncoder { w, comp }
469+
}
470+
471+
/// Create a new encoder that writes its output to `w` with `CompressionType` `compression`.
472+
///
473+
/// It is best to view the options as a _hint_ to the implementation on the smallest or fastest
474+
/// option for encoding a particular image. That is, using options that map directly to a TIFF
475+
/// image parameter will use this parameter where possible. But variants that have no direct
476+
/// mapping may be interpreted differently in minor versions. The exact output is expressly
477+
/// __not__ part of the SemVer stability guarantee.
478+
pub fn new_with_compression(w: W, comp: CompressionType) -> Self {
413479
TiffEncoder {
414480
w,
415-
comp: Compression::default(),
481+
comp: comp.into_tiff(),
416482
}
417483
}
418484

419-
/// Set the image compression setting
420-
pub fn with_compression(mut self, comp: Compression) -> Self {
421-
self.comp = comp;
422-
self
423-
}
424-
425485
/// Encodes the image `image` that has dimensions `width` and `height` and `ColorType` `c`.
426486
///
427487
/// 16-bit types assume the buffer is native endian.

tests/reference_images.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ where
4242
#[cfg(feature = "tiff")]
4343
#[test]
4444
fn compress_deflate() {
45-
use image::codecs::tiff::TiffEncoder;
45+
use image::codecs::tiff::{CompressionType, TiffDeflateLevel, TiffEncoder};
4646

4747
process_images(IMAGE_DIR, Some("tiff"), |base, path, _| {
4848
println!("compress_images {}", path.display());
@@ -64,8 +64,9 @@ fn compress_deflate() {
6464
out_path.push("deflate");
6565
std::fs::create_dir_all(&out_path).unwrap();
6666
out_path.push(path.file_name().unwrap());
67-
let encoder = TiffEncoder::new(fs::File::create(&out_path).unwrap()).with_compression(
68-
tiff::encoder::Compression::Deflate(tiff::encoder::DeflateLevel::Balanced),
67+
let encoder = TiffEncoder::new_with_compression(
68+
fs::File::create(&out_path).unwrap(),
69+
CompressionType::Deflate(TiffDeflateLevel::Balanced),
6970
);
7071
img.write_with_encoder(encoder).unwrap();
7172
})
@@ -74,7 +75,7 @@ fn compress_deflate() {
7475
#[cfg(feature = "tiff")]
7576
#[test]
7677
fn compress_lzw() {
77-
use image::codecs::tiff::TiffEncoder;
78+
use image::codecs::tiff::{CompressionType, TiffEncoder};
7879

7980
process_images(IMAGE_DIR, Some("tiff"), |base, path, _| {
8081
println!("compress_images {}", path.display());
@@ -96,8 +97,10 @@ fn compress_lzw() {
9697
out_path.push("lzw");
9798
std::fs::create_dir_all(&out_path).unwrap();
9899
out_path.push(path.file_name().unwrap());
99-
let encoder = TiffEncoder::new(fs::File::create(&out_path).unwrap())
100-
.with_compression(tiff::encoder::Compression::Lzw);
100+
let encoder = TiffEncoder::new_with_compression(
101+
fs::File::create(&out_path).unwrap(),
102+
CompressionType::Lzw,
103+
);
101104
img.write_with_encoder(encoder).unwrap();
102105
})
103106
}

0 commit comments

Comments
 (0)