Skip to content

PDF/X 印刷生产

PDF/X(ISO 15930)是可靠交换可印刷 PDF 文件的标准。PDF Oxide 可校验所有主要的 PDF/X 级别,检查页面框、色彩空间、透明度、ICC 配置文件和输出意图。

绑定支持情况。 PDF/X 校验在 Python(doc.validate_pdf_x(level))、Rust(validate_pdf_x + PdfXValidator 构建器)和 Go(doc.ValidatePdfX(level))中提供。WASM 和 C# 尚未暴露 PDF/X 校验——请使用 Rust CLI(pdf-oxide validate --pdfx 4 doc.pdf)或通过受支持的某个绑定来调用。

支持的级别

级别 标准 透明度 RGB 图层 外部 ICC 外部图形
X-1a:2001 ISO 15930-1
X-1a:2003 ISO 15930-4
X-3:2002 ISO 15930-3
X-3:2003 ISO 15930-6
X-4 ISO 15930-7
X-4p ISO 15930-7
X-5g ISO 15930-8
X-5n ISO 15930-8
X-5pg ISO 15930-8
X-6 ISO 15930-9
X-6n ISO 15930-9
X-6p ISO 15930-9

PDF/X-1a 限制最为严格:仅限 CMYK,不允许透明度,不允许图层。PDF/X-4 是当今最常用的现代级别,允许带 ICC 配置文件的透明度和 RGB。

快速校验

from pdf_oxide import PdfDocument

doc = PdfDocument("document.pdf")
result = doc.validate_pdf_x("4")
print(f"Valid: {result.valid}")
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::pdf_x::{validate_pdf_x, PdfXLevel};

let mut doc = PdfDocument::open("print-ready.pdf")?;
let result = validate_pdf_x(&mut doc, PdfXLevel::X4)?;

if result.has_errors() {
    println!("Not PDF/X-4 compliant ({} errors):", result.errors.len());
    for error in &result.errors {
        println!("  [{}] {} (clause {})",
            error.code, error.message,
            error.clause.as_deref().unwrap_or("n/a"));
    }
} else {
    println!("Document is PDF/X-4 compliant");
}
doc, _ := pdfoxide.Open("print-ready.pdf")
defer doc.Close()

// Level encoding: 0 = X-1a:2001, 1 = X-1a:2003, 2 = X-3:2002, 3 = X-3:2003, 4 = X-4, ...
valid, errs, err := doc.ValidatePdfX(4) // PDF/X-4
if err != nil { log.Fatal(err) }

if valid {
    fmt.Println("Document is PDF/X-4 compliant")
} else {
    fmt.Printf("Not PDF/X-4 compliant (%d errors):\n", len(errs))
    for _, e := range errs {
        fmt.Printf("  %s\n", e)
    }
}

校验器 API

PdfXValidator 构建器用于配置一次校验运行:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::pdf_x::{PdfXValidator, PdfXLevel};

let mut doc = PdfDocument::open("artwork.pdf")?;

let result = PdfXValidator::new(PdfXLevel::X1a2001)
    .stop_on_first_error(false)
    .include_warnings(true)
    .validate(&mut doc)?;

println!("Errors: {}", result.errors.len());
println!("Warnings: {}", result.warnings.len());
println!("Total issues: {}", result.total_issues());

校验内容

XMP 标识

校验器确认 XMP 元数据声明了正确的 PDF/X 版本:

  • pdfxid:GTS_PDFXVersion 必须与目标级别匹配
  • 声明的版本会与目标级别的 gts_pdfx_version() 进行比对

页面框关系

PDF/X 要求页面框之间具有特定的嵌套关系:

TrimBox <= BleedBox <= MediaBox
ArtBox  <= MediaBox

校验器会检查每一页,以确保:

  • TrimBox 存在(所有 PDF/X 级别均要求)
  • TrimBox 包含在 BleedBox 之内(如果定义了 BleedBox)
  • BleedBox 包含在 MediaBox 之内
  • ArtBox 包含在 MediaBox 之内(如果定义了 ArtBox)
  • 为浮点数取整保留 0.01 点的容差

透明度检测

