diff --git a/crates/create/src/extract.rs b/crates/create/src/extract.rs index 2b3a0ffd73..b5500f60c3 100644 --- a/crates/create/src/extract.rs +++ b/crates/create/src/extract.rs @@ -236,12 +236,16 @@ fn image(doc: &Document, s: &Stream) -> Result<(&'static str, Vec), String> let mut alpha = if mask { None } else { soft_mask(doc, s, w, h).or_else(|| stencil_mask(doc, s, w, h)) }; let key = if mask { None } else { colour_key(doc, s) }; // Keep the existing JPEG and stencil-mask Decode handling separate from lossless colour images. - let endpoint = |value: Option<&Object>| value.map(|v| doc.resolve(v)).and_then(|v| v.as_f64()); + let endpoint = |value: Option<&Object>| value.map(|v| doc.resolve(v)).and_then(|v| v.as_f64()).filter(|v| v.is_finite()); let inverted = (jpeg || mask) && s.dict .get(b"Decode") .map(|d| doc.resolve(d)) - .and_then(|d| d.as_array().map(|a| endpoint(a.first()) > endpoint(a.get(1)))) + // Both ends have to be finite numbers, as for lossless images, or the default mapping stands. + .and_then(|d| { + let a = d.as_array()?; + Some(endpoint(a.first())? > endpoint(a.get(1))?) + }) .unwrap_or(false); // In a PDF a CMYK JPEG's samples are ink amounts unless /Decode inverts them, while image // viewers read a CMYK JPEG file as inverted (Adobe's convention): as is, it would show as diff --git a/crates/create/src/tests.rs b/crates/create/src/tests.rs index 4a1e007fd4..ff871d53ae 100644 --- a/crates/create/src/tests.rs +++ b/crates/create/src/tests.rs @@ -2237,12 +2237,14 @@ 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}"); + // A reference that only leads back to itself holds no number, and an end that is missing or isn't + // a number leaves the default mapping, whichever end it is. + 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]", "[1]", "[1 /Name]", "[/Name 0]"] { + assert_eq!(export(decode), identity, "{decode}"); } + // Equal ends aren't the two ways round either, and a number too long to hold reads as infinite. + assert_eq!(export("[1 1]"), identity); + assert_eq!(export(&format!("[{} 0]", "9".repeat(400))), identity); } /// A mask of other proportions than its image is scaled to it, however far apart they are: the