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 | """Sets one paragraph in a column too narrow for a word in it, twice: above as it
comes, below cut to the column.
The Python twin of the `write_flow_break` example in Rust.
The paragraph and the two headings are held in `Words`, once per language, and
`HQF_PDF_LANG` picks which set is drawn. Each heading opens with the name the library
gives its setting, which is the same in every language.
Usage: python examples/write_flow_break.py [out.pdf] [font.ttf]
HQF_PDF_LANG=fr python examples/write_flow_break.py
"""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import _language
import _licence
import _out
import hqf_pdf
# The payment reference the paragraph carries: one word to a line breaker, longer than
# the column it is put in, and the same in every language.
REFERENCE = "GB29NWBK60161331926819-2026-07-DEPOSIT"
@dataclass(frozen=True)
class Words:
"""Every word the page draws, in one language.
What is not language stays out of it: the payment reference reads the same wherever
the page is read, and each heading opens with the name the library gives the setting
it stands over.
"""
# The heading over the setting that leaves the long word whole.
overflow: str
# The heading over the setting that cuts it.
breaking: str
# The paragraph, cut where the reference goes into it.
paragraph_before: str
paragraph_after: str
def paragraph(self) -> str:
"""Return the paragraph both settings are given, with the reference in it."""
return f"{self.paragraph_before}{REFERENCE}{self.paragraph_after}"
# The page in English.
ENGLISH = Words(
overflow="Overflow: the word is left whole, and runs past the edge.",
breaking="Break: the word is cut after its last glyph that fits.",
paragraph_before="Paid by bank transfer, reference ",
paragraph_after=(
", to be matched against the purchase order before the accounts are closed."
),
)
# The page in French.
FRENCH = Words(
overflow="Overflow : le mot reste entier et déborde du bord.",
breaking="Break : le mot est coupé après son dernier glyphe qui tient.",
paragraph_before="Réglé par virement, référence ",
paragraph_after=", à rapprocher du bon de commande avant la clôture des comptes.",
)
# 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}
COLUMN = 150.0
# The left edge of both columns. They are stacked rather than set side by side, so that
# the overflowing line runs out into the margin and not through the text of the other
# setting.
X = 80.0
def main() -> None:
language = _language.from_environment()
words = _language.words_of(WORDS, language)
paragraph = words.paragraph()
# 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("flow_break.pdf", language)).stem)
document = hqf_pdf.Document()
document.set_license(_licence.licensed())
handle = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))
content = hqf_pdf.Content()
for top, label, overlong in (
(760.0, words.overflow, hqf_pdf.Overlong.Overflow),
(620.0, words.breaking, hqf_pdf.Overlong.Break),
):
heading = hqf_pdf.TextFlow(handle, 8.0)
heading_lines = heading.break_lines(label, 400.0)
heading.draw(content, heading_lines, X, top, 400.0)
text_top = top - 20.0
flow = hqf_pdf.TextFlow(handle, 11.0, leading=15.0, overlong=overlong)
lines = flow.break_lines(paragraph, COLUMN)
flow.draw(content, lines, X, text_top, COLUMN)
# The column's edge, to show what each setting does about it.
height = flow.height(lines)
content.save_state()
content.set_stroke(hqf_pdf.Rgb.gray(0.8))
content.set_line_width(0.5)
content.rect(X, text_top - height, COLUMN, height)
content.stroke()
content.restore_state()
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()
|