Skip to content

Commit ceed4c2

Browse files
committed
pcf: black & lint
1 parent 6ae6e07 commit ceed4c2

File tree

1 file changed

+113
-61
lines changed

1 file changed

+113
-61
lines changed

adafruit_bitmap_font/pcf.py

Lines changed: 113 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,50 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright © 2020 Jeff Epler for Adafruit Industries LLC
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
"""
23+
`adafruit_bitmap_font.pcf`
24+
====================================================
25+
26+
Loads PCF format fonts.
27+
28+
* Author(s): Jeff Epler
29+
30+
Implementation Notes
31+
--------------------
32+
33+
**Hardware:**
34+
35+
**Software and Dependencies:**
36+
37+
* Adafruit CircuitPython firmware for the supported boards:
38+
https://github.com/adafruit/circuitpython/releases
39+
40+
"""
41+
142
from collections import namedtuple
243
import gc
44+
import struct
345

4-
from .glyph_cache import GlyphCache
546
from fontio import Glyph
6-
import displayio
7-
import struct
47+
from .glyph_cache import GlyphCache
848

949
_PCF_PROPERTIES = 1 << 0
1050
_PCF_ACCELERATORS = 1 << 1
@@ -66,29 +106,31 @@
66106

67107

68108
class PCF(GlyphCache):
109+
"""Loads glyphs from a PCF file in the given bitmap_class."""
110+
69111
def __init__(self, f, bitmap_class):
70112
super().__init__()
71113
self.file = f
72114
self.name = f
73115
f.seek(0)
74116
self.buffer = bytearray(1)
75117
self.bitmap_class = bitmap_class
76-
header, table_count = self.read("<4sI")
118+
_, table_count = self._read("<4sI")
77119
self.tables = {}
78120
for _ in range(table_count):
79-
type, format, size, offset = self.read("<IIII")
80-
self.tables[type] = Table(format, size, offset)
121+
type_, format_, size, offset = self._read("<IIII")
122+
self.tables[type_] = Table(format_, size, offset)
81123

82124
bitmap_format = self.tables[_PCF_BITMAPS].format
83125
if bitmap_format != 0xE:
84-
raise NotImplementedError(f"Unsupported format {bitmap_format:x}")
126+
raise NotImplementedError(f"Unsupported format_ {bitmap_format:x}")
85127

86-
self._accel = self.read_accelerator_tables()
87-
self._encoding = self.read_encoding_table()
88-
self._bitmaps = self.read_bitmap_table()
128+
self._accel = self._read_accelerator_tables()
129+
self._encoding = self._read_encoding_table()
130+
self._bitmaps = self._read_bitmap_table()
89131

90-
self.ascent = self._accel.font_ascent
91-
self.descent = self._accel.font_descent
132+
self._ascent = self._accel.font_ascent
133+
self._descent = self._accel.font_descent
92134

93135
minbounds = self._accel.ink_minbounds
94136
maxbounds = self._accel.ink_maxbounds
@@ -102,49 +144,60 @@ def __init__(self, f, bitmap_class):
102144
-maxbounds.character_descent,
103145
)
104146

147+
@property
148+
def ascent(self):
149+
"""The number of pixels above the baseline of a typical ascender"""
150+
return self._ascent
151+
152+
@property
153+
def descent(self):
154+
"""The number of pixels below the baseline of a typical descender"""
155+
return self._descent
156+
105157
def get_bounding_box(self):
158+
"""Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset"""
106159
return self._bounding_box
107160

108-
def read(self, format):
109-
s = struct.calcsize(format)
110-
if s != len(self.buffer):
111-
self.buffer = bytearray(s)
161+
def _read(self, format_):
162+
size = struct.calcsize(format_)
163+
if size != len(self.buffer):
164+
self.buffer = bytearray(size)
112165
self.file.readinto(self.buffer)
113-
return struct.unpack_from(format, self.buffer)
166+
return struct.unpack_from(format_, self.buffer)
114167

115-
def seek_table(self, table):
168+
def _seek_table(self, table):
116169
self.file.seek(table.offset)
117-
(format,) = self.read("<I")
170+
(format_,) = self._read("<I")
118171

