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 | //! Shows what an evaluation copy looks like: a document written with no licence
//! key, which the library stamps with a watermark on every page.
//!
//! A licensed document is what most examples show; this one is the opposite. No
//! key is set, so the library writes an evaluation copy and marks every page as
//! one. Set a licence key and the mark is gone.
//!
//! The page under the mark is held in `Words`, once per language, and
//! `HQF_PDF_LANG` picks which set is drawn. The watermark itself is the
//! library's, not the page's, and does not follow the page's language.
//!
//! Usage: `cargo run --example write_eval_watermark -- tmp/eval.pdf [font.ttf]`
//! `HQF_PDF_LANG=fr cargo run --example write_eval_watermark --
//! tmp/evaluation.pdf`
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use hqf_pdf::content::Content;
use hqf_pdf::{Document, Font, License, Page};
#[path = "shared/out.rs"]
mod out;
#[path = "shared/language.rs"]
mod language;
use language::Language;
/// The font the example draws with when none is given on the command line.
fn default_font() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("fonts")
.join("DejaVuSans.ttf")
}
/// How many lines the page under the watermark is set in.
const LINE_COUNT: usize = 6;
/// The size each line is set at, and the baseline it sits on, in the order they
/// are laid down.
const PLACES: [(f64, f64); LINE_COUNT] = [
(20.0, 760.0),
(11.0, 730.0),
(11.0, 700.0),
(11.0, 684.0),
(10.0, 120.0),
(10.0, 106.0),
];
/// The words the page is written in, one set per language.
///
/// The watermark is not among them: the library writes it, and it says the same
/// thing whatever language the page under it is in.
#[derive(Debug)]
struct Words {
/// A short document laid under the watermark, and under it a note that says
/// what the watermark is, in the order the lines are laid down.
lines: [&'static str; LINE_COUNT],
}
impl Words {
/// The words the page is written in, in `language`.
fn of(language: Language) -> &'static Self {
language::pick(&WORDS, language)
}
}
/// The page in English.
const ENGLISH: Words = Words {
lines: [
"Quarterly report",
"Prepared for HQF Development",
"Revenue held steady across the three months, and costs fell as the new",
"rendering pipeline replaced the tools it was built to retire.",
"This is an evaluation copy: the library stamps every page with the",
"watermark above until a licence key is set. Set one and it is gone.",
],
};
/// The page in French.
const FRENCH: Words = Words {
lines: [
"Rapport trimestriel",
"Établi pour HQF Development",
"Le chiffre d'affaires est resté stable sur les trois mois, et les",
"coûts ont baissé quand la nouvelle chaîne de rendu a pris la suite.",
"Ceci est une copie d'évaluation : la bibliothèque marque chaque page",
"du filigrane ci-dessus tant qu'aucune clé n'est posée. Posez-en une.",
],
};
/// Every language the example is written in. A language is added by writing its
/// own set of words and naming it here.
static WORDS: [(Language, &Words); 2] =
[(Language::English, &ENGLISH), (Language::French, &FRENCH)];
fn main() -> Result<(), Box<dyn std::error::Error>> {
let language = Language::from_environment()?;
let words = Words::of(language);
let mut args = env::args().skip(1);
// A named file is written as named; the default one carries the language,
// so the two languages do not overwrite each other in `tmp/`.
let out = args
.next()
.unwrap_or_else(|| language.file_name(&out::default_path("eval")));
let font_path = args.next().map_or_else(default_font, PathBuf::from);
let mut doc = Document::new();
// No key is set: the document is an evaluation copy, and the library marks
// every page of it with a watermark.
doc.set_license(License::evaluation());
let font = doc.add_font(Font::parse(fs::read(&font_path)?)?);
let mut content = Content::new();
for (line, (size, top)) in words.lines.iter().zip(PLACES) {
content.begin_text();
content.set_font(font.name(), size)?;
content.text_origin(72.0, top)?;
content.show_glyphs(&font.glyphs(line));
content.end_text();
}
let mut page = Page::a4();
page.content = content.into_bytes();
doc.add_page(page)?;
let bytes = doc.to_bytes()?;
if let Some(parent) = Path::new(&out).parent() {
fs::create_dir_all(parent)?;
}
fs::write(&out, &bytes)?;
println!("wrote {out}: {} bytes", bytes.len());
Ok(())
}
#[cfg(test)]
mod tests {
use super::{WORDS, language};
/// The lines two languages are allowed to write the same way. There are
/// none: the one name the page carries sits inside a sentence.
const SPARED: [&str; 0] = [];
#[test]
fn every_language_draws_the_page_in_its_own_words() {
let untranslated = language::untranslated_lines(&WORDS, &SPARED);
assert!(
untranslated.is_empty(),
"the page says these in more than one language: {untranslated:?}"
);
}
}
|