mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 09:59:47 -06:00
Fix PDF title display provenance
This commit is contained in:
committed by
bflatastic
parent
5e9df83dd4
commit
d548b4ff74
@@ -73,6 +73,7 @@ fn export_with_report_inner(doc: &Document, opts: &PdfOptions, left_out: &mut Ha
|
||||
let now = vectorcraft_doc::metadata::output_time();
|
||||
let created_at = opts.created.or(now);
|
||||
crate::pdfx::require_date(set.standard, created_at)?;
|
||||
let display_doc_title = opts.display_doc_title || opts.title.as_deref().is_some_and(|title| !title.trim().is_empty());
|
||||
let mut w = Writer::new(doc, set, &title, created_at, doc.color_mode == vectorcraft_doc::ColorMode::Cmyk)?;
|
||||
// Preserve Editing: the native document as an embedded file (`check` refused PDF/A with it).
|
||||
let mut warnings = set.warnings();
|
||||
@@ -132,7 +133,7 @@ fn export_with_report_inner(doc: &Document, opts: &PdfOptions, left_out: &mut Ha
|
||||
vectorcraft_doc::cancel::check().map_err(|_| PdfError::Cancelled)?;
|
||||
let (layers, overprinted, invisible) = (ex.layers, ex.overprinted, ex.invisible);
|
||||
w.absorb(ex);
|
||||
let (bytes, more) = w.finish(left_out)?;
|
||||
let (bytes, more) = w.finish(left_out, display_doc_title)?;
|
||||
let bytes = crate::forms::finish(bytes, doc, set, layers, overprinted, invisible)?;
|
||||
// The writer gives the file its creation date as its modification date too.
|
||||
let bytes = match opts.modified.filter(|m| Some(*m) != created_at) {
|
||||
@@ -233,8 +234,6 @@ pub(crate) struct Writer {
|
||||
rgb_in_cmyk: RgbInCmyk,
|
||||
/// A PDF 1.3 file ([`crate::PdfSettings::pdf13`]): flat, without page groups.
|
||||
pdf13: bool,
|
||||
/// The PDF has a document title, so viewers should display it instead of the file name.
|
||||
display_doc_title: bool,
|
||||
/// The document's images the exporters wrote, by key, gathered from the exporters
|
||||
/// ([`Self::absorb`]): [`Self::finish`] finds the key of an image the writer couldn't decode.
|
||||
images: Vec<(String, Image)>,
|
||||
@@ -319,7 +318,6 @@ impl Writer {
|
||||
warnings,
|
||||
rgb_in_cmyk: RgbInCmyk::default(),
|
||||
pdf13: set.pdf13(),
|
||||
display_doc_title: !title.trim().is_empty(),
|
||||
images: vec![],
|
||||
})
|
||||
}
|
||||
@@ -428,7 +426,7 @@ impl Writer {
|
||||
/// standard) and the warnings of its drawing. PDF/X-1a spot colours keep their CMYK
|
||||
/// alternates. When the writer couldn't decode one of the images, its key is added to
|
||||
/// `left_out` ([`leaving_out_undecodable`]) and the writer's error is returned.
|
||||
pub(crate) fn finish(mut self, left_out: &mut HashSet<String>) -> Result<(Vec<u8>, Vec<String>), PdfError> {
|
||||
pub(crate) fn finish(mut self, left_out: &mut HashSet<String>, display_doc_title: bool) -> Result<(Vec<u8>, Vec<String>), PdfError> {
|
||||
let images = std::mem::take(&mut self.images);
|
||||
let mut bytes = self.pdf.finish().map_err(|e| {
|
||||
if let write::WriteError::Serialization(k) = &e
|
||||
@@ -443,7 +441,7 @@ impl Writer {
|
||||
}
|
||||
let lab = !self.lab_spots.is_empty() && !self.out.standard.cmyk_only();
|
||||
let bytes = if lab { crate::lab_spot::lab_alternates(bytes, &self.lab_spots) } else { bytes };
|
||||
let (bytes, more) = self.out.write_catalog(bytes, self.display_doc_title)?;
|
||||
let (bytes, more) = self.out.write_catalog(bytes, display_doc_title)?;
|
||||
self.warnings.extend(more);
|
||||
self.warnings.extend(self.rgb_in_cmyk.warning());
|
||||
Ok((crate::pdfx::finish(bytes, self.out.standard, self.pdf13)?, self.warnings))
|
||||
|
||||
@@ -94,6 +94,8 @@ pub struct PdfOptions {
|
||||
pub artboards: Option<Vec<usize>>,
|
||||
/// Document title for the metadata; `None` = the document's title.
|
||||
pub title: Option<String>,
|
||||
/// Ask PDF viewers to display the document title instead of the file name.
|
||||
pub display_doc_title: bool,
|
||||
/// Creation date as Unix seconds (UTC); `None` = now (native) / omitted (wasm). PDF/A needs a date.
|
||||
pub created: Option<i64>,
|
||||
/// Modification date as Unix seconds (UTC); `None` = the creation date.
|
||||
|
||||
@@ -426,7 +426,7 @@ fn print_inner(doc: &Document, opts: &PrintOptions, left_out: &mut HashSet<Strin
|
||||
for ex in exporters {
|
||||
w.absorb(ex);
|
||||
}
|
||||
let (bytes, more) = w.finish(left_out)?;
|
||||
let (bytes, more) = w.finish(left_out, false)?;
|
||||
let bytes = crate::forms::finish(bytes, doc, &pdf, false, overprinted, invisible)?;
|
||||
let mut warnings = plan.warnings;
|
||||
for m in more {
|
||||
|
||||
@@ -902,11 +902,11 @@ fn empty_and_populated_file_info_preserve_key_presence() {
|
||||
for key in ["/Title", "/Author", "/Keywords", "<dc:title>", "<dc:creator>", "<pdf:Keywords>"] {
|
||||
assert!(!s.contains(key), "unexpected empty metadata {key}");
|
||||
}
|
||||
assert!(!s.contains("/DisplayDocTitle true"), "an untitled document has no title to display");
|
||||
assert!(!s.contains("/DisplayDocTitle true"), "the default export does not request displaying its metadata title");
|
||||
d.title = "Synthetic title".into();
|
||||
d.metadata.author = " Test author ".into();
|
||||
d.metadata.keywords = vec!["test keyword".into()];
|
||||
let bytes = export(&d, &PdfOptions { created: Some(1_700_000_000), ..PdfOptions::uncompressed() }).unwrap();
|
||||
let bytes = export(&d, &PdfOptions { display_doc_title: true, created: Some(1_700_000_000), ..PdfOptions::uncompressed() }).unwrap();
|
||||
let s = String::from_utf8_lossy(&bytes);
|
||||
for key in ["/Title", "/Author", "/Keywords", "/CreationDate", "<dc:title>", "<dc:creator>", "<pdf:Keywords>"] {
|
||||
assert!(s.contains(key), "missing populated metadata {key}");
|
||||
|
||||
Reference in New Issue
Block a user