editing: Decide editable based on true mime type

Previously it was decided on the early unreliable mime type.

Fixes #449
This commit is contained in:
Sophie Herold 2025-02-19 11:46:32 +01:00
parent e3a58270b1
commit 1d40a28b54
4 changed files with 31 additions and 12 deletions

View file

@ -0,0 +1 @@
Decide if an image has a format that supports editing based on the reliable mime-type. That way a wrong file extension will not impact the detection of the format being editable.

View file

@ -105,17 +105,28 @@ impl Metadata {
} }
pub fn mime_type(&self) -> Option<String> { pub fn mime_type(&self) -> Option<String> {
self.file_info self.mime_type.clone()
.as_ref() }
.and_then(|x| x.mime_type.as_ref())
.map(|x| x.to_string()) /// Unreliable mime type
///
/// Before the image is successfully loaded, this mime type might be wrong
/// since it is not yet based on the more complex mime type detection used
/// by glyin.
pub fn unreliable_mime_type(&self) -> Option<String> {
self.mime_type().or_else(|| {
self.file_info
.as_ref()
.and_then(|x| x.mime_type.as_ref())
.map(|x| x.to_string())
})
} }
pub fn format_name(&self) -> Option<String> { pub fn format_name(&self) -> Option<String> {
self.image_info self.image_info
.as_ref() .as_ref()
.and_then(|x| x.format_name.clone()) .and_then(|x| x.format_name.clone())
.or_else(|| self.mime_type()) .or_else(|| self.unreliable_mime_type())
} }
pub fn alpha_channel(&self) -> Option<bool> { pub fn alpha_channel(&self) -> Option<bool> {

View file

@ -34,14 +34,14 @@ impl imp::LpImage {
/// Set filename after filename changed /// Set filename after filename changed
async fn set_file_changed(&self, file: &gio::File) { async fn set_file_changed(&self, file: &gio::File) {
let obj = self.obj(); let obj = self.obj();
let prev_mime_type = obj.metadata().mime_type(); let prev_mime_type = obj.metadata().unreliable_mime_type();
self.file.replace(Some(file.clone())); self.file.replace(Some(file.clone()));
self.reload_file_info().await; self.reload_file_info().await;
// Reload if mime type changed since other decoding path might be responsible // Reload if mime type changed since other decoding path might be responsible
// now // now
if obj.metadata().mime_type() != prev_mime_type { if obj.metadata().unreliable_mime_type() != prev_mime_type {
obj.load(file).await; obj.load(file).await;
return; return;
} }
@ -80,6 +80,11 @@ impl imp::LpImage {
self.emmit_metadata_changed(); self.emmit_metadata_changed();
obj.reset_rotation(); obj.reset_rotation();
glib::spawn_future_local(glib::clone!(
#[weak(rename_to=obj)]
self,
async move { obj.check_editable().await },
));
} }
DecoderUpdate::Dimensions => { DecoderUpdate::Dimensions => {
log::debug!("Received dimensions: {:?}", self.untransformed_dimensions()); log::debug!("Received dimensions: {:?}", self.untransformed_dimensions());
@ -360,8 +365,12 @@ impl LpImage {
// Reset background color for reloads // Reset background color for reloads
imp.set_background_color(None); imp.set_background_color(None);
let (decoder, decoder_update) = let (decoder, decoder_update) = Decoder::new(
Decoder::new(file.clone(), self.metadata().mime_type(), tiles.clone()).await; file.clone(),
self.metadata().unreliable_mime_type(),
tiles.clone(),
)
.await;
let weak_obj = self.downgrade(); let weak_obj = self.downgrade();
glib::spawn_future_local(async move { glib::spawn_future_local(async move {
@ -374,7 +383,5 @@ impl LpImage {
}); });
imp.decoder.replace(Some(Arc::new(decoder))); imp.decoder.replace(Some(Arc::new(decoder)));
imp.check_editable().await;
} }
} }

View file

@ -231,7 +231,7 @@ impl LpImagePage {
imp.stack.set_visible_child(&*imp.error_page); imp.stack.set_visible_child(&*imp.error_page);
imp.error_more_info.set_visible(false); imp.error_more_info.set_visible(false);
} else if image.specific_error() == DecoderError::UnsupportedFormat { } else if image.specific_error() == DecoderError::UnsupportedFormat {
let mime_type = image.metadata().mime_type().unwrap_or_default(); let mime_type = image.metadata().unreliable_mime_type().unwrap_or_default();
let content_type = gio::content_type_from_mime_type(&mime_type).unwrap_or_default(); let content_type = gio::content_type_from_mime_type(&mime_type).unwrap_or_default();
let description = gio::content_type_get_description(&content_type).to_string(); let description = gio::content_type_get_description(&content_type).to_string();