properties_view: Use physical size and resolution

Replace the API that got removed from glycin
This commit is contained in:
Sophie Herold 2026-07-09 22:40:39 +02:00
parent ffe42a7c6c
commit c7223f6f69
11 changed files with 254 additions and 101 deletions

106
Cargo.lock generated
View file

@ -946,8 +946,8 @@ dependencies = [
[[package]] [[package]]
name = "glycin" name = "glycin"
version = "4.0.0-alpha" version = "4.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"glycin-builtin", "glycin-builtin",
"glycin-external", "glycin-external",
@ -955,16 +955,16 @@ dependencies = [
[[package]] [[package]]
name = "glycin-builtin" name = "glycin-builtin"
version = "4.0.0-alpha" version = "4.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"glycin-core", "glycin-core",
] ]
[[package]] [[package]]
name = "glycin-common" name = "glycin-common"
version = "2.0.0-alpha" version = "2.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"bitflags 2.13.0", "bitflags 2.13.0",
"gufo-common", "gufo-common",
@ -981,8 +981,8 @@ dependencies = [
[[package]] [[package]]
name = "glycin-core" name = "glycin-core"
version = "4.0.0-alpha" version = "4.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"async-fs", "async-fs",
"async-global-executor", "async-global-executor",
@ -1002,8 +1002,9 @@ dependencies = [
"glycin-common", "glycin-common",
"glycin-image-rs", "glycin-image-rs",
"glycin-utils", "glycin-utils",
"gufo",
"gufo-common", "gufo-common",
"gufo-exif", "gufo-exif 0.5.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
"half", "half",
"libc", "libc",
"libseccomp", "libseccomp",
@ -1018,36 +1019,38 @@ dependencies = [
[[package]] [[package]]
name = "glycin-external" name = "glycin-external"
version = "4.0.0-alpha" version = "4.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"glycin-core", "glycin-core",
] ]
[[package]] [[package]]
name = "glycin-image-rs" name = "glycin-image-rs"
version = "2.2.0-alpha" version = "2.2.0-alpha.6"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"bytemuck",
"exr", "exr",
"glycin-utils", "glycin-utils",
"gufo", "gufo",
"gufo-common", "gufo-common",
"gufo-exif", "gufo-exif 0.5.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gufo-jpeg", "gufo-jpeg 0.5.0-alpha.2",
"hayro-jpeg2000", "hayro-jpeg2000",
"image", "image",
"image-extras", "image-extras",
"jpeg-encoder", "jpeg-encoder",
"log", "log",
"moxcms", "moxcms",
"tiff",
"zune-jpeg", "zune-jpeg",
] ]
[[package]] [[package]]
name = "glycin-utils" name = "glycin-utils"
version = "5.0.0-alpha" version = "5.0.0-alpha.1"
source = "git+https://gitlab.gnome.org/GNOME/glycin.git#2b0f1b1e217ce17ebe45aecdda7096ed4eea8343" source = "git+https://gitlab.gnome.org/GNOME/glycin.git?rev=32083724ee730fb6b35b6382fb8af7b6ab1f2992#32083724ee730fb6b35b6382fb8af7b6ab1f2992"
dependencies = [ dependencies = [
"async-lock", "async-lock",
"bitflags 2.13.0", "bitflags 2.13.0",
@ -1192,14 +1195,13 @@ dependencies = [
[[package]] [[package]]
name = "gufo" name = "gufo"
version = "0.5.0-alpha" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "d97d857a79df06e10cd669541ed0a42d471a45a5201ce99535baf99b18c4129a"
dependencies = [ dependencies = [
"chrono", "chrono",
"gufo-common", "gufo-common",
"gufo-exif", "gufo-exif 0.5.0-alpha.3 (git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581)",
"gufo-jpeg", "gufo-jpeg 0.5.0-alpha.3",
"gufo-png", "gufo-png",
"gufo-tiff", "gufo-tiff",
"gufo-webp", "gufo-webp",
@ -1210,9 +1212,8 @@ dependencies = [
[[package]] [[package]]
name = "gufo-common" name = "gufo-common"
version = "2.0.0-alpha" version = "2.0.0-alpha.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "970e26402b2750cf3fbbf49116dca9fc010c939013125623c94da632f1ba76e8"
dependencies = [ dependencies = [
"chrono", "chrono",
"paste", "paste",
@ -1223,9 +1224,22 @@ dependencies = [
[[package]] [[package]]
name = "gufo-exif" name = "gufo-exif"
version = "0.5.0-alpha.1" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1597401629a6778cbea663e6af6680fbcd07ab243cc8eee9bc5ef5d2c9e5eab8" checksum = "e68d453f54f396ca43664463e3fa93de6ece835e113dd63f694349d669382821"
dependencies = [
"gufo-common",
"indexmap",
"ouroboros",
"thiserror",
"tracing",
"zerocopy",
]
[[package]]
name = "gufo-exif"
version = "0.5.0-alpha.3"
source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
dependencies = [ dependencies = [
"chrono", "chrono",
"gufo-common", "gufo-common",
@ -1238,22 +1252,34 @@ dependencies = [
[[package]] [[package]]
name = "gufo-jpeg" name = "gufo-jpeg"
version = "0.5.0-alpha" version = "0.5.0-alpha.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "004fec8f321842386ba7decc6ee03dde7ed35f29c3586861a5c708cca1e4259b" checksum = "fa46d802b33586d3a1fd412b3fbb2b10ffbcde5aecbe5fddb4d61c827a001b9e"
dependencies = [ dependencies = [
"gufo-common", "gufo-common",
"indexmap", "indexmap",
"jpeg-encoder", "jpeg-encoder",
"thiserror", "thiserror",
"tracing", "tracing",
"zerocopy",
]
[[package]]
name = "gufo-jpeg"
version = "0.5.0-alpha.3"
source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
dependencies = [
"gufo-common",
"indexmap",
"thiserror",
"tracing",
"zerocopy",
] ]
[[package]] [[package]]
name = "gufo-png" name = "gufo-png"
version = "0.5.0-alpha" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "810e7750b869abb84c6162ad01a240f388a924d2d469ae30a0c2c11a28e81813"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"encoding_rs", "encoding_rs",
@ -1265,9 +1291,8 @@ dependencies = [
[[package]] [[package]]
name = "gufo-tiff" name = "gufo-tiff"
version = "0.5.0-alpha" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "0a937aa0a245c9602aa9ed4857b6fc8f184cc43cf91e18d982c74c698e20afd5"
dependencies = [ dependencies = [
"gufo-common", "gufo-common",
"thiserror", "thiserror",
@ -1275,9 +1300,8 @@ dependencies = [
[[package]] [[package]]
name = "gufo-webp" name = "gufo-webp"
version = "0.5.0-alpha" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "662c18ba5eef44d65c1694ebede033783ab5b48eb81366c1625deaaf75c47a18"
dependencies = [ dependencies = [
"gufo-common", "gufo-common",
"thiserror", "thiserror",
@ -1285,9 +1309,8 @@ dependencies = [
[[package]] [[package]]
name = "gufo-xmp" name = "gufo-xmp"
version = "0.5.0-alpha" version = "0.5.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/gufo-rs/gufo.git?rev=ac92bd426543bc33b36b6cbc8443455b6a882581#ac92bd426543bc33b36b6cbc8443455b6a882581"
checksum = "ea3cc4abbf29cddc6ffc1a4473eec79f11cf742bc113f9bd319ca1d7fcedfc39"
dependencies = [ dependencies = [
"chrono", "chrono",
"gufo-common", "gufo-common",
@ -1625,7 +1648,6 @@ dependencies = [
"glycin", "glycin",
"gtk4", "gtk4",
"gufo", "gufo",
"gufo-common",
"gvdb-macros", "gvdb-macros",
"indexmap", "indexmap",
"libadwaita", "libadwaita",

View file

@ -6,7 +6,9 @@ rust-version = "1.93"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
[patch.crates-io] [patch.crates-io]
glycin = { git = "https://gitlab.gnome.org/GNOME/glycin.git" } glycin = { git = "https://gitlab.gnome.org/GNOME/glycin.git", rev = "32083724ee730fb6b35b6382fb8af7b6ab1f2992" }
gufo = { git = "https://github.com/gufo-rs/gufo.git", rev = "ac92bd426543bc33b36b6cbc8443455b6a882581" }
gufo-common = { git = "https://github.com/gufo-rs/gufo.git", rev = "ac92bd426543bc33b36b6cbc8443455b6a882581" }
[profile.release] [profile.release]
lto = true lto = true
@ -36,8 +38,7 @@ gtk = { package = "gtk4", version = "0.11.0", features = [
"v4_14", "v4_14",
"xml_validation", "xml_validation",
] } ] }
gufo = { version = "0.5.0-alpha", features = ["chrono"] } gufo = { version = "0.5.0-alpha.2", features = ["chrono"] }
gufo-common = { version = "2.0.0-alpha", features = ["serde"] }
gvdb-macros = "0.1.6" gvdb-macros = "0.1.6"
indexmap = "2.0.0" indexmap = "2.0.0"
libc = "0.2.158" libc = "0.2.158"

View file

@ -17,7 +17,7 @@
use glycin::{Operation, Operations}; use glycin::{Operation, Operations};
use gtk::prelude::*; use gtk::prelude::*;
use gufo_common::orientation::Rotation; use gufo::common::orientation::Rotation;
use crate::deps::*; use crate::deps::*;
@ -145,7 +145,7 @@ impl OperationsSnapshot {
fn rotate( fn rotate(
&mut self, &mut self,
rotation: gufo_common::orientation::Rotation, rotation: gufo::common::orientation::Rotation,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
let snapshot = gtk::Snapshot::new(); let snapshot = gtk::Snapshot::new();

View file

@ -30,6 +30,7 @@ use glib::TimeZone;
use glycin::{Frame, FrameDetails, ImageDetails, MemoryFormat}; use glycin::{Frame, FrameDetails, ImageDetails, MemoryFormat};
use gufo::common::datetime::DateTime; use gufo::common::datetime::DateTime;
use gufo::common::orientation::Orientation; use gufo::common::orientation::Orientation;
use gufo::common::physical_dimension;
use crate::deps::*; use crate::deps::*;
use crate::util; use crate::util;
@ -169,16 +170,6 @@ impl Metadata {
} }
} }
pub fn dimensions_inch(&self) -> Option<(f64, f64)> {
self.image_info.as_ref().and_then(|x| x.dimensions_inch())
}
pub fn dimensions_text(&self) -> Option<String> {
self.image_info
.as_ref()
.and_then(|x| x.info_dimensions_text().map(|x| x.to_string()))
}
pub fn file_name(&self) -> Option<String> { pub fn file_name(&self) -> Option<String> {
self.file_info.as_ref().map(|x| x.display_name.to_string()) self.file_info.as_ref().map(|x| x.display_name.to_string())
} }
@ -436,4 +427,12 @@ impl Metadata {
None None
} }
} }
pub fn pixel_density(&self) -> Option<physical_dimension::PixelDensity> {
self.frame_info.as_ref().and_then(|x| x.pixel_density())
}
pub fn physical_size(&self) -> Option<physical_dimension::PhysicalSize> {
self.frame_info.as_ref().and_then(|x| x.physical_size())
}
} }

View file

@ -267,3 +267,30 @@ pub enum ErrorType {
Loader, Loader,
General, General,
} }
pub fn locale_uses_inch() -> bool {
// Use inch for USA and Liberia
if let Some(unit_locale) = getlocale(gettextrs::LocaleCategory::LcMeasurement)
&& let Some(locale) = unit_locale
.split(|x| *x == b'_')
.nth(1)
.and_then(|x| x.get(0..2))
&& (locale == b"US" || locale == b"LR")
{
dbg!(true)
} else {
false
}
}
// TODO: Upstream to gettext if possible
fn getlocale(category: gettextrs::LocaleCategory) -> Option<Vec<u8>> {
unsafe {
let ret = gettext_sys::setlocale(category as i32, std::ptr::null());
if ret.is_null() {
None
} else {
Some(std::ffi::CStr::from_ptr(ret).to_bytes().to_owned())
}
}
}

View file

@ -254,14 +254,14 @@ mod imp {
fn apply_rotate_cw(&self) { fn apply_rotate_cw(&self) {
self.apply_crop(); self.apply_crop();
self.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_270)); self.add_operation(Operation::Rotate(gufo::common::orientation::Rotation::_270));
self.reset_selection(); self.reset_selection();
} }
fn apply_rotate_ccw(&self) { fn apply_rotate_ccw(&self) {
self.apply_crop(); self.apply_crop();
self.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_90)); self.add_operation(Operation::Rotate(gufo::common::orientation::Rotation::_90));
self.reset_selection(); self.reset_selection();
} }

View file

@ -53,7 +53,7 @@ use adw::prelude::*;
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::subclass::Signal; use glib::subclass::Signal;
use glib::{Properties, SignalGroup}; use glib::{Properties, SignalGroup};
use gufo_common::orientation::Orientation; use gufo::common::orientation::Orientation;
use crate::decoder::tiling::SharedFrameBuffer; use crate::decoder::tiling::SharedFrameBuffer;
use crate::decoder::{self, Decoder, DecoderUpdate, tiling}; use crate::decoder::{self, Decoder, DecoderUpdate, tiling};

View file

@ -104,8 +104,8 @@ impl LpImage {
zoom_animation.play(); zoom_animation.play();
} }
if let Ok(r) = gufo_common::orientation::Rotation::try_from(angle) if let Ok(r) = gufo::common::orientation::Rotation::try_from(angle)
&& r != gufo_common::orientation::Rotation::_0 && r != gufo::common::orientation::Rotation::_0
{ {
tracing::debug!("Editing image to rotate by {r:?}"); tracing::debug!("Editing image to rotate by {r:?}");
let operation = glycin::Operation::Rotate(r); let operation = glycin::Operation::Rotate(r);

View file

@ -201,6 +201,8 @@ impl Unit {
} }
mod imp { mod imp {
use crate::util;
use super::*; use super::*;
#[derive(Debug, Default, CompositeTemplate, Properties)] #[derive(Debug, Default, CompositeTemplate, Properties)]
@ -388,13 +390,7 @@ mod imp {
.set_value(size_unit.round(obj.original_size().0 * obj.width_unit_factor())); .set_value(size_unit.round(obj.original_size().0 * obj.width_unit_factor()));
// Default to inch for USA and Liberia // Default to inch for USA and Liberia
if let Some(unit_locale) = getlocale(gettextrs::LocaleCategory::LcMeasurement) if util::locale_uses_inch() {
&& let Some(locale) = unit_locale
.split(|x| *x == b'_')
.nth(1)
.and_then(|x| x.get(0..2))
&& (locale == b"US" || locale == b"LR")
{
imp.margin_unit.set_selected(Unit::Inch as u32); imp.margin_unit.set_selected(Unit::Inch as u32);
imp.size_unit.set_selected(Unit::Inch as u32); imp.size_unit.set_selected(Unit::Inch as u32);
} }
@ -525,13 +521,22 @@ impl LpPrint {
pub fn original_size(&self) -> (f64, f64) { pub fn original_size(&self) -> (f64, f64) {
let image = self.image(); let image = self.image();
let (x_pixels, y_pixels) = image.image_size();
let metadata = image.metadata(); let metadata = image.metadata();
if let Some((w, h)) = metadata.dimensions_inch() {
if let Some(physical_size) = metadata.physical_size().map(|x| x.dpi()).or_else(|| {
metadata
.pixel_density()
.map(|x| x.physical_size(x_pixels as u32, y_pixels as u32))
}) {
let dpi = self.dpi(); let dpi = self.dpi();
((w * dpi).round(), (h * dpi).round()) (
(physical_size.x.value() * dpi).round(),
(physical_size.y.value() * dpi).round(),
)
} else { } else {
let (w, h) = self.image().image_size(); let (w, h) = image.image_size();
(w as f64, h as f64) (w as f64, h as f64)
} }
@ -968,15 +973,3 @@ impl LpPrint {
Ok(()) Ok(())
} }
} }
// TODO: Upstream to gettext if possible
pub fn getlocale(category: gettextrs::LocaleCategory) -> Option<Vec<u8>> {
unsafe {
let ret = gettext_sys::setlocale(category as i32, std::ptr::null());
if ret.is_null() {
None
} else {
Some(std::ffi::CStr::from_ptr(ret).to_bytes().to_owned())
}
}
}

View file

@ -34,6 +34,8 @@ use crate::widgets::image::LpImage;
const FALLBACK: &str = "–"; const FALLBACK: &str = "–";
mod imp { mod imp {
use gufo::common::physical_dimension::PhysicalDimensionUnit;
use super::*; use super::*;
#[derive(Debug, Default, CompositeTemplate, Properties)] #[derive(Debug, Default, CompositeTemplate, Properties)]
@ -54,6 +56,10 @@ mod imp {
#[template_child] #[template_child]
image_size: TemplateChild<adw::ActionRow>, image_size: TemplateChild<adw::ActionRow>,
#[template_child] #[template_child]
physical_size: TemplateChild<adw::ActionRow>,
#[template_child]
pixel_density: TemplateChild<adw::ActionRow>,
#[template_child]
image_format: TemplateChild<adw::ActionRow>, image_format: TemplateChild<adw::ActionRow>,
#[template_child] #[template_child]
file_size: TemplateChild<adw::ActionRow>, file_size: TemplateChild<adw::ActionRow>,
@ -219,6 +225,8 @@ mod imp {
// Image info // Image info
Self::update_row(&self.image_size, self.image_size()); Self::update_row(&self.image_size, self.image_size());
Self::update_row(&self.physical_size, self.physical_size());
Self::update_row(&self.pixel_density, self.pixel_density());
Self::update_row(&self.image_format, self.format_name()); Self::update_row(&self.image_format, self.format_name());
Self::update_row(&self.file_size, metadata.file_size()); Self::update_row(&self.file_size, metadata.file_size());
@ -289,30 +297,113 @@ mod imp {
fn image_size(&self) -> Option<String> { fn image_size(&self) -> Option<String> {
let obj = self.obj(); let obj = self.obj();
let image = obj.image()?;
let physical_size = image.metadata().physical_size();
if let Some(image) = obj.image() { if physical_size.is_none() {
match image.metadata().dimensions_text() { let (width, height) = image.image_size();
Some(string) => Some(string.to_string()), if width > 0 && height > 0 {
_ => { Some(
let (width, height) = image.image_size(); // Translators: Image "<width> x <height>"
if width > 0 && height > 0 { gettext_f(
Some( r"{}\u{202F}\u{D7}\u{202F}{}",
// Translators: Image "<width> x <height>" [width.to_string(), height.to_string()],
gettext_f( ),
r"{}\u{202F}\u{D7}\u{202F}{}", )
[width.to_string(), height.to_string()], } else {
), None
)
} else {
None
}
}
} }
} else { } else {
None None
} }
} }
fn physical_size(&self) -> Option<String> {
let obj = self.obj();
let image = obj.image()?;
let (width, height) = image.image_size();
let metadata = image.metadata();
let default_unit = if util::locale_uses_inch() {
PhysicalDimensionUnit::Inch
} else {
PhysicalDimensionUnit::Centimeter
};
let physical_size = metadata.physical_size().or_else(|| {
metadata.pixel_density().map(|x| {
x.physical_size(width as u32, height as u32)
.convert(default_unit)
})
})?;
const ROUND: f64 = 100.;
let x = (physical_size.x.value() * ROUND).round() / ROUND;
let y = (physical_size.y.value() * ROUND).round() / ROUND;
let unit = |x| {
match x {
PhysicalDimensionUnit::Centimeter => {
// Translators: Shorthand for centimeter
gettext("\u{202F}cm")
}
PhysicalDimensionUnit::Inch => {
// Translators: Shorthand for inch
gettext("\u{2033}")
}
PhysicalDimensionUnit::Meter => {
// Translators: Shorthand for meter
gettext("\u{202F}m")
}
PhysicalDimensionUnit::Millimeter => {
// Translators: Shorthand for millimeter
gettext("\u{202F}mm")
}
PhysicalDimensionUnit::Pica => {
// Translators: Shorthand for pica (unit)
gettext("\u{202F}pc")
}
PhysicalDimensionUnit::Point => {
// Translators: Shorthand for pica (unit)
gettext("\u{202F}pt")
}
x => x.shorthand().to_string(),
}
};
let x_unit = unit(physical_size.x.unit());
let y_unit = unit(physical_size.y.unit());
Some(
// Translators: Image "<width> x <height>"
gettext_f(
r"{}{}\u{202F}\u{D7}\u{202F}{}{}",
[x.to_string(), x_unit, y.to_string(), y_unit],
),
)
}
fn pixel_density(&self) -> Option<String> {
let obj = self.obj();
let image = obj.image()?;
let metadata = image.metadata();
let pixel_density = metadata.pixel_density()?.dpi();
const ROUND: f64 = 10.;
let x = (pixel_density.x().value() * ROUND).round() / ROUND;
let y = (pixel_density.y().value() * ROUND).round() / ROUND;
Some(if x == y {
gettext_f(r"{}\u{202F}DPI", [x.to_string()])
} else {
// Translators: Image "<x-resolution> x <y-resolution>"
gettext_f(
r"{}\u{202F}DPI\u{202F}\u{D7}\u{202F}{}\u{202F}DPI",
[x.to_string(), y.to_string()],
)
})
}
fn file(&self) -> Option<gio::File> { fn file(&self) -> Option<gio::File> {
self.image.borrow().as_ref().and_then(|x| x.file()) self.image.borrow().as_ref().and_then(|x| x.file())
} }

View file

@ -61,6 +61,26 @@
</style> </style>
</object> </object>
</child> </child>
<child>
<object class="AdwActionRow" id="physical_size">
<property name="title" translatable="yes">Physical Size</property>
<property name="subtitle-selectable">True</property>
<property name="use-markup">False</property>
<style>
<class name="property" />
</style>
</object>
</child>
<child>
<object class="AdwActionRow" id="pixel_density">
<property name="title" translatable="yes">Resolution</property>
<property name="subtitle-selectable">True</property>
<property name="use-markup">False</property>
<style>
<class name="property" />
</style>
</object>
</child>
<child> <child>
<object class="AdwActionRow" id="image_format"> <object class="AdwActionRow" id="image_format">
<property name="title" translatable="yes">Image Format</property> <property name="title" translatable="yes">Image Format</property>