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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 | """Fills text and a shape with a gradient, through a shading pattern.
The Python twin of the `write_gradient_fill` example in Rust. Where
`write_gradient` paints a gradient into a clipped box, this makes a gradient the
colour something is filled with: a headline whose letters are windows onto a
three-stop blend, and a panel filled with a radial one. The gradient lives in
the page's own space, so the letters show the part of it behind them.
A band at the foot of the page is filled with a gradient laid along the pattern's own
horizontal axis and turned upright by the pattern's matrix, and edged with the panel's
radial gradient. The panel's pattern carries a graphics state of its own, which
paints it at 70 % opacity.
The three captions are held in `Words`, once per language, and `HQF_PDF_LANG` picks which
set is drawn. The headline is the library's own name and reads the same in every
language.
Usage: python examples/write_gradient_fill.py [out.pdf] [font.ttf]
HQF_PDF_LANG=fr python examples/write_gradient_fill.py
"""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import _language
import _licence
import _out
import hqf_pdf
# The headline the gradient fills, which is the library's own name.
HEADLINE = "hqf-pdf"
@dataclass(frozen=True)
class Words:
"""Every word the page draws, in one language."""
# The caption under the headline.
letters: str
# The caption under the panel.
shape: str
# The caption under the band.
placed: str
# The page in English.
ENGLISH = Words(
letters="Text filled with a gradient, through a shading pattern.",
shape="A radial gradient, painted by its pattern at 70 % opacity.",
placed="A gradient laid flat, stood upright by its pattern's matrix, edged in radial.",
)
# The page in French.
FRENCH = Words(
letters="Du texte rempli par un dégradé, au moyen d’un motif.",
shape="Un dégradé radial, peint par son motif à 70 % d’opacité.",
placed=(
"Un dégradé couché, redressé par la matrice de son motif, bordé en radial."
),
)
# The page in Dutch.
DUTCH = Words(
letters="Tekst gevuld met een verloop, via een arceringspatroon.",
shape="Een radiaal verloop, geschilderd door zijn patroon op 70 % dekking.",
placed="Een plat verloop, rechtgezet door de patroonmatrix; radiale rand.",
)
# The page in Portuguese.
PORTUGUESE = Words(
letters="Texto preenchido com um degradé, por um padrão de sombreado.",
shape="Um degradé radial, pintado pelo seu padrão a 70 % de opacidade.",
placed="Um degradé deitado, endireitado pela matriz do padrão, orlado em radial.",
)
# The page in Italian.
ITALIAN = Words(
letters="Testo riempito con un gradiente, tramite un motivo di sfumatura.",
shape="Un gradiente radiale, dipinto dal suo motivo al 70 % di opacità.",
placed="Un gradiente disteso, raddrizzato dalla matrice del motivo; bordo radiale.",
)
# The page in Spanish.
SPANISH = Words(
letters="Texto relleno con un degradado, mediante un patrón de sombreado.",
shape="Un degradado radial, pintado por su patrón al 70 % de opacidad.",
placed="Un degradado tumbado, enderezado por la matriz del patrón; borde radial.",
)
# The page in German.
GERMAN = Words(
letters="Text, über ein Schattierungsmuster mit einem Verlauf gefüllt.",
shape="Ein radialer Verlauf, vom Muster mit 70 % Deckkraft gemalt.",
placed="Ein flacher Verlauf, von der Mustermatrix aufgerichtet, radial umrandet.",
)
# Every language the example is written in. A language is added by writing its own set
# of words and naming it here.
WORDS = {_language.ENGLISH: ENGLISH, _language.FRENCH: FRENCH, _language.GERMAN: GERMAN, _language.SPANISH: SPANISH, _language.ITALIAN: ITALIAN, _language.PORTUGUESE: PORTUGUESE, _language.DUTCH: DUTCH}
def main() -> None:
language = _language.from_environment()
words = _language.words_of(WORDS, language)
# A named file is written as named; the default one carries the language, so the two
# languages do not overwrite each other in `tmp/`.
out = _out.output_path(Path(_language.file_name("gradient_fill.pdf", language)).stem)
document = hqf_pdf.Document()
document.set_license(_licence.licensed())
handle = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))
left = 70.0
# A three-stop gradient spanning the width of the headline, set as a fill pattern so
# the letters show it through their shapes.
headline_size = 84.0
headline_baseline = 660.0
headline_width = handle.measure(HEADLINE, headline_size)
ramp = hqf_pdf.Function.stitching(
(0.0, 1.0),
[
hqf_pdf.Function.exponential(
(0.0, 1.0), 1.0, ([0.85, 0.12, 0.12], [0.12, 0.55, 0.2])
),
hqf_pdf.Function.exponential(
(0.0, 1.0), 1.0, ([0.12, 0.55, 0.2], [0.12, 0.2, 0.8])
),
],
[0.5],
[(0.0, 1.0), (0.0, 1.0)],
)
letters = document.add_shading_pattern(
hqf_pdf.Axial(
(left, headline_baseline),
(left + headline_width, headline_baseline),
hqf_pdf.DeviceSpace.Rgb,
ramp,
)
)
# A radial gradient filling a panel below the headline, painted under a state of the
# pattern's own.
px, py, pw, ph = left, 350.0, 455.0, 190.0
see_through = document.add_ext_gstate(hqf_pdf.ExtGState(fill_alpha=0.7))
panel = document.add_shading_pattern(
hqf_pdf.Radial.rgb(
(px + pw / 2.0, py + ph / 2.0, 0.0),
(px + pw / 2.0, py + ph / 2.0, pw / 2.0),
hqf_pdf.Rgb(1.0, 1.0, 1.0),
hqf_pdf.Rgb(0.1, 0.15, 0.45),
).extend(False, True),
state=see_through,
)
# A gradient laid from red to blue along the pattern's own horizontal axis, over the
# band's height; the matrix turns that axis upright and stands it at the band's
# foot.
bx, by, bw, bh = left, 150.0, 455.0, 120.0
upright = document.add_shading_pattern(
hqf_pdf.Axial.rgb(
(0.0, 0.0),
(bh, 0.0),
hqf_pdf.Rgb(0.85, 0.12, 0.12),
hqf_pdf.Rgb(0.12, 0.2, 0.8),
).extend(True, True),
matrix=(0.0, 1.0, -1.0, 0.0, bx, by),
)
content = hqf_pdf.Content()
# The headline, its letters filled with the gradient.
content.save_state()
content.set_fill_pattern(letters)
content.draw_text(handle, headline_size, left, headline_baseline, HEADLINE)
content.restore_state()
# A caption, in plain black.
content.draw_text(handle, 13.0, left, headline_baseline - 26.0, words.letters)
# The panel, filled with the radial gradient.
content.save_state()
content.set_fill(hqf_pdf.Paint.pattern(panel))
content.rect(px, py, pw, ph)
content.fill()
content.restore_state()
content.draw_text(handle, 12.0, px, py - 16.0, words.shape)
# The band, filled with the turned gradient and edged with the panel's.
content.save_state()
content.set_fill(hqf_pdf.Paint.pattern(upright))
content.set_stroke_pattern(panel)
content.set_line_width(6.0)
content.rect(bx, by, bw, bh)
content.fill_and_stroke()
content.restore_state()
content.draw_text(handle, 12.0, bx, by - 16.0, words.placed)
page = hqf_pdf.Page.a4()
page.set_content(content)
document.add_page(page)
written = document.write(out)
print(f"wrote {out}: {written} bytes")
if __name__ == "__main__":
main()
|