https://bugs.kde.org/show_bug.cgi?id=522026
Bug ID: 522026
Summary: Add support for UA-1 and UA-2
Classification: Applications
Product: okular
Version First 26.04.1
Reported In:
Platform: Other
OS: Linux
Status: REPORTED
Severity: wishlist
Priority: NOR
Component: PDF backend
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
DESCRIPTION
When using Okular's "Speak Text" feature on a PDF containing equations, the raw
glyph stream is spoken instead of the semantic meaning. This is because
Okular's TTS ignores the PDF tag tree entirely, reading the raw content stream
instead.
Tagged PDFs (such as those produced by Typst) contain a semantic structure tree
with correct reading order and, when compiled with --pdf-standard ua-1, alt
text for equations. Okular does not use any of this information when speaking
text.
https://en.wikipedia.org/wiki/PDF/UA
https://www.adobe.com/uk/acrobat/resources/document-files/pdf-types/pdf-ua.html
STEPS TO REPRODUCE
1. Open a tagged PDF containing a math equation (e.g. one produced by Typst)
2 .Select text including an equation
3. Right-click β Speak Text (or Tools β Speak β Speak Whole Document)
For Typst
1. make PDF
2. Include this equation
```typst
#math.equation(
alt: "power equals RMS voltage squared divided by the resistance of the
speaker",
block: true,
$ P = V^2_"RMS"/R_"speaker" $,
)
<eq:power_formula>
```
3. compile with
```shell
typst compile first.typ --pdf-standard ua-1
```
OBSERVED RESULT
The raw text gets spoken
```
π=
π RMS
2
π
speaker
```
EXPECTED RESULT
Okular should use the PDF tag tree for reading order and alt text. For a
PDF/UA-1 conformant file with equation alt text, it should speak the alt text
instead, e.g.:
```
power equals RMS voltage squared divided by the resistance of the speaker
```
SOFTWARE/OS VERSIONS
Operating System (available in the Info Center app, or by running `kinfo` in a
terminal window):
KDE Plasma Version: N/A (running COSMIC on NixOS)
KDE Frameworks Version: not found
Qt Version: 6.11.0
ADDITIONAL INFORMATION
```
β― nix-shell -p python3Packages.pdfminer-six --run "python3 -c \"
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdftypes import resolve1
with open('first.pdf', 'rb') as f:
parser = PDFParser(f)
doc = PDFDocument(parser)
struct_root = resolve1(doc.catalog['StructTreeRoot'])
def decode(v):
if isinstance(v, bytes): return v.decode()
return str(v)
def walk(node, indent=0):
node = resolve1(node)
if not isinstance(node, dict): return
s = node.get('S', b'')
alt = node.get('Alt', None)
tag = s.name if hasattr(s, 'name') else decode(s)
line = ' ' * indent + tag
if alt:
line += f' [Alt: {decode(alt)}]'
print(line)
kids = node.get('K', None)
if kids is None: return
if isinstance(kids, list):
for k in kids: walk(k, indent+1)
else: walk(kids, indent+1)
walk(struct_root)
\""
Document
H1
P
Link
Formula [Alt: power equals RMS voltage squared divided by the resistance
of the speaker]
P
H1
P
P
P
Link
Link
P
Link
Table
TR
TD
Strong
TD
Strong
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
TR
TD
TD
H1
L
LI
Lbl
Link
LBody
BibEntry
Em
Link
LI
Lbl
Link
LBody
BibEntry
Em
P
Link
```
--
You are receiving this mail because:
You are watching all bug changes.