Skip to content

Commit 5c73695

Browse files
Add Typst image alt text for PDF/UA accessibility
Workaround for Pandoc not passing alt text to Typst image() calls. When an image has alt text (from caption or fig-alt), emits raw Typst with image(..., alt: "...") for accessibility compliance. Temporary fix until pandoc#11394 is merged upstream. Closes #13868 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 31d9500 commit 5c73695

17 files changed

Lines changed: 262 additions & 4 deletions

news/changelog-1.9.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ All changes included in 1.9:
4242
- ([#13589](https://github.com/quarto-dev/quarto-cli/issues/13589)): Fix callouts with invalid ID prefixes crashing with "attempt to index a nil value". Callouts with unknown reference types now render as non-crossreferenceable callouts with a warning, ignoring the invalid ID.
4343
- ([#13602](https://github.com/quarto-dev/quarto-cli/issues/13602)): Fix support for multiple files set in `bibliography` field in `biblio.typ` template partial.
4444
- ([#13775](https://github.com/quarto-dev/quarto-cli/issues/13775)): Fix brand fonts not being applied when using `citeproc: true` with Typst format. Format detection now properly handles Pandoc format variants like `typst-citations`.
45+
- ([#13868](https://github.com/quarto-dev/quarto-cli/issues/13868)): Add image alt text support for PDF/UA accessibility. Alt text from markdown captions and explicit `alt` attributes is now passed to Typst's `image()` function. (Temporary workaround until [jgm/pandoc#11394](https://github.com/jgm/pandoc/pull/11394) is merged.)
4546
- ([#13249](https://github.com/quarto-dev/quarto-cli/pull/13249)): Update to Pandoc's Typst template following Pandoc 3.8.3 and Typst 0.14.2 support:
4647
- Code syntax highlighting now uses Skylighting by default.
4748
- New template variables `mathfont`, `codefont`, and `linestretch` for font and line spacing customization.

src/resources/filters/quarto-post/typst.lua

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,48 @@ function render_typst_fixups()
9494
if image.attributes["width"] ~= nil and type(width_as_number) == "number" then
9595
image.attributes["width"] = tostring(image.attributes["width"] / PANDOC_WRITER_OPTIONS.dpi) .. "in"
9696
end
97+
98+
-- Workaround for Pandoc not passing alt text to Typst image() calls
99+
-- See: https://github.com/jgm/pandoc/issues/XXXX (TODO: file upstream)
100+
local alt_text = image.attributes["alt"]
101+
if (alt_text == nil or alt_text == "") and #image.caption > 0 then
102+
alt_text = pandoc.utils.stringify(image.caption)
103+
end
104+
105+
if alt_text and #alt_text > 0 then
106+
-- When returning RawInline instead of Image, Pandoc won't write mediabag
107+
-- entries to disk, so we must do it explicitly
108+
local src = image.src
109+
local mediabagPath = _quarto.modules.mediabag.write_mediabag_entry(src)
110+
if mediabagPath then
111+
src = mediabagPath
112+
end
113+
114+
-- Build image() parameters
115+
local params = {}
116+
117+
-- Source path (escape backslashes for Windows paths)
118+
src = src:gsub('\\', '\\\\')
119+
table.insert(params, '"' .. src .. '"')
120+
121+
-- Alt text second (escape backslashes and quotes)
122+
local escaped_alt = alt_text:gsub('\\', '\\\\'):gsub('"', '\\"')
123+
table.insert(params, 'alt: "' .. escaped_alt .. '"')
124+
125+
-- Height if present
126+
if image.attributes["height"] then
127+
table.insert(params, 'height: ' .. image.attributes["height"])
128+
end
129+
130+
-- Width if present
131+
if image.attributes["width"] then
132+
table.insert(params, 'width: ' .. image.attributes["width"])
133+
end
134+
135+
-- Use #box() wrapper for inline compatibility
136+
return pandoc.RawInline("typst", "#box(image(" .. table.concat(params, ", ") .. "))")
137+
end
138+
97139
return image
98140
end,
99141
Div = function(div)

tests/docs/smoke-all/crossrefs/float/typst/typst-float-4.qmd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ _quarto:
66
tests:
77
typst:
88
ensureTypstFileRegexMatches:
9-
-
9+
-
1010
- "#ref\\(<tbl-foo>, supplement: \\[Table\\]\\)"
1111
- "#ref\\(<fig-foo>, supplement: \\[Figure\\]\\)"
12-
- "#link\\(\"https://www.example.com/\"\\)\\[#.*image\\(\"img/surus.jpg\"\\)\\)"
12+
# Images with captions now include alt text for accessibility
13+
- '#link\("https://www\.example\.com/"\)\[#box\(image\("img/surus\.jpg", alt:'
1314
---
1415

1516
This tests:
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: "Alt text test"
3+
pdf-standard: ua-1
4+
keep-tex: true
5+
---
6+
7+
![This is the alt text](penrose.svg)
8+
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)