Data merge: a file that is not an image does not hide a later image candidate

The image search stopped at the first file that could be read and
checked whether it decodes afterwards. A non-image file at an earlier
candidate (the drive root, or beside the data file) then hid a valid
image beside the data file or the document, and the field was reported
missing. The decode check now runs inside the search, so only an image
ends it.
This commit is contained in:
dotCooCoo committed 2026-11-11 20:36:39 -08:00
1 parent d490e0fb18
commit b73c21db37
2 files changed
+28 -5

No files matched your search

+6 -5
View File
@@ -464,7 +464,7 @@ struct LoadedImage {
fn load_image(cell: &str, sources: &Sources) -> Option<LoadedImage> {
let Sources { data_dir, doc_dir, images, .. } = *sources;
let cands = image_candidates(cell, data_dir, doc_dir);
let (path, bytes) = cands.iter().find_map(|p| {
cands.iter().find_map(|p| {
// Read once per merge: many records naming one file is the normal case, and reading it
// per record is the amplification (#1595).
let bytes = images.get_or_read(p, || {
@@ -475,10 +475,11 @@ fn load_image(cell: &str, sources: &Sources) -> Option<LoadedImage> {
}
crate::io::read_file(p).ok().filter(|b| !b.is_empty())
})?;
Some((p.clone(), bytes))
})?;
let (pixels, natural) = designcraft_render::image_size(&bytes).zip(designcraft_render::natural_size(&bytes, 0))?;
Some(LoadedImage { path, bytes, pixels, natural })
// A file that does not decode leaves the search going, so a valid image at a later
// candidate is still found.
let (pixels, natural) = designcraft_render::image_size(&bytes).zip(designcraft_render::natural_size(&bytes, 0))?;
Some(LoadedImage { path: p.clone(), bytes, pixels, natural })
})
}
fn report_missing(report: &mut FillReport, record: u32, field: &str, cell: &str) {
+22
View File
@@ -914,6 +914,28 @@ fn an_image_path_with_a_leading_separator_is_found_beside_the_data_file() {
assert_eq!(r["missingImages"].as_array().map(Vec::len), Some(0), "{r}");
}
/// A file at an earlier candidate that is not an image does not hide a valid image at a later
/// one: the search goes on past it.
#[test]
fn a_non_image_file_beside_the_data_does_not_hide_the_image_beside_the_document() {
let dir = scratch("undecodable-image");
let (data, docs) = (dir.join("data"), dir.join("docs"));
write(&data.join("pics").join("a.png"), "not an image");
write_png_sized(&docs.join("pics").join("a.png"), 12, 12);
write(&data.join("cards.csv"), "@Photo\npics/a.png\n");
let mut s = Session::new();
new_doc(&mut s, 1);
exec(&mut s, "data.source.select", json!({"path": data.join("cards.csv")}));
exec(&mut s, "file.save", json!({"path": docs.join("layout.designcraft")}));
let frame = exec(&mut s, "frame.create", json!({"rect": [36.0, 36.0, 80.0, 80.0], "content": "graphic"}));
exec(&mut s, "data.placeholder.add", json!({"field": "Photo", "item": frame["id"]}));
exec(&mut s, "data.options", json!({"linkImages": true}));
let r = exec(&mut s, "data.merge", json!({}));
assert_eq!(r["missingImages"].as_array().map(Vec::len), Some(0), "{r}");
let link = graphic_link(&s).unwrap_or_default();
assert!(link.contains("docs"), "{link}");
}
#[test]
fn single_record_merge_copies_pages_and_leaves_the_template() {
let mut s = Session::new();