Watermark: ODT keeps a picture of unknown size in its header (#3001)

`picture_plan` chose the header frames as the document's watermark without
checking that `own_size` can read the picture. A picture shown in a header whose
size is not a raster's (an EMF or WMF) was taken out of the headers, then
`add` could not place it: the picture was lost. The plan now returns None for
such a picture, so the frames stay header pictures, as in the DOCX plan.

Co-Authored-By: C00kieMonsta <22135261+C00kieMonsta@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCVCCEo7u5wetHaJRU4
This commit is contained in:
Martin Ball
2026-11-06 01:20:46 +00:00
co-authored by C00kieMonsta Claude Sonnet 5.5
parent be2fef40a4
commit eb2cb3a7d9
2 changed files with 30 additions and 0 deletions
+3
View File
@@ -87,6 +87,9 @@ fn picture_plan(reads: &[SlotRead], pages: &Pages) -> Option<(Vec<u8>, (f32, f32
return None;
}
let first = headers.first()?.pictures.first()?;
// A picture whose size can't be read is no watermark (`add` couldn't place it, and the frames
// taken out of the headers would be lost): it stays a header picture, as in the DOCX plan.
wordcraft_doc::watermark::own_size(&first.0)?;
if !headers.iter().filter_map(|r| r.pictures.first()).all(|p| p.0 == first.0 && p.2 == first.2) {
return None;
}
@@ -420,6 +420,33 @@ fn a_picture_frame_in_the_headers_is_the_watermark_only_where_every_page_shows_i
assert_eq!(part_pictures(&d).iter().map(|(_, n)| n).sum::<usize>(), 1);
}
#[test]
fn a_picture_frame_of_unknown_size_is_not_a_watermark() {
// An EMF picture shows in a header, but its size isn't a raster's, which a watermark is sized
// from: the frames stay the pictures they are (taking them out would lose them).
let mut emf = vec![0u8; 88];
emf[0..4].copy_from_slice(&1u32.to_le_bytes());
emf[4..8].copy_from_slice(&88u32.to_le_bytes());
emf[24..40].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0x27, 0, 0, 0x10, 0x27, 0, 0]);
emf[40..44].copy_from_slice(&0x464D_4520u32.to_le_bytes());
assert!(wordcraft_doc::watermark::own_size(&emf).is_none());
let a = wm_frame("a.emf");
let pkg = watermark_package(&[(&a, ""), (&a, "")]);
let mut z = zip::ZipArchive::new(std::io::Cursor::new(&pkg)).unwrap();
let mut entries: Vec<(String, Vec<u8>)> = Vec::new();
for i in 0..z.len() {
let mut f = z.by_index(i).unwrap();
let mut b = Vec::new();
std::io::Read::read_to_end(&mut f, &mut b).unwrap();
entries.push((f.name().to_string(), b));
}
entries.push(("Pictures/a.emf".into(), emf));
let refs: Vec<(&str, &[u8])> = entries.iter().map(|(n, b)| (n.as_str(), b.as_slice())).collect();
let d = import(&crate::odt::tests::zip_of(&refs)).unwrap();
assert_eq!(d.settings.watermark, None);
assert_eq!(part_pictures(&d).iter().map(|(_, n)| n).sum::<usize>(), 2, "{:?}", part_pictures(&d));
}
#[test]
fn a_watermark_added_to_an_odt_file_is_saved() {
// Open an ODT, add a watermark, save as ODT: the watermark is written (the page setup was