From f6cab1980bbe422cc00c4b19d9f0f9ba337e1316 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Fri, 13 Nov 2026 02:54:31 -0500 Subject: [PATCH] Preserve SVG picture fallbacks in the Presentation model --- crates/drawingml/src/read.rs | 6 ++++++ crates/drawingml/src/style.rs | 3 +++ crates/drawingml/src/write.rs | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/crates/drawingml/src/read.rs b/crates/drawingml/src/read.rs index 496870774..9e9f8ff3e 100644 --- a/crates/drawingml/src/read.rs +++ b/crates/drawingml/src/read.rs @@ -166,6 +166,12 @@ pub fn blip_fill(src: &mut dyn Source, bf: &El) -> Option { { pf.artistic = Some(crate::style::Artistic { effect, original }); } + pf.svg = blip.and_then(|b| b.child(Local("extLst"))).and_then(|extensions| { + extensions + .elements() + .filter(|extension| extension.local() == "ext" && extension.attr_local("uri") == Some("{96DAC541-7B7A-43D3-8B79-37D633B846F1}")) + .find_map(|extension| extension.child(Local("svgBlip")).and_then(|svg| media_ref(src, svg))) + }); if let Some(b) = blip { for e in b.elements() { match e.local() { diff --git a/crates/drawingml/src/style.rs b/crates/drawingml/src/style.rs index 291ee4e76..36b5a6922 100644 --- a/crates/drawingml/src/style.rs +++ b/crates/drawingml/src/style.rs @@ -184,6 +184,9 @@ impl Default for PictureMode { #[serde(default, rename_all = "camelCase")] pub struct PictureFill { pub media: MediaId, + /// Optional vector SVG version of `media`; the regular media remains the bitmap fallback. + #[serde(skip_serializing_if = "Option::is_none")] + pub svg: Option, /// Source crop as fractions of the image (left, top, right, bottom); negative values pad. pub crop: [f64; 4], pub mode: PictureMode, diff --git a/crates/drawingml/src/write.rs b/crates/drawingml/src/write.rs index 0d9b83b1a..25bfb89db 100644 --- a/crates/drawingml/src/write.rs +++ b/crates/drawingml/src/write.rs @@ -107,6 +107,7 @@ pub fn blip_fill(w: &mut Writer, out: &mut dyn Sink, tag: &str, pf: &PictureFill w.tag(tag).attr("rotWithShape", if pf.upright { "0" } else { "1" }).open(); let adj = &pf.adjust; let has_kids = pf.alpha.is_some() + || pf.svg.is_some() || adj.brightness != 0.0 || adj.contrast != 0.0 || adj.grayscale @@ -168,6 +169,13 @@ pub fn blip_fill(w: &mut Writer, out: &mut dyn Sink, tag: &str, pf: &PictureFill w.close(); w.close(); } + if let Some(svg) = pf.svg.and_then(|id| out.media_rel(id, "image")) { + w.open("a:extLst", &[]); + w.tag("a:ext").attr("uri", "{96DAC541-7B7A-43D3-8B79-37D633B846F1}").open(); + w.tag("asvg:svgBlip").attr("xmlns:asvg", "http://schemas.microsoft.com/office/drawing/2016/SVG/main").attr("r:embed", &svg).empty(); + w.close(); + w.close(); + } w.close(); } else { w.tag("a:blip").list(a).empty();