image: Add newly designed thumbnail for DnD

The old method stopped working with the new decoder setup.

The new design features a frame for contrast and rotates
images based on EXIF information.

Closes #89
This commit is contained in:
Sophie Herold 2023-03-07 20:48:09 +01:00 • committed by Christopher Davis
parent 88efb9e5fd
commit 05ef429b86
6 changed files with 87 additions and 122 deletions

View file

@ -70,6 +70,11 @@ const RUBBERBANDING_EXPONENT: f64 = 0.4;
/// Max zoom level 2000%
const MAX_ZOOM_LEVEL: f64 = 20.0;
/// Thumbnail size in application pixels
///
/// The thumbnail is currently used for drag and drop.
const THUMBNAIL_SIZE: f32 = 128.;
mod imp {
use super::*;
@ -488,7 +493,6 @@ mod imp {
let widget = self.obj();
let widget_width = widget.width() as f64;
let widget_height = widget.height() as f64;
let (original_width, original_height) = widget.original_dimensions();
let display_width = widget.image_displayed_width();
let display_height = widget.image_displayed_height();
@ -535,31 +539,8 @@ mod imp {
// Apply zoom
snapshot.scale(applicable_zoom as f32, applicable_zoom as f32);
// Put image origin at (0, 0) again with rotation
snapshot.translate(&graphene::Point::new(
-(original_width as f32 - display_width as f32 / applicable_zoom as f32) / 2.,
-(original_height as f32 - display_height as f32 / applicable_zoom as f32) / 2.,
));
// Undo centering in coordinates
snapshot.translate(&graphene::Point::new(
original_width as f32 / 2.,
original_height as f32 / 2.,
));
// Apply the transformations from properties
snapshot.rotate(widget.rotation() as f32);
if widget.mirrored() {
snapshot.scale(-1., 1.);
}
// Center image in coordinates.
// Needed for rotating around the center of the image, and
// mirroring the image does not put it to a completely different position.
snapshot.translate(&graphene::Point::new(
-original_width as f32 / 2.,
-original_height as f32 / 2.,
));
// Apply rotation and mirroring
widget.snapshot_rotate_mirror(snapshot, widget.rotation() as f32, widget.mirrored());
// Add texture(s)
self.tiles
@ -843,9 +824,32 @@ impl LpImage {
}
}
/// Texture that contains the original image
pub fn texture(&self) -> Option<gdk::Texture> {
None
/// Returns a thumbnail of the displated image
pub fn thumbnail(&self) -> Option<gdk::Paintable> {
let (width, height) = self.original_dimensions();
let long_side = i32::max(width, height);
let orientation = self.metadata().orientation();
let scale = f32::min(1., THUMBNAIL_SIZE / long_side as f32);
let render_options = tiling::RenderOptions {
scaling_filter: gsk::ScalingFilter::Trilinear,
};
let snapshot = gtk::Snapshot::new();
snapshot.scale(scale, scale);
self.snapshot_rotate_mirror(
&snapshot,
-orientation.rotation as f32,
orientation.mirrored,
);
self.imp()
.tiles
.load()
.add_to_snapshot(&snapshot, scale as f64, &render_options);
snapshot.to_paintable(None)
}
fn mirrored(&self) -> bool {
@ -1361,6 +1365,43 @@ impl LpImage {
self.width() as f64
}
/// Mirrors and rotates snapshot according to arguments
///
/// After the operation the image is positioned such that it's origin
/// is a `(0, 0)` again.
pub fn snapshot_rotate_mirror(&self, snapshot: &gtk::Snapshot, rotation: f32, mirrored: bool) {
let applicable_zoom = self.applicable_zoom();
let (original_width, original_height) = self.original_dimensions();
let display_width = self.image_displayed_width();
let display_height = self.image_displayed_height();
// Put image origin at (0, 0) again with rotation
snapshot.translate(&graphene::Point::new(
-(original_width as f32 - display_width as f32 / applicable_zoom as f32) / 2.,
-(original_height as f32 - display_height as f32 / applicable_zoom as f32) / 2.,
));
// Undo centering in coordinates
snapshot.translate(&graphene::Point::new(
original_width as f32 / 2.,
original_height as f32 / 2.,
));
// Apply the transformations from properties
snapshot.rotate(rotation);
if mirrored {
snapshot.scale(-1., 1.);
}
// Center image in coordinates.
// Needed for rotating around the center of the image, and
// mirroring the image does not put it to a completely different position.
snapshot.translate(&graphene::Point::new(
-original_width as f32 / 2.,
-original_height as f32 / 2.,
));
}
pub fn metadata(&self) -> LpImageMetadata {
self.imp().image_metadata.borrow().clone()
}