Skip to content

Commit 4127c26

Browse files
Fix tagpdf alt text warning parsing and improve guidance
- Fix regex in parse-error.ts to handle tagpdf line continuations when filenames are long (the warning wraps across multiple (tagpdf) lines) - Update warning message to recommend fig-alt instead of caption-as-alt - Add printsMessage check to caption-not-alt-ua test to verify the missing alt text warning is surfaced - Use labeled figure in caption-not-alt-ua test to avoid unrelated UA-2 structural nesting issue with unlabeled figures - Add ua2-unlabeled-figure-caption test documenting known LaTeX/tagpdf limitation where unlabeled captioned figures produce <Caption> directly under <Document> instead of inside a grouping element
1 parent 9552637 commit 4127c26

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

src/command/render/latexmk/parse-error.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,10 @@ export function findPdfAccessibilityWarnings(
125125

126126
// Match: Package tagpdf Warning: Alternative text for graphic is missing.
127127
// (tagpdf) Using 'filename' instead.
128+
// Note: tagpdf wraps long filenames across multiple (tagpdf) continuation
129+
// lines, so we allow optional line breaks with (tagpdf) prefixes.
128130
const altTextRegex =
129-
/Package tagpdf Warning: Alternative text for graphic is missing\.\s*\n\(tagpdf\)\s*Using ['`]([^'`]+)['`] instead\./g;
131+
/Package tagpdf Warning: Alternative text for graphic is missing\.\s*\n\(tagpdf\)\s*Using ['`]([^'`]+)['`]\s*(?:\n\(tagpdf\)\s*)?instead\./g;
130132
let match;
131133
while ((match = altTextRegex.exec(logText)) !== null) {
132134
result.missingAltText.push(match[1]);

src/command/render/latexmk/pdf.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ async function initialCompileLatex(
204204
if (accessibilityWarnings.missingAltText.length > 0) {
205205
const fileList = accessibilityWarnings.missingAltText.join(", ");
206206
warning(
207-
`PDF accessibility: Missing alt text for image(s): ${fileList}. Add alt text using ![alt text](image.png) syntax for PDF/UA compliance.\n`,
207+
`PDF accessibility: Missing alt text for image(s): ${fileList}. Add alt text using fig-alt in YAML or {fig-alt="description"} on the image for PDF/UA compliance.\n`,
208208
);
209209
}
210210
if (accessibilityWarnings.missingLanguage) {

tests/docs/smoke-all/pdf-standard/caption-not-alt-ua.qmd

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ _quarto:
1919
- ['\\DocumentMetadata\{', 'pdfstandard=\{ua-2\}', 'tagging=on']
2020
- # Caption must NOT appear as alt text on \includegraphics
2121
['includegraphics\[.*alt=']
22+
printsMessage:
23+
# tagpdf warns about missing alt text and falls back to filename;
24+
# Quarto surfaces this as a user-facing warning
25+
level: WARN
26+
regex: "PDF accessibility:.*Missing alt text"
2227
typst:
2328
# Typst's own PDF/UA enforcement errors on missing alt
2429
shouldError: default
@@ -29,4 +34,8 @@ _quarto:
2934
A figure with a caption but no explicit `fig-alt`.
3035
The caption should NOT be copied into alt text.
3136

32-
![This is a caption, not alt text](penrose.svg)
37+
Uses a cross-ref label to go through FloatRefTarget, which produces
38+
valid UA-2 structure. See `ua2-unlabeled-figure-caption.qmd` for the
39+
known structural issue with unlabeled captioned figures.
40+
41+
![This is a caption, not alt text](penrose.svg){#fig-test}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: "UA-2: unlabeled figure caption produces invalid structure"
3+
lang: en
4+
format:
5+
pdf:
6+
pdf-standard: ua-2
7+
keep-tex: true
8+
_quarto:
9+
tests:
10+
run:
11+
# verapdf validation not available on Windows CI
12+
not_os: windows
13+
pdf:
14+
noErrors: default
15+
ensureLatexFileRegexMatches:
16+
- ['\\DocumentMetadata\{', 'pdfstandard=\{ua-2\}', 'tagging=on']
17+
- []
18+
printsMessage:
19+
# Known issue: unlabeled captioned figures go through pandoc3_figure.lua
20+
# which produces a bare \begin{figure}[H] environment. LaTeX's tagpdf
21+
# places <Caption> as a sibling of <Figure> under <Document> instead of
22+
# nesting them inside a grouping element. This violates UA-2 which
23+
# requires <Caption> to be a child of <Figure>, <Table>, or <Formula>.
24+
#
25+
# Labeled figures ({#fig-label}) go through FloatRefTarget, which wraps
26+
# the figure in a \Div that provides the grouping context tagpdf needs.
27+
#
28+
# Structure produced (invalid):
29+
# /Document
30+
# /Caption <- should be inside a grouping element
31+
# /Figure <- sibling instead of parent
32+
#
33+
# Expected (valid, as produced by labeled figures):
34+
# /Document
35+
# /Div
36+
# /Caption <- properly nested
37+
# /Figure
38+
level: WARN
39+
regex: "PDF validation failed for ua-2"
40+
---
41+
42+
# Known LaTeX tagging limitation
43+
44+
An unlabeled captioned figure produces invalid UA-2 structure because
45+
tagpdf does not nest `<Caption>` inside a grouping element.
46+
47+
![This is a caption on an unlabeled figure](penrose.svg)

0 commit comments

Comments
 (0)