Skip to content

Валідація PDF/A

PDF/A (ISO 19005) — це міжнародний стандарт для довгострокового архівування електронних документів. PDF Oxide валідує всі основні рівні PDF/A та може конвертувати невідповідні документи у напрямку відповідності.

Підтримувані рівні

Рівень Стандарт Структура Unicode Прозорість Вбудовані файли
1a ISO 19005-1 Required Required No No
1b ISO 19005-1 No No No No
2a ISO 19005-2 Required Required Yes No
2b ISO 19005-2 No No Yes No
2u ISO 19005-2 No Required Yes No
3a ISO 19005-3 Required Required Yes Yes
3b ISO 19005-3 No No Yes Yes
3u ISO 19005-3 No Required Yes Yes

Рівень “a” (accessible, доступний) вимагає тегованого дерева структури та відображення символів Unicode. Рівень “b” (basic, базовий) вимагає лише візуальної відтворюваності. Рівень “u” (Unicode) вимагає відображення тексту Unicode без повного дерева структури.

Швидка валідація

Використовуйте зручну функцію для перевірки за один виклик:

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");
}

API валідатора

PdfAValidator надає шаблон builder для детального контролю:

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());

Цільові перевірки

Запуск окремих категорій валідації замість повного набору:

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)?;

Окремі валідатори

Кожна категорія валідації також доступна як окрема функція для максимальної гнучкості:

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());

Підсумок валідатора

Функція Що перевіряє
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() Теговане дерево структури 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() Тип анотаціїs restricted per the relevant ISO 19005 part

ValidationResult

Структура ValidationResult містить повний результат перевірки валідації:

pub struct ValidationResult {
    pub level: PdfALevel,
    pub errors: Vec<ComplianceError>,
    pub warnings: Vec<ComplianceWarning>,
    pub stats: ValidationStats,
}
Поле Тип Опис
level PdfALevel The target compliance level
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>,
}

Поле code використовує enum ErrorCode 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

Конвертувати невідповідний документ у напрямку відповідності PDF/A:

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());
}

Конвертація Config

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)?;

Конвертер виконує ці дії автоматично:

  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)

Робочий процес: Валідація, Виправлення, Повторна валідація

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

Enum PdfALevel містить допоміжні методи для запиту можливостей рівня:

Метод Повертає Опис
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

Наступні кроки