Skip to content

Доступність PDF/UA

PDF/UA (ISO 14289) визначає вимоги до універсально доступних PDF-документів. PDF Oxide перевіряє дерева структури, послідовність заголовків, альтернативний текст, заголовки таблиць, оголошення мови та багато іншого.

Підтримка в прив’язках. Валідація PDF/UA доступна в Python (doc.validate_pdf_ua()), Rust (validate_pdf_ua і білдер PdfUaValidator) та Go (doc.ValidatePdfUa()). WASM, коли це доступно, надає базову перевірку «пройдено/не пройдено» через validatePdfUa. Публічну обгортку для C# ще не випущено — використовуйте Rust CLI (pdf-oxide validate --pdfua doc.pdf) або викликайте перевірку через одну з підтримуваних прив’язок.

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

Рівень Стандарт Опис
PDF/UA-1 ISO 14289-1:2014 Базові вимоги до доступності
PDF/UA-2 ISO 14289-2:2024 Розширені вимоги, узгоджені з WCAG 2.1

Швидка перевірка

from pdf_oxide import PdfDocument

doc = PdfDocument("document.pdf")
result = doc.validate_pdf_ua()
print(f"Valid: {result.valid}")
for error in result.errors:
    print(f"  {error}")
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_ua, PdfUaLevel};

let mut doc = PdfDocument::open("accessible.pdf")?;
let result = validate_pdf_ua(&mut doc, PdfUaLevel::UA1)?;

if result.has_errors() {
    println!("Not PDF/UA-1 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/UA-1 compliant");
}
doc, err := pdfoxide.Open("accessible.pdf")
if err != nil { log.Fatal(err) }
defer doc.Close()

valid, errs, err := doc.ValidatePdfUa()
if err != nil { log.Fatal(err) }

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

API валідатора

Білдер PdfUaValidator дає змогу налаштовувати конкретні перевірки:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfUaValidator, PdfUaLevel};

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

let result = PdfUaValidator::new()
    .check_heading_sequence(true)
    .check_color_contrast(true)
    .allow_custom_types(vec!["Caption".into(), "Aside".into()])
    .validate(&mut doc, PdfUaLevel::UA1)?;

println!("Errors: {}", result.errors.len());
println!("Warnings: {}", result.warnings.len());
println!("Structure elements checked: {}",
    result.stats.structure_elements_checked);

Параметри конфігурації

Метод За замовчуванням Опис
check_heading_sequence(bool) true Перевіряти, що H1-H6 не пропускають рівні
check_color_contrast(bool) true Позначати можливі проблеми з контрастністю
allow_custom_types(Vec<String>) [] Дозволяти нестандартні типи структури без попередження

Огляд дерева структури

Перед запуском валідації можна оглянути дерево структури документа та інформацію про розмітку:

use pdf_oxide::PdfDocument;

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

// Check if the document claims to be tagged
let mark_info = doc.mark_info()?;
println!("Marked: {}", mark_info.marked);
println!("Suspects: {}", mark_info.suspects);

// Access the structure tree
if let Some(tree) = doc.structure_tree()? {
    println!("Root tag: {}", tree.root_type);
    println!("Children: {}", tree.children.len());
}

Метод mark_info() повертає:

Поле Тип Опис
marked bool Чи оголошує документ себе розміченим (tagged)
suspects bool Чи можуть призначення тегів бути некоректними
user_properties bool Чи присутні користувацькі властивості

Коли suspects дорівнює true, PDF Oxide під час видобування тексту автоматично переходить до геометричного впорядкування замість того, щоб покладатися на потенційно ненадійне дерево структури.

Що саме перевіряється

Валідатор охоплює такі вимоги PDF/UA:

Рівень документа

Перевірка Пункт Опис
Мова 7.2 У каталозі присутній запис /Lang
Заголовок 7.1 Заголовок документа задано та відображено в рядку заголовка
Розміченість 7.1 Словник MarkInfo оголошує Marked = true
Метадані XMP 7.1 У потоці XMP оголошено pdfuaid:part

