diff --git a/Cargo.lock b/Cargo.lock index c68b822f..3cf777f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6824,6 +6824,7 @@ dependencies = [ "simdutf8", "strum_macros", "tempfile", + "thumbhash", "tokio 1.49.0", "tower-http 0.5.2", "tracing", @@ -8835,6 +8836,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "thumbhash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7726e0245a7331bd0c9a1fb4fd99fd695bcd478ca569f0eda2ff2cb14e7a00" + [[package]] name = "tiff" version = "0.10.3" diff --git a/crates/core/database/src/models/file_hashes/model.rs b/crates/core/database/src/models/file_hashes/model.rs index 756ce3d5..b25abb12 100644 --- a/crates/core/database/src/models/file_hashes/model.rs +++ b/crates/core/database/src/models/file_hashes/model.rs @@ -45,6 +45,7 @@ auto_derived!( Image { width: isize, height: isize, + thumbhash: Option>, #[serde(default)] animated: bool, }, diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index e5e888d6..2e637795 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -415,11 +415,13 @@ impl From for Metadata { crate::Metadata::Image { width, height, + thumbhash, animated, } => Metadata::Image { width: width as usize, height: height as usize, - animated: animated as bool, + thumbhash, + animated, }, crate::Metadata::Video { width, height } => Metadata::Video { width: width as usize, @@ -438,10 +440,12 @@ impl From for crate::Metadata { Metadata::Image { width, height, + thumbhash, animated, } => crate::Metadata::Image { width: width as isize, height: height as isize, + thumbhash, animated, }, Metadata::Video { width, height } => crate::Metadata::Video { @@ -531,7 +535,9 @@ impl From for SystemMessage { crate::SystemMessage::UserRemove { id, by } => Self::UserRemove { id, by }, crate::SystemMessage::MessagePinned { id, by } => Self::MessagePinned { id, by }, crate::SystemMessage::MessageUnpinned { id, by } => Self::MessageUnpinned { id, by }, - crate::SystemMessage::CallStarted { by, finished_at } => Self::CallStarted { by, finished_at } + crate::SystemMessage::CallStarted { by, finished_at } => { + Self::CallStarted { by, finished_at } + } } } } @@ -1398,7 +1404,7 @@ impl From for crate::FieldsMessage { impl From for crate::VoiceInformation { fn from(value: VoiceInformation) -> Self { crate::VoiceInformation { - max_users: value.max_users + max_users: value.max_users, } } } @@ -1406,7 +1412,7 @@ impl From for crate::VoiceInformation { impl From for VoiceInformation { fn from(value: crate::VoiceInformation) -> Self { VoiceInformation { - max_users: value.max_users + max_users: value.max_users, } } -} \ No newline at end of file +} diff --git a/crates/core/models/src/v0/files.rs b/crates/core/models/src/v0/files.rs index 7ed1e20e..32ccf0e1 100644 --- a/crates/core/models/src/v0/files.rs +++ b/crates/core/models/src/v0/files.rs @@ -50,6 +50,7 @@ auto_derived!( Image { width: usize, height: usize, + thumbhash: Option>, animated: bool, }, /// File is a video with specific dimensions diff --git a/crates/services/autumn/Cargo.toml b/crates/services/autumn/Cargo.toml index 84cf6531..ba426dc8 100644 --- a/crates/services/autumn/Cargo.toml +++ b/crates/services/autumn/Cargo.toml @@ -17,6 +17,7 @@ jxl-oxide = "0.8.1" kamadak-exif = "0.5.4" # revolt_little_exif = "0.5.1" image = { version = "0.25.2" } # avif encode requires dav1d system library: features = ["avif-native"] +thumbhash = "0.1.0" # File processing revolt_clamav-client = { version = "0.1.5" } diff --git a/crates/services/autumn/src/exif.rs b/crates/services/autumn/src/exif.rs index 562f975e..af02953e 100644 --- a/crates/services/autumn/src/exif.rs +++ b/crates/services/autumn/src/exif.rs @@ -19,6 +19,7 @@ pub async fn strip_metadata( Metadata::Image { width, height, + thumbhash, animated, } => match mime { // // little_exif does not appear to parse JPEGs correctly? had 2/2 files fail @@ -102,6 +103,7 @@ pub async fn strip_metadata( Metadata::Image { width, height, + thumbhash: thumbhash.clone(), animated: *animated, }, )) diff --git a/crates/services/autumn/src/metadata.rs b/crates/services/autumn/src/metadata.rs index 3c69cf84..3493cf49 100644 --- a/crates/services/autumn/src/metadata.rs +++ b/crates/services/autumn/src/metadata.rs @@ -1,5 +1,6 @@ use std::io::Cursor; +use image::{GenericImageView, ImageError, ImageReader}; use revolt_database::Metadata; use revolt_files::{image_size, is_animated, video_size}; use tempfile::NamedTempFile; @@ -26,6 +27,16 @@ pub fn generate_metadata(f: &NamedTempFile, mime_type: &str) -> Metadata { .map(|(width, height)| Metadata::Image { width: width as isize, height: height as isize, + thumbhash: ImageReader::open(f) + .and_then(|r| r.with_guessed_format()) + .map_err(ImageError::from) + .and_then(|r| r.decode()) + .map(|img| img.thumbnail(100, 100)) + .map(|img| (img.dimensions(), img.to_rgba8().into_raw())) + .map(|((width, height), rgba)| { + thumbhash::rgba_to_thumb_hash(width as usize, height as usize, &rgba) + }) + .ok(), animated: is_animated(f, mime_type).unwrap_or(false), }) .unwrap_or_default()