-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathtext.py
More file actions
161 lines (128 loc) · 5.84 KB
/
text.py
File metadata and controls
161 lines (128 loc) · 5.84 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import html
import reportlab.lib.enums
from reportlab.lib.styles import ParagraphStyle
from fontHandling import getAvailableFont
from lineScales import LineScales
def CreateParagraphStyle(textcolor, font, fontsize, font_size_adjust):
# apply a tiny adjustment to the font size used by ReportLab for measuring
adjusted_fs = fontsize * font_size_adjust
parastyle = ParagraphStyle(None, None,
alignment=reportlab.lib.enums.TA_LEFT, # will often be overridden
fontSize=adjusted_fs,
fontName=font,
leading=adjusted_fs * LineScales.lineScaleForFont(font), # line spacing (text + leading)
borderPadding=0,
borderWidth=0,
leftIndent=0,
rightIndent=0,
embeddedHyphenation=1, # allow line break on existing hyphens
# backColor=backgroundColor, # text bg not used since ColorFrame colours the whole bg
textColor=textcolor)
return parastyle
def IsBold(weight):
return weight > 400
def IsItalic(itemstyle, outerstyle):
if 'font-style' in itemstyle:
return itemstyle['font-style'].strip(" ") == "italic"
if 'font-style' in outerstyle:
return outerstyle['font-style'].strip(" ") == "italic"
return False
def IsUnderline(itemstyle, outerstyle):
if 'text-decoration' in itemstyle:
return itemstyle['text-decoration'].strip(" ") == "underline"
if 'text-decoration' in outerstyle:
return outerstyle['text-decoration'].strip(" ") == "underline"
return False
def Dequote(s):
"""
If a string has single or double quotes around it, remove them.
Make sure the pair of quotes match.
If a matching pair of quotes is not found, return the string unchanged.
"""
if (s[0] == s[-1]) and s.startswith(("'", '"')):
return s[1:-1]
return s
# we can not delete now, because file is opened by pdf library
def CollectFontInfo(item, pdf, additional_fonts, dfltfont, dfltfs, bweight, fontScaleFactor):
if item is None:
return dfltfont, dfltfs, bweight, {}
spanfont = dfltfont
spanfs = dfltfs
spanweight = bweight
spanstyle = dict([kv.split(':') for kv in
item.get('style').lstrip(' ').rstrip(';').split('; ')])
if 'font-family' in spanstyle:
spanfamily = spanstyle['font-family'].strip("'")
spanfont = getAvailableFont(spanfamily, pdf, additional_fonts)
if 'font-weight' in spanstyle:
try:
spanweight = int(Dequote(spanstyle['font-weight']))
except: # noqa: E722 # pylint: disable=bare-except
spanweight = 400
if 'font-size' in spanstyle:
# preserve fractional point sizes and apply the global adjustment
try:
spanfs = float(spanstyle['font-size'].strip("pt"))
except Exception: # pylint: disable=broad-except
spanfs = float(dfltfs)
# apply the small adjustment multiplier
spanfs = spanfs * fontScaleFactor
return spanfont, spanfs, spanweight, spanstyle
def CollectItemFontFamily(item, dfltfont):
if item is None:
return dfltfont
itemfont = dfltfont
itemstyle = dict([kv.split(':') for kv in
item.get('style').lstrip(' ').rstrip(';').split('; ')])
if 'font-family' in itemstyle:
itemfont = itemstyle['font-family'].strip("'")
return itemfont
def AppendText(paratext, newtext):
if newtext is None:
return paratext
return paratext + newtext.replace('\t', ' ')
def AppendBreak(paragraphText, parachild):
br = parachild
paragraphText = AppendText(paragraphText, "<br></br> ")
paragraphText = AppendText(paragraphText, br.tail)
return paragraphText
def AppendSpanStart(paragraphText, font, fsize, fweight, fstyle, outerstyle):
"""
Remember this is not really HTML, though it looks that way.
See 6.2 Paragraph XML Markup Tags in the reportlabs user guide.
"""
# format font size with two decimals so ReportLab receives a stable float
paragraphText = AppendText(paragraphText, f'<font name="{font}" size={fsize:.2f}')
if 'color' in fstyle:
paragraphText = AppendText(paragraphText, ' color=' + fstyle['color'])
# This old strategy doesn't interpret background alpha values correctly, background is
# now done in processAreaTextTag (credit seaeagle1, changeset 687fe50)
# if bgColorAttrib is not None:
# paragraphText = AppendText(paragraphText, ' backcolor=' + bgColorAttrib)
paragraphText = AppendText(paragraphText, '>')
if IsBold(fweight): # ref https://www.w3schools.com/csSref/pr_font_weight.asp
paragraphText = AppendText(paragraphText, "<b>")
if IsItalic(fstyle, outerstyle):
paragraphText = AppendText(paragraphText, '<i>')
if IsUnderline(fstyle, outerstyle):
paragraphText = AppendText(paragraphText, '<u>')
return paragraphText
def AppendSpanEnd(paragraphText, weight, style, outerstyle):
if IsUnderline(style, outerstyle):
paragraphText = AppendText(paragraphText, '</u>')
if IsItalic(style, outerstyle):
paragraphText = AppendText(paragraphText, '</i>')
if IsBold(weight):
paragraphText = AppendText(paragraphText, "</b>")
paragraphText = AppendText(paragraphText, '</font>')
return paragraphText
def AppendItemTextInStyle(paragraphText, text, item, pdf, additional_fonts, bodyfont, bodyfs,
bweight, bstyle, fontScaleFactor): # pylint: disable= too-many-arguments
pfont, pfs, pweight, pstyle = CollectFontInfo(item, pdf, additional_fonts, bodyfont, bodyfs, bweight, fontScaleFactor)
paragraphText = AppendSpanStart(paragraphText, pfont, pfs, pweight, pstyle, bstyle)
if text is None:
paragraphText = AppendText(paragraphText, "")
else:
paragraphText = AppendText(paragraphText, html.escape(text))
paragraphText = AppendSpanEnd(paragraphText, pweight, pstyle, bstyle)
return paragraphText, pfs