119-
if format & _PCF_BYTE_MASK == 0:
172+
if format_ & _PCF_BYTE_MASK == 0:
120173
raise RuntimeError("Only big endian supported")
121174

122-
return format
175+
return format_
123176

124-
def read_encoding_table(self):
177+
def _read_encoding_table(self):
125178
encoding = self.tables[_PCF_BDF_ENCODINGS]
126-
self.seek_table(encoding)
179+
self._seek_table(encoding)
127180

128-
return Encoding(*self.read(">hhhhh"))
181+
return Encoding(*self._read(">hhhhh"))
129182

130-
def read_bitmap_table(self):
183+
def _read_bitmap_table(self):
131184
bitmaps = self.tables[_PCF_BITMAPS]
132-
format = self.seek_table(bitmaps)
185+
format_ = self._seek_table(bitmaps)
133186

134-
(glyph_count,) = self.read(">I")
187+
(glyph_count,) = self._read(">I")
135188
self.file.seek(bitmaps.offset + 8 + 4 * glyph_count)
136-
bitmap_sizes = self.read(">4I")
137-
return Bitmap(glyph_count, bitmap_sizes[format & 3])
189+
bitmap_sizes = self._read(">4I")
190+
return Bitmap(glyph_count, bitmap_sizes[format_ & 3])
138191

139-
def read_metrics(self, compressed_metrics):
192+
def _read_metrics(self, compressed_metrics):
140193
if compressed_metrics:
141194
(
142195
left_side_bearing,
143196
right_side_bearing,
144197
character_width,
145198
character_ascent,
146199
character_descent,
147-
) = self.read("5B")
200+
) = self._read("5B")
148201
left_side_bearing -= 0x80
149202
right_side_bearing -= 0x80
150203
character_width -= 0x80
@@ -159,7 +212,7 @@ def read_metrics(self, compressed_metrics):
159212
character_ascent,
160213
character_descent,
161214
attributes,
162-
) = self.read(">5hH")
215+
) = self._read(">5hH")
163216
return Metrics(
164217
left_side_bearing,
165218
right_side_bearing,
@@ -169,17 +222,18 @@ def read_metrics(self, compressed_metrics):
169222
attributes,
170223
)
171224

172-
def read_accelerator_tables(self):
225+
def _read_accelerator_tables(self):
226+
# pylint: disable=too-many-locals
173227
accelerators = self.tables.get(_PCF_BDF_ACCELERATORS)
174228
if not accelerators:
175229
accelerators = self.tables.get(_PCF_ACCELERATORS)
176230
if not accelerators:
177231
raise RuntimeError("Accelerator table missing")
178232

179-
format = self.seek_table(accelerators)
233+
format_ = self._seek_table(accelerators)
180234

181-
has_inkbounds = format & _PCF_ACCEL_W_INKBOUNDS
182-
compressed_metrics = False # format & _PCF_COMPRESSED_METRICS
235+
has_inkbounds = format_ & _PCF_ACCEL_W_INKBOUNDS
236+
compressed_metrics = False # format_ & _PCF_COMPRESSED_METRICS
183237

184238
(
185239
no_overlap,
@@ -193,12 +247,12 @@ def read_accelerator_tables(self):
193247
font_ascent,
194248
font_descent,
195249
max_overlap,
196-
) = self.read(">BBBBBBBBIII")
197-
minbounds = self.read_metrics(compressed_metrics)
198-
maxbounds = self.read_metrics(compressed_metrics)
250+
) = self._read(">BBBBBBBBIII")
251+
minbounds = self._read_metrics(compressed_metrics)
252+
maxbounds = self._read_metrics(compressed_metrics)
199253
if has_inkbounds:
200-
ink_minbounds = self.read_metrics(compressed_metrics)
201-
ink_maxbounds = self.read_metrics(compressed_metrics)
254+
ink_minbounds = self._read_metrics(compressed_metrics)
255+
ink_maxbounds = self._read_metrics(compressed_metrics)
202256
else:
203257
ink_minbounds = minbounds
204258
ink_maxbounds = maxbounds
@@ -220,33 +274,33 @@ def read_accelerator_tables(self):
220274
ink_maxbounds,
221275
)
222276