对于 PDF/X-1a 和 PDF/X-3,不允许使用任何透明度。校验器会检查:

  • ExtGState 字典中的 SMask(必须为 /None 或不存在)
  • CA(描边不透明度)必须等于 1.0
  • ca(填充不透明度)必须等于 1.0
  • BM(混合模式)必须为 NormalCompatible

PDF/X-4 及更高级别允许使用透明度。

色彩空间校验

校验器会检查设备相关色彩的使用情况:

  • DeviceRGB 在 PDF/X-1a 中不被允许(仅限 CMYK)
  • 在更严格的级别中,未配合输出意图使用的 DeviceRGBDeviceCMYKDeviceGray 会触发错误
  • 会扫描页面内容流中的色彩运算符 rgRGkKgG

ICC 配置文件校验

对于 ICCBased 色彩空间,校验器会检查:

  • 配置文件流包含必需的 /N(组件数量)条目
  • /N 的值与预期的色彩空间维度匹配(灰度为 1,RGB 为 3,CMYK 为 4)
  • 配置文件数据存在且非空

输出意图

PDF/X 要求提供一个描述预期印刷条件的输出意图:

  • 文档目录中必须存在 /OutputIntents 数组
  • 至少需要一个子类型为 GTS_PDFX 的条目
  • 输出意图应引用一个 ICC 配置文件或已注册的印刷条件

XValidationResult

pub struct XValidationResult {
    pub level: PdfXLevel,
    pub errors: Vec<XComplianceError>,
    pub warnings: Vec<XComplianceError>,
    pub stats: XValidationStats,
}

XComplianceError

pub struct XComplianceError {
    pub code: XErrorCode,
    pub message: String,
    pub severity: XSeverity,
    pub page: Option<usize>,
    pub object_id: Option<u32>,
    pub clause: Option<String>,
}

错误中包含发现违规之处的页码和对象 ID,便于在源文件中直接定位并修复问题。

XErrorCode 类别

XErrorCode 枚举包含 40 多个按类别组织的具体错误代码:

元数据MissingOutputIntentInvalidGtsPdfxVersionMissingXmpIdentification

页面框MissingTrimBoxTrimBoxOutsideBleedBoxBleedBoxOutsideMediaBoxArtBoxOutsideMediaBox

透明度TransparencyNotAllowedInvalidBlendModeInvalidSMaskInvalidOpacity

色彩DeviceRgbNotAllowedDeviceDependentColorWithoutIntentInvalidIccProfileMissingIccComponents

内容ExternalContentNotAllowedEncryptionNotAllowedJavaScriptNotAllowed

PdfXLevel 方法

方法 返回值 描述
iso_standard() &str ISO 标准编号(例如 "ISO 15930-7"
required_pdf_version() &str 最低 PDF 版本(例如 "1.6"
allows_transparency() bool 是否允许透明度组
allows_rgb() bool 是否允许 RGB 色彩空间
allows_layers() bool 是否允许可选内容组
allows_external_icc() bool 是否允许外部 ICC 配置文件
allows_external_graphics() bool 是否允许外部图形引用
gts_pdfx_version() &str 预期的 GTS_PDFXVersion
xmp_version() &str 预期的 XMP 版本标识符
from_gts_version(version) Option<Self> 从 GTS 版本字符串解析级别

实际示例:印前检查

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::pdf_x::{validate_pdf_x, PdfXLevel, XSeverity};

let mut doc = PdfDocument::open("magazine-cover.pdf")?;
let result = validate_pdf_x(&mut doc, PdfXLevel::X4)?;

println!("=== PDF/X-4 Prepress Report ===");
println!("Status: {}", if result.has_errors() { "REJECT" } else { "ACCEPT" });

// Group errors by severity
let critical: Vec<_> = result.errors.iter()
    .filter(|e| e.is_error())
    .collect();
let advisory: Vec<_> = result.warnings.iter().collect();

if !critical.is_empty() {
    println!("\nCritical ({}):", critical.len());
    for e in &critical {
        let page_str = e.page
            .map(|p| format!("page {}", p + 1))
            .unwrap_or_else(|| "document".into());
        println!("  [{}] {} ({})", e.code, e.message, page_str);
    }
}

if !advisory.is_empty() {
    println!("\nAdvisory ({}):", advisory.len());
    for w in &advisory {
        println!("  [{}] {}", w.code, w.message);
    }
}

后续步骤