mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-02 14:38:13 -06:00
M2: a reference in /Decode, /W or a palette that leads back to itself ends
Colour spaces already had tests of this through their bases. `/Decode`, in the renderer and in image export, `/W`, `/W2` and an Indexed space's table hadn't: each read now has such a reference in its test, and ends. These hold that the read ends, not what value it comes to. A reference to a reference in a number array reads as the first number of that reference in the renderer (`/Decode [11 0 R 0]`, with 11 naming 6 and 6 holding 1, reads as 6). That is older than this branch, in `IndirectObject::read` for an object stored on its own and `ObjectStream::get` for one in an object stream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4c815786c6
commit
33d7a51301
@@ -2221,7 +2221,8 @@ fn a_stencil_masks_decode_array_can_hold_references() {
|
||||
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj\n\
|
||||
3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Resources << /XObject << /Im 4 0 R >> >> >> endobj\n\
|
||||
4 0 obj << /Subtype /Image /ImageMask true /Width 8 /Height 1 /BitsPerComponent 1 /Decode {decode} /Filter /ASCIIHexDecode /Length 3 >> stream\nF0>\nendstream endobj\n\
|
||||
5 0 obj 1 endobj\n6 0 obj 0 endobj\ntrailer << /Root 1 0 R >>\n%%EOF"
|
||||
5 0 obj 1 endobj\n6 0 obj 0 endobj\n7 0 obj 7 0 R endobj\n8 0 obj 9 0 R endobj\n9 0 obj 8 0 R endobj\n\
|
||||
trailer << /Root 1 0 R >>\n%%EOF"
|
||||
);
|
||||
let doc = Document::open(std::sync::Arc::new(pdf.into_bytes())).unwrap();
|
||||
let mut export = crate::extract::extract_images(&doc, &[0], 1);
|
||||
@@ -2236,4 +2237,10 @@ fn a_stencil_masks_decode_array_can_hold_references() {
|
||||
for decode in ["[0 5 0 R]", "[6 0 R 1]", "[6 0 R 5 0 R]"] {
|
||||
assert_eq!(export(decode), identity, "{decode}");
|
||||
}
|
||||
// A reference that only leads back to itself holds no number. The read ends, and the file comes
|
||||
// out one way round or the other.
|
||||
for decode in ["[7 0 R 0]", "[1 7 0 R]", "[8 0 R 0]", "[1 8 0 R]", "[7 0 R 8 0 R]"] {
|
||||
let file = export(decode);
|
||||
assert!(file == inverted || file == identity, "{decode}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,6 +1062,9 @@ fn a_decode_array_with_references_in_it_is_read() {
|
||||
5 0 obj << /Type /XObject /Subtype /Image /Width {width_of} /Height 1 /BitsPerComponent 8 /ColorSpace {space} /Decode {decode} /Filter /ASCIIHexDecode /Length {} >> stream\n{data}\nendstream endobj\n\
|
||||
6 0 obj 1 endobj\n\
|
||||
7 0 obj 0 endobj\n\
|
||||
8 0 obj 8 0 R endobj\n\
|
||||
9 0 obj 10 0 R endobj\n\
|
||||
10 0 obj 9 0 R endobj\n\
|
||||
trailer << /Root 1 0 R >>\n%%EOF",
|
||||
content.len(),
|
||||
data.len()
|
||||
@@ -1090,6 +1093,11 @@ fn a_decode_array_with_references_in_it_is_read() {
|
||||
for decode in ["[6 0 R 0 1 0 1 0]", "[1 0 6 0 R 0 1 0]", "[1 0 1 0 6 0 R 0]", "[6 0 R 7 0 R 6 0 R 7 0 R 6 0 R 7 0 R]"] {
|
||||
assert_eq!(render("1", decode, "/DeviceRGB", "204060>"), rgb, "{decode}");
|
||||
}
|
||||
// A reference that only leads back to itself holds no number. The read ends, and the image is
|
||||
// drawn over the red under it.
|
||||
for decode in ["[8 0 R 0]", "[1 8 0 R]", "[9 0 R 0]", "[1 9 0 R]", "[8 0 R 9 0 R]"] {
|
||||
assert_ne!(render("1", decode, "/DeviceGray", "40>"), [255, 0, 0, 255], "{decode}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A function's `/Encode`, `/Decode`, `/Domain` and `/Range` are read a pair at a time too, so they
|
||||
@@ -1193,6 +1201,11 @@ fn an_indexed_lookup_table_is_read_in_every_legal_form() {
|
||||
for space in ["[/Indexed /DeviceRGB 1 8 0 R]", "[/Indexed /DeviceRGB 1 99 0 R]", "[/Indexed /DeviceRGB 1]"] {
|
||||
let _ = render(space, paint, "");
|
||||
}
|
||||
// So does a table that only leads back to itself, and the read of it ends.
|
||||
let cycle = "11 0 obj 11 0 R endobj 12 0 obj 13 0 R endobj 13 0 obj 12 0 R endobj";
|
||||
for space in ["[/Indexed /DeviceRGB 1 11 0 R]", "[/Indexed /DeviceRGB 1 12 0 R]"] {
|
||||
let _ = render(space, paint, cycle);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn watchdog_skips_a_stuck_page_and_keeps_rendering() {
|
||||
|
||||
+9
@@ -712,6 +712,7 @@ mod width_tests {
|
||||
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj\n\
|
||||
3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 10 10] >> endobj\n\
|
||||
4 0 obj 20 endobj\n5 0 obj {array} endobj\n6 0 obj 22 endobj\n\
|
||||
7 0 obj 7 0 R endobj\n8 0 obj 9 0 R endobj\n9 0 obj 8 0 R endobj\n\
|
||||
trailer << /Root 1 0 R >>\n%%EOF\n"
|
||||
);
|
||||
Pdf::new(pdf.into_bytes()).unwrap()
|
||||
@@ -750,5 +751,13 @@ mod width_tests {
|
||||
let by_range = vec![(20, [-900.0, 400.0, 800.0]), (21, [-900.0, 400.0, 800.0]), (22, [-900.0, 400.0, 800.0])];
|
||||
assert_eq!(vertical("[20 22 -900 400 800]"), by_range);
|
||||
assert_eq!(vertical("[4 0 R 22 -900 400 800]"), by_range);
|
||||
|
||||
// A reference that only leads back to itself holds no number. The reads end.
|
||||
for array in ["[7 0 R [500 600]]", "[8 0 R [500 600]]", "[20 7 0 R 700]", "[7 0 R 8 0 R 700]", "[20 [7 0 R 600]]"] {
|
||||
widths(array);
|
||||
}
|
||||
for array in ["[7 0 R [-1000 500 880]]", "[8 0 R 22 -900 400 800]", "[20 [7 0 R 500 880]]"] {
|
||||
vertical(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user