diff --git a/src/components/avatar/editable.rs b/src/components/avatar/editable.rs index de48a6e5..e5241e93 100644 --- a/src/components/avatar/editable.rs +++ b/src/components/avatar/editable.rs @@ -14,7 +14,10 @@ use super::{AvatarData, AvatarImage}; use crate::{ components::{ActionButton, ActionState}, toast, - utils::{expression, media::image::load_image}, + utils::{ + expression, + media::image::{load_image, ImageDimensions}, + }, }; /// The state of the editable avatar. @@ -73,6 +76,8 @@ mod imp { #[template_child] pub stack: TemplateChild, #[template_child] + pub temp_avatar: TemplateChild, + #[template_child] pub button_remove: TemplateChild, #[template_child] pub button_edit: TemplateChild, @@ -332,8 +337,20 @@ impl EditableAvatar { self.imp().remove_sensitive.set(sensitive); } + /// The dimensions of the avatar in this widget. + fn avatar_dimensions(&self) -> ImageDimensions { + let scale_factor = self.scale_factor(); + let avatar_size = self.imp().temp_avatar.size(); + let size = (avatar_size * scale_factor) as u32; + + ImageDimensions { + width: size, + height: size, + } + } + async fn set_temp_image_from_file(&self, file: gio::File) { - let paintable = load_image(file).await.ok(); + let paintable = load_image(file, Some(self.avatar_dimensions())).await.ok(); self.set_temp_image(paintable); } diff --git a/src/components/avatar/editable.ui b/src/components/avatar/editable.ui index d5fd21b9..1566fdaa 100644 --- a/src/components/avatar/editable.ui +++ b/src/components/avatar/editable.ui @@ -23,7 +23,7 @@ temp - + 128 true diff --git a/src/components/avatar/image.rs b/src/components/avatar/image.rs index 4bca17eb..dfb15d60 100644 --- a/src/components/avatar/image.rs +++ b/src/components/avatar/image.rs @@ -199,7 +199,12 @@ impl AvatarImage { async fn load_inner(&self, uri: OwnedMxcUri) { let client = self.session().client(); let info = self.info(); + let needed_size = self.needed_size(); + let dimensions = ImageDimensions { + width: needed_size, + height: needed_size, + }; let downloader = ThumbnailDownloader { main: ImageSource { @@ -210,10 +215,7 @@ impl AvatarImage { alt: None, }; let settings = ThumbnailSettings { - dimensions: ImageDimensions { - width: needed_size, - height: needed_size, - }, + dimensions, method: Method::Crop, animated: true, prefer_thumbnail: true, @@ -221,7 +223,7 @@ impl AvatarImage { match downloader.download_to_file(&client, settings).await { Ok(file) => { - let paintable = load_image(file).await.ok(); + let paintable = load_image(file, Some(dimensions)).await.ok(); self.imp().set_paintable(paintable); } Err(error) => error!("Could not fetch avatar: {error}"), diff --git a/src/components/media/content_viewer.rs b/src/components/media/content_viewer.rs index ca740d42..105663d0 100644 --- a/src/components/media/content_viewer.rs +++ b/src/components/media/content_viewer.rs @@ -197,7 +197,7 @@ impl MediaContentViewer { .unwrap_or_default(); match content_type { - ContentType::Image => match load_image(file).await { + ContentType::Image => match load_image(file, None).await { Ok(texture) => { self.view_image(&texture); return; diff --git a/src/session/view/content/room_details/history_viewer/visual_media_item.rs b/src/session/view/content/room_details/history_viewer/visual_media_item.rs index 0a668217..5aaab794 100644 --- a/src/session/view/content/room_details/history_viewer/visual_media_item.rs +++ b/src/session/view/content/room_details/history_viewer/visual_media_item.rs @@ -162,12 +162,13 @@ mod imp { let scale_factor = self.obj().scale_factor(); let size = (THUMBNAIL_SIZE * scale_factor) as u32; + let dimensions = ImageDimensions { + width: size, + height: size, + }; let settings = ThumbnailSettings { - dimensions: ImageDimensions { - width: size, - height: size, - }, + dimensions, method: Method::Scale, animated: false, prefer_thumbnail: false, @@ -182,7 +183,7 @@ mod imp { } }; - match load_image(file).await { + match load_image(file, Some(dimensions)).await { Ok(paintable) => { self.picture.set_paintable(Some(&paintable)); } diff --git a/src/session/view/content/room_history/message_row/visual_media.rs b/src/session/view/content/room_history/message_row/visual_media.rs index 4a91a324..d1d77e48 100644 --- a/src/session/view/content/room_history/message_row/visual_media.rs +++ b/src/session/view/content/room_history/message_row/visual_media.rs @@ -334,7 +334,7 @@ impl MessageVisualMedia { } }; - match load_image(file).await { + match load_image(file, None).await { Ok(paintable) => { let child = if let Some(child) = imp.media.child().and_downcast::() { diff --git a/src/utils/media/image.rs b/src/utils/media/image.rs index 77d93fca..82a9b61a 100644 --- a/src/utils/media/image.rs +++ b/src/utils/media/image.rs @@ -73,11 +73,32 @@ async fn image_reader(file: gio::File) -> Result, glycin: } /// Load the given file as an image into a `GdkPaintable`. -pub async fn load_image(file: gio::File) -> Result { +/// +/// Set `request_dimensions` if the image will be shown at specific dimensions. +/// To show the image at its natural size, set it to `None`. +pub async fn load_image( + file: gio::File, + request_dimensions: Option, +) -> Result { let image = image_reader(file).await?; + let frame_request = request_dimensions.map(|request| { + let image_info = image.info(); + + let original_dimensions = ImageDimensions { + width: image_info.width, + height: image_info.height, + }; + + original_dimensions.to_image_loader_request(request) + }); + let (image, first_frame) = spawn_tokio!(async move { - let first_frame = image.next_frame().await?; + let first_frame = if let Some(frame_request) = frame_request { + image.specific_frame(frame_request).await? + } else { + image.next_frame().await? + }; Ok((image, first_frame)) }) .await @@ -374,6 +395,16 @@ impl ImageDimensions { Some(self.resize(thumbnail_dimensions, ResizeStrategy::Contain)) } + + /// Convert these dimensions to a request for the image loader with the + /// requested dimensions. + pub fn to_image_loader_request( + self, + requested_dimensions: ImageDimensions, + ) -> glycin::FrameRequest { + let resized_dimensions = self.resize(requested_dimensions, ResizeStrategy::Cover); + glycin::FrameRequest::new().scale(resized_dimensions.width, resized_dimensions.height) + } } impl From for BaseImageInfo {