本文へ移動
cccskills
無料GitHub で公開

pdf-accessibility-checker

Test PDF accessibility (PDF/UA conformance) - tagged-PDF structure (StructTreeRoot), alternative text on images (Alt), reading-order, language metadata (Lang), document title, heading hierarchy. Use veraPDF / PAC (PDF Accessibility Checker) / pdfix / Adobe Acrobat Pro headless; map each finding back to WCAG 2.1 PDF Techniques (PDF1 - PDF23). Use when a product ships customer-facing PDFs into a context that mandates PDF/UA - US Section 508, EU Directive 2016/2102, or a public-sector tender - and each file must be proven tagged before release.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qaスター 13(GitHub 13 + cccskills 0)

実行スコア 未検証

インストール方法を見る

含まれるファイル(2)

  • SKILL.md9.3 KB
  • .tessl-plugin/plugin.json688 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

pdf-accessibility-checker

Per the WCAG 2.1 spec, "Text alternatives" + "Structured information that can be programmatically determined" + "Language identification"

  • "Proper document organization" apply to PDFs. The PDF/UA standard (ISO 14289) operationalizes these into concrete file-level requirements: Tagged PDF, role mapping, Alt text, reading order, Lang metadata.

When to use

  • Producing PDFs in regulated industries (US Section 508, EU Directive 2016/2102, accessible-by-default policies).
  • Public-sector tenders that require PDF/UA compliance.
  • Pre-deployment gate: every customer-facing PDF passes the accessibility check before release.

Step 1 - Pick a checker

ToolStrength
veraPDF (open source)PDF/UA-1 + PDF/A validation; CI-friendly CLI
PAC (PDF Accessibility Checker) by axes4UI-first; comprehensive Matterhorn Protocol coverage
pdfixCommercial; auto-tagging fixes
Adobe Acrobat Pro Accessibility CheckIndustry default; manual-review-friendly

For CI, veraPDF is the default open-source choice.

Step 2 - Install veraPDF

# Download installer
curl -L -o verapdf.zip https://software.verapdf.org/releases/1.30/verapdf-greenfield-1.30.2-installer.zip
unzip verapdf.zip

# The zip ships an IzPack installer, not a ready-to-run binary
verapdf-greenfield-1.30.2/verapdf-install ./auto-install.xml
<install-dir>/bin/verapdf --version

Current release index (1.30.2 as of this writing): software.verapdf.org/releases. The headless verapdf-install ./auto-install.xml form and the bin/ layout are per docs.verapdf.org/install.

Step 3 - Run conformance check

verapdf --flavour ua1 --format json out.pdf > vera-report.json

Exit codes: 0 = conformant, 1 = non-conformant, 2 = parse error.

Step 4 - Parse and assert

import json, subprocess

def test_pdf_passes_pdf_ua_1():
    result = subprocess.run(
        ["verapdf", "--flavour", "ua1", "--format", "json", "out.pdf"],
        capture_output=True, text=True,
    )
    report = json.loads(result.stdout)

    # Iterate jobs[0].validationResult
    job = report["report"]["jobs"][0]
    failed = job["validationResult"]["details"]["failedRules"]

    assert failed == 0, f"PDF/UA validation failed: {job['validationResult']['details']}"

Step 5 - Verify tagged PDF (StructTreeRoot)

A PDF is "tagged" if its catalog has a StructTreeRoot and MarkInfo /Marked true. Without these, screen readers cannot read the document semantically.

import pikepdf

def test_pdf_is_tagged():
    pdf = pikepdf.open("out.pdf")
    catalog = pdf.Root
    assert "/StructTreeRoot" in catalog, "PDF lacks StructTreeRoot (untagged)"
    mark_info = catalog.get("/MarkInfo", {})
    # Use bool(), not `is True`: pikepdf can return a pikepdf.Object wrapper
    # rather than the singleton Python True, so `is True` is always False
    # even when /Marked is set (per [pikepdf objects]).
    assert bool(mark_info.get("/Marked", False)), "PDF MarkInfo /Marked is false"

Step 6 - Verify document title + language metadata

Per the WCAG 2.1 spec, language identification + descriptive title are required.

