Skip to content

PDF/UA-Validierung

PDF/UA (ISO 14289) definiert Anforderungen für universell zugängliche PDF-Dokumente. PDF Oxide validiert Strukturbäume, Überschriftensequenzen, Alternativtext, Tabellenüberschriften, Sprachdeklarationen und mehr.

Unterstützte Stufen

Stufe Standard Beschreibung
PDF/UA-1 ISO 14289-1:2014 Grundlegende Barrierefreiheitsanforderungen
PDF/UA-2 ISO 14289-2:2024 Erweiterte Anforderungen, ausgerichtet an WCAG 2.1

Schnellvalidierung

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

Der PdfUaValidator-Builder ermöglicht die Konfiguration spezifischer Prüfungen:

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);

Konfigurationsoptionen

Methode Standard Beschreibung
check_heading_sequence(bool) true Validieren, dass H1-H6 keine Ebenen überspringen
check_color_contrast(bool) true Potenzielle Kontrastprobleme markieren
allow_custom_types(Vec<String>) [] Nicht-standardmäßige Strukturtypen ohne Warnung erlauben

Strukturbaum-Inspektion

Vor der Validierung können Sie den Strukturbaum und die Mark-Info des Dokuments inspizieren:

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());
}

Die Methode mark_info() gibt zurück:

Feld Typ Beschreibung
marked bool Ob das Dokument sich als getaggt deklariert
suspects bool Ob Tag-Zuweisungen möglicherweise inkorrekt sind
user_properties bool Ob Benutzereigenschaften vorhanden sind

Wenn suspects true ist, fällt PDF Oxide automatisch auf geometrische Ordnung für die Textextraktion zurück, anstatt sich auf den potenziell unzuverlässigen Strukturbaum zu verlassen.

Was geprüft wird

Der Validator deckt die folgenden PDF/UA-Anforderungen ab:

Dokumentebene

Prüfung Klausel Beschreibung
Sprache 7.2 /Lang-Eintrag im Katalog vorhanden
Titel 7.1 Dokumenttitel gesetzt und in der Titelleiste angezeigt
Getaggt 7.1 MarkInfo-Wörterbuch deklariert Marked = true
XMP-Metadaten 7.1 pdfuaid:part im XMP-Stream deklariert

Struktur

Prüfung Klausel Beschreibung
Strukturbaum 7.1 Vollständiger Strukturbaum mit Wurzel bei StructTreeRoot
Rollenzuordnung 7.5 Nicht-standardmäßige Typen auf Standard-Strukturelemente abgebildet
Überschriftenhierarchie 7.4.2 Überschriften (H1-H6) überspringen keine Ebenen
Artefakt-Markierung 7.3 Dekorativer Inhalt als Artefakt markiert
Lesereihenfolge 7.2 Strukturbaum definiert eine logische Lesereihenfolge

Inhalt

Prüfung Klausel Beschreibung
Alternativtext für Bilder 7.3 /Alt oder /ActualText auf Figure-Elementen
Tabellenüberschriften 7.5 TH-Elemente in Tabellenstrukturen vorhanden
Formularbeschriftungen 7.6.2 Formularfelder haben zugehörige Beschriftungen oder Tooltips
Linktext 7.18 Link-Anmerkungen haben beschreibenden Inhalt
Listenstruktur 7.4.3 Listen verwenden L, LI, Lbl, LBody-Struktur

Schrift und Text

Prüfung Klausel Beschreibung
Unicode-Zuordnung 7.21.3 Aller Text hat eine Unicode-Darstellung
Schrifteinbettung 7.21.4 Schriften eingebettet oder Standard-Base14-Schriften
ActualText 7.21.5 Ligaturen und Spezialglyphen haben /ActualText

UaValidationResult

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

UaComplianceError

Jeder Fehler enthält optionale WCAG-Ausrichtung:

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

Das wcag_ref-Feld ordnet den PDF/UA-Verstoß dem entsprechenden WCAG-Erfolgskriterium zu (e.g., "1.1.1" for non-text content, "1.3.1" for info and relationships).

UaErrorCode Categories

Das UaErrorCode-Enum enthält Fehlerkategorien wie:

  • MissingLanguage – no /Lang entry on the document catalog
  • MissingStructureTree – document is not tagged
  • MissingAltText – Figure element lacks alt text
  • HeadingSkipped – heading levels jump (e.g., H1 to H3)
  • MissingTableHeaders – table lacks TH elements
  • FormFieldNoLabel – form field has no associated label
  • InvalidRoleMapping – non-standard type not mapped to a standard element
  • ArtifactNotMarked – decorative content not marked as artifact
  • MissingUnicode – text without Unicode mapping

Praktisches Beispiel: Barrierefreiheitsbericht

Einen menschenlesbaren Barrierefreiheitsbericht aus Validierungsergebnissen erstellen:

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);

Nächste Schritte