Use shared SVG viewBox sizing for placed artwork

This commit is contained in:
Dylan M. Taylor committed 2026-11-13 05:00:48 -05:00
1 parent ed81afe60b
commit 2f863f8c16
4 files changed
+67 -60

No files matched your search

Generated
+63 -32
View File
@@ -1247,7 +1247,29 @@ name = "craft-image-codecs"
version = "0.1.0"
source = "git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895#2e670cf9377b523112f3fe4b409399772c745895"
dependencies = [
"craft-jpeg",
"craft-jpeg 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"exr",
"flate2",
"half",
"image",
"image-webp",
"jpeg-encoder",
"png",
"rayon",
"serde_json",
"thiserror 2.0.21",
"tiff",
"zune-core",
"zune-jpeg",
"zune-jpegxl",
]
[[package]]
name = "craft-image-codecs"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f#cc23ffd4d26f3074808e2187d332564817624f8f"
dependencies = [
"craft-jpeg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"exr",
"flate2",
"half",
@@ -1280,6 +1302,14 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "craft-jpeg"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f#cc23ffd4d26f3074808e2187d332564817624f8f"
dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "craft-keymap"
version = "0.1.0"
@@ -1433,21 +1463,6 @@ name = "craft-sheet"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=ba24fe2435adb3c81ad6057faf36365fbba736cf#ba24fe2435adb3c81ad6057faf36365fbba736cf"
[[package]]
name = "craft-svg"
version = "0.1.0"
source = "git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895#2e670cf9377b523112f3fe4b409399772c745895"
dependencies = [
"craft-image-codecs",
"craft-xml 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"flate2",
"kurbo",
"resvg 0.48.1",
"roxmltree 0.21.2",
"thiserror 2.0.21",
"usvg 0.48.1",
]
[[package]]
name = "craft-svg"
version = "0.1.0"
@@ -1473,6 +1488,21 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "craft-svg"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f#cc23ffd4d26f3074808e2187d332564817624f8f"
dependencies = [
"craft-image-codecs 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"flate2",
"kurbo",
"resvg 0.48.1",
"roxmltree 0.21.2",
"thiserror 2.0.21",
"usvg 0.48.1",
]
[[package]]
name = "craft-ui"
version = "0.1.0"
@@ -1566,15 +1596,6 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "craft-xml"
version = "0.1.0"
source = "git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895#2e670cf9377b523112f3fe4b409399772c745895"
dependencies = [
"quick-xml 0.41.0",
"thiserror 2.0.21",
]
[[package]]
name = "craft-xml"
version = "0.1.0"
@@ -1602,6 +1623,15 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "craft-xml"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f#cc23ffd4d26f3074808e2187d332564817624f8f"
dependencies = [
"quick-xml 0.41.0",
"thiserror 2.0.21",
]
[[package]]
name = "craft-xml"
version = "0.1.0"
@@ -1842,7 +1872,7 @@ name = "designcraft-cli"
version = "0.20.1"
dependencies = [
"craft-file-formats",
"craft-image-codecs",
"craft-image-codecs 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"designcraft-color",
"designcraft-compose",
"designcraft-doc",
@@ -1913,7 +1943,7 @@ dependencies = [
"craft-indd",
"craft-prepress",
"craft-print",
"craft-svg 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-svg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=f23b0f33f0d00b157476533a43cbbcfd901aa1f1)",
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=fbdd905cdddd2f0de930021a3f92bcf1684973be)",
"designcraft-color",
@@ -1999,6 +2029,7 @@ name = "designcraft-idml"
version = "0.20.1"
dependencies = [
"craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=fbdd905cdddd2f0de930021a3f92bcf1684973be)",
"craft-svg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=fbdd905cdddd2f0de930021a3f92bcf1684973be)",
"designcraft-color",
"designcraft-compose",
@@ -2017,9 +2048,9 @@ dependencies = [
"craft-cms",
"craft-eps 0.1.0 (git+https://github.com/storytold/craft-libs?rev=ba24fe2435adb3c81ad6057faf36365fbba736cf)",
"craft-file-formats",
"craft-image-codecs",
"craft-image-codecs 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-psd",
"craft-svg 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-svg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)",
"designcraft-color",
"designcraft-fonts",
"flate2",
@@ -2049,7 +2080,7 @@ version = "0.20.1"
dependencies = [
"chrono",
"craft-cms",
"craft-image-codecs",
"craft-image-codecs 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-pdf",
"craft-prepress",
"designcraft-color",
@@ -2074,7 +2105,7 @@ name = "designcraft-pptx"
version = "0.20.1"
dependencies = [
"chrono",
"craft-image-codecs",
"craft-image-codecs 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-opc 0.1.0 (git+https://github.com/storytold/craft-libs?rev=8abfa9d0f14bafbfc3449fc552ffeafb9ca6a551)",
"craft-pptx",
"designcraft-color",
@@ -2094,7 +2125,7 @@ dependencies = [
name = "designcraft-render"
version = "0.20.1"
dependencies = [
"craft-image-codecs",
"craft-image-codecs 0.1.0 (git+https://github.com/dylanmtaylor/craft-libs?rev=2e670cf9377b523112f3fe4b409399772c745895)",
"craft-pdf",
"designcraft-color",
"designcraft-compose",
+1 -1
View File
@@ -18,7 +18,7 @@ craft-eps = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435
craft-epub = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" }
craft-idml = { git = "https://github.com/storytold/craft-libs", rev = "fbdd905cdddd2f0de930021a3f92bcf1684973be", version = "=0.1.0" }
craft-indd = { git = "https://github.com/storytold/craft-libs", rev = "47bf5650b0d503b97bfb5e841746c4957897d11f", version = "=0.1.0" }
craft-svg = { git = "https://github.com/dylanmtaylor/craft-libs", rev = "2e670cf9377b523112f3fe4b409399772c745895", version = "=0.1.0", features = ["tree-render", "tree-text"] }
craft-svg = { git = "https://github.com/storytold/craft-libs", rev = "cc23ffd4d26f3074808e2187d332564817624f8f", version = "=0.1.0", features = ["tree-render", "tree-text"] }
craft-xml = { git = "https://github.com/storytold/craft-libs", rev = "fbdd905cdddd2f0de930021a3f92bcf1684973be", version = "=0.1.0" }
craft-xml-dtd = { package = "craft-xml", git = "https://github.com/storytold/craft-libs", rev = "f23b0f33f0d00b157476533a43cbbcfd901aa1f1", version = "=0.1.0" }
craft-rtf = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" }
+1
View File
@@ -15,6 +15,7 @@ designcraft-doc = { workspace = true }
designcraft-images = { workspace = true }
craft-idml = { workspace = true }
craft-xml = { workspace = true }
craft-svg = { workspace = true }
thiserror = { workspace = true }
log = { workspace = true }
+2 -27
View File
@@ -7,31 +7,6 @@ use super::{
Story, StoryId, Stroke, SubPath, TextFrame, TextFrameOptions, base64_decode, names, sniff_image, swatch, unescape_id,
};
/// The viewBox size of an SVG whose root has a viewBox but no width/height (percentages count as
/// none): InDesign places such a file at one viewBox unit to the point.
fn svg_viewbox_size(data: &[u8]) -> Option<(f64, f64)> {
if data.iter().find(|b| !b.is_ascii_whitespace()) != Some(&b'<') {
return None;
}
let mut options = craft_xml::Options::default();
options.limits.max_input = 16 << 20;
let root = options.parse(data).ok()?;
if root.local() != "svg" {
return None;
}
let attr = |name: &str| root.attr(name).map(ToString::to_string);
let absolute = |name: &str| attr(name).is_some_and(|v| !v.trim().ends_with('%'));
if absolute("width") || absolute("height") {
return None;
}
let vb: Vec<f64> =
attr("viewBox")?.split(|c: char| c.is_whitespace() || c == ',').filter(|v| !v.is_empty()).filter_map(|v| v.parse().ok()).collect();
match vb[..] {
[_, _, w, h] if w.is_finite() && h.is_finite() && w > 0.0 && h > 0.0 => Some((w, h)),
_ => None,
}
}
impl<'r> Importer<'r> {
pub(super) fn item(&mut self, e: &El, parent: Affine) -> Option<Item> {
let model_item = craft_idml::model::PageItem::from_el(&crate::xml::to_craft(e))?;
@@ -326,7 +301,7 @@ impl<'r> Importer<'r> {
// file once.
let key = (p.clone(), page, pdf_crop);
if let Some(id) = self.linked_assets.get(&key) {
let size = self.assets.get(id).and_then(|a| svg_viewbox_size(&a.data)).unwrap_or(size);
let size = self.assets.get(id).and_then(|a| craft_svg::sniff::viewbox_size(&a.data)).unwrap_or(size);
return graphic(*id, size);
}
if let Some(d) = (self.read_link)(p) {
@@ -339,7 +314,7 @@ impl<'r> Importer<'r> {
let preview = data.is_empty().then(|| g.get("Self").and_then(|s| self.previews.get(s))).flatten();
// InDesign draws a viewBox-only SVG at one unit to the point: its GraphicBounds are the
// art's bounds, which can overhang the viewBox, so they must not size the viewBox.
let size = svg_viewbox_size(&data).unwrap_or(size);
let size = craft_svg::sniff::viewbox_size(&data).unwrap_or(size);
let (mime, px) = if preview.is_some() { (None, None) } else { sniff_image(&data) };
let mime = mime.map(str::to_string).unwrap_or_else(|| match link.and_then(|k| k.get("LinkResourceFormat")).unwrap_or("") {
f if f.contains("EPS") || g.local() == "EPS" => "application/postscript".into(),