mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-31 13:37:35 -06:00
Printing: a layer that is off in the document stays off on the sheets (#1135)
The print-ready PDF that `pdfcraft_print::impose` builds starts from a new catalog with only /Type and /Pages, so the document's /OCProperties was not carried over. The pages' marked content still refers to its optional-content groups, but nothing said a group was off, so a layer that is switched off in the document (and not drawn on screen) was printed anyway. Keep /OCProperties in the new catalog, so the sheets hide the same layers the document hides. Test: a one-page document whose red square is in a layer; with the layer off by default it is not drawn on screen and, now, not on the printed sheet; with the layer on it is drawn in both. Printing still follows the layers' default state only; applying the Print event of /AS (a layer shown only on screen or only in print) is not done here.
This commit is contained in:
@@ -1827,6 +1827,42 @@ fn printing_lays_out_sheets_that_render() {
|
||||
assert_eq!(s4.print_pdf(id4, &print::Settings { pages: vec![0], ..Default::default() }), Err(EditError::NotPermitted("printing")));
|
||||
}
|
||||
|
||||
/// A one-page document whose red square is in a layer; `off` switches the layer off by default.
|
||||
fn red_layer_pdf(off: bool) -> Vec<u8> {
|
||||
let content = "/OC /L1 BDC 1 0 0 rg 0 0 100 100 re f EMC";
|
||||
let off = if off { "/OFF [5 0 R] " } else { "" };
|
||||
format!(
|
||||
"%PDF-1.7\n\
|
||||
1 0 obj << /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [5 0 R] /D << {off}/Order [5 0 R] >> >> >> endobj\n\
|
||||
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] /Contents 4 0 R /Resources << /Properties << /L1 5 0 R >> >> >> endobj\n\
|
||||
4 0 obj << /Length {} >> stream\n{content}\nendstream endobj\n\
|
||||
5 0 obj << /Type /OCG /Name (Red) >> endobj\n\
|
||||
trailer << /Root 1 0 R >>\n%%EOF",
|
||||
content.len()
|
||||
)
|
||||
.into_bytes()
|
||||
}
|
||||
|
||||
/// Does the first page of `pdf` show any red when drawn?
|
||||
fn first_page_has_red(pdf: Vec<u8>) -> bool {
|
||||
let mut renderer = pdfcraft_render::PageRenderer::new(Arc::new(pdf), pdfcraft_render::RenderConfig::default());
|
||||
let page = renderer.render(pdfcraft_render::RenderRequest { page: 0, scale: 0.5, ..Default::default() });
|
||||
page.rgba.as_chunks::<4>().0.iter().any(|p| p[0] > 200 && p[1] < 60 && p[2] < 60)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_layer_that_is_off_does_not_print_and_one_that_is_on_does() {
|
||||
for (off, prints) in [(true, false), (false, true)] {
|
||||
let source = red_layer_pdf(off);
|
||||
assert_eq!(first_page_has_red(source.clone()), prints, "on screen (off: {off})");
|
||||
let mut s = Session::new();
|
||||
let id = s.open("layers.pdf", None, Arc::new(source), None).unwrap();
|
||||
let sheet = s.print_pdf(id, &print::Settings { pages: vec![0], ..Default::default() }).unwrap();
|
||||
assert_eq!(first_page_has_red(sheet), prints, "printed (layer off by default: {off})");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crop_and_duplicate_pages_show_in_the_viewer() {
|
||||
let (mut s, id) = session_with(2);
|
||||
|
||||
@@ -723,6 +723,12 @@ pub fn impose(src: &Document, settings: &Settings) -> Result<Vec<u8>, PrintError
|
||||
let mut cat = Dict::new();
|
||||
cat.set(b"Type".to_vec(), Object::name("Catalog"));
|
||||
cat.set(b"Pages".to_vec(), Object::Ref(pages_root));
|
||||
// Keep the layers' configuration, or a layer that is off in the document would print: the
|
||||
// pages' marked content still refers to its groups, and without this nothing says they are off.
|
||||
let layers = src.trailer().get(b"Root").and_then(|r| src.resolve(r).as_dict().and_then(|root| root.get(b"OCProperties").cloned()));
|
||||
if let Some(layers) = layers {
|
||||
cat.set(b"OCProperties".to_vec(), layers);
|
||||
}
|
||||
let root = doc.add(Object::Dict(cat));
|
||||
doc.trailer_mut().set(b"Root".to_vec(), Object::Ref(root));
|
||||
doc.trailer_mut().remove(b"Info");
|
||||
|
||||
Reference in New Issue
Block a user