diff --git a/crates/core/files/src/lib.rs b/crates/core/files/src/lib.rs index f5832c80..5d1382c2 100644 --- a/crates/core/files/src/lib.rs +++ b/crates/core/files/src/lib.rs @@ -4,7 +4,7 @@ use aes_gcm::{ aead::{AeadCore, AeadMutInPlace, OsRng}, Aes256Gcm, Key, KeyInit, Nonce, }; -use image::DynamicImage; +use image::{DynamicImage, ImageBuffer}; use revolt_config::{config, report_internal_error, FilesS3}; use revolt_result::{create_error, Result}; @@ -152,38 +152,67 @@ pub fn video_size(f: &NamedTempFile) -> Option<(i64, i64)> { } /// Decode image from reader -pub fn decode_image( - reader: &mut R, - is_jxl: bool, -) -> Result { - if is_jxl { - Err(create_error!(LabelMe)) - } else { +pub fn decode_image(reader: &mut R, mime: &str) -> Result { + match mime { + // Read image using jxl-oxide crate + "image/jxl" => { + let jxl_image = report_internal_error!(jxl_oxide::JxlImage::builder().read(reader))?; + if let Ok(frame) = jxl_image.render_frame(0) { + match frame.color_channels().len() { + 3 => Ok(DynamicImage::ImageRgb8( + DynamicImage::ImageRgb32F( + ImageBuffer::from_vec( + jxl_image.width(), + jxl_image.height(), + frame.image().buf().to_vec(), + ) + .ok_or_else(|| create_error!(LabelMe))?, + ) + .to_rgb8(), + )), + 4 => Ok(DynamicImage::ImageRgba8( + DynamicImage::ImageRgba32F( + ImageBuffer::from_vec( + jxl_image.width(), + jxl_image.height(), + frame.image().buf().to_vec(), + ) + .ok_or_else(|| create_error!(LabelMe))?, + ) + .to_rgba8(), + )), + _ => Err(create_error!(LabelMe)), + } + } else { + Err(create_error!(LabelMe)) + } + } + // Read image using resvg + "image/svg+xml" => Err(create_error!(LabelMe)), // Check if we can read using image-rs crate - report_internal_error!(report_internal_error!( + _ => report_internal_error!(report_internal_error!( image::ImageReader::new(reader).with_guessed_format() )? - .decode()) + .decode()), } } /// Check whether given reader has a valid image -pub fn is_valid_image(reader: &mut R, is_jxl: bool) -> bool { - if is_jxl { +pub fn is_valid_image(reader: &mut R, mime: &str) -> bool { + match mime { // Check if we can read using jxl-oxide crate - jxl_oxide::JxlImage::builder() + "image/jxl" => jxl_oxide::JxlImage::builder() .read(reader) .inspect_err(|err| tracing::error!("Failed to read JXL! {err:?}")) - .is_ok() - } else { - !matches!( - // Check if we can read using image-rs crate + .is_ok(), + // Check if we can read using image-rs crate + _ => !matches!( image::ImageReader::new(reader) .with_guessed_format() .inspect_err(|err| tracing::error!("Failed to read image! {err:?}")) .map(|f| f.decode()), Err(_) | Ok(Err(_)) - ) + ), } } diff --git a/crates/services/autumn/src/api.rs b/crates/services/autumn/src/api.rs index 86b1dcc1..bc1bcfaa 100644 --- a/crates/services/autumn/src/api.rs +++ b/crates/services/autumn/src/api.rs @@ -11,7 +11,6 @@ use axum::{ Json, Router, }; use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart}; -use image::ImageReader; use lazy_static::lazy_static; use revolt_config::{config, report_internal_error}; use revolt_database::{iso8601_timestamp::Timestamp, Database, FileHash, Metadata, User}; @@ -355,7 +354,11 @@ async fn fetch_preview( let data = retrieve_file_by_hash(&hash).await?; // Read image and create thumbnail - let data = create_thumbnail(decode_image(&mut Cursor::new(data), false)?, tag).await; + let data = create_thumbnail( + decode_image(&mut Cursor::new(data), &file.content_type)?, + tag, + ) + .await; Ok(( [ diff --git a/crates/services/january/src/requests.rs b/crates/services/january/src/requests.rs index 6f4c5dc6..90ce7bf0 100644 --- a/crates/services/january/src/requests.rs +++ b/crates/services/january/src/requests.rs @@ -71,7 +71,7 @@ impl Request { let reader = &mut Cursor::new(&bytes); if matches!(mime.subtype(), mime::GIF) { - if is_valid_image(reader, false) { + if is_valid_image(reader, "image/gif") { Ok(("image/gif".to_owned(), bytes.to_vec())) } else { Err(create_error!(LabelMe)) @@ -79,8 +79,11 @@ impl Request { } else { Ok(( "image/webp".to_owned(), - create_thumbnail(decode_image(reader, false)?, "attachments") - .await, + create_thumbnail( + decode_image(reader, mime.as_ref())?, + "attachments", + ) + .await, )) } } else {