Skip to content

Commit 7eee238

Browse files
sunipkm197g
authored andcommitted
Tiff crate internal compression types hidden in public interface
1 parent a11147d commit 7eee238

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]);
@@ -450,18 +504,24 @@ fn u8_slice_as_u16(buf: &[u8]) -> ImageResult<DtypeContainer<u16>> {
450504
impl<W: Write + Seek> TiffEncoder<W> {
451505
/// Create a new encoder that writes its output to `w`
452506
pub fn new(w: W) -> TiffEncoder<W> {
507+
let comp = CompressionType::default().into_tiff();
508+
TiffEncoder { w, comp }
509+
}
510+
511+
/// Create a new encoder that writes its output to `w` with `CompressionType` `compression`.
512+
///
513+
/// It is best to view the options as a _hint_ to the implementation on the smallest or fastest
514+
/// option for encoding a particular image. That is, using options that map directly to a TIFF
515+
/// image parameter will use this parameter where possible. But variants that have no direct
516+
/// mapping may be interpreted differently in minor versions. The exact output is expressly
517+
/// __not__ part of the SemVer stability guarantee.
518+
pub fn new_with_compression(w: W, comp: CompressionType) -> Self {
453519
TiffEncoder {
454520
w,
455-
comp: Compression::default(),
521+
comp: comp.into_tiff(),
456522
}
457523
}
458524

459-
/// Set the image compression setting
460-
pub fn with_compression(mut self, comp: Compression) -> Self {
461-
self.comp = comp;
462-
self
463-
}
464-
465525
/// Encodes the image `image` that has dimensions `width` and `height` and `ColorType` `c`.
466526
///
467527
/// 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)