From 4ba9263c7339da9bbc810f14ec99003e3f4b513e Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Mon, 4 Nov 2024 22:42:47 -0300 Subject: [PATCH 01/11] Add proper support for animated images --- apps/labrinth/Cargo.toml | 2 +- apps/labrinth/src/util/img.rs | 95 ++++++++++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 7 deletions(-) diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml index 376045a0a..075019b53 100644 --- a/apps/labrinth/Cargo.toml +++ b/apps/labrinth/Cargo.toml @@ -107,7 +107,7 @@ sentry = { version = "0.34.0", default-features = false, features = [ ] } sentry-actix = "0.34.0" -image = "0.24.6" +image = "0.25.4" color-thief = "0.2.2" webp = "0.3.0" diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 4e5cb24fb..4219782cb 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -7,11 +7,15 @@ use crate::routes::ApiError; use color_thief::ColorFormat; use image::imageops::FilterType; use image::{ - DynamicImage, EncodableLayout, GenericImageView, ImageError, - ImageOutputFormat, + AnimationDecoder, DynamicImage, EncodableLayout, Frame, + GenericImageView, ImageError, ImageFormat }; use std::io::Cursor; -use webp::Encoder; +use std::ops::Div; +use image::codecs::gif::GifDecoder; +use image::codecs::png::PngDecoder; +use image::codecs::webp::WebPDecoder; +use webp::{AnimEncoder, AnimFrame, Encoder, WebPConfig}; pub fn get_color_from_img(data: &[u8]) -> Result, ImageError> { let image = image::load_from_memory(data)? @@ -118,10 +122,89 @@ fn process_image( target_width: Option, min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { - if content_type.to_lowercase() == "image/gif" { - return Ok((image_bytes.clone(), "gif".to_string())); + match content_type { + "image/gif" => process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio), + "image/png" => { + let decoder = PngDecoder::new(Cursor::new(image_bytes.clone()))?; + if decoder.is_apng()? { + process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio) + } else { + process_static_image(image_bytes, target_width, min_aspect_ratio) + } + }, + "image/webp" => process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio), + _ => process_static_image(image_bytes, target_width, min_aspect_ratio), + } +} + +fn process_animated_image( + image_bytes: bytes::Bytes, + content_type: &str, + target_width: Option, + min_aspect_ratio: Option, +) -> Result<(bytes::Bytes, String), ImageError> { + let dimensions = image::load_from_memory(&*image_bytes.clone())?.dimensions(); + let mut frames2: Vec = match content_type { + "image/gif" => GifDecoder::new(Cursor::new(image_bytes))?.into_frames().collect_frames()?, + "image/png" => PngDecoder::new(Cursor::new(image_bytes))?.apng()?.into_frames().collect_frames()?, + "image/webp" => WebPDecoder::new(Cursor::new(image_bytes))?.into_frames().collect_frames()?, + _ => unimplemented!(), + }; + + // Resize the image + let (orig_width, orig_height) = dimensions; + let og_aspect_ratio = orig_width as f32 / orig_height as f32; + let mut width = orig_width; + let mut height = orig_height; + let mut crop_image = false; + + if let Some(target_width) = target_width { + if dimensions.0 > target_width { + width = target_width; + height = (target_width as f32 / og_aspect_ratio).round() as u32; + } + } + + if let Some(min_aspect_ratio) = min_aspect_ratio { + // Crop if necessary + if og_aspect_ratio < min_aspect_ratio { + crop_image = true; + } + } + + let mut config = WebPConfig::new().unwrap(); + config.quality = 75f32; + config.method = 6; + let mut encoder = AnimEncoder::new(width, height, &config); + encoder.set_loop_count(0); + + let mut frames = vec![]; + frames2.iter().for_each(|frame| { + let mut img = image::imageops::resize(frame.buffer(), width, height, FilterType::Lanczos3); + if (crop_image) { + let crop_height = (width as f32 / min_aspect_ratio.unwrap()).round() as u32; + let y_offset = (height - crop_height) / 2; + img = image::imageops::crop_imm(&img, 0, y_offset, img.width(), crop_height).to_image(); + } + frames.push((img.clone(), frame.delay())); + }); + + let mut t = 0; + for f in &frames { + encoder.add_frame(AnimFrame::from_rgba(&*f.0, width, height, t)); + t += f.1.numer_denom_ms().0.div(f.1.numer_denom_ms().1) as i32; } + let webp_bytes = encoder.encode(); + + Ok((bytes::Bytes::from(webp_bytes.to_vec()), "webp".to_string())) +} + +fn process_static_image( + image_bytes: bytes::Bytes, + target_width: Option, + min_aspect_ratio: Option, +) -> Result<(bytes::Bytes, String), ImageError> { let mut img = image::load_from_memory(&image_bytes)?; let webp_bytes = convert_to_webp(&img)?; @@ -151,7 +234,7 @@ fn process_image( // Optimize and compress let mut output = Vec::new(); - img.write_to(&mut Cursor::new(&mut output), ImageOutputFormat::WebP)?; + img.write_to(&mut Cursor::new(&mut output), ImageFormat::WebP)?; Ok((bytes::Bytes::from(output), "webp".to_string())) } From 1e0c873caf1d5b26737c772ca1699a671e338d90 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:17:36 -0300 Subject: [PATCH 02/11] Tackle linting Why does all of this look so arbitrary? --- apps/labrinth/src/util/img.rs | 76 ++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 4219782cb..a04379026 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -5,16 +5,16 @@ use crate::file_hosting::FileHost; use crate::models::images::ImageContext; use crate::routes::ApiError; use color_thief::ColorFormat; +use image::codecs::gif::GifDecoder; +use image::codecs::png::PngDecoder; +use image::codecs::webp::WebPDecoder; use image::imageops::FilterType; use image::{ - AnimationDecoder, DynamicImage, EncodableLayout, Frame, - GenericImageView, ImageError, ImageFormat + AnimationDecoder, DynamicImage, EncodableLayout, Frame, GenericImageView, + ImageError, ImageFormat }; use std::io::Cursor; use std::ops::Div; -use image::codecs::gif::GifDecoder; -use image::codecs::png::PngDecoder; -use image::codecs::webp::WebPDecoder; use webp::{AnimEncoder, AnimFrame, Encoder, WebPConfig}; pub fn get_color_from_img(data: &[u8]) -> Result, ImageError> { @@ -123,16 +123,35 @@ fn process_image( min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { match content_type { - "image/gif" => process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio), + "image/gif" => process_animated_image( + image_bytes, + content_type, + target_width, + min_aspect_ratio, + ), "image/png" => { let decoder = PngDecoder::new(Cursor::new(image_bytes.clone()))?; if decoder.is_apng()? { - process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio) + process_animated_image( + image_bytes, + content_type, + target_width, + min_aspect_ratio, + ) } else { - process_static_image(image_bytes, target_width, min_aspect_ratio) + process_static_image( + image_bytes, + target_width, + min_aspect_ratio, + ) } }, - "image/webp" => process_animated_image(image_bytes, content_type, target_width, min_aspect_ratio), + "image/webp" => process_animated_image( + image_bytes, + content_type, + target_width, + min_aspect_ratio, + ), _ => process_static_image(image_bytes, target_width, min_aspect_ratio), } } @@ -143,11 +162,19 @@ fn process_animated_image( target_width: Option, min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { - let dimensions = image::load_from_memory(&*image_bytes.clone())?.dimensions(); + let dimensions = + image::load_from_memory(&*image_bytes.clone())?.dimensions(); let mut frames2: Vec = match content_type { - "image/gif" => GifDecoder::new(Cursor::new(image_bytes))?.into_frames().collect_frames()?, - "image/png" => PngDecoder::new(Cursor::new(image_bytes))?.apng()?.into_frames().collect_frames()?, - "image/webp" => WebPDecoder::new(Cursor::new(image_bytes))?.into_frames().collect_frames()?, + "image/gif" => GifDecoder::new(Cursor::new(image_bytes))? + .into_frames() + .collect_frames()?, + "image/png" => PngDecoder::new(Cursor::new(image_bytes))? + .apng()? + .into_frames() + .collect_frames()?, + "image/webp" => WebPDecoder::new(Cursor::new(image_bytes))? + .into_frames() + .collect_frames()?, _ => unimplemented!(), }; @@ -180,11 +207,24 @@ fn process_animated_image( let mut frames = vec![]; frames2.iter().for_each(|frame| { - let mut img = image::imageops::resize(frame.buffer(), width, height, FilterType::Lanczos3); - if (crop_image) { - let crop_height = (width as f32 / min_aspect_ratio.unwrap()).round() as u32; + let mut img = image::imageops::resize( + frame.buffer(), + width, + height, + FilterType::Lanczos3, + ); + if crop_image { + let crop_height = + (width as f32 / min_aspect_ratio.unwrap()).round() as u32; let y_offset = (height - crop_height) / 2; - img = image::imageops::crop_imm(&img, 0, y_offset, img.width(), crop_height).to_image(); + img = image::imageops::crop_imm( + &img, + 0, + y_offset, + img.width(), + crop_height, + ) + .to_image(); } frames.push((img.clone(), frame.delay())); }); @@ -195,7 +235,7 @@ fn process_animated_image( t += f.1.numer_denom_ms().0.div(f.1.numer_denom_ms().1) as i32; } - let webp_bytes = encoder.encode(); + let webp_bytes = encoder.encode(); Ok((bytes::Bytes::from(webp_bytes.to_vec()), "webp".to_string())) } From 34544291895ed06e539f8b8cd0c2d905c794a983 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:34:27 -0300 Subject: [PATCH 03/11] Truly pacify linting --- apps/labrinth/src/util/img.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index a04379026..5f1ab0c34 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -11,7 +11,7 @@ use image::codecs::webp::WebPDecoder; use image::imageops::FilterType; use image::{ AnimationDecoder, DynamicImage, EncodableLayout, Frame, GenericImageView, - ImageError, ImageFormat + ImageError, ImageFormat, }; use std::io::Cursor; use std::ops::Div; @@ -145,7 +145,7 @@ fn process_image( min_aspect_ratio, ) } - }, + } "image/webp" => process_animated_image( image_bytes, content_type, From 272eb3fcbdd55f39aa7c81edf4ffd6f725c43e5f Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:54:11 -0300 Subject: [PATCH 04/11] Use CI's Clippy This is the best part of CI: when stuff is so broken you can't even test things on the repo itself, use someone else's tooling! --- apps/labrinth/src/util/img.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 5f1ab0c34..a0193f4b9 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -163,8 +163,8 @@ fn process_animated_image( min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { let dimensions = - image::load_from_memory(&*image_bytes.clone())?.dimensions(); - let mut frames2: Vec = match content_type { + image::load_from_memory(&image_bytes.clone())?.dimensions(); + let frames2: Vec = match content_type { "image/gif" => GifDecoder::new(Cursor::new(image_bytes))? .into_frames() .collect_frames()?, @@ -231,7 +231,7 @@ fn process_animated_image( let mut t = 0; for f in &frames { - encoder.add_frame(AnimFrame::from_rgba(&*f.0, width, height, t)); + encoder.add_frame(AnimFrame::from_rgba(&f.0, width, height, t)); t += f.1.numer_denom_ms().0.div(f.1.numer_denom_ms().1) as i32; } From e0d913fd7a13f04b84153db2e104c72eaaf80e29 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Tue, 5 Nov 2024 20:39:44 -0300 Subject: [PATCH 05/11] Update to image-rs 0.25.5 Does it matter? No, Modrinth does not support AVIF images as an input yet, but we are already updating the dependency anyway so we might as well do it --- apps/labrinth/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml index 075019b53..f833365b2 100644 --- a/apps/labrinth/Cargo.toml +++ b/apps/labrinth/Cargo.toml @@ -107,7 +107,7 @@ sentry = { version = "0.34.0", default-features = false, features = [ ] } sentry-actix = "0.34.0" -image = "0.25.4" +image = "0.25.5" color-thief = "0.2.2" webp = "0.3.0" From 6707e98a9b485e006c40459e30e879a2b28452db Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:12:12 -0300 Subject: [PATCH 06/11] Do not process GIFs if not asked --- apps/labrinth/src/util/img.rs | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index a0193f4b9..28159872f 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -8,6 +8,7 @@ use color_thief::ColorFormat; use image::codecs::gif::GifDecoder; use image::codecs::png::PngDecoder; use image::codecs::webp::WebPDecoder; +use image::error::{UnsupportedError, UnsupportedErrorKind}; use image::imageops::FilterType; use image::{ AnimationDecoder, DynamicImage, EncodableLayout, Frame, GenericImageView, @@ -123,12 +124,32 @@ fn process_image( min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { match content_type { - "image/gif" => process_animated_image( - image_bytes, - content_type, - target_width, - min_aspect_ratio, - ), + "image/gif" => { + if target_width.is_none() && min_aspect_ratio.is_none() { + process_animated_image( + image_bytes, + content_type, + target_width, + min_aspect_ratio, + ) + } else { + // Skip animated image processing for GIFs that won't be modified + // But not before checking if it's indeed a GIF + let format = image::guess_format(&image_bytes)?; + if format == ImageFormat::Gif { + Ok((image_bytes.clone(), "gif".to_string())) + } else { + Err(ImageError::Unsupported( + UnsupportedError::from_format_and_kind( + ImageFormat::Gif.into(), + UnsupportedErrorKind::GenericFeature( + "Attempted to process an invalid GIF!".to_owned() + ) + ) + )) + } + } + }, "image/png" => { let decoder = PngDecoder::new(Cursor::new(image_bytes.clone()))?; if decoder.is_apng()? { From ffa3a91747db04e8b43fd4066d3fcbcba3f25876 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:51:23 -0300 Subject: [PATCH 07/11] Trim unnecessary image-rs features --- apps/labrinth/Cargo.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml index f833365b2..fb648eb8b 100644 --- a/apps/labrinth/Cargo.toml +++ b/apps/labrinth/Cargo.toml @@ -107,7 +107,14 @@ sentry = { version = "0.34.0", default-features = false, features = [ ] } sentry-actix = "0.34.0" -image = "0.25.5" +image = { version = "0.25.5", default-features = false, features = [ + "rayon", + "bmp", + "gif", + "jpeg", + "png", + "webp", +] } color-thief = "0.2.2" webp = "0.3.0" From 3defab8a9712b9067bfb5e31c1664ccbaadd5f06 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:52:25 -0300 Subject: [PATCH 08/11] Fix linting --- apps/labrinth/src/util/img.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 28159872f..7155d466b 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -143,13 +143,14 @@ fn process_image( UnsupportedError::from_format_and_kind( ImageFormat::Gif.into(), UnsupportedErrorKind::GenericFeature( - "Attempted to process an invalid GIF!".to_owned() - ) - ) + "Attempted to process an invalid GIF!" + .to_owned() + ), + ), )) } } - }, + } "image/png" => { let decoder = PngDecoder::new(Cursor::new(image_bytes.clone()))?; if decoder.is_apng()? { From e7cf8c33fcd43c11dcebba436040441953db3117 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:39:32 -0300 Subject: [PATCH 09/11] Revert back into universal WebP conversion --- apps/labrinth/src/util/img.rs | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 7155d466b..1fef2f6e6 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -124,33 +124,12 @@ fn process_image( min_aspect_ratio: Option, ) -> Result<(bytes::Bytes, String), ImageError> { match content_type { - "image/gif" => { - if target_width.is_none() && min_aspect_ratio.is_none() { - process_animated_image( - image_bytes, - content_type, - target_width, - min_aspect_ratio, - ) - } else { - // Skip animated image processing for GIFs that won't be modified - // But not before checking if it's indeed a GIF - let format = image::guess_format(&image_bytes)?; - if format == ImageFormat::Gif { - Ok((image_bytes.clone(), "gif".to_string())) - } else { - Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Gif.into(), - UnsupportedErrorKind::GenericFeature( - "Attempted to process an invalid GIF!" - .to_owned() - ), - ), - )) - } - } - } + "image/gif" => process_animated_image( + image_bytes, + content_type, + target_width, + min_aspect_ratio, + ), "image/png" => { let decoder = PngDecoder::new(Cursor::new(image_bytes.clone()))?; if decoder.is_apng()? { From 924788800bc788643ccced379caf2ab970e4a93c Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:13:31 -0300 Subject: [PATCH 10/11] Fix linting (Please?) --- apps/labrinth/src/util/img.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/labrinth/src/util/img.rs b/apps/labrinth/src/util/img.rs index 1fef2f6e6..a0193f4b9 100644 --- a/apps/labrinth/src/util/img.rs +++ b/apps/labrinth/src/util/img.rs @@ -8,7 +8,6 @@ use color_thief::ColorFormat; use image::codecs::gif::GifDecoder; use image::codecs::png::PngDecoder; use image::codecs::webp::WebPDecoder; -use image::error::{UnsupportedError, UnsupportedErrorKind}; use image::imageops::FilterType; use image::{ AnimationDecoder, DynamicImage, EncodableLayout, Frame, GenericImageView, From 610cb8f136ce53488592bc2fe947c6400972920f Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:18:11 -0300 Subject: [PATCH 11/11] Update Cargo.lock --- Cargo.lock | 345 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 242 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8dffdfd5a..698112a68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,12 +301,6 @@ dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -357,6 +351,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -414,6 +414,17 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "argon2" version = "0.5.3" @@ -752,6 +763,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +dependencies = [ + "arrayvec", +] + [[package]] name = "aws-creds" version = "0.34.1" @@ -787,7 +821,7 @@ dependencies = [ "addr2line", "cfg-if 1.0.0", "libc", - "miniz_oxide 0.8.0", + "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -853,12 +887,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - [[package]] name = "bitflags" version = "1.3.2" @@ -874,6 +902,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "bitvec" version = "1.0.1" @@ -1008,6 +1042,12 @@ dependencies = [ "serde", ] +[[package]] +name = "built" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" + [[package]] name = "bumpalo" version = "3.16.0" @@ -2503,22 +2543,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "exr" -version = "1.72.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" -dependencies = [ - "bit_field", - "flume", - "half", - "lebe", - "miniz_oxide 0.7.4", - "rayon-core", - "smallvec 1.13.2", - "zune-inflate", -] - [[package]] name = "fancy-regex" version = "0.11.0" @@ -2604,7 +2628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -3242,16 +3266,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if 1.0.0", - "crunchy", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -3806,33 +3820,39 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "image" -version = "0.24.9" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", - "byteorder", + "byteorder-lite", "color_quant", - "exr", "gif", - "jpeg-decoder", + "image-webp", "num-traits", "png", - "qoi", - "tiff", + "ravif", + "rayon", + "zune-core", + "zune-jpeg", ] [[package]] -name = "image" -version = "0.25.3" +name = "image-webp" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97eb9a8e0cd5b76afea91d7eecd5cf8338cd44ced04256cf1f800474b227c52" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" dependencies = [ - "bytemuck", "byteorder-lite", - "num-traits", + "quick-error", ] +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "impl-more" version = "0.1.8" @@ -3927,6 +3947,17 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "iovec" version = "0.1.4" @@ -4112,15 +4143,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -dependencies = [ - "rayon", -] - [[package]] name = "js-sys" version = "0.3.70" @@ -4255,7 +4277,7 @@ dependencies = [ "hmac 0.11.0", "hyper 0.14.31", "hyper-tls 0.5.0", - "image 0.24.9", + "image", "itertools 0.12.1", "jemallocator", "json-patch", @@ -4316,12 +4338,6 @@ dependencies = [ "spin 0.9.8", ] -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - [[package]] name = "lettre" version = "0.11.10" @@ -4387,6 +4403,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libfuzzer-sys" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libloading" version = "0.7.4" @@ -4495,6 +4521,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru-cache" version = "0.1.2" @@ -4601,6 +4636,16 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if 1.0.0", + "rayon", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -4724,15 +4769,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a05b5d0594e0cb1ad8cee3373018d2b84e25905dc75b2468114cc9a8e86cfc20" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -4964,6 +5000,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "normpath" version = "1.3.0" @@ -5054,6 +5096,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -5074,6 +5127,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -5937,7 +6001,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -6095,6 +6159,25 @@ dependencies = [ "hex", ] +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn 2.0.90", +] + [[package]] name = "prometheus" version = "0.13.4" @@ -6140,15 +6223,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - [[package]] name = "quanta" version = "0.12.3" @@ -6368,6 +6442,56 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if 1.0.0", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.64", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "raw-cpuid" version = "11.2.0" @@ -7689,6 +7813,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simdutf8" version = "0.1.5" @@ -9034,17 +9167,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "time" version = "0.3.36" @@ -9829,6 +9951,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "v_htmlescape" version = "0.15.8" @@ -10198,7 +10331,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f53152f51fb5af0c08484c33d16cca96175881d1f3dec068c23b31a158c2d99" dependencies = [ - "image 0.25.3", + "image", "libwebp-sys", ] @@ -11228,12 +11361,18 @@ dependencies = [ ] [[package]] -name = "zune-inflate" -version = "0.2.54" +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" dependencies = [ - "simd-adler32", + "zune-core", ] [[package]]