1pub mod configuration;
4pub mod manager;
5pub mod styles;
6
7use std::fs::File;
8use std::io::Cursor;
9use std::path::{Path, PathBuf};
10
11use freetype::{face, Face, Library};
12use printpdf::types::plugins::graphics::two_dimensional::font::IndirectFontRef;
13use printpdf::Pt;
14
15use crate::document::Document;
16use crate::{Error, Result};
17
18#[derive(Debug)]
21pub struct Font {
22 freetype: Face,
24
25 printpdf: IndirectFontRef,
27}
28
29impl Font {
30 pub fn from_file<P: AsRef<Path>>(
32 path: P,
33 library: &Library,
34 document: &mut Document,
35 ) -> Result<Font> {
36 let file = File::open(path.as_ref())
37 .map_err(|_| Error::FontNotFound(PathBuf::from(path.as_ref())))?;
38 Ok(Font {
39 freetype: library.new_face(path.as_ref(), 0)?,
40 printpdf: document.inner_mut().add_external_font(file)?,
41 })
42 }
43
44 pub fn from_bytes(bytes: &[u8], library: &Library, document: &mut Document) -> Result<Font> {
46 let cursor = Cursor::new(bytes);
47 Ok(Font {
48 freetype: library.new_memory_face(bytes.to_vec(), 0)?,
51 printpdf: document.inner_mut().add_external_font(cursor)?,
52 })
53 }
54
55 pub fn char_width(&self, c: char, scale: Pt) -> Pt {
57 let scale = scale.0;
58
59 let vert_scale = {
61 if self
62 .freetype
63 .load_char(0x0020, face::LoadFlag::NO_SCALE)
64 .is_ok()
65 {
66 self.freetype.glyph().metrics().vertAdvance
67 } else {
68 1000
69 }
70 };
71
72 let is_ok = self
74 .freetype
75 .load_char(c as usize, face::LoadFlag::NO_SCALE)
76 .is_ok();
77
78 let width = if is_ok {
79 self.freetype.glyph().metrics().horiAdvance
80 } else {
81 0
82 };
83
84 Pt(width as f64 / (vert_scale as f64 / scale))
85 }
86
87 pub fn text_width(&self, text: &str, scale: Pt) -> Pt {
89 let scale = scale.0;
90
91 let vert_scale = {
93 if self
94 .freetype
95 .load_char(0x0020, face::LoadFlag::NO_SCALE)
96 .is_ok()
97 {
98 self.freetype.glyph().metrics().vertAdvance
99 } else {
100 1000
101 }
102 };
103
104 let sum_width = text.chars().fold(0, |acc, ch| {
106 let is_ok = self
107 .freetype
108 .load_char(ch as usize, face::LoadFlag::NO_SCALE)
109 .is_ok();
110
111 if is_ok {
112 acc + self.freetype.glyph().metrics().horiAdvance
113 } else {
114 acc
115 }
116 });
117
118 Pt(sum_width as f64 / (vert_scale as f64 / scale))
119 }
120
121 pub fn printpdf(&self) -> &IndirectFontRef {
123 &self.printpdf
124 }
125}