Create feature flags for more compression algorithms (#270)
This commit is contained in:
1 parent
dc2c67469b
commit
83e6d64751
8 files changed
+64
-15
No files matched your search
@@ -32,6 +32,19 @@ jobs:
|
||||
if: ${{ matrix.rust != '1.74.0' }}
|
||||
run: cargo test -v && cargo doc -v
|
||||
|
||||
features:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
feature: ["", deflate, jpeg, lzw, zstd, default, "default,zstd"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
- name: Cargo check
|
||||
run: cargo check --features "${{ matrix.feature }}" --no-default-features
|
||||
|
||||
rustfmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
+11
-4
@@ -18,16 +18,23 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"]
|
||||
|
||||
[dependencies]
|
||||
half = { version = "2.4.1" }
|
||||
weezl = "0.1.0"
|
||||
zune-jpeg = "0.4.17"
|
||||
flate2 = "1.0.20"
|
||||
zstd = { version = "0.13", optional = true }
|
||||
quick-error = "2.0.1"
|
||||
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
weezl = { version = "0.1.0", optional = true }
|
||||
zstd = { version = "0.13", optional = true }
|
||||
zune-jpeg = { version = "0.4.17", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.1"
|
||||
|
||||
[features]
|
||||
default = ["deflate", "jpeg", "lzw"]
|
||||
|
||||
# Compression algorithms
|
||||
deflate = ["dep:flate2"]
|
||||
jpeg = ["dep:zune-jpeg"]
|
||||
lzw = ["dep:weezl"]
|
||||
zstd = ["dep:zstd"]
|
||||
|
||||
[[bench]]
|
||||
|
||||
+13
-8
@@ -1,5 +1,5 @@
|
||||
use super::ifd::{Directory, Value};
|
||||
use super::stream::{ByteOrder, DeflateReader, LZWReader, PackBitsReader};
|
||||
use super::stream::{ByteOrder, PackBitsReader};
|
||||
use super::tag_reader::TagReader;
|
||||
use super::{predict_f16, predict_f32, predict_f64, Limits};
|
||||
use super::{stream::EndianReader, ChunkType};
|
||||
@@ -9,7 +9,6 @@ use crate::tags::{
|
||||
use crate::{ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError};
|
||||
use std::io::{self, Cursor, Read, Seek};
|
||||
use std::sync::Arc;
|
||||
use zune_jpeg::zune_core;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StripDecodeState {
|
||||
@@ -370,23 +369,29 @@ impl Image {
|
||||
|
||||
fn create_reader<'r, R: 'r + Read>(
|
||||
reader: R,
|
||||
photometric_interpretation: PhotometricInterpretation,
|
||||
#[allow(unused_variables)] photometric_interpretation: PhotometricInterpretation,
|
||||
compression_method: CompressionMethod,
|
||||
compressed_length: u64,
|
||||
jpeg_tables: Option<&[u8]>,
|
||||
#[allow(unused_variables)] jpeg_tables: Option<&[u8]>,
|
||||
) -> TiffResult<Box<dyn Read + 'r>> {
|
||||
Ok(match compression_method {
|
||||
CompressionMethod::None => Box::new(reader),
|
||||
CompressionMethod::LZW => {
|
||||
Box::new(LZWReader::new(reader, usize::try_from(compressed_length)?))
|
||||
}
|
||||
#[cfg(feature = "lzw")]
|
||||
CompressionMethod::LZW => Box::new(super::stream::LZWReader::new(
|
||||
reader,
|
||||
usize::try_from(compressed_length)?,
|
||||
)),
|
||||
#[cfg(feature = "zstd")]
|
||||
CompressionMethod::ZSTD => Box::new(zstd::Decoder::new(reader)?),
|
||||
CompressionMethod::PackBits => Box::new(PackBitsReader::new(reader, compressed_length)),
|
||||
#[cfg(feature = "deflate")]
|
||||
CompressionMethod::Deflate | CompressionMethod::OldDeflate => {
|
||||
Box::new(DeflateReader::new(reader))
|
||||
Box::new(super::stream::DeflateReader::new(reader))
|
||||
}
|
||||
#[cfg(feature = "jpeg")]
|
||||
CompressionMethod::ModernJPEG => {
|
||||
use zune_jpeg::zune_core;
|
||||
|
||||
if jpeg_tables.is_some() && compressed_length < 2 {
|
||||
return Err(TiffError::FormatError(
|
||||
TiffFormatError::InvalidTagValueType(Tag::JPEGTables),
|
||||
|
||||
@@ -140,6 +140,7 @@ impl<R: Read + Seek> EndianReader<R> {
|
||||
/// ## Deflate Reader
|
||||
///
|
||||
|
||||
#[cfg(feature = "deflate")]
|
||||
pub type DeflateReader<R> = flate2::read::ZlibDecoder<R>;
|
||||
|
||||
///
|
||||
@@ -147,11 +148,13 @@ pub type DeflateReader<R> = flate2::read::ZlibDecoder<R>;
|
||||
///
|
||||
|
||||
/// Reader that decompresses LZW streams
|
||||
#[cfg(feature = "lzw")]
|
||||
pub struct LZWReader<R: Read> {
|
||||
reader: BufReader<Take<R>>,
|
||||
decoder: weezl::decode::Decoder,
|
||||
}
|
||||
|
||||
#[cfg(feature = "lzw")]
|
||||
impl<R: Read> LZWReader<R> {
|
||||
/// Wraps a reader
|
||||
pub fn new(reader: R, compressed_length: usize) -> LZWReader<R> {
|
||||
@@ -165,6 +168,7 @@ impl<R: Read> LZWReader<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lzw")]
|
||||
impl<R: Read> Read for LZWReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
loop {
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
use crate::tags::CompressionMethod;
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[cfg(feature = "deflate")]
|
||||
mod deflate;
|
||||
#[cfg(feature = "lzw")]
|
||||
mod lzw;
|
||||
mod packbits;
|
||||
mod uncompressed;
|
||||
|
||||
#[cfg(feature = "deflate")]
|
||||
pub use self::deflate::{Deflate, DeflateLevel};
|
||||
|
||||
#[cfg(feature = "lzw")]
|
||||
pub use self::lzw::Lzw;
|
||||
|
||||
pub use self::packbits::Packbits;
|
||||
pub use self::uncompressed::Uncompressed;
|
||||
|
||||
@@ -30,7 +36,9 @@ pub trait Compression: CompressionAlgorithm {
|
||||
/// An enum to store each compression algorithm.
|
||||
pub enum Compressor {
|
||||
Uncompressed(Uncompressed),
|
||||
#[cfg(feature = "lzw")]
|
||||
Lzw(Lzw),
|
||||
#[cfg(feature = "deflate")]
|
||||
Deflate(Deflate),
|
||||
Packbits(Packbits),
|
||||
}
|
||||
@@ -46,7 +54,9 @@ impl CompressionAlgorithm for Compressor {
|
||||
fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
|
||||
match self {
|
||||
Compressor::Uncompressed(algorithm) => algorithm.write_to(writer, bytes),
|
||||
#[cfg(feature = "lzw")]
|
||||
Compressor::Lzw(algorithm) => algorithm.write_to(writer, bytes),
|
||||
#[cfg(feature = "deflate")]
|
||||
Compressor::Deflate(algorithm) => algorithm.write_to(writer, bytes),
|
||||
Compressor::Packbits(algorithm) => algorithm.write_to(writer, bytes),
|
||||
}
|
||||
|
||||
@@ -34,12 +34,15 @@ use self::writer::*;
|
||||
///
|
||||
/// [Predictor::FloatingPoint] is currently not supported.
|
||||
pub type Predictor = crate::tags::Predictor;
|
||||
#[cfg(feature = "deflate")]
|
||||
pub type DeflateLevel = compression::DeflateLevel;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Compression {
|
||||
Uncompressed,
|
||||
#[cfg(feature = "lzw")]
|
||||
Lzw,
|
||||
#[cfg(feature = "deflate")]
|
||||
Deflate(DeflateLevel),
|
||||
Packbits,
|
||||
}
|
||||
@@ -54,7 +57,9 @@ impl Compression {
|
||||
fn tag(&self) -> CompressionMethod {
|
||||
match self {
|
||||
Compression::Uncompressed => CompressionMethod::None,
|
||||
#[cfg(feature = "lzw")]
|
||||
Compression::Lzw => CompressionMethod::LZW,
|
||||
#[cfg(feature = "deflate")]
|
||||
Compression::Deflate(_) => CompressionMethod::Deflate,
|
||||
Compression::Packbits => CompressionMethod::PackBits,
|
||||
}
|
||||
@@ -63,7 +68,9 @@ impl Compression {
|
||||
fn get_algorithm(&self) -> Compressor {
|
||||
match self {
|
||||
Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(),
|
||||
#[cfg(feature = "lzw")]
|
||||
Compression::Lzw => compression::Lzw {}.get_algorithm(),
|
||||
#[cfg(feature = "deflate")]
|
||||
Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(),
|
||||
Compression::Packbits => compression::Packbits {}.get_algorithm(),
|
||||
}
|
||||
|
||||
+4
-3
@@ -3,7 +3,6 @@ use std::str;
|
||||
use std::string;
|
||||
|
||||
use quick_error::quick_error;
|
||||
use weezl::LzwError;
|
||||
|
||||
use crate::decoder::ChunkType;
|
||||
use crate::tags::{
|
||||
@@ -206,12 +205,14 @@ impl From<std::num::TryFromIntError> for TiffError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LzwError> for TiffError {
|
||||
fn from(err: LzwError) -> TiffError {
|
||||
#[cfg(feature = "lzw")]
|
||||
impl From<weezl::LzwError> for TiffError {
|
||||
fn from(err: weezl::LzwError) -> TiffError {
|
||||
TiffError::FormatError(TiffFormatError::CompressedDataCorrupt(err.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "jpeg")]
|
||||
impl From<zune_jpeg::errors::DecodeErrors> for TiffError {
|
||||
fn from(err: zune_jpeg::errors::DecodeErrors) -> Self {
|
||||
TiffError::FormatError(TiffFormatError::CompressedDataCorrupt(err.to_string()))
|
||||
|
||||
@@ -139,11 +139,13 @@ fn encode_decode_without_compression() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "lzw")]
|
||||
fn encode_decode_with_lzw() {
|
||||
encode_decode_with_compression(Compression::Lzw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "deflate")]
|
||||
fn encode_decode_with_deflate() {
|
||||
encode_decode_with_compression(Compression::Deflate(DeflateLevel::Fast));
|
||||
encode_decode_with_compression(Compression::Deflate(DeflateLevel::Balanced));
|
||||
|
||||
Reference in new issue
Block a user