Compare commits

..
Author SHA1 Message Date
A. Molzer 812bc970ba Document Decoder::open behavior 2026-03-06 21:09:32 +01:00
Aurelia Molzer e8be8656f2 Merge pull request #353 from Shnatsel/non-exhaustive-compression
Make Compression enum non-exhaustive
2026-03-06 10:45:28 +00:00
Sergey "Shnatsel" Davidoff e1e9f36c5a Make Compression enum non-exhaustive 2026-03-06 09:49:10 +00:00
Aurelia Molzer 0ad653433a Merge pull request #352 from image-rs/iterate-over-raw-tiff-or-exif
Open a Tiff without interpreting the first directory
2026-03-06 08:34:19 +00:00
Aurelia Molzer 54dddc4943 Merge pull request #347 from image-rs/iterate-over-raw-tiff-or-exif
Enable iteration over raw, malformed tiff or exif
2026-03-06 07:31:13 +00:00
Aurelia Molzer 31c49ea6ef Merge pull request #351 from Shnatsel/semver-breaking-deflate-level
Implement DEFLATE compression level control properly, with a semver break
2026-03-05 20:12:27 +00:00
Sergey "Shnatsel" Davidoff 0362e6e31d Implement DEFLATE compression level control properly, with a semver break 2026-03-05 17:59:18 +00:00
Sergey "Shnatsel" Davidoff 0fe5b2804e Merge pull request #348 from Shnatsel/deflate-level
Expose precise DEFLATE level controls
2026-03-05 17:23:59 +00:00
Sergey "Shnatsel" Davidoff a589010099 Fix typo 2026-03-05 12:22:37 +00:00
Sergey "Shnatsel" Davidoff 53498074a4 Merge impl blocks 2026-03-05 12:22:25 +00:00
Sergey "Shnatsel" Davidoff cb543cded7 Expose precise DEFLATE level controls 2026-03-05 11:58:18 +00:00
6 changed files with 83 additions and 38 deletions

No files matched your search

