Fix PDF title display provenance

This commit is contained in:
Mirko Kerezovic
2026-10-23 01:01:25 +07:00
committed by bflatastic
parent 5e9df83dd4
commit d548b4ff74
9 changed files with 62 additions and 21 deletions
+24 -7
View File
@@ -19,8 +19,15 @@ pub(super) fn serialize(s: &mut Session, p: &Value) -> Result<Value> {
let f = writable("document.serialize", Some(str_param(p, "format").unwrap_or("vectorcraft")), None)?;
let expanded = expand_presets(s, "document.serialize", p)?;
let p = with_black_output(s, &expanded);
let doc = &*source(s, f, &p, "document.serialize")?;
let enc = encode_all(doc, f.id, &p)?;
let (doc, display_doc_title) = source(s, f, &p, "document.serialize")?;
let doc = &*doc;
let mut q = p.clone();
if f.id == "pdf"
&& let Some(o) = q.as_object_mut()
{
o.insert("_displayDocTitle".into(), json!(display_doc_title));
}
let enc = encode_all(doc, f.id, &q)?;
let files = enc.named(doc, &default_name(doc, f.extensions[0]));
let (main, linked) = files.split_at(enc.files.len());
// Text formats come back as text; an SVG in UTF-16 or ISO 8859-1 also as its bytes.
@@ -53,8 +60,15 @@ pub(super) fn export(s: &mut Session, p: &Value) -> Result<Value> {
let f = writable("document.export", str_param(p, "format"), path)?;
let expanded = expand_presets(s, "document.export", p)?;
let p = with_black_output(s, &expanded);
let doc = &*source(s, f, &p, "document.export")?;
let enc = encode_all(doc, f.id, &p)?;
let (doc, display_doc_title) = source(s, f, &p, "document.export")?;
let doc = &*doc;
let mut q = p.clone();
if f.id == "pdf"
&& let Some(o) = q.as_object_mut()
{
o.insert("_displayDocTitle".into(), json!(display_doc_title));
}
let enc = encode_all(doc, f.id, &q)?;
write_encoded(path, &default_name(doc, f.extensions[0]), doc, &enc, json!({ "format": f.id, "warnings": enc.warnings }))
}
@@ -154,13 +168,16 @@ fn expand_presets<'a>(s: &Session, cmd: &str, p: &'a Value) -> Result<Cow<'a, Va
/// The document an export of `f` writes: the active one (see [`export_source`]), or for text
/// with `selectionOnly` the selected objects alone.
fn source<'a>(s: &'a mut Session, f: &Format, p: &Value, cmd: &str) -> Result<Cow<'a, Document>> {
fn source<'a>(s: &'a mut Session, f: &Format, p: &Value, cmd: &str) -> Result<(Cow<'a, Document>, bool)> {
if f.id == "txt" && bool_or(p, "selectionOnly", false) {
return Ok(Cow::Owned(selection(s, cmd)?.0));
let doc = selection(s, cmd)?.0;
let display_doc_title = super::has_own_title(&doc);
return Ok((Cow::Owned(doc), display_doc_title));
}
let st = s.doc()?;
let doc = export_source(st, p)?;
Ok(super::titled_for_export(&doc, st.path.as_deref(), f.id).map_or(doc, Cow::Owned))
let display_doc_title = super::has_own_title(&doc);
Ok((super::titled_for_export(&doc, st.path.as_deref(), f.id).map_or(doc, Cow::Owned), display_doc_title))
}
/// The selected objects (not on template layers) alone on one layer, with one artboard: their
+5 -2
View File
@@ -871,9 +871,12 @@ pub fn file_stem(name: &str) -> String {
/// document that only has the Untitled-N name New gave it is titled after its file, as its tab is
/// (the title PDF, PNG and SVG metadata carry). A title of its own stays, and native files keep
/// the stored title.
pub fn has_own_title(doc: &vectorcraft_doc::Document) -> bool {
!doc.title.strip_prefix("Untitled-").is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit()))
}
pub fn titled_for_export(doc: &vectorcraft_doc::Document, path: Option<&str>, format: &str) -> Option<vectorcraft_doc::Document> {
let untitled = doc.title.strip_prefix("Untitled-").is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit()));
let path = path.filter(|_| untitled && !matches!(format, "vectorcraft" | "template" | "ai"))?;
let path = path.filter(|_| !has_own_title(doc) && !matches!(format, "vectorcraft" | "template" | "ai"))?;
let mut d = doc.clone();
d.title = file_stem(path);
Some(d)
+14 -2
View File
@@ -243,7 +243,14 @@ pub fn options(cmd: &str, doc: &Document, p: &Value) -> Result<PdfOptions> {
let pick = if p.is_object() { ArtboardPick::deserialize(p).map_err(|e| bad(cmd, format!("PDF options: {e}")))? } else { ArtboardPick::default() };
let artboards = pick.resolve(doc.artboards.len()).map_err(|e| bad(cmd, e))?;
let now = vectorcraft_doc::metadata::output_time();
Ok(PdfOptions { settings: settings(cmd, p)?, artboards, created: doc.metadata.created.or(now), modified: now, ..Default::default() })
Ok(PdfOptions {
settings: settings(cmd, p)?,
artboards,
display_doc_title: bool_or(p, "_displayDocTitle", super::has_own_title(doc)),
created: doc.metadata.created.or(now),
modified: now,
..Default::default()
})
}
/// Why a PDF of some artboards carries no editing data.
@@ -387,8 +394,13 @@ fn export_pdf(s: &mut Session, p: &Value) -> Result<Value> {
let expanded = expand_preset(s, C, p)?;
let p = &*expanded;
let st = s.doc()?;
let display_doc_title = super::has_own_title(&st.doc);
let titled = super::titled_for_export(&st.doc, st.path.as_deref(), "pdf");
let (bytes, warnings) = encode(C, titled.as_ref().unwrap_or(&st.doc), p)?;
let mut q = p.clone();
if let Some(o) = q.as_object_mut() {
o.insert("_displayDocTitle".into(), json!(display_doc_title));
}
let (bytes, warnings) = encode(C, titled.as_ref().unwrap_or(&st.doc), &q)?;
write_or_return(str_param(p, "path"), &bytes, json!({ "warnings": warnings }))
}