Enable tagged PDF export for html2pdf renders

Chrome PrintToPDF now requests a structure tree and document
outline by default, with optional RenderConfig overrides. Add
lang="en" on the e-signature certificate template so /Lang is
emitted.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
This commit is contained in:
Cursor Agent
2026-07-29 15:56:26 +00:00
committed by Bryan Frimin
parent b229da0115
commit 4960abab9e
3 changed files with 51 additions and 1 deletions

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8" />
<style>

View File

@@ -58,6 +58,12 @@ type (
Scale float64 // Print scale (0.1 to 2.0)
WaitForExpression string // Optional JS expression polled until true before printing
WaitForExpressionTimeout time.Duration // Max time to wait (default 15s)
// GenerateTaggedPDF enables accessible PDF tagging (structure tree, reading
// order). Nil defaults to true.
GenerateTaggedPDF *bool
// GenerateDocumentOutline embeds a document outline (bookmarks). Nil defaults
// to true.
GenerateDocumentOutline *bool
}
Option func(*Converter)
@@ -122,6 +128,22 @@ func getPageDimensions(format PageFormat, orientation Orientation) (width, heigh
return w, h
}
func generateTaggedPDFEnabled(cfg RenderConfig) bool {
if cfg.GenerateTaggedPDF != nil {
return *cfg.GenerateTaggedPDF
}
return true
}
func generateDocumentOutlineEnabled(cfg RenderConfig) bool {
if cfg.GenerateDocumentOutline != nil {
return *cfg.GenerateDocumentOutline
}
return true
}
func (c *Converter) GeneratePDF(ctx context.Context, htmlDocument []byte, cfg RenderConfig) (io.Reader, error) {
var (
rootSpan = trace.SpanFromContext(ctx)
@@ -155,6 +177,9 @@ func (c *Converter) GeneratePDF(ctx context.Context, htmlDocument []byte, cfg Re
scale = 1.0
}
generateTaggedPDF := generateTaggedPDFEnabled(cfg)
generateDocumentOutline := generateDocumentOutlineEnabled(cfg)
var pdfBytes []byte
c.l.InfoCtx(
@@ -168,6 +193,8 @@ func (c *Converter) GeneratePDF(ctx context.Context, htmlDocument []byte, cfg Re
log.Float64("marginRight", marginRight),
log.Float64("scale", scale),
log.Bool("printBackground", cfg.PrintBackground),
log.Bool("generateTaggedPDF", generateTaggedPDF),
log.Bool("generateDocumentOutline", generateDocumentOutline),
)
htmlContent := string(htmlDocument)
@@ -231,6 +258,8 @@ func (c *Converter) GeneratePDF(ctx context.Context, htmlDocument []byte, cfg Re
WithMarginRight(marginRight).
WithScale(scale).
WithPreferCSSPageSize(false).
WithGenerateTaggedPDF(generateTaggedPDF).
WithGenerateDocumentOutline(generateDocumentOutline).
Do(ctx)
return err

View File

@@ -72,6 +72,26 @@ func TestWithLogger(t *testing.T) {
assert.NotNil(t, converter.l)
}
func TestGenerateTaggedPDFEnabled(t *testing.T) {
assert.True(t, generateTaggedPDFEnabled(RenderConfig{}))
disabled := false
assert.False(t, generateTaggedPDFEnabled(RenderConfig{GenerateTaggedPDF: &disabled}))
enabled := true
assert.True(t, generateTaggedPDFEnabled(RenderConfig{GenerateTaggedPDF: &enabled}))
}
func TestGenerateDocumentOutlineEnabled(t *testing.T) {
assert.True(t, generateDocumentOutlineEnabled(RenderConfig{}))
disabled := false
assert.False(t, generateDocumentOutlineEnabled(RenderConfig{GenerateDocumentOutline: &disabled}))
enabled := true
assert.True(t, generateDocumentOutlineEnabled(RenderConfig{GenerateDocumentOutline: &enabled}))
}
func TestGetPageDimensions(t *testing.T) {
tests := []struct {
name string
@@ -212,6 +232,7 @@ func TestGeneratePDF_WithValidChrome(t *testing.T) {
// Verify it looks like a PDF file (starts with PDF magic bytes)
assert.True(t, bytes.HasPrefix(pdfContent, []byte("%PDF-")))
assert.Contains(t, string(pdfContent), "/StructTreeRoot")
}
func TestGeneratePDF_ScaleHandling(t *testing.T) {