Skip to content

Commit

Permalink
Add predictor/compression sanity checks
Browse files Browse the repository at this point in the history
  • Loading branch information
spoutn1k committed Aug 3, 2024
1 parent 829d433 commit 3ffc54a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 5 deletions.
30 changes: 25 additions & 5 deletions src/encoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use std::{
};

use crate::{
error::TiffResult,
tags::{CompressionMethod, ResolutionUnit, Tag},
error::{TiffResult, UsageError},
tags::{CompressionMethod, ResolutionUnit, SampleFormat, Tag},
TiffError, TiffFormatError,
};

Expand All @@ -36,7 +36,7 @@ use self::writer::*;
pub type Predictor = crate::tags::Predictor;
pub type DeflateLevel = compression::DeflateLevel;

#[derive(Default, Clone, Copy)]
#[derive(Default, Clone, Copy, PartialEq)]
pub enum Compression {
#[default]
Uncompressed,
Expand Down Expand Up @@ -135,14 +135,17 @@ impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
Ok(encoder)
}

/// Set the predictor used to simplify the file before writing it. This is very useful when
/// writing a file compressed using LZW
/// Set the predictor to use
///
/// A predictor is used to simplify the file before writing it. This is very
/// useful when writing a file compressed using LZW as it can improve efficiency
pub fn with_predictor(mut self, predictor: Predictor) -> Self {
self.predictor = predictor;

self
}

/// Set the compression method to use
pub fn with_compression(mut self, compression: Compression) -> Self {
self.compression = compression;

Expand Down Expand Up @@ -361,6 +364,21 @@ pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> {
}

impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> {
fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> {
match (predictor, compression, T::SAMPLE_FORMAT[0]) {
(Predictor::Horizontal, Compression::Uncompressed, _) => Err(TiffError::UsageError(
UsageError::PredictorCompressionMismatch,
)),
(Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => {
Err(TiffError::UsageError(UsageError::PredictorIncompatible))
}
(Predictor::FloatingPoint, _, _) => {
Err(TiffError::UsageError(UsageError::PredictorUnavailable))
}
_ => Ok(()),
}
}

fn new(
mut encoder: DirectoryEncoder<'a, W, K>,
width: u32,
Expand All @@ -374,6 +392,8 @@ impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T,
)));
}

Self::sanity_check(compression, predictor)?;

let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);

Expand Down
12 changes: 12 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ impl fmt::Display for TiffUnsupportedError {
pub enum UsageError {
InvalidChunkType(ChunkType, ChunkType),
InvalidChunkIndex(u32),
PredictorCompressionMismatch,
PredictorIncompatible,
PredictorUnavailable,
}

impl fmt::Display for UsageError {
Expand All @@ -250,6 +253,15 @@ impl fmt::Display for UsageError {
)
}
InvalidChunkIndex(index) => write!(fmt, "Image chunk index ({}) requested.", index),
PredictorCompressionMismatch => write!(
fmt,
"The requested predictor is not compatible with the requested compression"
),
PredictorIncompatible => write!(
fmt,
"The requested predictor is not compatible with the image's format"
),
PredictorUnavailable => write!(fmt, "The requested predictor is not available"),
}
}
}
Expand Down

0 comments on commit 3ffc54a

Please sign in to comment.