PDF/X Print Production
PDF/X(ISO 15930)는 인쇄용 PDF 파일의 안정적인 교환을 위한 표준입니다. PDF Oxide는 페이지 박스, 색 공간, 투명도, ICC 프로필, 출력 의도를 검사하여 모든 주요 PDF/X 레벨을 검증합니다.
지원 레벨
| Level | Standard | Transparency | RGB | Layers | External ICC | External Graphics |
|---|---|---|---|---|---|---|
| X-1a:2001 | ISO 15930-1 | No | No | No | No | No |
| X-1a:2003 | ISO 15930-4 | No | No | No | No | No |
| X-3:2002 | ISO 15930-3 | No | Yes | No | No | No |
| X-3:2003 | ISO 15930-6 | No | Yes | No | No | No |
| X-4 | ISO 15930-7 | Yes | Yes | Yes | No | No |
| X-4p | ISO 15930-7 | Yes | Yes | Yes | Yes | No |
| X-5g | ISO 15930-8 | Yes | Yes | Yes | No | Yes |
| X-5n | ISO 15930-8 | Yes | Yes | Yes | No | Yes |
| X-5pg | ISO 15930-8 | Yes | Yes | Yes | Yes | Yes |
| X-6 | ISO 15930-9 | Yes | Yes | Yes | No | No |
| X-6n | ISO 15930-9 | Yes | Yes | Yes | No | Yes |
| X-6p | ISO 15930-9 | Yes | Yes | Yes | Yes | No |
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");
}
Validator API
The PdfXValidator builder configures the validation run:
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());
What Gets Checked
XMP Identification
The validator confirms that XMP metadata declares the correct PDF/X version:
pdfxid:GTS_PDFXVersionmust match the target level- The declared version is compared against the
gts_pdfx_version()for the target level
Page Box Relationships
PDF/X requires specific nesting of page boxes:
TrimBox <= BleedBox <= MediaBox
ArtBox <= MediaBox
The validator checks every page to ensure:
- TrimBox is present (required by all PDF/X levels)
- TrimBox is contained within BleedBox (if BleedBox is defined)
- BleedBox is contained within MediaBox
- ArtBox is contained within MediaBox (if ArtBox is defined)
- Tolerance of 0.01 points for floating-point rounding
Transparency Detection
For PDF/X-1a and PDF/X-3, 투명도는 허용되지 않습니다. The validator checks:
- SMask in ExtGState dictionaries (must be
/Noneor absent) - CA (stroke opacity) must equal 1.0
- ca (fill opacity) must equal 1.0
- BM (blend mode) must be
NormalorCompatible
PDF/X-4 and later levels permit transparency.
Color Space Validation
The validator checks for device-dependent color usage:
- DeviceRGB is not allowed in PDF/X-1a (CMYK-only)
- DeviceRGB, DeviceCMYK, and DeviceGray used without an output intent trigger errors in stricter levels
- Color operators
rg,RG,k,K,g,Gin page content streams are scanned
ICC Profile Validation
For ICCBased color spaces, the validator checks:
- The profile stream contains the required
/N(number of components) entry - The
/Nvalue matches the expected color space dimension (1 for gray, 3 for RGB, 4 for CMYK) - The profile data is present and non-empty
Output Intent
PDF/X requires an output intent that describes the intended print condition:
/OutputIntentsarray must be present in the document catalog- At least one entry with subtype
GTS_PDFXis required - The output intent should reference an ICC profile or a registered print condition
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>,
}
Errors include the page number and object ID where the violation was found, making it straightforward to locate and fix issues in the source file.
XErrorCode Categories
The XErrorCode enum contains 40+ specific error codes organized by category:
Metadata: MissingOutputIntent, InvalidGtsPdfxVersion, MissingXmpIdentification
Page boxes: MissingTrimBox, TrimBoxOutsideBleedBox, BleedBoxOutsideMediaBox, ArtBoxOutsideMediaBox
Transparency: TransparencyNotAllowed, InvalidBlendMode, InvalidSMask, InvalidOpacity
Color: DeviceRgbNotAllowed, DeviceDependentColorWithoutIntent, InvalidIccProfile, MissingIccComponents
Content: ExternalContentNotAllowed, EncryptionNotAllowed, JavaScriptNotAllowed
PdfXLevel 메서드s
| 메서드 | Return | 설명 |
|---|---|---|
iso_standard() |
&str |
ISO standard number (e.g., "ISO 15930-7") |
required_pdf_version() |
&str |
Minimum PDF version (e.g., "1.6") |
allows_transparency() |
bool |
Whether transparency groups are permitted |
allows_rgb() |
bool |
Whether RGB color space is permitted |
allows_layers() |
bool |
Whether optional content groups are permitted |
allows_external_icc() |
bool |
Whether external ICC profiles are permitted |
allows_external_graphics() |
bool |
Whether external graphics references are permitted |
gts_pdfx_version() |
&str |
Expected GTS_PDFXVersion value |
xmp_version() |
&str |
Expected XMP version identifier |
from_gts_version(version) |
Option<Self> |
Parse level from a GTS version string |
Practical Example: Prepress Check
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);
}
}
다음 단계
- PDF/A Validation – archival compliance
- PDF/UA Accessibility – accessibility validation
- API Reference – complete Rust API