mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 03:06:57 -06:00
Package: reads placed pages and document previews only for the options that use them
With Copy Links on and Copy Fonts off, File › Package still read every placed PDF or .ai page to find the fonts of its type, and then dropped them. With Copy Links on and Relink off, it still read the preview and the PDF of each placed .vectorcraft document, which only the rewritten copy uses. Package now reads the placed pages for their fonts only with Copy Fonts on, and it reads the preview and the PDF only with Relink on. With Copy Fonts off, packaging a document that places the 60 pages of a PDF took about 390 ms in a release build and now takes about 20 ms. The package it writes is the same.
This commit is contained in:
@@ -104,12 +104,23 @@ fn safe_asset_name(name: &str) -> String {
|
||||
/// A file placed: (page, bounding, page box) of each placed object showing it.
|
||||
type PlacedPages = Vec<(u32, bool, vectorcraft_doc::PageBox)>;
|
||||
|
||||
#[cfg(test)]
|
||||
thread_local! {
|
||||
/// Tests: how many placed PDF or `.ai` pages [`page_fonts`] read on this thread.
|
||||
pub(crate) static PAGES_READ: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
|
||||
/// Tests: how many linked `.vectorcraft` files had their preview and PDF read on this thread,
|
||||
/// to keep them in the rewritten copy.
|
||||
pub(crate) static PARTS_READ: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
|
||||
}
|
||||
|
||||
/// The fonts of the type on `pages` of the PDF or `.ai` file `name` (`bytes`, found at `path`);
|
||||
/// none for other files.
|
||||
fn page_fonts(name: &str, bytes: &[u8], path: &str, pages: &PlacedPages) -> BTreeSet<super::fonts::UsedFont> {
|
||||
let mut fonts = BTreeSet::new();
|
||||
if super::place::document::is_pdf(name, bytes) {
|
||||
for &(page, bounding, page_box) in pages {
|
||||
#[cfg(test)]
|
||||
PAGES_READ.with(|c| c.set(c.get() + 1));
|
||||
if let Ok(a) = super::place::document::document_art(name, bytes, Some(path), page, bounding, page_box, C) {
|
||||
fonts.extend(super::fonts::art_fonts(&a.doc, &a.nodes));
|
||||
}
|
||||
@@ -231,7 +242,9 @@ impl<'a> Collector<'a> {
|
||||
self.renamed(&mut lines, source, &file.path, &file.name, &existing.name);
|
||||
}
|
||||
// Another document may place other pages of a PDF copied already.
|
||||
if let (Some(pages), Some(bytes)) = (placed.get(&file.path), &file.bytes) {
|
||||
if self.opts.copy_fonts
|
||||
&& let (Some(pages), Some(bytes)) = (placed.get(&file.path), &file.bytes)
|
||||
{
|
||||
placed_fonts.extend(page_fonts(&file.name, bytes, found_path, pages));
|
||||
}
|
||||
local.insert(file.path.clone(), existing);
|
||||
@@ -262,7 +275,9 @@ impl<'a> Collector<'a> {
|
||||
} else {
|
||||
self.collect(&mut art, found_path, &destination_file, depth + 1, true)?;
|
||||
}
|
||||
} else if let Some(pages) = pages {
|
||||
} else if self.opts.copy_fonts
|
||||
&& let Some(pages) = pages
|
||||
{
|
||||
placed_fonts.extend(page_fonts(&file.name, &bytes, found_path, pages));
|
||||
}
|
||||
if placed_file && super::place::document::is_native(&file.name, &bytes) {
|
||||
@@ -271,18 +286,18 @@ impl<'a> Collector<'a> {
|
||||
} else {
|
||||
match vectorcraft_format::load_file(&bytes) {
|
||||
Ok(saved) => {
|
||||
let preview = vectorcraft_format::preview(&bytes);
|
||||
let pdf = vectorcraft_format::pdf_content(&bytes);
|
||||
let compressed = bytes.starts_with(&[0x1f, 0x8b]);
|
||||
let include_linked =
|
||||
saved.doc.linked_only_images().iter().any(|key| saved.doc.images.get(key).is_some_and(|blob| !blob.is_proxy()));
|
||||
let mut nested = saved.doc;
|
||||
self.collect(&mut nested, found_path, &destination_file, depth + 1, false)?;
|
||||
if self.opts.relink {
|
||||
#[cfg(test)]
|
||||
PARTS_READ.with(|c| c.set(c.get() + 1));
|
||||
// Preserve auxiliary native-file content when rewriting.
|
||||
let mut options = vectorcraft_format::SaveOptions::for_doc(&nested);
|
||||
options.preview = preview;
|
||||
options.pdf = pdf;
|
||||
options.preview = vectorcraft_format::preview(&bytes);
|
||||
options.pdf = vectorcraft_format::pdf_content(&bytes);
|
||||
options.profiles = saved.profiles;
|
||||
options.compress = compressed;
|
||||
options.include_linked = include_linked;
|
||||
|
||||
@@ -471,6 +471,35 @@ fn package_copies_the_fonts_of_each_page_of_a_pdf_that_two_documents_place() {
|
||||
assert_eq!((r["links"].as_u64(), r["fonts"].as_u64(), r["skippedFonts"].clone()), (Some(2), Some(2), json!([])), "{r}");
|
||||
}
|
||||
|
||||
/// With Copy Fonts off, Package reads no placed PDF page for its type: neither a page of a PDF it
|
||||
/// copies nor a page of one another document placed and it copied already.
|
||||
#[test]
|
||||
fn package_reads_no_placed_pdf_page_without_copy_fonts() {
|
||||
use cmd::package::PAGES_READ;
|
||||
let dir = Folder::new("package-placed-pdf-no-fonts");
|
||||
let mut src = session();
|
||||
run(&mut src, "text.create", json!({"x": 10, "y": 40, "text": "One"}));
|
||||
run(&mut src, "artboard.new", json!({"x": 500, "y": 0, "width": 400, "height": 300}));
|
||||
run(&mut src, "text.create", json!({"x": 510, "y": 40, "text": "Two"}));
|
||||
let pdf = run(&mut src, "document.serialize", json!({"format": "pdf", "preserveEditing": false}));
|
||||
let path = dir.file("art/flyer.pdf");
|
||||
write(&path, &vectorcraft_format::base64_decode(pdf["dataBase64"].as_str().unwrap()).unwrap());
|
||||
let mut part = session();
|
||||
run(&mut part, "file.place", json!({"path": path, "page": 2}));
|
||||
let part_path = dir.file("art/part.vectorcraft");
|
||||
save(&mut part, &part_path);
|
||||
let mut s = session();
|
||||
run(&mut s, "file.place", json!({"path": path, "page": 1}));
|
||||
run(&mut s, "file.place", json!({"path": part_path}));
|
||||
save(&mut s, &dir.file("poster.vectorcraft"));
|
||||
for (copy_links, copy_fonts, fonts, reads, out) in [(true, false, 0, 0, "links"), (false, false, 0, 0, "neither"), (true, true, 1, 2, "both")] {
|
||||
let before = PAGES_READ.with(std::cell::Cell::get);
|
||||
let r = run(&mut s, "file.package", json!({"folder": dir.file(out), "copyLinks": copy_links, "copyFonts": copy_fonts}));
|
||||
let read = PAGES_READ.with(std::cell::Cell::get) - before;
|
||||
assert_eq!((r["fonts"].as_u64(), read), (Some(fonts), reads), "{out}: {r}");
|
||||
}
|
||||
}
|
||||
|
||||
/// `dir/art/badge.ai`, saved without its PDF part, its art placing each of `pics` (600 × 300 px,
|
||||
/// with a 2×1 preview) → its path.
|
||||
fn ai_placing(dir: &Folder, pics: &[&str]) -> String {
|
||||
@@ -664,6 +693,21 @@ fn packaging_nested_files_preserves_embedded_preview_pdf_and_compression() {
|
||||
assert_eq!(images[0].as_ref().unwrap().relative.as_deref(), Some("photo.png"));
|
||||
}
|
||||
|
||||
/// Without Relink, Package copies a placed document as it is and reads no preview or PDF from it.
|
||||
#[test]
|
||||
fn package_reads_no_preview_or_pdf_of_a_placed_document_without_relink() {
|
||||
use cmd::package::PARTS_READ;
|
||||
let dir = Folder::new("package-native-no-relink");
|
||||
let mut parent = poster_with_placed_document(&dir);
|
||||
let original = std::fs::read(dir.file("art/part.vectorcraft")).unwrap();
|
||||
for (relink, reads, out) in [(false, 0, "as is"), (true, 1, "relinked")] {
|
||||
let before = PARTS_READ.with(std::cell::Cell::get);
|
||||
let r = run(&mut parent, "file.package", json!({"folder": dir.file(out), "relink": relink}));
|
||||
assert_eq!((r["links"].as_u64(), PARTS_READ.with(std::cell::Cell::get) - before), (Some(2), reads), "{out}: {r}");
|
||||
}
|
||||
assert_eq!(std::fs::read(dir.0.join("as is/poster Folder/Links/part.vectorcraft")).unwrap(), original);
|
||||
}
|
||||
|
||||
/// The report keeps the packaged document's sections as they were, then gives each placed
|
||||
/// document's own, headed by its file, instead of nesting them inside the parent's list.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user