Skip to content

Commit

Permalink
Merge pull request #232 from SalOne22/feature/tiff
Browse files Browse the repository at this point in the history
TIFF Support
  • Loading branch information
SalOne22 authored Jul 13, 2024
2 parents 2dbd737 + 43d171c commit abc78f5
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 2 deletions.
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ path = "./src/main.rs"
required-features = ["build-binary"]

[features]
default = ["resize", "quantization", "mozjpeg", "oxipng", "webp", "avif", "threads", "metadata"]
default = ["resize", "quantization", "mozjpeg", "oxipng", "webp", "avif", "tiff", "threads", "metadata"]

# Used for binary
build-binary = ["dep:anyhow", "dep:clap", "dep:indoc", "dep:rayon", "dep:pretty_env_logger", "dep:zune-imageprocs", "dep:glob", "zune-image/default", "dep:indicatif", "dep:indicatif-log-bridge", "dep:console"]
Expand All @@ -47,6 +47,8 @@ oxipng = ["dep:oxipng"]
webp = ["dep:webp"]
# Enables avif codec
avif = ["dep:ravif", "dep:libavif", "dep:rgb"]
# Enables tiff codec
tiff = ["dep:tiff"]
icc = ["dep:lcms2"]
console = ["dep:console"]

Expand All @@ -63,6 +65,7 @@ webp = { version = "0.3.0", default-features = false, optional = true }
ravif = { version = "0.11.4", optional = true }
libavif = { version = "0.13.0", default-features = false, features = ["codec-aom"], optional = true }
lcms2 = { version = "6.1.0", optional = true }
tiff = { version = "0.9.1", default-features = false, optional = true }

# cli
anyhow = { version = "1.0.86", optional = true }
Expand Down
17 changes: 16 additions & 1 deletion src/cli/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::io::{Seek, SeekFrom};
use std::{collections::BTreeMap, fs::File, io::Read, path::Path};

use clap::ArgMatches;
Expand Down Expand Up @@ -26,7 +27,7 @@ pub fn decode<P: AsRef<Path>>(f: P) -> Result<Image, ImageErrors> {
Image::open(f.as_ref()).or_else(|e| {
if matches!(e, ImageErrors::ImageDecoderNotImplemented(_)) {
#[cfg(any(feature = "avif", feature = "webp"))]
let mut file = File::open("tests/files/avif/f1t.avif")?;
let mut file = File::open(f.as_ref())?;

#[cfg(feature = "avif")]
{
Expand All @@ -41,6 +42,8 @@ pub fn decode<P: AsRef<Path>>(f: P) -> Result<Image, ImageErrors> {

return Image::from_decoder(decoder);
};

file.seek(SeekFrom::Start(0))?;
}

#[cfg(feature = "webp")]
Expand All @@ -55,6 +58,18 @@ pub fn decode<P: AsRef<Path>>(f: P) -> Result<Image, ImageErrors> {
return Image::from_decoder(decoder);
};

#[cfg(feature = "tiff")]
if f.as_ref()
.extension()
.is_some_and(|f| f.eq_ignore_ascii_case("tiff") | f.eq_ignore_ascii_case("tif"))
{
use rimage::codecs::tiff::TiffDecoder;

let decoder = TiffDecoder::try_new(file)?;

return Image::from_decoder(decoder);
}

Err(ImageErrors::ImageDecoderNotImplemented(
ImageFormat::Unknown,
))
Expand Down
4 changes: 4 additions & 0 deletions src/codecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ pub mod mozjpeg;
#[cfg(feature = "oxipng")]
pub mod oxipng;

/// Tiff encoding support
#[cfg(feature = "tiff")]
pub mod tiff;

/// WebP encoding support
#[cfg(feature = "webp")]
pub mod webp;
92 changes: 92 additions & 0 deletions src/codecs/tiff/decoder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::io::{Read, Seek};

use zune_core::colorspace::ColorSpace;
use zune_image::{errors::ImageErrors, image::Image, traits::DecoderTrait};

/// A Tiff decoder
pub struct TiffDecoder<R: Read + Seek> {
inner: tiff::decoder::Decoder<R>,
dimensions: Option<(usize, usize)>,
colorspace: ColorSpace,
}

impl<R: Read + Seek> TiffDecoder<R> {
/// Create a new tiff decoder that reads data from `source`
pub fn try_new(source: R) -> Result<Self, ImageErrors> {
let inner = tiff::decoder::Decoder::new(source).map_err(|e| {
ImageErrors::ImageDecodeErrors(format!("Unable to create TIFF decoder: {}", e))
})?;

Ok(Self {
inner,
dimensions: None,
colorspace: ColorSpace::Unknown,
})
}
}

impl<R> DecoderTrait for TiffDecoder<R>
where
R: Read + Seek,
{
fn decode(&mut self) -> Result<Image, ImageErrors> {
let (width, height) = self.inner.dimensions().map_err(|e| {
ImageErrors::ImageDecodeErrors(format!("Unable to read dimensions - {}", e))
})?;

let (width, height) = (width as usize, height as usize);
self.dimensions = Some((width, height));

let colorspace = self
.inner
.colortype()
.map(|colortype| match colortype {
tiff::ColorType::RGB(_) => ColorSpace::RGB,
tiff::ColorType::RGBA(_) => ColorSpace::RGBA,
tiff::ColorType::CMYK(_) => ColorSpace::CMYK,
tiff::ColorType::Gray(_) => ColorSpace::Luma,
tiff::ColorType::GrayA(_) => ColorSpace::LumaA,
tiff::ColorType::YCbCr(_) => ColorSpace::YCbCr,
_ => ColorSpace::Unknown,
})
.map_err(|e| {
ImageErrors::ImageDecodeErrors(format!("Unable to read colorspace - {}", e))
})?;

self.colorspace = colorspace;

let result = self.inner.read_image().map_err(|e| {
ImageErrors::ImageDecodeErrors(format!("Unable to decode TIFF file - {}", e))
})?;

match result {
tiff::decoder::DecodingResult::U8(data) => {
Ok(Image::from_u8(&data, width, height, colorspace))
}
tiff::decoder::DecodingResult::U16(data) => {
Ok(Image::from_u16(&data, width, height, colorspace))
}
tiff::decoder::DecodingResult::F32(data) => {
Ok(Image::from_f32(&data, width, height, colorspace))
}
_ => Err(ImageErrors::ImageDecodeErrors(
"Tiff Data format not supported".to_string(),
)),
}
}

fn dimensions(&self) -> Option<(usize, usize)> {
self.dimensions
}

fn out_colorspace(&self) -> ColorSpace {
self.colorspace
}

fn name(&self) -> &'static str {
"tiff-decoder"
}
}

#[cfg(test)]
mod tests;
15 changes: 15 additions & 0 deletions src/codecs/tiff/decoder/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::fs::File;

use super::*;

#[test]
fn decode() {
let file_content = File::open("tests/files/tiff/f1t.tif").unwrap();

let decoder = TiffDecoder::try_new(file_content).unwrap();

let img = Image::from_decoder(decoder).unwrap();

assert_eq!(img.dimensions(), (48, 80));
assert_eq!(img.colorspace(), ColorSpace::RGB);
}
3 changes: 3 additions & 0 deletions src/codecs/tiff/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod decoder;

pub use decoder::*;
Binary file added tests/files/tiff/f1t.tif
Binary file not shown.

0 comments on commit abc78f5

Please sign in to comment.