def test_pdf_has_title_and_lang():
    pdf = pikepdf.open("out.pdf")
    info = pdf.docinfo

    title = info.get("/Title")
    assert title and str(title).strip(), "PDF has no /Info /Title"

    lang = pdf.Root.get("/Lang")
    assert lang and str(lang) in ("en", "en-US", "en-GB", "de", "fr"), f"PDF /Lang invalid: {lang}"

Step 7 - Verify image Alt text presence

def test_all_images_have_alt():
    pdf = pikepdf.open("out.pdf")
    structure_root = pdf.Root["/StructTreeRoot"]

    # The structure tree is NESTED: each element's /K can hold child
    # elements to arbitrary depth, so /Figure tags live below /Document,
    # /Sect, /P, etc. A top-level-only scan misses nested figures and
    # passes vacuously. Walk every /K recursively. Each /Figure must carry
    # an /Alt (or /ActualText) per [WCAG PDF1].
    untagged_images = []

    def walk(node):
        if isinstance(node, pikepdf.Array):
            for child in node:
                walk(child)
            return
        if not isinstance(node, pikepdf.Dictionary):
            return  # marked-content id (int) or other leaf
        if node.get("/S") == "/Figure":
            alt = node.get("/Alt")
            if not alt or not str(alt).strip():
                untagged_images.append(node)
        kids = node.get("/K")
        if kids is not None:
            walk(kids)

    walk(structure_root.get("/K"))
    assert untagged_images == [], f"Images without /Alt: {len(untagged_images)}"

Step 8 - Reading order verification

Reading order determined by structure-tree DFS. Verify the generated structure puts content in the order a human reader would expect:

def test_reading_order_matches_visual_order():
    # TEMPLATE: the title and section labels below are placeholders for an
    # invoice layout. Replace them with the expected reading-order landmarks
    # for your own document before using this test.
    text_per_page = extract_text_with_structure_order("out.pdf")

    # First page should start with the document's leading landmark.
    assert text_per_page[0].startswith("Invoice #")  # replace per document
    # Each expected landmark appears on its page, in reading order.
    expected = ["Bill To", "Items", "Total", "Footer"]  # replace per document
    for i, section in enumerate(expected):
        assert section in text_per_page[i] or i == 0

This is best done via PAC or visual inspection for high-stakes documents - automating reading-order verification is hard.

Step 9 - Map findings to WCAG 2.1 Techniques

Per the WCAG 2.1 spec, PDF Techniques document specific patterns:

TechniqueWhat it covers
PDF1Applying alt text to images
PDF2Creating bookmarks
PDF3Ensuring correct tab order
PDF4Hiding decorative images via Artifact tagging
PDF6Using table elements (<Table> / <TR> / <TH> / <TD>)
PDF9Heading structure (H1 / H2 / H3)
PDF15Form field accessibility
PDF18Document title in DocInfo
PDF19Lang in document or per-element

When a check fails, cite the technique in the failure message:

assert title, "PDF18: Document title required (WCAG 2.1)"

Step 10 - CI gate

