mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-14 19:27:07 -04:00
PDF/X-4: warn when a transparency group still blends in RGB
The CMYK rewrite matches krilla's exact output; if that ever changes, the export says so instead of silently writing RGB groups. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
0ce21b476c
commit
e7ad37517e
4 files changed
+16
-3
No files matched your search
@@ -888,12 +888,14 @@ mod print_group_tests {
|
||||
let t = text(&mut s);
|
||||
assert!(t.contains("/S/Transparency/I true/CS/DeviceCMYK>>"), "CMYK group");
|
||||
assert!(!t.contains("DeviceRGB"), "no RGB left");
|
||||
assert!(!designcraft_pdf::has_rgb_groups(t.as_bytes()));
|
||||
// The file still reads, with the same page.
|
||||
let r = s.execute("file.exportPdf", &json!({})).unwrap();
|
||||
let bytes = base64_decode(r["base64"].as_str().unwrap());
|
||||
assert_eq!(hayro_syntax::Pdf::new(bytes).unwrap().pages().len(), 1);
|
||||
// An RGB blend space keeps RGB groups.
|
||||
s.execute("edit.transparencyBlendSpace", &json!({"space": "rgb"})).unwrap();
|
||||
assert!(text(&mut s).contains("/CS/DeviceRGB"));
|
||||
let t = text(&mut s);
|
||||
assert!(t.contains("/CS/DeviceRGB") && designcraft_pdf::has_rgb_groups(t.as_bytes()));
|
||||
}
|
||||
}
|
||||
@@ -205,10 +205,14 @@ pub fn export_pdf_with_report(doc: &Document, cache: &Cache, opts: &PdfOptions)
|
||||
ex.check_placed_versions()?;
|
||||
let mut bytes = pdf.finish().map_err(|e| PdfError::Write(format!("{e:?}")))?;
|
||||
// Transparency blends in the document's blend space: CMYK for print (and always in PDF/X).
|
||||
let mut warnings = ex.warnings;
|
||||
if !ex.rgb_only && (doc.settings.blend_space == designcraft_doc::BlendSpace::Cmyk || opts.standard == Standard::PdfX4) {
|
||||
crate::pdfx::cmyk_group_spaces(&mut bytes);
|
||||
// The rewrite matches krilla's exact output; say so if a group got past it.
|
||||
if opts.standard == Standard::PdfX4 && crate::pdfx::has_rgb_groups(&bytes) {
|
||||
warnings.push("PDF/X-4: some transparency groups still blend in RGB".into());
|
||||
}
|
||||
}
|
||||
let mut warnings = ex.warnings;
|
||||
// Form fields (Buttons and Forms) and, for interactive PDF, video and sound; not in PDF/X.
|
||||
let fields = crate::forms::collect(doc, &sheets);
|
||||
let media = if opts.media { crate::forms::collect_media(doc, &sheets) } else { Vec::new() };
|
||||
|
||||
@@ -35,7 +35,7 @@ mod forms;
|
||||
mod pdfx;
|
||||
mod transitions;
|
||||
pub use export::{BookletKind, BookletOptions, booklet_pairs, export_booklet, export_pdf, export_pdf_with_report, merge_pdfs, sheet_spreads};
|
||||
pub use pdfx::{check_pdfx4, cmyk_group_spaces, make_pdfx4};
|
||||
pub use pdfx::{check_pdfx4, cmyk_group_spaces, has_rgb_groups, make_pdfx4};
|
||||
pub use transitions::{add_blend_space, add_catalog_entries, add_page_entries, add_transitions};
|
||||
|
||||
/// PDF standard to target.
|
||||
|
||||
@@ -125,6 +125,13 @@ pub fn make_pdfx4(pdf: &[u8], title: &str) -> Option<Vec<u8>> {
|
||||
/// DeviceCMYK in place and at the same length (the optional `/Type/Group` gives the room), so
|
||||
/// every cross-reference offset stays valid. Only object dictionaries are touched, never stream
|
||||
/// data. Returns how many groups changed.
|
||||
/// Whether a transparency group dictionary still names DeviceRGB as its blending space.
|
||||
pub fn has_rgb_groups(pdf: &[u8]) -> bool {
|
||||
pdf.windows(b"/CS/DeviceRGB".len()).enumerate().any(|(i, w)| {
|
||||
w == b"/CS/DeviceRGB" && pdf.get(i.saturating_sub(64)..i).is_some_and(|before| before.windows(15).any(|b| b == b"/S/Transparency"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn cmyk_group_spaces(pdf: &mut [u8]) -> usize {
|
||||
const FORMS: [(&[u8], &[u8]); 2] = [
|
||||
(b"/Group<</Type/Group/S/Transparency/I true/CS/DeviceRGB>>", b"/Group<</S/Transparency/I true/CS/DeviceCMYK>>"),
|
||||
|
||||
Reference in new issue
Block a user