1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// Package export renders a day's readings (or a passage) to shareable formats:
// plain text, Markdown, and PDF -- plus a printable A4 month calendar. The PDF
// uses an embedded DejaVu Sans (regular + bold) so Polish, Latin and Greek all
// render; it is pure Go (no cgo), keeping the single-binary cross-compile.
package export
import (
"bytes"
_ "embed"
"fmt"
"strings"
"github.com/go-pdf/fpdf"
"github.com/lukaszkasprzak/lectio/internal/i18n"
"github.com/lukaszkasprzak/lectio/internal/liturgy"
"github.com/lukaszkasprzak/lectio/internal/render"
)
// versionLabel is the localized name of a version (i18n), or the bare code.
func versionLabel(version, lang string) string {
if l, ok := i18n.Get(lang).Version[version]; ok {
return l
}
return version
}
// title is the document heading: the celebration name if the source carries
// one, else a plain "readings for DATE" style line.
func title(date string, info liturgy.DayInfo) string {
if info.Name != "" {
return info.Name
}
return date
}
// Text renders a day's readings as plain UTF-8 text: a title, the day-info,
// then each section's localized heading and its version blocks.
func Text(date string, info liturgy.DayInfo, secs []liturgy.Section, version, lectionary, lang string) string {
var b strings.Builder
fmt.Fprintf(&b, "%s\n", title(date, info))
if info.Season != "" {
fmt.Fprintf(&b, "%s\n", info.Season)
}
fmt.Fprintf(&b, "%s · %s\n\n", date, versionLabel(version, lang))
for _, sec := range secs {
fmt.Fprintf(&b, "%s\n\n", render.HeadingWithRef(sec, lang))
_, blocks := render.GatherVersion(version, sec, lectionary, lang)
for _, blk := range blocks {
fmt.Fprintf(&b, "%s\n", blk)
}
b.WriteString("\n")
}
return b.String()
}
// Markdown renders a day's readings as Markdown (# title, ## section headings,
// verse/paragraph blocks).
func Markdown(date string, info liturgy.DayInfo, secs []liturgy.Section, version, lectionary, lang string) string {
var b strings.Builder
fmt.Fprintf(&b, "# %s\n\n", title(date, info))
if info.Season != "" {
fmt.Fprintf(&b, "*%s*\n\n", info.Season)
}
fmt.Fprintf(&b, "**%s · %s**\n\n", date, versionLabel(version, lang))
for _, sec := range secs {
fmt.Fprintf(&b, "## %s\n\n", render.HeadingWithRef(sec, lang))
_, blocks := render.GatherVersion(version, sec, lectionary, lang)
for _, blk := range blocks {
fmt.Fprintf(&b, "%s\n\n", blk)
}
}
return b.String()
}
// ReadingsPDF renders a day's readings as a clean printable PDF.
func ReadingsPDF(date string, info liturgy.DayInfo, secs []liturgy.Section, version, lectionary, lang string) ([]byte, error) {
pdf := newPDF()
pdf.AddPage()
pdf.SetFont(fontFamily, "B", 18)
pdf.MultiCell(0, 9, title(date, info), "", "L", false)
if info.Season != "" {
pdf.SetFont(fontFamily, "", 10)
pdf.MultiCell(0, 6, info.Season, "", "L", false)
}
pdf.SetFont(fontFamily, "", 10)
pdf.MultiCell(0, 6, date+" · "+versionLabel(version, lang), "", "L", false)
pdf.Ln(3)
for _, sec := range secs {
pdf.Ln(2)
pdf.SetFont(fontFamily, "B", 13)
pdf.MultiCell(0, 7, render.HeadingWithRef(sec, lang), "", "L", false)
pdf.Ln(1)
pdf.SetFont(fontFamily, "", 11)
_, blocks := render.GatherVersion(version, sec, lectionary, lang)
for _, blk := range blocks {
pdf.MultiCell(0, 6, blk, "", "L", false)
pdf.Ln(1)
}
}
var buf bytes.Buffer
if err := pdf.Output(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
//go:embed fonts/DejaVuSans.ttf
var fontRegular []byte
//go:embed fonts/DejaVuSans-Bold.ttf
var fontBold []byte
const fontFamily = "dejavu"
// newPDF returns an A4 portrait document with the embedded Unicode font
// registered (regular + bold) and sensible margins/auto page break.
func newPDF() *fpdf.Fpdf {
pdf := fpdf.New("P", "mm", "A4", "")
pdf.AddUTF8FontFromBytes(fontFamily, "", fontRegular)
pdf.AddUTF8FontFromBytes(fontFamily, "B", fontBold)
pdf.SetMargins(18, 16, 18)
pdf.SetAutoPageBreak(true, 16)
return pdf
}
|