Доступность PDF/UA
PDF/UA (ISO 14289) определяет требования к универсально доступным PDF-документам. PDF Oxide валидирует деревья структуры, последовательности заголовков, альтернативный текст, заголовки таблиц, объявления языка и многое другое.
Поддерживаемые уровни
| Уровень | Стандарт | Описание |
|---|---|---|
| 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");
}
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);
Параметры настройки
| Method | Default | Описание |
|---|---|---|
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 |
Объявляет ли документ себя тегированным |
suspects |
bool |
Могут ли назначения тегов быть некорректными |
user_properties |
bool |
Присутствуют ли пользовательские свойства |
Когда suspects равен true, PDF Oxide автоматически переключается на геометрическое упорядочивание для извлечения текста вместо использования потенциально ненадёжного дерева структуры.
Что проверяется
Валидатор проверяет следующие требования PDF/UA:
Уровень документа
| Проверка | Пункт | Описание |
|---|---|---|
| Язык | 7.2 | Запись /Lang присутствует в каталоге |
| Заголовок | 7.1 | Заголовок документа задан и отображается в строке заголовка |
| Тегирование | 7.1 | Словарь MarkInfo объявляет Marked = true |
| Метаданные XMP | 7.1 | pdfuaid:part объявлен в потоке XMP |
Структура
| Проверка | Пункт | Описание |
|---|---|---|
| Дерево структуры | 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 Categories
Перечисление UaErrorCode включает категории ошибок, такие как:
MissingLanguage— отсутствует запись/Langв каталоге документаMissingStructureTree— документ не тегированMissingAltText— элемент Figure не имеет альтернативного текстаHeadingSkipped— уровни заголовков пропускаются (напр., H1 к H3)MissingTableHeaders— таблица не содержит элементовTHFormFieldNoLabel— поле формы не имеет связанной метки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);
Следующие шаги
- Валидация PDF/A — соответствие для архивного хранения
- Печатное производство PDF/X — соответствие для печатного производства
- Справочник API — полный Rust API