Files
vectorcraft/crates/pdf/src/marks.rs
T
dotCooCoo a8a1c82a43 PDF export: warn when a PDF/X file leaves out the document's bleed
Choosing a PDF/X standard without a PDF/X preset writes a file with no bleed
(BleedBox = TrimBox) even when Document Setup sets one, and the export gave no
warning about it. The export now warns when a PDF/X file has no bleed on a side
where the document's bleed has one. The warning comes ahead of the flattening
note, because the status bar shows only the first warning. The code adds a
warning and does not change what is written.

These cases do not warn: the PDF/X presets, Use document bleed settings, a
nonzero bleed on every side the document sets, a document with no bleed, files
that aren't PDF/X files, and Export for Screens rows whose artboards Include
Bleed grows.

The warning has a row in every catalog. The Summary's warning and error rows in
the Save PDF and Print dialogs now go through the catalog, so they show its
translations.
2026-11-08 11:42:47 +07:00

112 lines
4.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Marks and Bleeds: the boxes of each exported page and its printer's marks. The marks' geometry
//! is the shared [`PrinterMarks`] (print draws the same marks); here it gets the page's bleed,
//! spot inks and page information.
use vectorcraft_color::Paint;
use vectorcraft_doc::marks::{MarkStyle, PrinterMarks, outset};
use vectorcraft_doc::setup::{MAX_BLEED, bleed_in_range};
use vectorcraft_doc::{Document, Node, NodeId};
use vectorcraft_geom::Rect;
use crate::{BleedSettings, MarkKind, MarkSettings, PdfSettings};
impl MarkSettings {
/// These settings as the shared mark geometry.
pub fn printer_marks(&self) -> PrinterMarks {
PrinterMarks {
trim: self.trim,
registration: self.registration,
color_bars: self.color_bars,
page_info: self.page_info,
style: match self.kind {
MarkKind::Roman => MarkStyle::Roman,
MarkKind::Japanese => MarkStyle::Japanese,
},
weight: self.weight,
offset: self.offset,
}
}
}
impl PdfSettings {
/// The bleed of `doc`'s pages, `[top, bottom, left, right]` in points: the document's (Document
/// Setup; one read from a file is kept to 0–[`MAX_BLEED`]) with Use Document Bleed, else the
/// settings' own.
pub fn bleed_of(&self, doc: &Document) -> [f64; 4] {
self.bleed.of(doc)
}
/// A PDF/X file of `doc` has no bleed on a side where the document's bleed (Document Setup) has
/// one.
pub fn leaves_out_bleed(&self, doc: &Document) -> bool {
self.standard.is_pdfx()
&& self.bleed_of(doc).into_iter().zip(bleed_in_range(doc.setup.bleed)).any(|(page, document)| page <= 0.0 && document > 0.0)
}
}
impl BleedSettings {
/// The bleed of `doc`'s pages, `[top, bottom, left, right]` in points: the document's with
/// [`Self::use_document`] (kept to 0–[`MAX_BLEED`]), else these values.
pub fn of(&self, doc: &Document) -> [f64; 4] {
if self.use_document { doc.setup.bleed.map(|b| if b.is_finite() { b.clamp(0.0, MAX_BLEED) } else { 0.0 }) } else { self.values() }
}
}
/// The boxes of one page, in document coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct PageBoxes {
/// The artboard: the finished page.
pub trim: Rect,
/// The trim box grown by the bleed: the art it holds is kept.
pub bleed: Rect,
/// The sheet: the bleed box, grown to hold the printer's marks.
pub media: Rect,
}
impl PageBoxes {
pub fn new(trim: Rect, bleed: [f64; 4], marks: &PrinterMarks) -> Self {
let reach = marks.reach(bleed);
let most: [f64; 4] = std::array::from_fn(|i| bleed[i].max(reach[i]));
Self { trim, bleed: outset(trim, bleed), media: outset(trim, most) }
}
}
/// The page information printed under the marks: the file's title, the artboard (its name and
/// number) and the date and time of the export (UTC).
pub(crate) fn page_info(doc: &Document, title: &str, artboard: usize, created: Option<i64>) -> String {
page_info_of(doc, title, Some(artboard), created)
}
/// [`page_info`] of a page that may show no artboard (print with artboards ignored).
pub(crate) fn page_info_of(doc: &Document, title: &str, artboard: Option<usize>, created: Option<i64>) -> String {
let title = if title.trim().is_empty() { "Untitled" } else { title.trim() };
let mut info = title.to_string();
if let Some(i) = artboard {
let name = doc.artboards.get(i).map_or("", |a| a.name.as_str());
info.push_str(&format!(" · {name} ({} of {})", i + 1, doc.artboards.len()));
}
if let Some(t) = created {
let [y, mo, d, h, mi, _] = vectorcraft_doc::metadata::civil(t);
info.push_str(&format!(" · {y:04}-{mo:02}-{d:02} {h:02}:{mi:02} UTC"));
}
info
}
/// The marks of a page as art (`None` without marks): its spot inks get colour bar patches.
pub(crate) fn art(doc: &Document, marks: &PrinterMarks, boxes: &PageBoxes, bleed: [f64; 4], info: &str) -> Option<Node> {
if !marks.any() {
return None;
}
let spots: Vec<Paint> = doc
.spot_names()
.into_iter()
.filter_map(|name| doc.global_color(&name).map(|color| Paint::Solid { color, swatch: Some(name), tint: 1.0 }))
.collect();
// The marks are drawn straight from this art, so their ids don't matter.
let mut next = 0;
Some(marks.art(boxes.trim, bleed, &spots, info, &mut || {
next += 1;
NodeId(next)
}))
}