Skip to content

PDF/A Validation

PDF/A(ISO 19005)는 전자 문서의 장기 보존을 위한 국제 표준입니다. PDF Oxide는 모든 주요 PDF/A 레벨을 검증하고 비준수 문서를 준수로 변환할 수 있습니다.

지원 레벨

Level Standard Structure Unicode Transparency Embedded Files
1a ISO 19005-1 필수 필수 No No
1b ISO 19005-1 No No No No
2a ISO 19005-2 필수 필수 Yes No
2b ISO 19005-2 No No Yes No
2u ISO 19005-2 No 필수 Yes No
3a ISO 19005-3 필수 필수 Yes Yes
3b ISO 19005-3 No No Yes Yes
3u ISO 19005-3 No 필수 Yes Yes

레벨 “a” (접근성)는 태그된 구조 트리와 유니코드 문자 매핑이 필요합니다. 레벨 “b” (기본)는 시각적 재현성만 필요합니다. 레벨 “u” (유니코드)는 전체 구조 트리 없이 유니코드 텍스트 매핑이 필요합니다.

빠른 검증

한 번의 호출로 확인하기 위해 편의 함수를 사용합니다:

from pdf_oxide import PdfDocument

doc = PdfDocument("document.pdf")
result = doc.validate_pdf_a("2b")
print(f"Valid: {result.valid}")
print(f"Level: {result.level}")
for error in result.errors:
    print(f"  Error: {error}")
const doc = new WasmPdfDocument(bytes);
const result = doc.validatePdfA("2b");
console.log(`Valid: ${result.valid}`);
console.log(`Errors: ${result.errors.length}`);
doc.free();
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_a, PdfALevel};

let mut doc = PdfDocument::open("archive.pdf")?;
let result = validate_pdf_a(&mut doc, PdfALevel::A1b)?;

if result.has_errors() {
    println!("Not PDF/A-1b compliant:");
    for error in &result.errors {
        println!("  [{}] {} (clause {})",
            error.code, error.message,
            error.clause.as_deref().unwrap_or("n/a"));
    }
} else {
    println!("Document is PDF/A-1b compliant");
}

Validator API

The PdfAValidator provides a builder pattern for fine-grained control:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAValidator, PdfALevel};

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

let result = PdfAValidator::new()
    .stop_on_first_error(false)
    .include_warnings(true)
    .validate(&mut doc, PdfALevel::A2b)?;

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

대상 검사

Run individual validation categories instead of the full suite:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAValidator, PdfALevel};

let mut doc = PdfDocument::open("report.pdf")?;
let validator = PdfAValidator::new();

// Check only metadata
let result = validator.check_metadata(&mut doc, PdfALevel::A1b)?;

// Check only fonts
let result = validator.check_fonts(&mut doc, PdfALevel::A1b)?;

// Check only color spaces
let result = validator.check_colors(&mut doc, PdfALevel::A1b)?;

// Check only transparency
let result = validator.check_transparency(&mut doc, PdfALevel::A2b)?;

// Check only structure tags
let result = validator.check_structure(&mut doc, PdfALevel::A1a)?;

Standalone Validators

Each validation category is also available as a standalone function for maximum flexibility:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::validators::*;
use pdf_oxide::compliance::{PdfALevel, ValidationResult};

let mut doc = PdfDocument::open("document.pdf")?;
let mut result = ValidationResult::new(PdfALevel::A1b);

// Run each validator independently
validate_xmp_metadata(&mut doc, PdfALevel::A1b, &mut result)?;
validate_fonts(&mut doc, PdfALevel::A1b, &mut result)?;
validate_colors(&mut doc, PdfALevel::A1b, &mut result)?;
validate_encryption(&mut doc, PdfALevel::A1b, &mut result)?;
validate_transparency(&mut doc, PdfALevel::A1b, &mut result)?;
validate_structure(&mut doc, PdfALevel::A1b, &mut result)?;
validate_javascript(&mut doc, PdfALevel::A1b, &mut result)?;
validate_embedded_files(&mut doc, PdfALevel::A1b, &mut result)?;
validate_annotations(&mut doc, PdfALevel::A1b, &mut result)?;

println!("Total errors: {}", result.errors.len());

검증기 요약

Function What It Checks
validate_xmp_metadata() XMP stream exists, pdfaid:part and pdfaid:conformance entries present, metadata consistency
validate_fonts() All fonts embedded, glyph widths present, Unicode mapping available (for level “a” and “u”)
validate_colors() No device-dependent color operators (rg, RG, k, K, g, G) without output intent
validate_encryption() No encryption permitted in PDF/A documents
validate_transparency() No transparency in PDF/A-1; allowed in PDF/A-2 and later
validate_structure() Tagged structure tree present with valid role mapping (required for level “a”)
validate_javascript() No JavaScript actions or triggers present
validate_embedded_files() Not allowed in PDF/A-1 or PDF/A-2; PDF/A-3 requires AFRelationship key on each file spec
validate_annotations() 해당 ISO 19005 파트에 따라 허용되는 주석 타입이 제한됩니다

