Skip to content

Перевірка PDF/A

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

Підтримка в прив’язках. Перевірка PDF/A доступна у Python (doc.validate_pdf_a(level)), Rust (validate_pdf_a + будівник PdfAValidator), WASM (doc.validatePdfA(level)) та Go (doc.ValidatePdfA(level)). Публічної обгортки для C# поки що немає — скористайтеся Rust CLI (pdf-oxide validate --pdfa 2b doc.pdf) або викликайте через одну з підтримуваних прив’язок. Конвертація PDF/A (PdfAConverter) наразі доступна лише в Rust та Python.

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

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

Рівень «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");
}
package main

import (
    "fmt"
    "log"
    pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)

func main() {
    doc, err := pdfoxide.Open("archive.pdf")
    if err != nil { log.Fatal(err) }
    defer doc.Close()

    // Level encoding: 0 = 1b, 1 = 1a, 2 = 2b, 3 = 2a, 4 = 2u, 5 = 3b, 6 = 3a, 7 = 3u
    result, err := doc.ValidatePdfA(0) // PDF/A-1b
    if err != nil { log.Fatal(err) }

    if result.Valid {
        fmt.Println("Document is PDF/A-1b compliant")
    } else {
        fmt.Println("Not PDF/A-1b compliant:")
        for _, e := range result.Errors {
            fmt.Printf("  %s\n", e)
        }
    }
}

API валідатора

PdfAValidator надає патерн будівника для тонкого керування:

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-потоку, присутність записів pdfaid:part і pdfaid:conformance, узгодженість метаданих
validate_fonts() Усі шрифти вбудовано, ширини гліфів присутні, доступне зіставлення з Unicode (для рівнів «a» та «u»)
validate_colors() Відсутність апаратно залежних операторів кольору (rg, RG, k, K, g, G) без output intent
validate_encryption() У документах PDF/A шифрування не дозволяється
validate_transparency() Прозорість не дозволяється в PDF/A-1; дозволена в PDF/A-2 та новіших
validate_structure() Наявність тегованого дерева структури з коректним зіставленням ролей (обов’язково для рівня «a»)
validate_javascript() Відсутність дій або тригерів JavaScript
validate_embedded_files() Не дозволено в PDF/A-1 чи PDF/A-2; PDF/A-3 вимагає ключ AFRelationship у кожній специфікації файлу
validate_annotations() Типи анотацій обмежені відповідною частиною ISO 19005

ValidationResult

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

pub struct ValidationResult {
    pub level: PdfALevel,
    pub errors: Vec<ComplianceError>,
    pub warnings: Vec<ComplianceWarning>,
    pub stats: ValidationStats,
}
Поле Тип Опис
level PdfALevel Цільовий рівень відповідності
errors Vec<ComplianceError> Блокуючі порушення, що перешкоджають відповідності
warnings Vec<ComplianceWarning> Неблокуючі проблеми, що можуть вплинути на якість
stats ValidationStats Кількість перевірених сторінок, шрифтів та об’єктів

ComplianceError

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

Поле code використовує перелік ErrorCode з такими категоріями, як MissingXmpMetadata, FontNotEmbedded, DeviceDependentColor, EncryptionPresent, TransparencyNotAllowed, MissingStructureTree, JavaScriptPresent та 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());
}

Конфігурація конвертації

Тонко налаштуйте процес конвертації:

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-метаданих – додає записи pdfaid:part та pdfaid:conformance
  2. Вбудовування шрифтів – вбудовує всі використовувані, але не вбудовані шрифти
  3. Вилучення JavaScript – видаляє дії та тригери JavaScript
  4. Зведення прозорості – відтворює прозорі елементи як непрозорі (лише PDF/A-1)
  5. Конвертація ICC-профілю – перетворює апаратно залежні кольори на колірні простори на основі ICC
  6. Теґування структури – додає базові теги структури (для цільових рівнів «a»)

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

Типовий архівний робочий процес виконує перевірку, намагається автоматично сконвертувати документ, а потім перевіряє повторно:

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

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

Метод Повертає Опис
part() PdfAPart Частина ISO 19005 (Part1, Part2, Part3)
conformance() char Літера відповідності (‘a’, ‘b’ або ‘u’)
requires_structure() bool Чи є тегованe дерево структури обов’язковим
requires_unicode() bool Чи є зіставлення з Unicode обов’язковим
allows_transparency() bool Чи дозволена прозорість
allows_jpeg2000() bool Чи дозволені зображення JPEG 2000
allows_embedded_files() bool Чи дозволені вкладення файлів
xmp_part() &str Значення XMP pdfaid:part
xmp_conformance() &str Значення XMP pdfaid:conformance
from_xmp(part, conformance) Option<Self> Розбір рівня зі значень XMP-метаданих

Подальші кроки