diff --git a/crates/io/src/svg_read.rs b/crates/io/src/svg_read.rs index 58d8dd11a..36f8c458a 100644 --- a/crates/io/src/svg_read.rs +++ b/crates/io/src/svg_read.rs @@ -620,8 +620,15 @@ fn viewport(e: &BytesStart) -> Result { _ => None, } }); - let w_mm = attr(e, b"width").as_deref().and_then(parse_length_mm); - let h_mm = attr(e, b"height").as_deref().and_then(parse_length_mm); + // A bare or `px` root size is in CSS pixels, not millimetres. + let root_mm = |name: &[u8]| { + let raw = attr(e, name)?; + let mm = parse_length_mm(&raw)?; + let unit = raw.trim().trim_start_matches(|c: char| c.is_ascii_digit() || matches!(c, '.' | '-' | '+' | 'e' | 'E')).trim(); + Some(if matches!(unit, "" | "px") { mm * 25.4 / 96.0 } else { mm }) + }; + let w_mm = root_mm(b"width"); + let h_mm = root_mm(b"height"); let unit = match (vb, w_mm, h_mm) { (Some((_, _, vw, _)), Some(w), _) if w > 0.0 => w / vw, (Some((_, _, _, vh)), _, Some(h)) if h > 0.0 => h / vh, diff --git a/crates/io/src/tests.rs b/crates/io/src/tests.rs index ffd524b99..47ceaf16f 100644 --- a/crates/io/src/tests.rs +++ b/crates/io/src/tests.rs @@ -2274,6 +2274,18 @@ fn svg_viewbox_scaling_and_mm_units() { assert!((c.center.x - 10.0).abs() < 1e-9 && (c.center.y - 5.0).abs() < 1e-9, "{c:?}"); } +#[test] +fn svg_viewbox_with_px_or_unitless_root_size_uses_reference_pixel() { + for w in ["800", "800px"] { + let svg = format!( + r#""# + ); + let d = read(svg.as_bytes(), "vb.svg").unwrap(); + let l = first(&d, |k| if let EntityKind::Line(l) = k { Some(l.clone()) } else { None }); + assert!((l.b.x - 800.0 * 25.4 / 96.0).abs() < 1e-9, "{w}: {l:?}"); + } +} + #[test] fn svg_inkscape_layers_are_kept() { let svg = format!(