From e2adbe7faa44a405878da33ed76842ff37bc6963 Mon Sep 17 00:00:00 2001 From: Grzegorz Martens Date: Sat, 31 Oct 2026 00:41:23 +0100 Subject: [PATCH] M11: tests: an indexed palette is read by its colours' luma, and only a real palette counts Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY --- crates/optimize/tests/optimize.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/optimize/tests/optimize.rs b/crates/optimize/tests/optimize.rs index 3fe59a1325..34df39cb15 100644 --- a/crates/optimize/tests/optimize.rs +++ b/crates/optimize/tests/optimize.rs @@ -3539,6 +3539,33 @@ fn an_indexed_image_used_beyond_the_page_content_read_is_not_averaged() { } } +/// Which palette entry is darker comes from the colours, weighted as luma, and blue is darker than +/// red whichever comes first. An array shaped like an indexed colour space and named otherwise has +/// no palette, so its samples aren't averaged. +#[test] +fn an_indexed_palette_is_read_by_the_luma_of_its_colours() { + let (w, h) = (1200u32, 480u32); + let stride = (w as usize).div_ceil(8); + let mut data = vec![0xFF; stride * h as usize]; + for y in 0..h as usize { + data[y * stride + 101 / 8] &= !(0x80 >> (101 % 8)); + } + let palette = Object::String(pdfcraft_cos::PdfString::literal(vec![0, 0, 255, 255, 0, 0])); + let optimized = |space: &str| { + let cs = Object::Array(vec![Object::name(space), Object::name("DeviceRGB"), 1.into(), palette.clone()]); + let mut doc = Document::new_empty(); + let image = mono_image(&mut doc, w, h, &data, None, &[("BitsPerComponent", 1.into()), ("ColorSpace", cs)]); + page(&mut doc, &[("Im", image)], "q 144 0 0 57.6 20 600 cm /Im Do Q"); + optimize(&mut doc, &Settings::default()).unwrap(); + let s = stream(&doc, image); + (s.dict.int(b"Width"), doc.decoded_image(&s).unwrap()) + }; + let (width, samples) = optimized("Indexed"); + assert_eq!(width, Some(600)); + assert!(samples.iter().any(|b| *b != 0xFF), "the blue line, half a new pixel wide, stays as the dark sample"); + assert_eq!(optimized("NotIndexed").0, Some(1200)); +} + /// White margins must not hide a small screened photograph from the tone guard. #[test] fn mixed_text_and_small_halftone_regions_keep_their_tones_with_wide_white_margins() {