diff --git a/crates/pptx/src/read.rs b/crates/pptx/src/read.rs index 4ee3c4d32..47f6229c3 100644 --- a/crates/pptx/src/read.rs +++ b/crates/pptx/src/read.rs @@ -1351,6 +1351,7 @@ fn read_show(sp: &El, shows: &HashMap) -> ShowSettings { without_narration: sp.bool("showNarration") == Some(false), without_animation: sp.bool("showAnimation") == Some(false), use_timings: sp.bool("useTimings").unwrap_or(true), + show_media_controls: sp.find("showMediaCtrls").and_then(|e| e.bool("val")).unwrap_or(true), ..Default::default() }; if sp.child("browse").is_some() { diff --git a/crates/pptx/src/write.rs b/crates/pptx/src/write.rs index 3d80adef1..e4c0858c9 100644 --- a/crates/pptx/src/write.rs +++ b/crates/pptx/src/write.rs @@ -1206,6 +1206,14 @@ fn pres_props_xml(p: &Presentation) -> Vec { w.open0("p:penClr"); w.val("a:srgbClr", s.pen_color.hex()); w.close("p:penClr"); + if !s.show_media_controls { + // "Show media controls" is PowerPoint's p14 extension; absent means shown. + w.open0("p:extLst"); + w.open("p:ext", A::new().a("uri", "{2FDB2607-1784-4EEB-B798-7EB5836EED8A}")); + w.empty("p14:showMediaCtrls", A::new().a("xmlns:p14", NS_P14).a("val", 0)); + w.close("p:ext"); + w.close("p:extLst"); + } w.close("p:showPr"); w.close("p:presentationPr"); w.finish() diff --git a/crates/pptx/tests/it/roundtrip.rs b/crates/pptx/tests/it/roundtrip.rs index ee8f2bc5d..f44b0c152 100644 --- a/crates/pptx/tests/it/roundtrip.rs +++ b/crates/pptx/tests/it/roundtrip.rs @@ -2258,6 +2258,34 @@ fn default_durations_match_powerpoint() { } } +/// Show media controls is PowerPoint's `p14:showMediaCtrls` extension inside `p:showPr`: off is +/// written there, under its extension uri and with the p14 namespace declared on the element; +/// on (the default) writes nothing. +#[test] +fn hidden_media_controls_survive_save_and_reopen() { + let props = |p: &Presentation| { + let bytes = deckcraft_pptx::export(p).expect("export"); + let mut zip = zip::ZipArchive::new(std::io::Cursor::new(bytes)).expect("zip"); + let mut x = String::new(); + std::io::Read::read_to_string(&mut zip.by_name("ppt/presProps.xml").expect("presProps"), &mut x).expect("read"); + x + }; + let mut p = Presentation::default(); + p.show.show_media_controls = false; + let xml = props(&p); + let show = xml.split("").next()).expect("p:showPr"); + assert!( + show.contains( + "" + ), + "{xml}" + ); + assert!(!round(&p).show.show_media_controls); + let default = Presentation::default(); + assert!(!props(&default).contains("showMediaCtrls")); + assert!(round(&default).show.show_media_controls); +} + #[test] fn reflection_angles_and_skews_out_of_range_are_written_inside_the_schema() { let mut p = Presentation::default();