1use std::iter::repeat;
4
5#[derive(Debug, thiserror::Error)]
7pub enum Error {
8 #[error("I/O {0}")]
9 Io(#[from] std::io::Error),
10
11 #[error("Expected property '{0}'")]
12 Expected(&'static str),
13
14 #[error("Unknown font format")]
15 UnknownFormat(),
16}
17
18pub(crate) type Result<T> = std::result::Result<T, Error>;
20
21pub struct Bitmap {
23 pub(crate) height: u8,
25 pub(crate) width: u8,
27 bmap: Vec<u8>,
29}
30
31pub(crate) struct PixIter<'a> {
33 bmap: &'a Bitmap,
34 pos: usize,
35}
36
37pub enum Prop<'a> {
39 Unknown(&'a str),
41 FontName(&'a str),
43 FontNumber(u8),
45 FontHeight(u8),
47 FontWidth(u8),
49 CharSpacing(u8),
51 LineSpacing(u8),
53 Baseline(u8),
55 MaxCharNumber(u16),
57 CodePoint(u16),
59 Bitmap(Bitmap),
61}
62
63impl Iterator for PixIter<'_> {
64 type Item = bool;
65
66 fn next(&mut self) -> Option<bool> {
67 let pos = self.pos;
68 let len = usize::from(self.bmap.height) * usize::from(self.bmap.width);
69 if pos < len {
70 self.pos += 1;
71 let off = pos >> 3;
72 let bit = 7 - (pos & 0b111);
73 Some((self.bmap.bmap[off] >> bit) & 1 != 0)
74 } else {
75 None
76 }
77 }
78}
79
80impl Bitmap {
81 pub(crate) fn new(width: u8) -> Self {
83 Bitmap {
84 height: 0,
85 width,
86 bmap: Vec::with_capacity(32),
87 }
88 }
89
90 pub fn from_bits(height: u8, width: u8, bmap: Vec<u8>) -> Option<Self> {
92 let len = usize::from(height) * usize::from(width);
93 if bmap.len() == (len + 7) / 8 {
94 Some(Bitmap {
95 height,
96 width,
97 bmap,
98 })
99 } else {
100 None
101 }
102 }
103
104 pub fn height(&self) -> u8 {
106 self.height
107 }
108
109 pub fn width(&self) -> u8 {
111 self.width
112 }
113
114 pub(crate) fn push_row(&mut self, row: impl Iterator<Item = bool>) {
116 let width = usize::from(self.width);
117 let mut pos = usize::from(self.height) * width;
118 for pix in row.chain(repeat(false)).take(width) {
119 if pos & 0b111 == 0 {
120 self.bmap.push(0);
121 }
122 if pix {
123 let off = pos >> 3;
124 let bit = 7 - (pos & 0b111);
125 self.bmap[off] |= 1 << bit;
126 }
127 pos += 1;
128 }
129 self.height += 1;
130 }
131
132 pub(crate) fn pixels(&self) -> impl Iterator<Item = bool> + '_ {
134 PixIter { bmap: self, pos: 0 }
135 }
136
137 pub fn into_bits(self) -> Vec<u8> {
139 self.bmap
140 }
141}
142
143impl<'a> Prop<'a> {
144 pub fn font_name(&self) -> Option<&'a str> {
146 match self {
147 Prop::FontName(nm) => Some(nm),
148 _ => None,
149 }
150 }
151
152 pub fn font_number(&self) -> Option<u8> {
154 match self {
155 Prop::FontNumber(num) => Some(*num),
156 _ => None,
157 }
158 }
159
160 pub fn char_spacing(&self) -> Option<u8> {
162 match self {
163 Prop::CharSpacing(cs) => Some(*cs),
164 _ => None,
165 }
166 }
167
168 pub fn line_spacing(&self) -> Option<u8> {
170 match self {
171 Prop::LineSpacing(ls) => Some(*ls),
172 _ => None,
173 }
174 }
175
176 pub fn font_height(&self) -> Option<u8> {
178 match self {
179 Prop::FontHeight(fh) => Some(*fh),
180 Prop::Bitmap(bmap) => Some(bmap.height),
181 _ => None,
182 }
183 }
184
185 pub fn code_point(&self) -> Option<u16> {
187 match self {
188 Prop::CodePoint(cp) => Some(*cp),
189 _ => None,
190 }
191 }
192}