mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 07:10:13 +00:00
Export: hidden PDF layers place symbol art effects when a long page raises the version
A PDF/A-2b export at PDF 1.4 with Create PDF Layers and a page longer than 14,400 pt is written as PDF 1.6, which has PDF layers. The export decided which layers place their instances' symbol art before it raised the version, so a hidden layer, written as a PDF layer that is off, kept its instances' art without the art's live effects. The version a long page needs is now settled before the document is baked. The pages come from the artboards, which baking leaves as they are.
This commit is contained in:
@@ -45,6 +45,11 @@ fn export_with_report_inner(doc: &Document, opts: &PdfOptions, left_out: &mut Ha
|
||||
let set = &opts.settings;
|
||||
set.check()?;
|
||||
vectorcraft_doc::cancel::check().map_err(|_| PdfError::Cancelled)?;
|
||||
// The pages come from the artboards, which baking leaves as they are. The version a long page
|
||||
// raises the file to decides whether the layers are written, so it is settled before baking.
|
||||
let pages = pages(doc, opts)?;
|
||||
let raised = for_long_pages(set, &pages)?;
|
||||
let set = raised.as_ref().unwrap_or(set);
|
||||
// Live geometry effects export as their result, in symbols' art too; raster effects are
|
||||
// reported below.
|
||||
// Only the layers this export writes place their instances' art (see `ex.non_printing` and
|
||||
@@ -57,9 +62,6 @@ fn export_with_report_inner(doc: &Document, opts: &PdfOptions, left_out: &mut Ha
|
||||
// Baking stops early when cancelled, leaving a half-baked copy that must not be written.
|
||||
vectorcraft_doc::cancel::check().map_err(|_| PdfError::Cancelled)?;
|
||||
let doc = baked.as_ref().unwrap_or(doc);
|
||||
let pages = pages(doc, opts)?;
|
||||
let raised = for_long_pages(set, &pages)?;
|
||||
let set = raised.as_ref().unwrap_or(set);
|
||||
|
||||
// The file's Title is File Info's; the page information names the document, as its tab does.
|
||||
let title = crate::pdfx::title(set.standard, opts.title.clone().unwrap_or_else(|| doc.info_title().to_owned()));
|
||||
|
||||
@@ -131,6 +131,37 @@ fn pdf_layers_import_back_as_layers() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A hidden layer written as a PDF layer places the live effects of its instances' symbol art,
|
||||
/// also in a PDF/A-2b file at PDF 1.4 whose 17,000 pt page has it written as PDF 1.6: the symbol's
|
||||
/// square from x = 10 to 40, which a Transform effect moves 100 pt right, is written from x = 110
|
||||
/// to 140.
|
||||
#[test]
|
||||
fn a_hidden_layer_places_symbol_art_effects_when_a_long_page_raises_the_version() {
|
||||
let mut d = Document::new(17_000.0, 300.0);
|
||||
d.layers.clear();
|
||||
let mut square = rect(&mut d, 10.0, RED);
|
||||
square.appearance.effects.push(vectorcraft_doc::Effect { id: "distort.transform".into(), params: json!({"moveH": 100.0}), visible: true });
|
||||
d.symbols.push(vectorcraft_doc::Symbol { dynamic: false, name: "Moved".into(), art: square.into() });
|
||||
let instance = Node::new(d.alloc_id(), NodeKind::SymbolInstance { symbol: "Moved".into(), xf: vectorcraft_geom::Affine::IDENTITY });
|
||||
let mut l = Node::layer(d.alloc_id(), "Hidden", LayerColor::Preset(0));
|
||||
l.visible = false;
|
||||
if let NodeKind::Layer { children, .. } = &mut l.kind {
|
||||
children.push(instance.into());
|
||||
}
|
||||
d.layers.push(l.into());
|
||||
for compatibility in [Compatibility::Pdf14, Compatibility::Pdf16] {
|
||||
let settings = PdfSettings { standard: Standard::PdfA2b, compatibility, create_layers: true, ..PdfSettings::default() };
|
||||
let r = export_with_report(&d, &PdfOptions { settings, created: Some(1_791_200_000), ..Default::default() }).unwrap();
|
||||
assert!(r.bytes.starts_with(b"%PDF-1.6"), "{compatibility:?}");
|
||||
let back = import_with_report(&r.bytes, &ImportOptions::default()).unwrap().document;
|
||||
let hidden = back.layers.iter().find(|l| l.name.as_deref() == Some("Hidden")).expect("the hidden layer");
|
||||
let art = hidden.children().unwrap();
|
||||
assert_eq!(art.len(), 1, "{compatibility:?}");
|
||||
let b = art[0].geometric_bounds().unwrap();
|
||||
assert!((b.x0 - 110.0).abs() < 0.1 && (b.x1 - 140.0).abs() < 0.1, "{compatibility:?}: {b:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The rows of `nodes` in paint order, depth first: `depth name visible` for layers, `depth fill`
|
||||
/// for art.
|
||||
fn tree(nodes: &[std::sync::Arc<Node>], depth: usize, out: &mut Vec<String>) {
|
||||
|
||||
Reference in New Issue
Block a user