PDF/UA Accessibility
PDF/UA(ISO 14289)는 보편적으로 접근 가능한 PDF 문서에 대한 요구 사항을 정의합니다. PDF Oxide는 구조 트리, 제목 시퀀스, 대체 텍스트, 표 헤더, 언어 선언 등을 검증합니다.
지원 레벨
| Level | Standard | 설명 |
|---|---|---|
| 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");
}
Validator API
The PdfUaValidator builder allows configuring specific checks:
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);
Configuration Options
| 메서드 | 기본값 | 설명 |
|---|---|---|
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 |
Structure Tree Inspection
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());
}
The mark_info() method returns:
| Field | 타입 | 설명 |
|---|---|---|
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 |
When suspects is true, PDF Oxide automatically falls back to geometric ordering for text extraction instead of relying on the potentially unreliable structure tree.
What Gets Checked
The validator covers the following PDF/UA requirements:
Document-Level
| Check | Clause | 설명 |
|---|---|---|
| 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
| Check | Clause | 설명 |
|---|---|---|
| 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 |
Content
| Check | Clause | 설명 |
|---|---|---|
| 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 |
글꼴 및 텍스트
| Check | Clause | 설명 |
|---|---|---|
| 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
Each error includes optional WCAG alignment:
pub struct UaComplianceError {
pub code: UaErrorCode,
pub message: String,
pub location: Option<String>,
pub wcag_ref: Option<String>,
pub clause: Option<String>,
}
The wcag_ref field maps the PDF/UA violation to the corresponding WCAG success criterion (e.g., "1.1.1" for non-text content, "1.3.1" for info and relationships).
UaErrorCode Categories
The UaErrorCode enum includes error categories such as:
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
Practical Example: Accessibility Report
Generate a human-readable accessibility report from validation results:
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