From 92bcf7c1ae5fa8f7b48ae82bc56b7a868435bd4f Mon Sep 17 00:00:00 2001 From: con3code Date: Tue, 20 Oct 2026 21:31:22 +0900 Subject: [PATCH] IDML: Q ruler units are Q, as InDesign writes them (#1360) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2 --- crates/idml/src/import.rs | 16 +++++++++++----- crates/idml/src/names.rs | 25 +++++++------------------ crates/idml/src/tests.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/crates/idml/src/import.rs b/crates/idml/src/import.rs index d770aef79..209706991 100644 --- a/crates/idml/src/import.rs +++ b/crates/idml/src/import.rs @@ -593,11 +593,17 @@ impl<'r> Importer<'r> { self.default_margins = Some((m, c)); } "ViewPreference" => { - if let Some(u) = e.get("HorizontalMeasurementUnits") { - self.settings.horizontal_units = names::unit_in(u); - } - if let Some(u) = e.get("VerticalMeasurementUnits") { - self.settings.vertical_units = names::unit_in(u); + for (attr, ruler) in [("HorizontalMeasurementUnits", "horizontal"), ("VerticalMeasurementUnits", "vertical")] { + let Some(u) = e.get(attr) else { continue }; + let unit = names::unit_in(u).unwrap_or_else(|| { + self.warnings.push(format!("{ruler} ruler units `{u}` are not available; read as points")); + designcraft_geom::Unit::Points + }); + if ruler == "horizontal" { + self.settings.horizontal_units = unit; + } else { + self.settings.vertical_units = unit; + } } if let Some(v) = e.num("CursorKeyIncrement") { self.settings.keyboard_increment = v; diff --git a/crates/idml/src/names.rs b/crates/idml/src/names.rs index 569244470..571ff0f64 100644 --- a/crates/idml/src/names.rs +++ b/crates/idml/src/names.rs @@ -634,6 +634,8 @@ pub fn number_style_in(s: &str) -> NumberStyle { } } +/// IDML `MeasurementUnits` of a unit. Q is `Q`; `U` is a different unit, which DesignCraft +/// doesn't have. pub fn unit_out(u: Unit) -> &'static str { match u { Unit::Points => "Points", @@ -645,27 +647,14 @@ pub fn unit_out(u: Unit) -> &'static str { Unit::Ciceros => "Ciceros", Unit::Agates => "Agates", Unit::Pixels => "Pixels", - Unit::Q => "U", + Unit::Q => "Q", Unit::Ha => "Ha", } } -pub fn unit_in(s: &str) -> Unit { - [ - Unit::Points, - Unit::Picas, - Unit::Inches, - Unit::InchesDecimal, - Unit::Millimeters, - Unit::Centimeters, - Unit::Ciceros, - Unit::Agates, - Unit::Pixels, - Unit::Q, - Unit::Ha, - ] - .into_iter() - .find(|u| unit_out(*u) == s) - .unwrap_or(Unit::Points) +/// The unit an IDML `MeasurementUnits` value names, if DesignCraft has it (not `U`, `Bai`, +/// `Mils`, `AmericanPoints` or `Custom`). +pub fn unit_in(s: &str) -> Option { + Unit::ALL.into_iter().find(|u| unit_out(*u) == s) } /// IDML layer colour enumeration names for our layer colour table. diff --git a/crates/idml/src/tests.rs b/crates/idml/src/tests.rs index 035333da4..a55857143 100644 --- a/crates/idml/src/tests.rs +++ b/crates/idml/src/tests.rs @@ -2773,6 +2773,38 @@ fn round_trips_the_zero_point_and_ruler_origin() { assert_eq!(fixture("NaN 4").settings.zero_point, [0.0, 0.0]); } +/// Q is `Q` in IDML, as InDesign writes it (`U` is another unit). Units DesignCraft lacks are +/// read as points, and the import report says so. +#[test] +fn ruler_units_in_q_and_ha_round_trip_and_unknown_units_are_reported() { + use designcraft_geom::Unit; + let mut d = Document::new(&NewDocument::default()); + for (h, v) in [(Unit::Q, Unit::Ha), (Unit::Ha, Unit::Q), (Unit::Millimeters, Unit::Points)] { + (d.settings.horizontal_units, d.settings.vertical_units) = (h, v); + let bytes = export_idml(&d); + let back = import_idml(&bytes).unwrap(); + assert_eq!((back.settings.horizontal_units, back.settings.vertical_units), (h, v)); + } + d.settings.horizontal_units = Unit::Q; + let prefs = zip_text(&export_idml(&d), "Resources/Preferences.xml"); + assert!(prefs.contains(r#"HorizontalMeasurementUnits="Q""#), "{prefs}"); + + let prefs = + PREFS.replace("