Files
vectorcraft/crates/pdf/src/presets.rs
T
00xJ0 91107c89d2 PDF: a Document CMYK destination; Press Quality converts to it in RGB documents too (#3012 review)
A blank destination is the document's own profile, so in an RGB document Press Quality (Preserve
Numbers, blank) converted CMYK colours and images to RGB. Output › Destination can now be
DOCUMENT_CMYK, the CMYK profile of the colour settings in effect whatever the document's colour
mode (Illustrator's "Document CMYK"); Press Quality uses it, and the Save PDF dialog lists it after
Document profile. Test: in an RGB document a CMYK image keeps its inks and an RGB image comes out
CMYK.
2026-10-21 16:55:17 +07:00

112 lines
5.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.
//! PDF presets: named [`PdfSettings`]. The built-in ones are generated here (the app default,
//! which keeps the document editable, plus presets for print, press, small files and the PDF/X
//! standards); the user's own live in the app's preferences.
use serde::{Deserialize, Serialize};
use crate::{
BleedSettings, ColorConversion, Compatibility, CompressionSettings, DOCUMENT_CMYK, Downsample, ImageCodec, ImageCompression, JpegQuality,
MonoCodec, MonoCompression, OutputSettings, PdfSettings, Standard,
};
/// The built-in preset every PDF export starts from.
pub const DEFAULT_PRESET: &str = "VectorCraft Default";
/// A named set of PDF settings: a built-in preset or one the user saved.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PdfPreset {
pub name: String,
/// What the preset is for.
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default)]
pub settings: PdfSettings,
}
/// Colour and greyscale images resampled (bicubic) to `ppi` above `above` ppi, compressed with
/// `codec`.
fn images(ppi: f64, above: f64, codec: ImageCodec, quality: JpegQuality) -> ImageCompression {
ImageCompression { downsample: Downsample::Bicubic, ppi, above_ppi: above, compression: codec, quality }
}
/// Compression with the same settings for colour and greyscale images, and CCITT Group 4
/// monochrome images resampled to `mono_ppi` above 1.5 × that.
fn compression(img: ImageCompression, mono_ppi: f64) -> CompressionSettings {
let mono = MonoCompression { downsample: Downsample::Bicubic, ppi: mono_ppi, above_ppi: mono_ppi * 1.5, compression: MonoCodec::CcittG4 };
CompressionSettings { color: img.clone(), gray: img, mono, compress_text: true }
}
/// Settings for print: PDF 1.6, images kept at 300 ppi, the document's bleed when `bleed`.
fn print(codec: ImageCodec, bleed: bool) -> PdfSettings {
PdfSettings {
compatibility: Compatibility::Pdf16,
compression: compression(images(300.0, 450.0, codec, JpegQuality::Maximum), 1200.0),
bleed: BleedSettings { use_document: bleed, ..Default::default() },
..Default::default()
}
}
/// A PDF/X preset: print settings for `standard` at PDF version `compatibility`.
fn pdf_x(standard: Standard, compatibility: Compatibility) -> PdfSettings {
PdfSettings { standard, compatibility, ..print(ImageCodec::Auto, true) }
}
/// Every built-in preset, the app default first.
pub fn builtin_presets() -> Vec<PdfPreset> {
let preset = |name: &str, description: &str, settings| PdfPreset { name: name.into(), description: description.into(), settings };
vec![
preset(
DEFAULT_PRESET,
"Keeps the document editable: VectorCraft reopens the PDF with nothing lost. For files you'll edit again.",
PdfSettings { preserve_editing: true, ..Default::default() },
),
preset("High Quality Print", "For desktop printers and proofs: images stay at print resolution.", print(ImageCodec::Auto, false)),
// Converted to Document CMYK, the numbers of colours already in it kept: RGB colours and
// images come out CMYK, in an RGB document too, as a press needs (#2950). A printer's published settings for
// the [Press Quality] preset list the same Output: Convert to Destination (Preserve
// Numbers), Document CMYK, no profiles included
// (https://postmediasolutions.com/hubfs/Website/Client%20Resources/PostmediaPrintPDFSpecSheet.pdf).
preset(
"Press Quality",
"For commercial printing: high-resolution images compressed losslessly, the document's bleed, and colours converted to the CMYK profile in effect (Document CMYK), keeping the numbers of colours already in it.",
PdfSettings {
output: OutputSettings { conversion: ColorConversion::PreserveNumbers, destination: DOCUMENT_CMYK.into(), ..Default::default() },
..print(ImageCodec::Zip, true)
},
),
preset(
"Smallest File Size",
"For screens, email and the web: images resampled to 100 ppi and compressed.",
PdfSettings {
compatibility: Compatibility::Pdf16,
fast_web_view: true,
compression: compression(images(100.0, 150.0, ImageCodec::Jpeg, JpegQuality::Medium), 300.0),
..Default::default()
},
),
preset(
"PDF/X-1a:2001",
"Print exchange with CMYK and spot colours only: transparency flattened, fonts embedded.",
pdf_x(Standard::PdfX1a, Compatibility::Pdf13),
),
preset(
"PDF/X-3:2002",
"Print exchange allowing colour-managed colours: transparency flattened, fonts embedded.",
pdf_x(Standard::PdfX3, Compatibility::Pdf13),
),
preset(
"PDF/X-4:2010",
"Print exchange keeping live transparency and layers, colour-managed colours and embedded fonts.",
pdf_x(Standard::PdfX4, Compatibility::Pdf16),
),
]
}
/// The built-in preset `name` names (any case; `default` is the app default).
pub fn builtin_preset(name: &str) -> Option<PdfPreset> {
let name = name.trim();
let name = if name.eq_ignore_ascii_case("default") { DEFAULT_PRESET } else { name };
builtin_presets().into_iter().find(|p| p.name.eq_ignore_ascii_case(name))
}