@@ -4,7 +4,7 @@ use aes_gcm::{
|
|||||||
aead::{AeadCore, AeadMutInPlace, OsRng},
|
aead::{AeadCore, AeadMutInPlace, OsRng},
|
||||||
Aes256Gcm, Key, KeyInit, Nonce,
|
Aes256Gcm, Key, KeyInit, Nonce,
|
||||||
};
|
};
|
||||||
use image::DynamicImage;
|
use image::{DynamicImage, ImageBuffer};
|
||||||
use revolt_config::{config, report_internal_error, FilesS3};
|
use revolt_config::{config, report_internal_error, FilesS3};
|
||||||
use revolt_result::{create_error, Result};
|
use revolt_result::{create_error, Result};
|
||||||
|
|
||||||
@@ -152,38 +152,67 @@ pub fn video_size(f: &NamedTempFile) -> Option<(i64, i64)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decode image from reader
|
/// Decode image from reader
|
||||||
pub fn decode_image<R: Read + BufRead + Seek>(
|
pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Result<DynamicImage> {
|
||||||
reader: &mut R,
|
match mime {
|
||||||
is_jxl: bool,
|
// Read image using jxl-oxide crate
|
||||||
) -> Result<DynamicImage> {
|
"image/jxl" => {
|
||||||
if is_jxl {
|
let jxl_image = report_internal_error!(jxl_oxide::JxlImage::builder().read(reader))?;
|
||||||
Err(create_error!(LabelMe))
|
if let Ok(frame) = jxl_image.render_frame(0) {
|
||||||
} else {
|
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
|
// 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()
|
image::ImageReader::new(reader).with_guessed_format()
|
||||||
)?
|
)?
|
||||||
.decode())
|
.decode()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether given reader has a valid image
|
/// Check whether given reader has a valid image
|
||||||
pub fn is_valid_image<R: Read + BufRead + Seek>(reader: &mut R, is_jxl: bool) -> bool {
|
pub fn is_valid_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> bool {
|
||||||
if is_jxl {
|
match mime {
|
||||||
// Check if we can read using jxl-oxide crate
|
// Check if we can read using jxl-oxide crate
|
||||||
jxl_oxide::JxlImage::builder()
|
"image/jxl" => jxl_oxide::JxlImage::builder()
|
||||||
.read(reader)
|
.read(reader)
|
||||||
.inspect_err(|err| tracing::error!("Failed to read JXL! {err:?}"))
|
.inspect_err(|err| tracing::error!("Failed to read JXL! {err:?}"))
|
||||||
.is_ok()
|
.is_ok(),
|
||||||
} else {
|
// Check if we can read using image-rs crate
|
||||||
!matches!(
|
_ => !matches!(
|
||||||
// Check if we can read using image-rs crate
|
|
||||||
image::ImageReader::new(reader)
|
image::ImageReader::new(reader)
|
||||||
.with_guessed_format()
|
.with_guessed_format()
|
||||||
.inspect_err(|err| tracing::error!("Failed to read image! {err:?}"))
|
.inspect_err(|err| tracing::error!("Failed to read image! {err:?}"))
|
||||||
.map(|f| f.decode()),
|
.map(|f| f.decode()),
|
||||||
Err(_) | Ok(Err(_))
|
Err(_) | Ok(Err(_))
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use axum::{
|
|||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart};
|
use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart};
|
||||||
use image::ImageReader;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use revolt_config::{config, report_internal_error};
|
use revolt_config::{config, report_internal_error};
|
||||||
use revolt_database::{iso8601_timestamp::Timestamp, Database, FileHash, Metadata, User};
|
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?;
|
let data = retrieve_file_by_hash(&hash).await?;
|
||||||
|
|
||||||
// Read image and create thumbnail
|
// 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((
|
Ok((
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ impl Request {
|
|||||||
let reader = &mut Cursor::new(&bytes);
|
let reader = &mut Cursor::new(&bytes);
|
||||||
|
|
||||||
if matches!(mime.subtype(), mime::GIF) {
|
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()))
|
Ok(("image/gif".to_owned(), bytes.to_vec()))
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(LabelMe))
|
Err(create_error!(LabelMe))
|
||||||
@@ -79,8 +79,11 @@ impl Request {
|
|||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
"image/webp".to_owned(),
|
"image/webp".to_owned(),
|
||||||
create_thumbnail(decode_image(reader, false)?, "attachments")
|
create_thumbnail(
|
||||||
.await,
|
decode_image(reader, mime.as_ref())?,
|
||||||
|
"attachments",
|
||||||
|
)
|
||||||
|
.await,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user