diff --git a/Cargo.lock b/Cargo.lock index c7c5fefd..d2ad9cc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + [[package]] name = "crc32fast" version = "1.4.0" @@ -377,12 +386,176 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-encoder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cf3affe27ffd9f1992690ec7575568b222abe9cb39738f6531968aca8e64906" + +[[package]] +name = "jxl-bitstream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c3205d18cf6229b3f694de66e592886ff7afb0740bc0e85594e3b28d6f6622" +dependencies = [ + "tracing", +] + +[[package]] +name = "jxl-coding" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7075600c762c1ce9e2dd1fbc3fa8ded2af1401fe2221449eca943977742dd0b4" +dependencies = [ + "jxl-bitstream", +] + +[[package]] +name = "jxl-color" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9084bc33b6d01e26b1db6c187514a51a57f4e3780335f3120ab55ee0b08f6e73" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", +] + +[[package]] +name = "jxl-frame" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d63bdd104e3746669a123de86f940aa5d59fdc9c5a65f16a4f867dde75e45e1" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-grid" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48800b21ed6bb3bbc2f818ae9cd40530bdfb1a211f57d5a7a49b8b10f62145e8" + +[[package]] +name = "jxl-image" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86f7f74acc9c9e66604c8d030e00cdef5a0c455ea3d7d26bd9ddbb9160be59" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-grid", + "tracing", +] + +[[package]] +name = "jxl-modular" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504e6b55db362568592be81993c772fc6786c56fb67ae769ff62dc514c3e6748" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "tracing", +] + +[[package]] +name = "jxl-oxide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e3b7e459d823979c4ca0c9584f391581db154437f34596ea443b082e9b6064" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-render", + "tracing", +] + +[[package]] +name = "jxl-render" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7157d1c6c4896ddc800cb0cc8ba545ba7417ab9afc51f39e69484e6607c8707e" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-vardct" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb4a2d9ba8c48a52f6143ba01c38aac67d1309c9b939a9f84cd60f650d15053e" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-modular", + "tracing", +] + +[[package]] +name = "kamadak-exif" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "libavif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e307eb041038a7a1b4fefe41d098a691ea1c3c111d58e0e21cc4fc304409a66f" +dependencies = [ + "libavif-sys", +] + +[[package]] +name = "libavif-sys" +version = "0.16.0+libavif.1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb05b7f9437ad312ad3dec250781fc95df54d4a1ec69d8b6cf5d503c5f5a51d" +dependencies = [ + "cmake", + "libc", + "libdav1d-sys", + "rav1e 0.7.1", +] + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libdav1d-sys" +version = "0.7.0+libdav1d.1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0de922cdce0f7aca62567c9c454cbf49e5b1a7a79a10f97a3130547692aca71" +dependencies = [ + "libc", +] + [[package]] name = "libdeflate-sys" version = "1.19.3" @@ -493,6 +666,12 @@ dependencies = [ "nasm-rs 0.3.0", ] +[[package]] +name = "mutate_once" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" + [[package]] name = "nasm-rs" version = "0.2.5" @@ -633,6 +812,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + [[package]] name = "pkg-config" version = "0.3.30" @@ -792,6 +977,7 @@ dependencies = [ "profiling", "rand", "rand_chacha", + "scan_fmt", "simd_helpers", "system-deps", "thiserror", @@ -858,6 +1044,7 @@ version = "0.11.0-next" dependencies = [ "fast_image_resize", "imagequant", + "libavif", "log", "mozjpeg", "oxipng", @@ -905,6 +1092,12 @@ dependencies = [ "semver", ] +[[package]] +name = "scan_fmt" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" + [[package]] name = "semver" version = "1.0.22" @@ -1099,6 +1292,25 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -1319,11 +1531,42 @@ dependencies = [ "typed-arena", ] +[[package]] +name = "zune-bmp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b1d6d8d84344ba202fcf02d6505ab57c2d775ae07dcb64809421735d8ce8c0f" +dependencies = [ + "zune-core", +] + [[package]] name = "zune-core" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +dependencies = [ + "log", + "serde", +] + +[[package]] +name = "zune-farbfeld" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea864ca80549c562044a8632421897a1e419ca460c20bd07fe84371f410f011" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zune-hdr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ff474631f80b14afc6dbc6bab78702ed2de7cd6af85f7a4ab21d3b08686426" +dependencies = [ + "zune-core", +] [[package]] name = "zune-image" @@ -1332,5 +1575,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6b98ac0fc8c650406e88f7b33f264798b85b7eff88cc09a8f86688c24d0261" dependencies = [ "bytemuck", + "jpeg-encoder", + "jxl-oxide", + "kamadak-exif", + "serde", + "zune-bmp", + "zune-core", + "zune-farbfeld", + "zune-hdr", + "zune-jpeg", + "zune-jpegxl", + "zune-png", + "zune-ppm", + "zune-psd", + "zune-qoi", +] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zune-jpegxl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71ffee484384b15f99ed4768bfdb3fa186d63e1f8c3aafba1d6d141a7b9e3674" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zune-png" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d29c085769c6f29effea890f093120ac019375fdc789d2a496ba8ba96c77509" +dependencies = [ + "zune-core", + "zune-inflate", +] + +[[package]] +name = "zune-ppm" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0527e645233e3b34b10aa576b4b156e60f52f15b01f906789eb820f7ef4b2774" +dependencies = [ + "log", + "zune-core", +] + +[[package]] +name = "zune-psd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab11275d621813206ba4c20f4ec647eab0733c0fc71c3276d1238229fd834d49" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zune-qoi" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc598b6729ede546413cb5077d8ddb83b46055a156d5cc3c625cfe122484e9c9" +dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 431d64c5..69a08813 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ oxipng = ["dep:oxipng"] # Enables webp codec webp = ["dep:webp"] # Enables avif codec -avif = ["dep:ravif", "dep:rgb"] +avif = ["dep:ravif", "dep:libavif", "dep:rgb"] [dependencies] zune-core = "0.4.12" @@ -49,3 +49,8 @@ mozjpeg = { version = "0.10.7", default-features = false, features = ["with_simd oxipng = { version = "9.0", default-features = false, features = ["zopfli", "filetime"], optional = true } webp = { version = "0.2.6", default-features = false, optional = true } ravif = { version = "0.11.4", optional = true } +libavif = { version = "0.13.0", optional = true } + +[dev-dependencies] +zune-core = { version = "0.4.12", features = ["std"] } +zune-image = "0.4.15" diff --git a/src/codecs/avif/decoder/mod.rs b/src/codecs/avif/decoder/mod.rs new file mode 100644 index 00000000..d8a80d60 --- /dev/null +++ b/src/codecs/avif/decoder/mod.rs @@ -0,0 +1,54 @@ +use std::{io::Read, marker::PhantomData}; + +use zune_core::{bytestream::ZReaderTrait, colorspace::ColorSpace}; +use zune_image::{errors::ImageErrors, image::Image, traits::DecoderTrait}; + +pub struct AvifDecoder { + inner: Vec, + dimensions: Option<(usize, usize)>, + phantom: PhantomData, +} + +impl AvifDecoder { + pub fn try_new(mut source: R) -> Result, ImageErrors> { + let mut buf = Vec::new(); + source.read_to_end(&mut buf)?; + + Ok(AvifDecoder { + inner: buf, + dimensions: None, + phantom: PhantomData, + }) + } +} + +impl DecoderTrait for AvifDecoder +where + R: Read, + T: ZReaderTrait, +{ + fn decode(&mut self) -> Result { + let img = libavif::decode_rgb(&self.inner) + .map_err(|e| ImageErrors::ImageDecodeErrors(e.to_string()))?; + + let (w, h) = (img.width() as usize, img.height() as usize); + self.dimensions = Some((w, h)); + + Ok(Image::from_u8(&img, w, h, ColorSpace::RGBA)) + } + + fn dimensions(&self) -> Option<(usize, usize)> { + self.dimensions + } + + fn out_colorspace(&self) -> ColorSpace { + ColorSpace::RGBA + } + + fn name(&self) -> &'static str { + "avif-decoder (aom)" + } +} + +#[cfg(test)] +mod tests; diff --git a/src/codecs/avif/decoder/tests.rs b/src/codecs/avif/decoder/tests.rs new file mode 100644 index 00000000..7e132dea --- /dev/null +++ b/src/codecs/avif/decoder/tests.rs @@ -0,0 +1,20 @@ +use std::fs::read; + +use zune_core::bytestream::ZByteReader; + +use super::*; + +#[test] +fn decode() { + let file_content = read("tests/files/avif/f1t.avif").unwrap(); + + let reader = ZByteReader::new(file_content); + + let mut decoder = AvifDecoder::try_new(reader).unwrap(); + + let img = + >> as DecoderTrait>>::decode(&mut decoder).unwrap(); + + assert_eq!(img.dimensions(), (48, 80)); + assert_eq!(img.colorspace(), ColorSpace::RGBA); +} diff --git a/src/codecs/avif/mod.rs b/src/codecs/avif/mod.rs index 7d92bfe1..091e2131 100644 --- a/src/codecs/avif/mod.rs +++ b/src/codecs/avif/mod.rs @@ -1,3 +1,5 @@ +mod decoder; mod encoder; +pub use decoder::*; pub use encoder::*;