mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 04:22:20 +00:00
M2.6: tests pin damage in an earlier filter stage, on another page, and in the saved file
- cos: a filter chain whose first stage stops at damage and whose second reads all it was given is damaged. - optimize: a page damaged partway stops resampling for the whole document, so another page drawing the same image whole doesn't get it resampled. - redact: after redacting content with /DecodeParms by reference, no stream in the saved file holds the text, read with its parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
This commit is contained in:
1 parent
22eb55225f
commit
11bf10613b
3 files changed
+37
-1
No files matched your search
@@ -850,6 +850,17 @@ mod tests {
|
||||
dict.set(b"Filter".to_vec(), Object::Array(vec![Object::name("FlateDecode"), Object::name("ASCIIHexDecode")]));
|
||||
let hex = Stream::from_raw(dict, Stream::flate(Dict::new(), b"4142zz4344>").raw.to_vec());
|
||||
assert_eq!(budget.decode_with_damage(&doc, &hex, usize::MAX).ok(), Some((b"AB".to_vec(), true)));
|
||||
// So is an earlier stage's, though the stage after it reads all it was given: a stored
|
||||
// block of whole hex, then a block of the reserved type (RFC 1951 §3.2.3).
|
||||
let readable = b"4142>";
|
||||
let len = u16::try_from(readable.len()).unwrap_or_default();
|
||||
let mut raw = vec![0x78, 0x01, 0x00];
|
||||
raw.extend_from_slice(&len.to_le_bytes());
|
||||
raw.extend_from_slice(&(!len).to_le_bytes());
|
||||
raw.extend_from_slice(readable);
|
||||
raw.push(0x07);
|
||||
let flate_damaged = Stream::from_raw(hex.dict.clone(), raw);
|
||||
assert_eq!(budget.decode_with_damage(&doc, &flate_damaged, usize::MAX).ok(), Some((b"AB".to_vec(), true)));
|
||||
}
|
||||
|
||||
/// `/DecodeParms` given by reference, or a parameter given by reference in them, is read: a
|
||||
|
||||
@@ -3220,6 +3220,24 @@ fn content_damaged_partway_leaves_every_image_at_its_resolution() {
|
||||
}
|
||||
}
|
||||
|
||||
/// One page damaged partway stops resampling for the whole document: another page drawing the same
|
||||
/// image at its full resolution, whole, doesn't get it resampled either.
|
||||
#[test]
|
||||
fn content_damaged_partway_on_one_page_leaves_the_image_another_page_draws() {
|
||||
let mut doc = Document::new_empty();
|
||||
let img = image(&mut doc, 720, 720, 1, false, None);
|
||||
let damaged = page(&mut doc, &[("Im", img)], "");
|
||||
let bad = doc.add(Object::Stream(damaged_flate(b"0 g\n", b"q 720 0 0 720 0 0 cm /Im Do Q")));
|
||||
doc.update_dict(damaged, |d| d.set(b"Contents".to_vec(), Object::Ref(bad))).unwrap();
|
||||
let whole = page(&mut doc, &[("Im", img)], "q 72 0 0 72 0 0 cm /Im Do Q");
|
||||
assert_eq!(effective_resolutions(&doc, &[whole])[&img], 720.0);
|
||||
let ppi = effective_resolutions(&doc, &[damaged, whole]).get(&img).copied().unwrap_or(f64::INFINITY);
|
||||
assert_eq!(ppi, f64::INFINITY);
|
||||
let r = optimize(&mut doc, &Settings::default()).unwrap();
|
||||
assert_eq!(r.images_resampled, 0, "{r:?}");
|
||||
assert_eq!(doc.get(img).as_dict().and_then(|d| d.int(b"Width")), Some(720));
|
||||
}
|
||||
|
||||
/// `levels` nested forms with their own resources, the innermost drawing `img` over the unit square.
|
||||
fn nested_forms(doc: &mut Document, img: ObjRef, levels: usize) -> ObjRef {
|
||||
let mut inner = form(doc, Some(Object::Dict(resources(xobjects(&[("Im", img)])))), "/Im Do");
|
||||
|
||||
@@ -130,7 +130,14 @@ fn content_with_parameters_given_by_reference_is_redacted() {
|
||||
mark(&mut doc, 0, &marked, "");
|
||||
let r = apply(&mut doc, None).unwrap();
|
||||
assert_eq!((r.marks, r.glyphs), (1, 6), "{what}");
|
||||
assert_eq!(under(&mut reopen(&doc), 0, &marked), 0, "{what}");
|
||||
let mut saved = reopen(&doc);
|
||||
assert_eq!(under(&mut saved, 0, &marked), 0, "{what}");
|
||||
// Nor is the text left in a stream the page no longer draws, read with its parameters.
|
||||
for (r, o) in saved.scan_objects() {
|
||||
let Object::Stream(s) = &*o else { continue };
|
||||
let data = pdfcraft_cos::DecodeBudget::new(usize::MAX, 0).decode_with_damage(&saved, s, usize::MAX).map(|(d, _)| d).unwrap_or_default();
|
||||
assert!(!data.windows(6).any(|w| w == b"SECRET"), "{what}: {r:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user