Summary
When exporting a tagged PDF (PDF/A-3A with setTagged(true)) containing run-level hyperlinks (HTML <a> tags in markup="html" text fields), the generated PDF fails PDF/UA validation. No Link structure element is created for inline links — the annotation is orphaned, violating ISO 14289-1 (PDF/UA-1) and WCAG 2.1 — 4.1.2 Name, Role, Value.
Element-level links (linkType="Reference") work correctly — Link structure element is created with proper MCID and OBJR. PAC passes for those.
Environment
| Component |
Version |
| JasperReports |
7.0.7 |
| jasperreports-pdf |
7.0.7 |
| OpenPDF (transitive) |
1.3.43.jaspersoft.2 |
| Java |
21 |
Reproduction project
ukufd/jasperreports-wcag-bugreport — contains templates, pre-generated PDFs, and PAC validation reports.
mvn clean compile exec:java
Then open target/accessibility-output/with_links.pdf in PAC 2024 and run the WCAG check.
Template snippet
<element kind="textField" markup="html" textAdjust="StretchHeight" hTextAlign="Justified"
x="0" y="0" width="420" height="20">
<expression><![CDATA["This section contains <a href='https://jasperreports.sourceforge.net'
style='color:#267CB8'>a link with custom text</a> inside a paragraph."]]></expression>
</element>
Actual structure (JasperReports 7.0.7)
Text (→P)
└─ MC (MCID=5) → "This section contains " + "a link with custom text" + " inside a paragraph."
^^^ all three text runs in a SINGLE marked content sequence
/Link annotation on page:
├─ NO /StructParent
├─ NO /Contents
└─ /A → URI(https://jasperreports.sourceforge.net)
- ❌ No
Link structure element — annotation is orphaned.
- ❌ No
/StructParent → invisible to the structure tree.
- ❌ No
/Contents → PAC warning.
- ❌ PAC error:
"Link" annotation is not nested inside a "Link" structure element.
Expected PDF/UA structure
P
├─ MC (MCID=N) → "This section contains "
├─ Link
│ ├─ MC (MCID=N+1) → "a link with custom text"
│ └─ OBJR → /Link annotation
└─ MC (MCID=N+2) → " inside a paragraph."
Root cause
The issue originates in JRPdfExporterTagHelper.startText() and JRPdfExporter.getPhrase():
-
Single marked content sequence covers entire paragraph — startText() opens one beginMarkedContentSequence() for the whole paragraph. All chunk text rendered by ColumnText.go() lands inside this single MC — there is no mechanism to close the MC before a link, open a new MC under a Link structure element, and resume the paragraph MC after.
-
No Link structure element for run-level hyperlinks — startText() only checks textElement.getLinkType() (element-level links). HTML <a> tags parsed as JRTextAttribute.HYPERLINK run attributes are not detected — no Link structure element is created for them.
-
ColumnText dual-buffer architecture prevents inline MC splitting — OpenPDF's ColumnText.go() writes text to a duplicate PdfContentByte buffer and appends it to the main canvas only after all chunks are rendered. MC operations during chunk iteration go to the main canvas, not the text buffer — resulting in MC boundaries that do not wrap the actual text operators.
-
Link annotation OBJR silently dropped when /K is null or PdfDictionary — ClassicChunk.addAnnotationToTag() only handles PdfArray and PdfNumber for the /K entry. If /K is null or a PdfDictionary, the annotation's OBJR is not added to the structure tree.
References
Summary
When exporting a tagged PDF (PDF/A-3A with
setTagged(true)) containing run-level hyperlinks (HTML<a>tags inmarkup="html"text fields), the generated PDF fails PDF/UA validation. NoLinkstructure element is created for inline links — the annotation is orphaned, violating ISO 14289-1 (PDF/UA-1) and WCAG 2.1 — 4.1.2 Name, Role, Value.Element-level links (
linkType="Reference") work correctly —Linkstructure element is created with proper MCID and OBJR. PAC passes for those.Environment
Reproduction project
ukufd/jasperreports-wcag-bugreport — contains templates, pre-generated PDFs, and PAC validation reports.
Then open
target/accessibility-output/with_links.pdfin PAC 2024 and run the WCAG check.Template snippet
Actual structure (JasperReports 7.0.7)
Linkstructure element — annotation is orphaned./StructParent→ invisible to the structure tree./Contents→ PAC warning."Link" annotation is not nested inside a "Link" structure element.Expected PDF/UA structure
Root cause
The issue originates in
JRPdfExporterTagHelper.startText()andJRPdfExporter.getPhrase():Single marked content sequence covers entire paragraph —
startText()opens onebeginMarkedContentSequence()for the whole paragraph. All chunk text rendered byColumnText.go()lands inside this single MC — there is no mechanism to close the MC before a link, open a new MC under aLinkstructure element, and resume the paragraph MC after.No
Linkstructure element for run-level hyperlinks —startText()only checkstextElement.getLinkType()(element-level links). HTML<a>tags parsed asJRTextAttribute.HYPERLINKrun attributes are not detected — noLinkstructure element is created for them.ColumnTextdual-buffer architecture prevents inline MC splitting — OpenPDF'sColumnText.go()writes text to a duplicatePdfContentBytebuffer and appends it to the main canvas only after all chunks are rendered. MC operations during chunk iteration go to the main canvas, not the text buffer — resulting in MC boundaries that do not wrap the actual text operators.Link annotation OBJR silently dropped when
/Kis null orPdfDictionary—ClassicChunk.addAnnotationToTag()only handlesPdfArrayandPdfNumberfor the/Kentry. If/Kisnullor aPdfDictionary, the annotation's OBJR is not added to the structure tree.References