ValidationResult

The ValidationResult struct contains the full outcome of a validation run:

pub struct ValidationResult {
    pub level: PdfALevel,
    pub errors: Vec<ComplianceError>,
    pub warnings: Vec<ComplianceWarning>,
    pub stats: ValidationStats,
}
Field 타입 설명
level PdfALevel 대상 준수 수준
errors Vec<ComplianceError> Blocking violations that prevent compliance
warnings Vec<ComplianceWarning> Non-blocking issues that may affect quality
stats ValidationStats Counts of pages, fonts, and objects checked

ComplianceError

pub struct ComplianceError {
    pub code: ErrorCode,
    pub message: String,
    pub location: Option<String>,
    pub clause: Option<String>,
}

The code field uses the ErrorCode enum with categories like MissingXmpMetadata, FontNotEmbedded, DeviceDependentColor, EncryptionPresent, TransparencyNotAllowed, MissingStructureTree, JavaScriptPresent, and InvalidEmbeddedFile.

ComplianceWarning

pub struct ComplianceWarning {
    pub code: WarningCode,
    pub message: String,
    pub location: Option<String>,
}

PDF/A Conversion

Convert a non-compliant document toward PDF/A compliance:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{convert_to_pdf_a, PdfALevel};

let mut doc = PdfDocument::open("input.pdf")?;
let result = convert_to_pdf_a(&mut doc, PdfALevel::A1b)?;

println!("Conversion actions taken:");
for action in &result.actions {
    println!("  - {}: {}", action.action_type, action.description);
}

if result.remaining_errors.is_empty() {
    println!("Document is now PDF/A-1b compliant");
} else {
    println!("{} issues could not be resolved automatically",
        result.remaining_errors.len());
}

변환 설정

Fine-tune the conversion process:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAConverter, PdfALevel, ConversionConfig};

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

let config = ConversionConfig::new()
    .embed_fonts(true)
    .remove_javascript(true)
    .flatten_transparency(true)
    .add_structure(true);

let result = PdfAConverter::new(PdfALevel::A2b)
    .with_config(config)
    .convert(&mut doc)?;

The converter performs these actions automatically:

  1. XMP metadata injection – adds pdfaid:part and pdfaid:conformance entries
  2. Font embedding – embeds any referenced but non-embedded fonts
  3. JavaScript removal – strips JavaScript actions and triggers
  4. Transparency flattening – renders transparent elements to opaque (PDF/A-1 only)
  5. ICC profile conversion – converts device-dependent colors to ICC-based color spaces
  6. Structure tagging – adds basic structure tags (for level “a” targets)

Workflow: Validate, Fix, Re-validate

A typical archival workflow validates, attempts automatic conversion, then re-validates:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_a, convert_to_pdf_a, PdfALevel};

let level = PdfALevel::A2b;
let mut doc = PdfDocument::open("input.pdf")?;

// Step 1: Initial validation
let result = validate_pdf_a(&mut doc, level)?;
if !result.has_errors() {
    println!("Already compliant");
    return Ok(());
}

println!("{} errors found, attempting conversion...", result.errors.len());

// Step 2: Automatic conversion
let conversion = convert_to_pdf_a(&mut doc, level)?;
println!("{} actions taken", conversion.actions.len());

// Step 3: Re-validate
let result = validate_pdf_a(&mut doc, level)?;
if result.has_errors() {
    println!("{} errors remain after conversion:", result.errors.len());
    for e in &result.errors {
        println!("  {} -- {}", e.code, e.message);
    }
} else {
    println!("Document is now PDF/A-2b compliant");
}

PdfALevel 메서드s

The PdfALevel enum includes helper methods for querying level capabilities:

메서드 Return 설명
part() PdfAPart ISO 19005 part (Part1, Part2, Part3)
conformance() char Conformance letter (‘a’, ‘b’, or ‘u’)
requires_structure() bool Whether tagged structure tree is mandatory
requires_unicode() bool Whether Unicode mapping is mandatory
allows_transparency() bool Whether transparency is permitted
allows_jpeg2000() bool Whether JPEG 2000 images are permitted
allows_embedded_files() bool Whether file attachments are permitted
xmp_part() &str XMP pdfaid:part value
xmp_conformance() &str XMP pdfaid:conformance value
from_xmp(part, conformance) Option<Self> Parse level from XMP metadata values

다음 단계