- name: PDF/UA conformance
  run: |
    for pdf in out/*.pdf; do
      # jq -e sets the exit status from the result: false/null gives exit 1,
      # so the gate actually fails on violations. Plain jq exits 0 regardless
      # of the printed boolean (per [jq manual]), so `|| exit 1` never fired.
      verapdf --flavour ua1 --format json "$pdf" \
        | jq -e '.report.jobs[0].validationResult.details.failedRules == 0' > /dev/null || exit 1
    done

Anti-patterns

Anti-patternWhy it failsFix
Generate PDF with printBackground: true and skip tag checkVisually fine; screen-reader-brokenveraPDF flavour ua1 (Step 3)
Convert via tools that strip tags (some HTML→PDF engines)Pre-tag stripped during convertUse tagged-PDF-capable engines (WeasyPrint with tagged-pdf option)
Skip /LangScreen readers use wrong pronunciationStep 6
Auto-generate Alt = filename"logo.png" doesn't help screen readerManual Alt review for high-stakes
Only run in pre-prod, not CIInaccessible PDFs shipBlock PR (Step 10)

Limitations

  • veraPDF/UA1 catches structural issues; semantic correctness (helpful Alt text vs filename Alt) needs human review.
  • PAC is more complete than veraPDF for the Matterhorn Protocol but GUI-only.
  • WeasyPrint produces tagged PDFs; older versions of wkhtmltopdf do not. Check engine output capabilities.
  • WCAG 2.1 PDF Techniques are non-normative; consult the WCAG 2.1 spec + the per-technique test pages for current guidance.

References

  • WCAG 2.1 spec - accessibility principles applicable to PDFs
  • veraPDF (PDF/UA-1 + PDF/A validator) - verapdf.org
  • PAC by axes4 - pac.pdf-accessibility.org (Matterhorn Protocol)
  • ISO 14289-1 (PDF/UA-1) - cite by stable ID; consult ISO for spec text
  • pikepdf Python library - pikepdf.readthedocs.io
  • pikepdf objects - how pikepdf maps PDF scalars to Python types
  • WCAG PDF1 - applying /Alt text to /Figure structure elements
  • jq manual - the -e / --exit-status flag for CI gating
  • pdf-snapshot-tester - sister skill for visual-regression on the same PDFs

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

Builds a CI gate that fails the build on **new** WCAG / a11y violations introduced by a PR while grandfathering pre-existing violations on a per-rule / per-page baseline. Aggregates verdicts from axe-core / pa11y / Lighthouse a11y / WAVE / IBM Equal Access scans. Use when a project has accumulated a11y debt and a strict "zero violations" gate would block every PR - the ratchet pattern lets the team ship while preventing regressions.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Workflow skill that builds an A/B-test validity checklist from an experiment proposal, walking the canonical design-correctness gates - pre-registered OEC/power/guardrails, randomization unit + SRM check, assignment integrity, telemetry, peeking discipline, novelty/primacy, post-experiment SRM re-check - into a per-experiment checklist + sign-off form. Use when launching, auditing, or governing an experiment. For pitfall mechanics (guardrails, peeking) see experiment-results-interpreter's references; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use experiment-sdk-testing - this gates DESIGN, not SDK code.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

The single install-flow skill: the reference contract for the PWA install flow (installability gate fields, `beforeinstallprompt` handshake, per-platform paths - Android WebAPK / iOS Share menu / Firefox no-op - and the `display-mode` post-install signal, in references/install-flow-reference.md) plus the build-an-X workflow that emits the Add-to-Home-Screen suite. Walks the four-stage timeline, emitting one test per gate cell per [web.dev/articles/install-criteria][install-criteria], the deferred-prompt → `prompt()` → `userChoice` chain per [web.dev/articles/customize-install][customize-install], the iOS Safari manual-metadata branch (`apple-touch-icon`) per [web.dev/learn/pwa/installation][learn-pwa], and the post-install `(display-mode: standalone)` MQ assertion. Output: a Playwright spec with per-stage cells plus a coverage matrix. Use when a PWA's manifest, icons, or install handler change, when install conversion drops at an unknown stage, or when triaging a flaky install assertion.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Build-an-X workflow that uses an LLM to map existing tests to spec sections - given a spec doc + the test suite, the LLM identifies which tests cover which sections, surfaces uncovered sections (gap), and recommends specific tests to add. Output is a coverage matrix per spec ID. Scope is mapping tests that already exist and naming the gaps, not authoring tests for new acceptance criteria. Use when a spec doc and a test suite both exist but nobody can say which requirements are actually covered - before a release sign-off, an audit, or a decision about where to spend the next round of test effort.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Generates tests from natural-language specs (acceptance criteria, user stories, requirements) using an LLM, with confidence scoring per test case (LLM self-assessment plus heuristics: assertion quality, naming, completeness), batching uncertain cases for human review, and integration with the team's existing test framework. Use when the user asks to generate unit tests from acceptance criteria, convert user stories to test cases, automate test creation from requirements, or augment a spec-driven test suite with AI-generated stubs that are then curated before merge.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Configures Allure Report (test-runner adapter install, `allure-results` directory wiring, `categories.json` for failure classification, `history-trend.json` retention via the copy-history-between-runs pattern), runs the Allure CLI to convert `allure-results` to a static HTML site, and uploads the report as a CI artifact. Use when the team needs richer test reporting than JUnit XML - step-level attachments, per-test history, retry tracking, and severity / epic / feature labeling across framework-agnostic adapters (pytest, Jest, JUnit, TestNG, NUnit, Mocha). As a rich static HTML report generator, it is the open-source alternative to the sunset ExtentReports (JVM/.NET per-test HTML narrative); for hosted cross-run flakiness analytics rather than a static per-run report use currents-integration.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

testland のスキルをすべて見る

このスキルの問題を報告する