editing: Fix preroateted images
Editing does not work correctly if PNGs or JPEGs are already rotated via an Exif orientation entry before editing. This needs the glycin-image-rs 1.2.1 loader to work correctly. Closes #481
This commit is contained in:
parent
a49096ffde
commit
ef5f94859b
10 changed files with 74 additions and 40 deletions
|
|
@ -25,12 +25,20 @@ pub fn apply_operations(
|
|||
node: gsk::RenderNode,
|
||||
width: u32,
|
||||
height: u32,
|
||||
operations: &Operations,
|
||||
operations: Option<&Operations>,
|
||||
snapshot: >k::Snapshot,
|
||||
scale: f64,
|
||||
initial_operations: &Operations,
|
||||
) -> Result<(u32, u32), EditingError> {
|
||||
let os = OperationsSnapshot::new(node, width, height, scale as f32);
|
||||
os.apply(operations, snapshot)
|
||||
let mut os = OperationsSnapshot::new(node, width, height, scale as f32);
|
||||
|
||||
os.apply(initial_operations)?;
|
||||
|
||||
if let Some(operations) = operations {
|
||||
os.apply_and_commit(operations, snapshot)
|
||||
} else {
|
||||
os.apply_and_commit(&Operations::new(Vec::new()), snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
struct OperationsSnapshot {
|
||||
|
|
@ -50,11 +58,19 @@ impl OperationsSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply(
|
||||
fn apply_and_commit(
|
||||
mut self,
|
||||
operations: &Operations,
|
||||
snapshot: >k::Snapshot,
|
||||
) -> Result<(u32, u32), EditingError> {
|
||||
self.apply(operations)?;
|
||||
|
||||
snapshot.append_node(self.current_node);
|
||||
|
||||
Ok((self.width, self.height))
|
||||
}
|
||||
|
||||
fn apply(&mut self, operations: &Operations) -> Result<(), EditingError> {
|
||||
for operation in operations.operations() {
|
||||
let operation_result = match operation {
|
||||
Operation::Clip(rect) => self.clip(*rect),
|
||||
|
|
@ -77,9 +93,7 @@ impl OperationsSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
snapshot.append_node(self.current_node);
|
||||
|
||||
Ok((self.width, self.height))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clip(&mut self, (x, y, width, height): (u32, u32, u32, u32)) -> Result<(), OperationError> {
|
||||
|
|
@ -138,7 +152,11 @@ impl OperationsSnapshot {
|
|||
let x_center = self.width as f32 * self.scale / 2.;
|
||||
let y_center = self.height as f32 * self.scale / 2.;
|
||||
|
||||
snapshot.translate(&graphene::Point::new(y_center, x_center));
|
||||
if rotation == Rotation::_90 || rotation == Rotation::_270 {
|
||||
snapshot.translate(&graphene::Point::new(y_center, x_center));
|
||||
} else {
|
||||
snapshot.translate(&graphene::Point::new(x_center, y_center));
|
||||
}
|
||||
snapshot.rotate(-(rotation.degrees() as f32));
|
||||
snapshot.translate(&graphene::Point::new(-x_center, -y_center));
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@
|
|||
//! Shows an resizable cropping selection
|
||||
|
||||
use std::cell::OnceCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use adw::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::{glib, gtk};
|
||||
use glycin::Operation;
|
||||
use glycin::{Operation, Operations};
|
||||
|
||||
use crate::deps::*;
|
||||
use crate::editing::preview::EditingError;
|
||||
|
|
@ -269,7 +270,9 @@ mod imp {
|
|||
fn apply_reset(&self) -> Result<(), EditingError> {
|
||||
let obj = self.obj();
|
||||
|
||||
self.image.set_operations(None)?;
|
||||
self.image
|
||||
.set_operations(Some(Arc::new(Operations::new(Vec::new()))))?;
|
||||
|
||||
obj.edit_window().set_operations(None);
|
||||
self.reset_selection();
|
||||
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ mod imp {
|
|||
|
||||
if let Some(operations) = obj.operations() {
|
||||
log::debug!("Computing edited image.");
|
||||
let result = editor.apply_complete(&operations).await;
|
||||
let result = editor.apply_complete(dbg!(&operations)).await;
|
||||
match result {
|
||||
Err(err) if matches!(err.error(), glycin::Error::Canceled(_)) => {
|
||||
log::debug!("Computing edited image canceled");
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ use adw::prelude::*;
|
|||
use adw::subclass::prelude::*;
|
||||
use glib::subclass::Signal;
|
||||
use glib::{Properties, SignalGroup};
|
||||
use gufo_common::orientation::Orientation;
|
||||
|
||||
use crate::decoder::{self, tiling, Decoder, DecoderUpdate};
|
||||
use crate::deps::*;
|
||||
|
|
@ -225,6 +226,7 @@ mod imp {
|
|||
|
||||
/// Currently EXIF data
|
||||
pub(super) metadata: RefCell<Metadata>,
|
||||
pub(super) original_orientation: Cell<Option<Orientation>>,
|
||||
|
||||
#[property(get=Self::image_size_available)]
|
||||
_image_size_available: bool,
|
||||
|
|
@ -393,5 +395,8 @@ impl LpImage {
|
|||
*imp.file.borrow_mut() = original_imp.file.borrow().clone();
|
||||
imp.frame_buffer
|
||||
.swap(Arc::new((*(original_imp.frame_buffer).load_full()).clone()));
|
||||
|
||||
imp.original_orientation
|
||||
.set(Some(original_imp.metadata.borrow().orientation()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2024 Sophie Herold
|
||||
// Copyright (c) 2024-2025 Sophie Herold
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use glycin::Operations;
|
||||
use tiling::RenderOptions;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -26,19 +27,25 @@ impl imp::LpImage {
|
|||
node: gsk::RenderNode,
|
||||
snapshot: >k::Snapshot,
|
||||
) -> Result<(), crate::editing::preview::EditingError> {
|
||||
if let Some(operations) = self.operations.borrow().as_ref() {
|
||||
let (width, height) = self.original_dimensions();
|
||||
let new_dimensions = crate::editing::preview::apply_operations(
|
||||
node,
|
||||
width as u32,
|
||||
height as u32,
|
||||
operations,
|
||||
snapshot,
|
||||
self.applicable_zoom(),
|
||||
)?;
|
||||
let (width, height) = self.original_dimensions();
|
||||
|
||||
self.overwrite_dimensions.set(Some(new_dimensions));
|
||||
}
|
||||
let initial_operations = if let Some(orientation) = self.original_orientation.get() {
|
||||
Operations::new_orientation(orientation)
|
||||
} else {
|
||||
Operations::new(Vec::new())
|
||||
};
|
||||
|
||||
let new_dimensions = crate::editing::preview::apply_operations(
|
||||
node,
|
||||
width as u32,
|
||||
height as u32,
|
||||
self.operations.borrow().as_ref().map(|x| x.as_ref()),
|
||||
snapshot,
|
||||
self.applicable_zoom(),
|
||||
&initial_operations,
|
||||
)?;
|
||||
|
||||
self.overwrite_dimensions.set(Some(new_dimensions));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,14 +114,6 @@ impl WidgetImpl for imp::LpImage {
|
|||
let y = obj.image_rendering_y();
|
||||
snapshot.translate(&graphene::Point::new(x as f32, y as f32));
|
||||
|
||||
// Apply rotation and mirroring
|
||||
self.snapshot_rotate_mirror(
|
||||
snapshot,
|
||||
obj.rotation() as f32,
|
||||
obj.mirrored(),
|
||||
applicable_zoom,
|
||||
);
|
||||
|
||||
// Add texture(s)
|
||||
|
||||
// Don't use current frame buffer if it empty during an image reload
|
||||
|
|
@ -138,6 +130,14 @@ impl WidgetImpl for imp::LpImage {
|
|||
log::error!("Render node is empty");
|
||||
}
|
||||
} else {
|
||||
// Apply rotation and mirroring
|
||||
self.snapshot_rotate_mirror(
|
||||
snapshot,
|
||||
obj.rotation() as f32,
|
||||
obj.mirrored(),
|
||||
applicable_zoom,
|
||||
);
|
||||
|
||||
frame_buffer.add_to_snapshot(snapshot, applicable_zoom, &render_options);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue