.ai import: a file whose PDF part is an empty page opens from its editing data

Squashed from #4651 onto main.
This commit is contained in:
Don Omondi
2026-10-30 08:15:16 +07:00
committed by bflatastic
parent 0f1b70f8b1
commit 87cb19c589
3 changed files with 37 additions and 3 deletions
+14 -2
View File
@@ -197,6 +197,13 @@ fn from_editing_data_alone(bytes: &[u8], opts: &LoadOptions) -> Option<Result<(D
)
}
/// Does `doc` hold no art: only layers, with nothing in them?
fn draws_nothing(doc: &Document) -> bool {
let mut art = false;
doc.walk(|n| art |= !n.is_layer());
!art
}
/// Is `e` the error of a file whose pages are only a placeholder
/// ([`vectorcraft_pdf::PdfError::PlaceholderOnly`])?
pub(crate) fn is_placeholder(e: &EngineError) -> bool {
@@ -272,8 +279,13 @@ pub fn load_with(name: &str, bytes: &[u8], opts: &LoadOptions) -> Result<Loaded>
restore_or_import(editing, || match super::pdfimport::import(bytes, opts, format.id != "pdf") {
Ok(r) => {
// Pages of text alone: the editing copy alone where it reads, as for a file
// saved without its PDF part (#1387: else the page, which is the art).
let alone = r.only_text.then(|| from_editing_data_alone(bytes, opts)).flatten().and_then(|read| read.ok());
// saved without its PDF part (#1387: else the page, which is the art). So too
// pages that draw nothing at all: there is no page art to check the layers
// against, and the empty page would lose all of it.
let alone = (r.only_text || draws_nothing(&r.document))
.then(|| from_editing_data_alone(bytes, opts))
.flatten()
.and_then(|read| read.ok());
let (doc, warnings, read) = match alone {
Some((doc, warnings)) => (doc, warnings, true),
None => through_editing_data(bytes, opts, r.document, r.warnings, r.user_unit),
@@ -556,6 +556,26 @@ fn an_ai_file_whose_pdf_part_is_cropped_to_its_art_opens_from_its_layers() {
assert!((b.x0 - 100.0).abs() < 0.01 && (b.y0 - 50.0).abs() < 0.01, "where the artboard has it: {b:?}");
}
#[test]
fn an_ai_file_whose_pdf_part_draws_nothing_opens_from_its_editing_data() {
// A PDF-compatible `.ai` whose PDF part is a page with nothing on it (no notice text either),
// with or without the boxes that say where its art is: its editing data is the art.
for boxed in ["", "/ArtBox [0 0 200 100] /TrimBox [0 0 200 100]"] {
let mut s = Session::new();
let r = open(&mut s, "blank.ai", &ai::ai_with(&compressed(&ai::sample_data()), "", boxed), json!({})).unwrap();
assert_eq!(r["warnings"], json!([]), "{boxed:?}: {r}");
check_sample(&s);
// The PDF part alone, as asked: its empty page.
open(&mut s, "blank.ai", &ai::ai_with(&compressed(&ai::sample_data()), "", boxed), json!({"editingData": false})).unwrap();
let layers = &s.doc().unwrap().doc.layers;
assert!(layers.iter().all(|l| l.children().is_none_or(|c| c.is_empty())), "{boxed:?}");
}
// Editing data that can't be read leaves the empty page, as before.
let mut s = Session::new();
open(&mut s, "blank.ai", &ai::ai(b"%AI24_ZStandard_Data\0\0\0\0\0\0\0\0", ""), json!({})).unwrap();
assert_ne!(names(&s.doc().unwrap().doc.layers), ["Art", "Hidden"]);
}
#[test]
fn editing_data_false_opens_only_what_the_page_prints() {
let mut s = Session::new();
File diff suppressed because one or more lines are too long