Валідація PDF/UA
PDF/UA (ISO 14289) визначає вимоги до універсально доступних PDF-документів. PDF Oxide валідує дерева структури, послідовності заголовків, альтернативний текст, заголовки таблиць, оголошення мов та інше.
Підтримувані рівні
| Рівень | Стандарт | Опис |
|---|---|---|
| PDF/UA-1 | ISO 14289-1:2014 | Base accessibility requirements |
| PDF/UA-2 | ISO 14289-2:2024 | Enhanced requirements, aligned with 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 валідатора
Builder 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 |
Validate H1-H6 do not skip levels |
check_color_contrast(bool) |
true |
Flag potential contrast issues |
allow_custom_types(Vec<String>) |
[] |
Permit non-standard structure types without warning |
Інспекція дерева структури
Before running validation, you can inspect the document’s structure tree and mark info:
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 |
Whether the document declares itself as tagged |
suspects |
bool |
Whether tag assignments may be incorrect |
user_properties |
bool |
Whether user properties are present |
Коли suspects є true, PDF Oxide автоматично повертається до геометричного упорядкування для вилучення тексту замість покладання на потенційно ненадійне дерево структури.
Що перевіряється
Валідатор охоплює наступні вимоги PDF/UA:
Рівень документа
| Перевірка | Стаття | Опис |
|---|---|---|
| Language | 7.2 | /Lang entry present in the catalog |
| Title | 7.1 | Назва документа set and displayed in title bar |
| Tagged | 7.1 | MarkInfo dictionary declares Marked = true |
| XMP metadata | 7.1 | pdfuaid:part declared in XMP stream |
Структура
| Перевірка | Стаття | Опис |
|---|---|---|
| Structure tree | 7.1 | Complete structure tree rooted at StructTreeRoot |
| Role mapping | 7.5 | Non-standard types mapped to standard structure elements |
| Heading hierarchy | 7.4.2 | Headings (H1-H6) do not skip levels |
| Artifact marking | 7.3 | Decorative content marked as artifact |
| Reading order | 7.2 | Structure tree defines a logical reading order |
Вміст
| Перевірка | Стаття | Опис |
|---|---|---|
| Alt text for images | 7.3 | /Alt or /ActualText on Figure elements |
| Table headers | 7.5 | TH elements present in table structures |
| Form labels | 7.6.2 | Form fields have associated labels or tooltips |
| Link text | 7.18 | Link annotations have descriptive content |
| List structure | 7.4.3 | Lists use L, LI, Lbl, LBody structure |
Шрифт та текст
| Перевірка | Стаття | Опис |
|---|---|---|
| Unicode mapping | 7.21.3 | All text has a Unicode representation |
| Font embedding | 7.21.4 | Fonts embedded or standard Base14 fonts |
| ActualText | 7.21.5 | Ligatures and special glyphs have /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 (e.g., "1.1.1" for non-text content, "1.3.1" for info and relationships).
UaErrorCode Categories
Enum UaErrorCode включає категорії помилок, такі як:
MissingLanguage– no/Langentry on the document catalogMissingStructureTree– document is not taggedMissingAltText– Figure element lacks alt textHeadingSkipped– heading levels jump (e.g., H1 to H3)MissingTableHeaders– table lacksTHelementsFormFieldNoLabel– form field has no associated labelInvalidRoleMapping– non-standard type not mapped to a standard elementArtifactNotMarked– decorative content not marked as artifactMissingUnicode– text without Unicode mapping
Практичний приклад: Звіт про доступність
Згенерувати зрозумілий для людини звіт про доступність з результатів валідації:
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 Validation – archival compliance
- PDF/X Print Production – print production compliance
- API Reference – complete Rust API