mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 04:22:20 +00:00
M2: the oversized-/Rows fax test also checks white rows after the first (hayro-syntax patch 41)
Through /Indexed, samples past the decoded data read as black, so an all-black image could not tell a decoder that stopped after one row from one that decoded all four. A second Group 4 image striped black, white, black, white (horizontal-mode rows, ITU-T T.6 §2.2.3.3) is now rendered through both colour spaces with every /Rows value, and each row is checked for its own colour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
This commit is contained in:
1 parent
d4b4218cf1
commit
5c2f4b8383
1 file changed
+14
-6
@@ -3457,11 +3457,19 @@ trailer << /Root 1 0 R >>
|
||||
/// PDFBOX-771: a fax image whose `/Rows` says more rows than its `/Height` (1,084,975,104 on a
|
||||
/// 2,592-column scan) is decoded to its height, as the image is (ISO 32000-2 Table 87): the
|
||||
/// decoder was asked for `/Rows` rows, which the size check refused, so every page drew blank.
|
||||
/// Also through an `/Indexed` colour space, the filter's other output path.
|
||||
/// Also through an `/Indexed` colour space, the filter's other output path. Samples past the
|
||||
/// decoded data read as black there, so a second image striped black, white, black, white shows
|
||||
/// that every row up to the last is decoded.
|
||||
#[test]
|
||||
fn group4_fax_with_rows_past_its_height_decodes_to_the_image_height() {
|
||||
const ALL_BLACK_8X4: [u8; 6] = [0x26, 0xa2, 0xfe, 0x00, 0x20, 0x02];
|
||||
for space in ["/DeviceGray", "[/Indexed /DeviceRGB 1 <000000FFFFFF>]"] {
|
||||
// Each row in horizontal mode: black rows as white 0 + black 8, white rows as white 8 +
|
||||
// black 0 (ITU-T T.6 §2.2.3.3, codes from Table 2/T.6), then EOFB.
|
||||
const STRIPED_8X4: [u8; 12] = [0x26, 0xa2, 0x99, 0x86, 0xe4, 0xd4, 0x53, 0x30, 0xdc, 0x00, 0x40, 0x04];
|
||||
const BLACK: [u8; 4] = [0, 0, 0, 255];
|
||||
const WHITE: [u8; 4] = [255, 255, 255, 255];
|
||||
let images: [(&[u8], [[u8; 4]; 4]); 2] = [(&ALL_BLACK_8X4, [BLACK; 4]), (&STRIPED_8X4, [BLACK, WHITE, BLACK, WHITE])];
|
||||
for ((data, expected), space) in images.iter().flat_map(|i| ["/DeviceGray", "[/Indexed /DeviceRGB 1 <000000FFFFFF>]"].map(|s| (i, s))) {
|
||||
for rows in ["/Rows 5", "/Rows 1000000000", "/Rows 4294967295"] {
|
||||
let content = "q 20 0 0 20 5 5 cm /Im1 Do Q";
|
||||
let mut pdf = format!(
|
||||
@@ -3475,10 +3483,10 @@ endstream endobj
|
||||
5 0 obj << /Type /XObject /Subtype /Image /Width 8 /Height 4 /ColorSpace {space} /BitsPerComponent 1 /Filter /CCITTFaxDecode /DecodeParms << /K -1 /Columns 8 {rows} >> /Length {} >> stream
|
||||
",
|
||||
content.len(),
|
||||
ALL_BLACK_8X4.len()
|
||||
data.len()
|
||||
)
|
||||
.into_bytes();
|
||||
pdf.extend_from_slice(&ALL_BLACK_8X4);
|
||||
pdf.extend_from_slice(data);
|
||||
pdf.extend_from_slice(
|
||||
b"
|
||||
endstream endobj
|
||||
@@ -3488,8 +3496,8 @@ trailer << /Root 1 0 R >>
|
||||
let mut renderer = PageRenderer::new(Arc::new(pdf), RenderConfig::default());
|
||||
let page = renderer.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 1.0, tag: 0, ..Default::default() });
|
||||
assert!(page.error.is_none(), "{space} {rows}: {:?}", page.error);
|
||||
for y in [17, 22, 27, 32] {
|
||||
assert_eq!(&page.rgba[((y * 40 + 15) * 4)..][..4], &[0, 0, 0, 255], "{space} {rows}: image row at y {y} paints black");
|
||||
for (y, colour) in [17, 22, 27, 32].into_iter().zip(expected) {
|
||||
assert_eq!(&page.rgba[((y * 40 + 15) * 4)..][..4], colour, "{space} {rows}: image row at y {y}");
|
||||
}
|
||||
assert_eq!(&page.rgba[((38 * 40 + 1) * 4)..][..4], &[255, 255, 255, 255], "{space} {rows}: outside the image stays white");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user