/
text.go
142 lines (111 loc) · 3.65 KB
/
text.go
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package internal
import (
"strings"
"github.com/johnfercher/maroto/internal/fpdf"
"github.com/johnfercher/maroto/pkg/consts"
"github.com/johnfercher/maroto/pkg/props"
)
// Text is the abstraction which deals of how to add text inside PDF.
type Text interface {
Add(text string, cell Cell, textProp props.Text)
GetLinesQuantity(text string, fontFamily props.Text, colWidth float64) int
}
type text struct {
pdf fpdf.Fpdf
math Math
font Font
}
// NewText create a Text.
func NewText(pdf fpdf.Fpdf, math Math, font Font) *text {
return &text{
pdf,
math,
font,
}
}
// Add a text inside a cell.
func (s *text) Add(text string, cell Cell, textProp props.Text) {
s.font.SetFont(textProp.Family, textProp.Style, textProp.Size)
originalColor := s.font.GetColor()
s.font.SetColor(textProp.Color)
// duplicated
_, _, fontSize := s.font.GetFont()
fontHeight := fontSize / s.font.GetScaleFactor()
cell.Y += fontHeight
// Apply Unicode before calc spaces
unicodeText := s.textToUnicode(text, textProp)
stringWidth := s.pdf.GetStringWidth(unicodeText)
words := strings.Split(unicodeText, " ")
accumulateOffsetY := 0.0
// If should add one line
if stringWidth < cell.Width || textProp.Extrapolate || len(words) == 1 {
s.addLine(textProp, cell.X, cell.Width, cell.Y, stringWidth, unicodeText)
} else {
lines := s.getLines(words, cell.Width)
for index, line := range lines {
lineWidth := s.pdf.GetStringWidth(line)
_, _, fontSize := s.font.GetFont()
textHeight := fontSize / s.font.GetScaleFactor()
s.addLine(textProp, cell.X, cell.Width, cell.Y+float64(index)*textHeight+accumulateOffsetY, lineWidth, line)
accumulateOffsetY += textProp.VerticalPadding
}
}
s.font.SetColor(originalColor)
}
// GetLinesQuantity retrieve the quantity of lines which a text will occupy to avoid that text to extrapolate a cell.
func (s *text) GetLinesQuantity(text string, textProp props.Text, colWidth float64) int {
translator := s.pdf.UnicodeTranslatorFromDescriptor("")
s.font.SetFont(textProp.Family, textProp.Style, textProp.Size)
// Apply Unicode.
textTranslated := translator(text)
stringWidth := s.pdf.GetStringWidth(textTranslated)
words := strings.Split(textTranslated, " ")
// If should add one line.
if stringWidth < colWidth || textProp.Extrapolate || len(words) == 1 {
return 1
}
lines := s.getLines(words, colWidth)
return len(lines)
}
func (s *text) getLines(words []string, colWidth float64) []string {
currentlySize := 0.0
actualLine := 0
lines := []string{}
lines = append(lines, "")
for _, word := range words {
if s.pdf.GetStringWidth(word+" ")+currentlySize < colWidth {
lines[actualLine] = lines[actualLine] + word + " "
currentlySize += s.pdf.GetStringWidth(word + " ")
} else {
lines = append(lines, "")
actualLine++
lines[actualLine] = lines[actualLine] + word + " "
currentlySize = s.pdf.GetStringWidth(word + " ")
}
}
return lines
}
func (s *text) addLine(textProp props.Text, xColOffset, colWidth, yColOffset, textWidth float64, text string) {
left, top, _, _ := s.pdf.GetMargins()
if textProp.Align == consts.Left {
s.pdf.Text(xColOffset+left, yColOffset+top, text)
return
}
var modifier float64 = 2
if textProp.Align == consts.Right {
modifier = 1
}
dx := (colWidth - textWidth) / modifier
s.pdf.Text(dx+xColOffset+left, yColOffset+top, text)
}
func (s *text) textToUnicode(txt string, props props.Text) string {
if props.Family == consts.Arial ||
props.Family == consts.Helvetica ||
props.Family == consts.Symbol ||
props.Family == consts.ZapBats ||
props.Family == consts.Courier {
translator := s.pdf.UnicodeTranslatorFromDescriptor("")
return translator(txt)
}
return txt
}