Структура

Перевірка Пункт Опис
Дерево структури 7.1 Повне дерево структури з коренем StructTreeRoot
Зіставлення ролей 7.5 Нестандартні типи зіставлено зі стандартними елементами структури
Ієрархія заголовків 7.4.2 Заголовки (H1-H6) не пропускають рівні
Розмітка артефактів 7.3 Декоративний вміст позначено як артефакт
Порядок читання 7.2 Дерево структури визначає логічний порядок читання

Вміст

Перевірка Пункт Опис
Альтернативний текст для зображень 7.3 /Alt або /ActualText на елементах Figure
Заголовки таблиць 7.5 Елементи TH присутні в структурах таблиць
Підписи полів форм 7.6.2 Поля форм мають пов’язані підписи або підказки
Текст посилань 7.18 Анотації посилань мають описовий вміст
Структура списків 7.4.3 Списки використовують структуру L, LI, Lbl, LBody

Шрифт і текст

Перевірка Пункт Опис
Зіставлення з Unicode 7.21.3 Увесь текст має представлення в Unicode
Вбудовування шрифтів 7.21.4 Шрифти вбудовано або це стандартні шрифти Base14
ActualText 7.21.5 Лігатури та спеціальні гліфи мають /ActualText

UaValidationResult

pub struct UaValidationResult {
    pub level: PdfUaLevel,
    pub errors: Vec<UaComplianceError>,
    pub warnings: Vec<ComplianceWarning>,
    pub stats: UaValidationStats,
}

UaComplianceError

Кожна помилка містить необов’язкове зіставлення з WCAG:

pub struct UaComplianceError {
    pub code: UaErrorCode,
    pub message: String,
    pub location: Option<String>,
    pub wcag_ref: Option<String>,
    pub clause: Option<String>,
}

Поле wcag_ref зіставляє порушення PDF/UA з відповідним критерієм успіху WCAG (наприклад, "1.1.1" для нетекстового вмісту, "1.3.1" для інформації та зв’язків).

Категорії UaErrorCode

Перелік UaErrorCode містить такі категорії помилок, як:

  • MissingLanguage – немає запису /Lang у каталозі документа
  • MissingStructureTree – документ не розмічено
  • MissingAltText – елемент Figure не має альтернативного тексту
  • HeadingSkipped – рівні заголовків перестрибують (наприклад, з H1 на H3)
  • MissingTableHeaders – у таблиці відсутні елементи TH
  • FormFieldNoLabel – поле форми не має пов’язаного підпису
  • InvalidRoleMapping – нестандартний тип не зіставлено зі стандартним елементом
  • ArtifactNotMarked – декоративний вміст не позначено як артефакт
  • MissingUnicode – текст без зіставлення з Unicode

Практичний приклад: звіт про доступність

Сформуйте читабельний для людини звіт про доступність на основі результатів валідації:

use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_ua, PdfUaLevel};

let mut doc = PdfDocument::open("document.pdf")?;
let result = validate_pdf_ua(&mut doc, PdfUaLevel::UA1)?;

println!("=== PDF/UA Accessibility Report ===");
println!("Level: PDF/UA-{}", result.level.xmp_part());
println!("Status: {}", if result.has_errors() { "FAIL" } else { "PASS" });
println!();

if result.has_errors() {
    println!("Errors ({}):", result.errors.len());
    for (i, error) in result.errors.iter().enumerate() {
        print!("  {}. [{}] {}", i + 1, error.code, error.message);
        if let Some(ref wcag) = error.wcag_ref {
            print!("  (WCAG {})", wcag);
        }
        println!();
    }
}

if result.has_warnings() {
    println!("\nWarnings ({}):", result.warnings.len());
    for warning in &result.warnings {
        println!("  - [{}] {}", warning.code, warning.message);
    }
}

println!("\nStats:");
println!("  Structure elements checked: {}",
    result.stats.structure_elements_checked);

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