223-
def read_properties(self):
277+
def _read_properties(self):
224278
property_table_offset = self.tables[_PCF_PROPERTIES]["offset"]
225279
self.file.seek(property_table_offset)
226-
(format,) = self.read("<I")
280+
(format_,) = self._read("<I")
227281

228-
if format & _PCF_BYTE_MASK == 0:
282+
if format_ & _PCF_BYTE_MASK == 0:
229283
raise RuntimeError("Only big endian supported")
230-
(nprops,) = self.read(">I")
284+
(nprops,) = self._read(">I")
231285
self.file.seek(property_table_offset + 8 + 9 * nprops)
232286

233287
pos = self.file.tell()
234288
if pos % 4 > 0:
235289
self.file.read(4 - pos % 4)
236-
(string_size,) = self.read(">I")
290+
(string_size,) = self._read(">I")
237291

238292
strings = self.file.read(string_size)
239293
string_map = {}
240294
i = 0
241-
for s in strings.split(b"\x00"):
242-
string_map[i] = s
243-
i += len(s) + 1
295+
for value in strings.split(b"\x00"):
296+
string_map[i] = value
297+
i += len(value) + 1
244298

245299
self.file.seek(property_table_offset + 8)
246300
for _ in range(nprops):
247-
name_offset, isStringProp, value = self.read(">IBI")
301+
name_offset, is_string_prop, value = self._read(">IBI")
248302

249-
if isStringProp:
303+
if is_string_prop:
250304
yield (string_map[name_offset], string_map[value])
251305
else:
252306
yield (string_map[name_offset], value)
@@ -295,7 +349,7 @@ def load_glyphs(self, code_points):
295349
- self._encoding.min_byte2
296350
)
297351
self.file.seek(indices_offset + 2 * encoding_idx)
298-
(glyph_idx,) = self.read(">H")
352+
(glyph_idx,) = self._read(">H")
299353
if glyph_idx != 65535:
300354
indices[i] = glyph_idx
301355

@@ -305,24 +359,23 @@ def load_glyphs(self, code_points):
305359
if index is None:
306360
continue
307361
self.file.seek(first_metric_offset + metrics_size * index)
308-
all_metrics[i] = self.read_metrics(metrics_compressed)
362+
all_metrics[i] = self._read_metrics(metrics_compressed)
309363
bitmap_offsets = [None] * len(code_points)
310364
for i, code_point in enumerate(code_points):
311365
index = indices[i]
312366
if index is None:
313367
continue
314368
self.file.seek(bitmap_offset_offsets + 4 * index)
315-
(bitmap_offset,) = self.read(">I")
369+
(bitmap_offset,) = self._read(">I")
316370
bitmap_offsets[i] = bitmap_offset
317371

318372
# Batch creation of glyphs and bitmaps so that we need only gc.collect
319373
# once
320374
gc.collect()
321375
bitmaps = [None] * len(code_points)
322-
for i in range(len(all_metrics)):
376+
for i in range(len(all_metrics)): # pylint: disable=consider-using-enumerate
323377
metrics = all_metrics[i]
324378
if metrics is not None:
325-
shift = metrics.character_width
326379
width = metrics.right_side_bearing - metrics.left_side_bearing
327380
height = metrics.character_ascent + metrics.character_descent
328381
bitmap = bitmaps[i] = self.bitmap_class(width, height, 2)
@@ -342,17 +395,16 @@ def load_glyphs(self, code_points):
342395
if metrics is None:
343396
continue
344397
self.file.seek(first_bitmap_offset + bitmap_offsets[i])
345-
shift = metrics.character_width
346398
width = metrics.right_side_bearing - metrics.left_side_bearing
347399
height = metrics.character_ascent + metrics.character_descent
348400

349401
bitmap = bitmaps[i]
350402
words_per_row = (width + 31) // 32
351403
buf = bytearray(4 * words_per_row)
352404
start = 0
353-
for i in range(height):
405+
for _ in range(height):
354406
self.file.readinto(buf)
355-
for j in range(width):
356-
if buf[j // 8] & (128 >> (j % 8)):
357-
bitmap[start + j] = 1
407+
for k in range(width):
408+
if buf[k // 8] & (128 >> (k % 8)):
409+
bitmap[start + k] = 1
358410
start += width

0 commit comments

Comments
 (0)