diff --git a/src/blob.rs b/src/blob.rs index bbb5635c9..331dcc282 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -8,11 +8,14 @@ use async_std::prelude::*; use async_std::{fs, io}; use image::GenericImageView; +use num_traits::FromPrimitive; use thiserror::Error; -use crate::constants::AVATAR_SIZE; +use crate::config::Config; +use crate::constants::*; use crate::context::Context; use crate::events::Event; +use crate::message; /// Represents a file in the blob directory. /// @@ -377,6 +380,44 @@ impl<'a> BlobObject<'a> { Ok(()) } + + pub async fn recode_to_image_size(&self, context: &Context) -> Result<(), BlobError> { + let blob_abs = self.to_abs_path(); + if message::guess_msgtype_from_suffix(Path::new(&blob_abs)) + != Some((Viewtype::Image, "image/jpeg")) + { + return Ok(()); + } + + let img = image::open(&blob_abs).map_err(|err| BlobError::RecodeFailure { + blobdir: context.get_blobdir().to_path_buf(), + blobname: blob_abs.to_str().unwrap_or_default().to_string(), + cause: err, + })?; + + let img_wh = if MediaQuality::from_i32(context.get_config_int(Config::MediaQuality).await) + .unwrap_or_default() + == MediaQuality::Balanced + { + BALANCED_IMAGE_SIZE + } else { + WORSE_IMAGE_SIZE + }; + + if img.width() <= img_wh && img.height() <= img_wh { + return Ok(()); + } + + let img = img.thumbnail(img_wh, img_wh); + + img.save(&blob_abs).map_err(|err| BlobError::WriteFailure { + blobdir: context.get_blobdir().to_path_buf(), + blobname: blob_abs.to_str().unwrap_or_default().to_string(), + cause: err, + })?; + + Ok(()) + } } impl<'a> fmt::Display for BlobObject<'a> { diff --git a/src/chat.rs b/src/chat.rs index 60aa036f7..abc3fed4e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1332,6 +1332,12 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<(), Er .ok_or_else(|| { format_err!("Attachment missing for message of type #{}", msg.viewtype) })?; + + if msg.viewtype == Viewtype::Image { + if let Err(e) = blob.recode_to_image_size(context).await { + warn!(context, "Cannot recode image, using original data: {:?}", e); + } + } msg.param.set(Param::File, blob.as_name()); if msg.viewtype == Viewtype::File || msg.viewtype == Viewtype::Image { diff --git a/src/constants.rs b/src/constants.rs index dbdad54db..0e23e0ceb 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -227,6 +227,10 @@ pub const DC_BOB_SUCCESS: i32 = 1; // max. width/height of an avatar pub const AVATAR_SIZE: u32 = 192; +// max. width/height of images +pub const BALANCED_IMAGE_SIZE: u32 = 1280; +pub const WORSE_IMAGE_SIZE: u32 = 640; + // this value can be increased if the folder configuration is changed and must be redone on next program start pub const DC_FOLDERS_CONFIGURED_VERSION: i32 = 3;