+2 -2
View File
@@ -4,7 +4,7 @@ extern crate tiff;
use criterion::{black_box, Criterion, Throughput}; use criterion::{black_box, Criterion, Throughput};
use std::io::Cursor; use std::io::Cursor;
use tiff::encoder::colortype::RGB32Float; use tiff::encoder::colortype::RGB32Float;
use tiff::encoder::{Compression, DeflateLevel, Predictor, TiffEncoder}; use tiff::encoder::{Compression, Predictor, TiffEncoder};
const WIDTH: u32 = 500; const WIDTH: u32 = 500;
const HEIGHT: u32 = 500; const HEIGHT: u32 = 500;
@@ -14,7 +14,7 @@ fn encode_image_f32_float_predictor_deflate(data: &[f32]) {
TiffEncoder::new(&mut buf) TiffEncoder::new(&mut buf)
.unwrap() .unwrap()
.with_predictor(Predictor::FloatingPoint) .with_predictor(Predictor::FloatingPoint)
.with_compression(Compression::Deflate(DeflateLevel::Fast)) .with_compression(Compression::Deflate(1))
.write_image::<RGB32Float>(WIDTH, HEIGHT, black_box(data)) .write_image::<RGB32Float>(WIDTH, HEIGHT, black_box(data))
.unwrap(); .unwrap();
} }
+55 -11
View File
@@ -857,11 +857,64 @@ impl TiffHeader {
} }
impl<R: Read + Seek> Decoder<R> { impl<R: Read + Seek> Decoder<R> {
/// Parse the image header from the underlying file and create a decoder positioned before its
/// first directory.
///
/// This method opens the file in a state _before_ the first (image) directory. You need to
/// call one of [`Self::next_image`], [`Self::next_directory`] or [`Self::seek_to_directory`]
/// to choose a directory before interacting with the tag methods.
///
/// # Examples
///
/// ```
/// use tiff::decoder::{Decoder, DecodingResult};
///
/// let buffered_file = /* */
/// # std::io::Cursor::new(include_bytes!(concat!(
/// # env!("CARGO_MANIFEST_DIR"), "/tests/images/tiled-gray-i1.tif"
/// # )));
///
/// let mut decoder = Decoder::open(buffered_file)?;
/// let mut img_buffer = DecodingResult::U8(vec![]);
///
/// while decoder.more_images() {
/// decoder.next_image()?;
/// decoder.read_image_to_buffer(&mut img_buffer)?;
/// }
///
/// # Ok::<_, tiff::TiffError>(())
/// ```
///
/// # Relations
///
/// The [`TiffHeader`] type allows opening a file with a custom offset.
pub fn open(mut r: R) -> TiffResult<Decoder<R>> {
let header = TiffHeader::parse(&mut r)?;
Ok(header.open(r))
}
/// Create a decoder and attempt to parse the first image directory. /// Create a decoder and attempt to parse the first image directory.
/// ///
/// To open a file without parsing any directory yet (for instance to retain a [`Decoder`] on /// To open a file without parsing any directory yet (for instance to retain a [`Decoder`] on
/// errors in the directory), use [`TiffHeader::parse`] and [`TiffHeader::open`] instead.. /// errors in the directory), use [`TiffHeader::parse`] and [`TiffHeader::open`] instead.
#[deprecated = "Prefer `Decoder::open`. These methods will become aliases in a future major release."] ///
/// This method is equivalent to [`Decoder::open`] except it provides no decoder when the first
/// IFD errors due to not being an image or an IO problem. It can be replaced precisely with
/// this sequence:
///
/// ```no_run
/// # use tiff::decoder::Decoder;
/// # let r = std::io::BufReader::new(std::io::empty());
/// let decoder = {
/// let mut tmp = Decoder::open(r)?;
/// tmp.next_image()?;
/// tmp
/// };
///
/// # Ok::<_, tiff::TiffError>(())
/// ```
///
#[deprecated = "Prefer `Decoder::open` followed by an explicit `next_image` call. These methods will become aliases in a future major release."]
pub fn new(mut r: R) -> TiffResult<Decoder<R>> { pub fn new(mut r: R) -> TiffResult<Decoder<R>> {
let header = TiffHeader::parse(&mut r)?; let header = TiffHeader::parse(&mut r)?;
let mut decoder = header.open(r); let mut decoder = header.open(r);
@@ -869,15 +922,6 @@ impl<R: Read + Seek> Decoder<R> {
Ok(decoder) Ok(decoder)
} }
/// Parse the image header from the underlying file and create a decoder positioned before its
/// first directory.
///
/// The [`TiffHeader`] type allows opening a file with a custom.
pub fn open(mut r: R) -> TiffResult<Decoder<R>> {
let header = TiffHeader::parse(&mut r)?;
Ok(header.open(r))
}
/// Configure allocation limits for all subsequent operations. /// Configure allocation limits for all subsequent operations.
/// ///
/// Limits apply to allocated return values such as from [`Decoder::read_image`] and /// Limits apply to allocated return values such as from [`Decoder::read_image`] and
+20 -17
View File
@@ -7,24 +7,27 @@ pub struct Deflate {
level: FlateCompression, level: FlateCompression,
} }
/// The level of compression used by the Deflate algorithm.
/// It allows trading compression ratio for compression speed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
#[derive(Default)]
pub enum DeflateLevel {
/// The fastest possible compression mode.
Fast = 1,
/// The conserative choice between speed and ratio.
#[default]
Balanced = 6,
/// The best compression available with Deflate.
Best = 9,
}
impl Deflate { impl Deflate {
/// Create a new deflate compressor with a specific level of compression. /// Create a new deflate compressor with a specific level of compression.
pub fn with_level(level: DeflateLevel) -> Self { ///
/// The valid levels are 1 through 9 inclusive. The default level is 6.
///
/// - `1` stands for light but fast compression
/// - `6` is the recommended balanced default
/// - `9` is maximum compression ratio at the cost of slow encoding
pub fn with_level(level: u8) -> Self {
Self {
level: FlateCompression::new(level as u32),
}
}
/// Create a new deflate compressor with an exact level of compression.
///
/// `0` stands for uncompressed
/// `1` stands for light but fast compression
/// `6` is the recommended balanced default
/// `9` is maximum compression ratio at the cost of slow encoding
pub fn exact_level(level: u8) -> Self {
Self { Self {
level: FlateCompression::new(level as u32), level: FlateCompression::new(level as u32),
} }
@@ -33,7 +36,7 @@ impl Deflate {
impl Default for Deflate { impl Default for Deflate {
fn default() -> Self { fn default() -> Self {
Self::with_level(DeflateLevel::default()) Self::with_level(6)
} }
} }
+1 -1
View File
@@ -9,7 +9,7 @@ mod packbits;
mod uncompressed; mod uncompressed;
#[cfg(feature = "deflate")] #[cfg(feature = "deflate")]
pub use self::deflate::{Deflate, DeflateLevel}; pub use self::deflate::Deflate;
#[cfg(feature = "lzw")] #[cfg(feature = "lzw")]
pub use self::lzw::Lzw; pub use self::lzw::Lzw;
+2 -3
View File
@@ -38,9 +38,8 @@ use self::writer::*;
/// [Predictor::Horizontal] is for integer sample types. /// [Predictor::Horizontal] is for integer sample types.
/// [Predictor::FloatingPoint] is for floating-point sample types (f32, f64). /// [Predictor::FloatingPoint] is for floating-point sample types (f32, f64).
pub type Predictor = crate::tags::Predictor; pub type Predictor = crate::tags::Predictor;
#[cfg(feature = "deflate")]
pub type DeflateLevel = compression::DeflateLevel;
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Default)] #[derive(Clone, Copy, PartialEq, Default)]
pub enum Compression { pub enum Compression {
#[default] #[default]
@@ -48,7 +47,7 @@ pub enum Compression {
#[cfg(feature = "lzw")] #[cfg(feature = "lzw")]
Lzw, Lzw,
#[cfg(feature = "deflate")] #[cfg(feature = "deflate")]
Deflate(DeflateLevel), Deflate(u8),
Packbits, Packbits,
} }
+3 -4
View File
@@ -5,7 +5,6 @@ use tiff::{
decoder::{Decoder, DecodingResult}, decoder::{Decoder, DecodingResult},
encoder::{ encoder::{
colortype::{self, ColorType}, colortype::{self, ColorType},
compression::*,
Compression, TiffEncoder, TiffValue, Compression, TiffEncoder, TiffValue,
}, },
}; };
@@ -148,9 +147,9 @@ fn encode_decode_with_lzw() {
#[test] #[test]
#[cfg(feature = "deflate")] #[cfg(feature = "deflate")]
fn encode_decode_with_deflate() { fn encode_decode_with_deflate() {
encode_decode_with_compression(Compression::Deflate(DeflateLevel::Fast)); encode_decode_with_compression(Compression::Deflate(1));
encode_decode_with_compression(Compression::Deflate(DeflateLevel::Balanced)); encode_decode_with_compression(Compression::Deflate(6));
encode_decode_with_compression(Compression::Deflate(DeflateLevel::Best)); encode_decode_with_compression(Compression::Deflate(9));
} }
#[test] #[test]