Compare commits
10 commits
master
...
optimize-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
004085e34c | ||
|
|
cbf2261016 | ||
|
|
51e9a1fa2e | ||
|
|
8c1fa9b684 | ||
|
|
c38baeb932 | ||
|
|
7e153547f5 | ||
|
|
ca48d4afde | ||
|
|
1f46cc3a68 | ||
|
|
977edcbd88 | ||
|
|
2501072843 |
4 changed files with 138 additions and 100 deletions
|
|
@ -57,37 +57,68 @@ class BDF(GlyphCache):
|
|||
self.file.seek(0)
|
||||
self.bitmap_class = bitmap_class
|
||||
line = self.file.readline()
|
||||
line = str(line, "utf-8")
|
||||
if not line or not line.startswith("STARTFONT 2.1"):
|
||||
if not line or not line.startswith(b"STARTFONT 2.1"):
|
||||
raise ValueError("Unsupported file version")
|
||||
self.point_size = None
|
||||
self.x_resolution = None
|
||||
self.y_resolution = None
|
||||
self._ascent = None
|
||||
self._descent = None
|
||||
|
||||
@property
|
||||
def descent(self):
|
||||
"""The number of pixels below the baseline of a typical descender"""
|
||||
if self._descent is None:
|
||||
self.file.seek(0)
|
||||
while True:
|
||||
line = self.file.readline()
|
||||
if not line:
|
||||
break
|
||||
|
||||
if line.startswith(b"FONT_DESCENT "):
|
||||
self._descent = int(line.split()[1])
|
||||
break
|
||||
|
||||
return self._descent
|
||||
|
||||
@property
|
||||
def ascent(self):
|
||||
"""The number of pixels above the baseline of a typical ascender"""
|
||||
if self._ascent is None:
|
||||
self.file.seek(0)
|
||||
while True:
|
||||
line = self.file.readline()
|
||||
if not line:
|
||||
break
|
||||
|
||||
if line.startswith(b"FONT_ASCENT "):
|
||||
self._ascent = int(line.split()[1])
|
||||
break
|
||||
|
||||
return self._ascent
|
||||
|
||||
def get_bounding_box(self):
|
||||
"""Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset"""
|
||||
self.file.seek(0)
|
||||
while True:
|
||||
line = self.file.readline()
|
||||
line = str(line, "utf-8")
|
||||
if not line:
|
||||
break
|
||||
|
||||
if line.startswith("FONTBOUNDINGBOX "):
|
||||
if line.startswith(b"FONTBOUNDINGBOX "):
|
||||
_, x, y, x_offset, y_offset = line.split()
|
||||
return (int(x), int(y), int(x_offset), int(y_offset))
|
||||
return None
|
||||
|
||||
def _read_to(self, prefix):
|
||||
_readline = self.file.readline
|
||||
while True:
|
||||
line = _readline()
|
||||
if not line or line.startswith(prefix):
|
||||
return line
|
||||
|
||||
def load_glyphs(self, code_points):
|
||||
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
||||
metadata = True
|
||||
character = False
|
||||
code_point = None
|
||||
bytes_per_row = 1
|
||||
desired_character = False
|
||||
current_info = {}
|
||||
current_y = 0
|
||||
rounded_x = 1
|
||||
if isinstance(code_points, int):
|
||||
remaining = set()
|
||||
remaining.add(code_points)
|
||||
|
|
@ -97,98 +128,61 @@ class BDF(GlyphCache):
|
|||
remaining = code_points
|
||||
else:
|
||||
remaining = set(code_points)
|
||||
for code_point in remaining:
|
||||
for code_point in remaining.copy():
|
||||
if code_point in self._glyphs and self._glyphs[code_point]:
|
||||
remaining.remove(code_point)
|
||||
if not remaining:
|
||||
return
|
||||
|
||||
x, _, _, _ = self.get_bounding_box()
|
||||
_readline = self.file.readline
|
||||
_read = self.file.read
|
||||
|
||||
self.file.seek(0)
|
||||
while True:
|
||||
line = self.file.readline()
|
||||
_, point_size, x_resolution, y_resolution = self._read_to(b"SIZE ").split()
|
||||
self.point_size = int(point_size)
|
||||
self.x_resolution = int(x_resolution)
|
||||
self.y_resolution = int(y_resolution)
|
||||
|
||||
while remaining:
|
||||
line = self._read_to(b"ENCODING ")
|
||||
if not line:
|
||||
break
|
||||
if line.startswith(b"CHARS "):
|
||||
metadata = False
|
||||
elif line.startswith(b"SIZE"):
|
||||
_, self.point_size, self.x_resolution, self.y_resolution = line.split()
|
||||
elif line.startswith(b"COMMENT"):
|
||||
pass
|
||||
elif line.startswith(b"STARTCHAR"):
|
||||
# print(lineno, line.strip())
|
||||
# _, character_name = line.split()
|
||||
character = True
|
||||
elif line.startswith(b"ENDCHAR"):
|
||||
character = False
|
||||
if desired_character:
|
||||
bounds = current_info["bounds"]
|
||||
shift = current_info["shift"]
|
||||
gc.collect()
|
||||
self._glyphs[code_point] = Glyph(
|
||||
current_info["bitmap"],
|
||||
0,
|
||||
bounds[0],
|
||||
bounds[1],
|
||||
bounds[2],
|
||||
bounds[3],
|
||||
shift[0],
|
||||
shift[1],
|
||||
)
|
||||
remaining.remove(code_point)
|
||||
if not remaining:
|
||||
return
|
||||
desired_character = False
|
||||
elif line.startswith(b"BBX"):
|
||||
if desired_character:
|
||||
_, x, y, x_offset, y_offset = line.split()
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
x_offset = int(x_offset)
|
||||
y_offset = int(y_offset)
|
||||
current_info["bounds"] = (x, y, x_offset, y_offset)
|
||||
current_info["bitmap"] = self.bitmap_class(x, y, 2)
|
||||
elif line.startswith(b"BITMAP"):
|
||||
if desired_character:
|
||||
rounded_x = x // 8
|
||||
if x % 8 > 0:
|
||||
rounded_x += 1
|
||||
bytes_per_row = rounded_x
|
||||
if bytes_per_row % 4 > 0:
|
||||
bytes_per_row += 4 - bytes_per_row % 4
|
||||
current_y = 0
|
||||
elif line.startswith(b"ENCODING"):
|
||||
_, code_point = line.split()
|
||||
code_point = int(code_point)
|
||||
if code_point in remaining:
|
||||
desired_character = True
|
||||
current_info = {"bitmap": None, "bounds": None, "shift": None}
|
||||
elif line.startswith(b"DWIDTH"):
|
||||
if desired_character:
|
||||
_, shift_x, shift_y = line.split()
|
||||
shift_x = int(shift_x)
|
||||
shift_y = int(shift_y)
|
||||
current_info["shift"] = (shift_x, shift_y)
|
||||
elif line.startswith(b"SWIDTH"):
|
||||
pass
|
||||
elif character:
|
||||
if desired_character:
|
||||
bits = int(line.strip(), 16)
|
||||
width = current_info["bounds"][0]
|
||||
start = current_y * width
|
||||
x = 0
|
||||
for i in range(rounded_x):
|
||||
val = (bits >> ((rounded_x - i - 1) * 8)) & 0xFF
|
||||
for j in range(7, -1, -1):
|
||||
if x >= width:
|
||||
break
|
||||
bit = 0
|
||||
if val & (1 << j) != 0:
|
||||
bit = 1
|
||||
current_info["bitmap"][start + x] = bit
|
||||
x += 1
|
||||
current_y += 1
|
||||
elif metadata:
|
||||
# print(lineno, line.strip())
|
||||
pass
|
||||
|
||||
_, code_point = line.split()
|
||||
code_point = int(code_point)
|
||||
if code_point not in remaining:
|
||||
continue
|
||||
|
||||
line = self._read_to(b"DWIDTH ")
|
||||
_, shift_x, shift_y = line.split()
|
||||
shift_x = int(shift_x)
|
||||
shift_y = int(shift_y)
|
||||
|
||||
line = self._read_to(b"BBX ")
|
||||
_, x, y, x_offset, y_offset = line.split()
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
x_offset = int(x_offset)
|
||||
y_offset = int(y_offset)
|
||||
|
||||
line = self._read_to(b"BITMAP")
|
||||
|
||||
bitmap = self.bitmap_class(x, y, 2)
|
||||
start = 0
|
||||
for _ in range(y):
|
||||
idx = 0
|
||||
for idx in range(x):
|
||||
if idx % 4 == 0:
|
||||
value = int(_read(1), 16)
|
||||
if value & 8:
|
||||
bitmap[start + idx] = 1
|
||||
value <<= 1
|
||||
_readline()
|
||||
start += x
|
||||
|
||||
gc.collect()
|
||||
self._glyphs[code_point] = Glyph(
|
||||
bitmap, 0, x, y, x_offset, y_offset, shift_x, shift_y
|
||||
)
|
||||
|
||||
remaining.remove(code_point)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ bitmap with pixels matching glyphs from a given String
|
|||
|
||||
|
||||
import board
|
||||
from adafruit_bitmap_font import bitmap_font # pylint: disable=wrong-import-position
|
||||
import displayio
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
|
||||
font = bitmap_font.load_font("fonts/Arial-16.bdf")
|
||||
|
||||
|
|
|
|||
44
examples/bitmap_font_label_magtag.py
Normal file
44
examples/bitmap_font_label_magtag.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
"""
|
||||
This example uses addfruit_display_text.label to display text using a custom font
|
||||
loaded by adafruit_bitmap_font.
|
||||
Adapted for use on MagTag
|
||||
"""
|
||||
import time
|
||||
import board
|
||||
from adafruit_display_text import label
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
|
||||
# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.)
|
||||
# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.)
|
||||
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus
|
||||
display = board.DISPLAY
|
||||
# wait until we can refresh the display
|
||||
time.sleep(display.time_to_refresh)
|
||||
|
||||
# Set text, font, and color
|
||||
text = "HELLO WORLD\nbitmap_font example"
|
||||
font = bitmap_font.load_font("fonts/Arial-16.bdf")
|
||||
color = 0xFFFFFF
|
||||
background_color = 0x999999
|
||||
|
||||
# Create the tet label
|
||||
text_area = label.Label(
|
||||
font,
|
||||
text=text,
|
||||
color=color,
|
||||
background_color=background_color,
|
||||
padding_top=3,
|
||||
padding_bottom=3,
|
||||
padding_right=4,
|
||||
padding_left=4,
|
||||
)
|
||||
text_area.line_spacing = 1.0
|
||||
# Set the location
|
||||
text_area.x = 20
|
||||
text_area.y = 20
|
||||
|
||||
# Show it and refresh
|
||||
display.show(text_area)
|
||||
display.refresh()
|
||||
while True:
|
||||
pass
|
||||
|
|
@ -4,8 +4,8 @@ loaded by adafruit_bitmap_font
|
|||
"""
|
||||
|
||||
import board
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
from adafruit_display_text import label
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
|
||||
display = board.DISPLAY
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue