Make mkfont run during the build

rip out whatever made it not work
This commit is contained in:
Jeff Epler 2024-10-27 16:26:13 -05:00
parent 419ee60a97
commit e02de00a56
8 changed files with 19 additions and 508 deletions

1
5x9.h

File diff suppressed because one or more lines are too long

View file

@ -42,6 +42,18 @@ add_custom_command(
DEPENDS vgamode.py
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/5x9.h
COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/mkfont/mkfont.py
${CMAKE_CURRENT_LIST_DIR}/mkfont/5x9.bdf
${CMAKE_CURRENT_BINARY_DIR}/5x9.h
DEPENDS
${CMAKE_CURRENT_LIST_DIR}/mkfont/*.py
${CMAKE_CURRENT_LIST_DIR}/mkfont/adafruit_bitmap_font/*.py
${CMAKE_CURRENT_LIST_DIR}/mkfont/5x9.bdf
)
add_custom_target(font_h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/5x9.h)
add_dependencies(cr100 font_h)
pico_generate_pio_header(cr100 ${CMAKE_CURRENT_BINARY_DIR}/vga_660x477_60.pio)
pico_generate_pio_header(cr100 ${CMAKE_CURRENT_LIST_DIR}/atkbd.pio)

View file

@ -581,6 +581,9 @@ int main(void) {
// stdio_set_driver_enabled(&stdio_kbd, true);
}
scrnprintf("\033[H\033[J\r\n ** \033[1mCR100 Terminal \033[7m READY \033[m "
"**\r\n\r\n");
while (true) {
int c = port_getc();
if (c > 0) {

View file

@ -16,9 +16,7 @@ class Bitmap:
def __getitem__(self, index):
if isinstance(index, tuple):
print(index[0], index[1], self.width, len(self))
index = index[0] + index[1] * self.width
print(index)
return self.values[index]
def __len__(self):

View file

@ -24,22 +24,12 @@ Implementation Notes
"""
try:
from typing import Optional, Union
from displayio import Bitmap
from . import bdf
from . import pcf
from . import ttf
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Bitmap_Font.git"
def load_font(
filename: str, bitmap_class: Optional[Bitmap] = None
) -> Union[bdf.BDF, pcf.PCF, ttf.TTF]:
def load_font(filename: str, bitmap_class=None):
"""Loads a font file. Returns None if unsupported."""
# pylint: disable=import-outside-toplevel, redefined-outer-name, consider-using-with
if not bitmap_class:
@ -52,13 +42,5 @@ def load_font(
from . import bdf
return bdf.BDF(font_file, bitmap_class)
if filename.endswith("pcf") and first_four == b"\x01fcp":
from . import pcf
return pcf.PCF(font_file, bitmap_class)
if filename.endswith("ttf") and first_four == b"\x00\x01\x00\x00":
from . import ttf
return ttf.TTF(font_file, bitmap_class)
raise ValueError("Unknown magic number %r" % first_four)

View file

@ -1,412 +0,0 @@
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_bitmap_font.pcf`
====================================================
Loads PCF format fonts.
* Author(s): Jeff Epler
Implementation Notes
--------------------
**Hardware:**
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
try:
from typing import Union, Tuple, Iterator, Iterable
from io import FileIO
from displayio import Bitmap as displayioBitmap
except ImportError:
pass
from collections import namedtuple
import gc
import struct
from micropython import const
from fontio import Glyph
from .glyph_cache import GlyphCache
try:
from bitmaptools import readinto as _bitmap_readinto
except ImportError:
_bitmap_readinto = None # pylint: disable=invalid-name
_PCF_PROPERTIES = const(1 << 0)
_PCF_ACCELERATORS = const(1 << 1)
_PCF_METRICS = const(1 << 2)
_PCF_BITMAPS = const(1 << 3)
_PCF_INK_METRICS = const(1 << 4)
_PCF_BDF_ENCODINGS = const(1 << 5)
_PCF_SWIDTHS = const(1 << 6)
_PCF_GLYPH_NAMES = const(1 << 7)
_PCF_BDF_ACCELERATORS = const(1 << 8)
_PCF_DEFAULT_FORMAT = const(0x00000000)
_PCF_ACCEL_W_INKBOUNDS = const(0x00000100)
_PCF_COMPRESSED_METRICS = const(0x00000100)
_PCF_GLYPH_PAD_MASK = const(3 << 0) # See the bitmap table for explanation */
_PCF_BYTE_MASK = const(1 << 2) # If set then Most Sig Byte First */
_PCF_BIT_MASK = const(1 << 3) # If set then Most Sig Bit First */
_PCF_SCAN_UNIT_MASK = const(3 << 4)
# https://fontforge.org/docs/techref/pcf-format.html
Table = namedtuple("Table", ("format", "size", "offset"))
Metrics = namedtuple(
"Metrics",
(
"left_side_bearing",
"right_side_bearing",
"character_width",
"character_ascent",
"character_descent",
"character_attributes",
),
)
Accelerators = namedtuple(
"Accelerators",
(
"no_overlap",
"constant_metrics",
"terminal_font",
"constant_width",
"ink_inside",
"ink_metrics",
"draw_direction",
"font_ascent",
"font_descent",
"max_overlap",
"minbounds",
"maxbounds",
"ink_minbounds",
"ink_maxbounds",
),
)
Encoding = namedtuple(
"Encoding", ("min_byte2", "max_byte2", "min_byte1", "max_byte1", "default_char")
)
Bitmap = namedtuple("Bitmap", ("glyph_count", "bitmap_sizes"))
class PCF(GlyphCache):
"""Loads glyphs from a PCF file in the given bitmap_class."""
def __init__(self, f: FileIO, bitmap_class: displayioBitmap) -> None:
super().__init__()
self.file = f
self.name = f
f.seek(0)
self.buffer = bytearray(1)
self.bitmap_class = bitmap_class
_, table_count = self._read("<4sI")
self.tables = {}
for _ in range(table_count):
type_, format_, size, offset = self._read("<IIII")
self.tables[type_] = Table(format_, size, offset)
bitmap_format = self.tables[_PCF_BITMAPS].format
if bitmap_format != 0xE:
raise NotImplementedError("Unsupported format %s" % bitmap_format)
self._accel = self._read_accelerator_tables()
self._encoding = self._read_encoding_table()
self._bitmaps = self._read_bitmap_table()
self._ascent = self._accel.font_ascent
self._descent = self._accel.font_descent
minbounds = self._accel.ink_minbounds
maxbounds = self._accel.ink_maxbounds
width = maxbounds.right_side_bearing - minbounds.left_side_bearing
height = maxbounds.character_ascent + maxbounds.character_descent
self._bounding_box = (
width,
height,
minbounds.left_side_bearing,
-maxbounds.character_descent,
)
@property
def ascent(self) -> int:
"""The number of pixels above the baseline of a typical ascender"""
return self._ascent
@property
def descent(self) -> int:
"""The number of pixels below the baseline of a typical descender"""
return self._descent
def get_bounding_box(self) -> Tuple[int, int, int, int]:
"""Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset"""
return self._bounding_box
def _read(self, format_: str) -> Tuple:
size = struct.calcsize(format_)
if size != len(self.buffer):
self.buffer = bytearray(size)
self.file.readinto(self.buffer)
return struct.unpack_from(format_, self.buffer)
def _seek_table(self, table: Table) -> int:
self.file.seek(table.offset)
(format_,) = self._read("<I")
if format_ & _PCF_BYTE_MASK == 0:
raise RuntimeError("Only big endian supported")
return format_
def _read_encoding_table(self) -> Encoding:
encoding = self.tables[_PCF_BDF_ENCODINGS]
self._seek_table(encoding)
return Encoding(*self._read(">hhhhh"))
def _read_bitmap_table(self) -> Bitmap:
bitmaps = self.tables[_PCF_BITMAPS]
format_ = self._seek_table(bitmaps)
(glyph_count,) = self._read(">I")
self.file.seek(bitmaps.offset + 8 + 4 * glyph_count)
bitmap_sizes = self._read(">4I")
return Bitmap(glyph_count, bitmap_sizes[format_ & 3])
def _read_metrics(self, compressed_metrics: bool) -> Metrics:
if compressed_metrics:
(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
) = self._read("5B")
left_side_bearing -= 0x80
right_side_bearing -= 0x80
character_width -= 0x80
character_ascent -= 0x80
character_descent -= 0x80
attributes = 0
else:
(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
attributes,
) = self._read(">5hH")
return Metrics(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
attributes,
)
def _read_accelerator_tables(self) -> Accelerators:
# pylint: disable=too-many-locals
accelerators = self.tables.get(_PCF_BDF_ACCELERATORS)
if not accelerators:
accelerators = self.tables.get(_PCF_ACCELERATORS)
if not accelerators:
raise RuntimeError("Accelerator table missing")
format_ = self._seek_table(accelerators)
has_inkbounds = format_ & _PCF_ACCEL_W_INKBOUNDS
(
no_overlap,
constant_metrics,
terminal_font,
constant_width,
ink_inside,
ink_metrics,
draw_direction,
_,
font_ascent,
font_descent,
max_overlap,
) = self._read(">BBBBBBBBIII")
minbounds = self._read_metrics(False)
maxbounds = self._read_metrics(False)
if has_inkbounds:
ink_minbounds = self._read_metrics(False)
ink_maxbounds = self._read_metrics(False)
else:
ink_minbounds = minbounds
ink_maxbounds = maxbounds
return Accelerators(
no_overlap,
constant_metrics,
terminal_font,
constant_width,
ink_inside,
ink_metrics,
draw_direction,
font_ascent,
font_descent,
max_overlap,
minbounds,
maxbounds,
ink_minbounds,
ink_maxbounds,
)
def _read_properties(self) -> Iterator[Tuple[bytes, Union[bytes, int]]]:
property_table_offset = self.tables[_PCF_PROPERTIES]["offset"]
self.file.seek(property_table_offset)
(format_,) = self._read("<I")
if format_ & _PCF_BYTE_MASK == 0:
raise RuntimeError("Only big endian supported")
(nprops,) = self._read(">I")
self.file.seek(property_table_offset + 8 + 9 * nprops)
pos = self.file.tell()
if pos % 4 > 0:
self.file.read(4 - pos % 4)
(string_size,) = self._read(">I")
strings = self.file.read(string_size)
string_map = {}
i = 0
for value in strings.split(b"\x00"):
string_map[i] = value
i += len(value) + 1
self.file.seek(property_table_offset + 8)
for _ in range(nprops):
name_offset, is_string_prop, value = self._read(">IBI")
if is_string_prop:
yield (string_map[name_offset], string_map[value])
else:
yield (string_map[name_offset], value)
def load_glyphs(self, code_points: Union[int, str, Iterable[int]]) -> None:
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
if isinstance(code_points, int):
code_points = (code_points,)
elif isinstance(code_points, str):
code_points = [ord(c) for c in code_points]
code_points = sorted(
c for c in code_points if self._glyphs.get(c, None) is None
)
if not code_points:
return
indices_offset = self.tables[_PCF_BDF_ENCODINGS].offset + 14
bitmap_offset_offsets = self.tables[_PCF_BITMAPS].offset + 8
first_bitmap_offset = self.tables[_PCF_BITMAPS].offset + 4 * (
6 + self._bitmaps.glyph_count
)
metrics_compressed = self.tables[_PCF_METRICS].format & _PCF_COMPRESSED_METRICS
first_metric_offset = self.tables[_PCF_METRICS].offset + (
6 if metrics_compressed else 8
)
metrics_size = 5 if metrics_compressed else 12
# These will each _tend to be_ forward reads in the file, at least
# sometimes we'll benefit from oofatfs's 512 byte cache and avoid
# excess reads
indices = [None] * len(code_points)
for i, code_point in enumerate(code_points):
enc1 = (code_point >> 8) & 0xFF
enc2 = code_point & 0xFF
if enc1 < self._encoding.min_byte1 or enc1 > self._encoding.max_byte1:
continue
if enc2 < self._encoding.min_byte2 or enc2 > self._encoding.max_byte2:
continue
encoding_idx = (
(enc1 - self._encoding.min_byte1)
* (self._encoding.max_byte2 - self._encoding.min_byte2 + 1)
+ enc2
- self._encoding.min_byte2
)
self.file.seek(indices_offset + 2 * encoding_idx)
(glyph_idx,) = self._read(">H")
if glyph_idx != 65535:
indices[i] = glyph_idx
all_metrics = [None] * len(code_points)
for i, code_point in enumerate(code_points):
index = indices[i]
if index is None:
continue
self.file.seek(first_metric_offset + metrics_size * index)
all_metrics[i] = self._read_metrics(metrics_compressed)
bitmap_offsets = [None] * len(code_points)
for i, code_point in enumerate(code_points):
index = indices[i]
if index is None:
continue
self.file.seek(bitmap_offset_offsets + 4 * index)
(bitmap_offset,) = self._read(">I")
bitmap_offsets[i] = bitmap_offset
# Batch creation of glyphs and bitmaps so that we need only gc.collect
# once
gc.collect()
bitmaps = [None] * len(code_points)
for i in range(len(all_metrics)): # pylint: disable=consider-using-enumerate
metrics = all_metrics[i]
if metrics is not None:
width = metrics.right_side_bearing - metrics.left_side_bearing
height = metrics.character_ascent + metrics.character_descent
bitmap = bitmaps[i] = self.bitmap_class(width, height, 2)
self._glyphs[code_points[i]] = Glyph(
bitmap,
0,
width,
height,
metrics.left_side_bearing,
-metrics.character_descent,
metrics.character_width,
0,
)
for i, code_point in enumerate(code_points):
metrics = all_metrics[i]
if metrics is None:
continue
self.file.seek(first_bitmap_offset + bitmap_offsets[i])
width = metrics.right_side_bearing - metrics.left_side_bearing
height = metrics.character_ascent + metrics.character_descent
bitmap = bitmaps[i]
if _bitmap_readinto:
_bitmap_readinto(
bitmap,
self.file,
bits_per_pixel=1,
element_size=4,
reverse_pixels_in_element=True,
)
else:
words_per_row = (width + 31) // 32
buf = bytearray(4 * words_per_row)
start = 0
for _ in range(height):
self.file.readinto(buf)
for k in range(width):
if buf[k // 8] & (128 >> (k % 8)):
bitmap[start + k] = 1
start += width

View file

@ -1,65 +0,0 @@
# SPDX-FileCopyrightText: 2019 Scott Shawcroft for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# pylint: skip-file
# Remove the above when TTF is actually supported.
try:
from typing import Tuple
from io import FileIO
from displayio import Bitmap
except ImportError:
pass
import struct
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html
class TTF:
def __init__(self, f: FileIO, bitmap: Bitmap) -> None:
f.seek(0)
self.file = f
self.characters = {}
def read(format: str) -> Tuple:
s = struct.calcsize(format)
return struct.unpack_from(format, f.read(s))
read(">I") # discard "scalar_type
numTables, searchRange, entrySelector, rangeShift = read(">HHHH")
print(numTables)
table_info = {}
for _ in range(numTables):
tag, checkSum, offset, length = read(">4sIII")
print(tag.decode("utf-8"), hex(checkSum), offset, length)
table_info[tag] = (offset, length)
head_offset, head_length = table_info[b"head"]
f.seek(head_offset)
version, fontRevision, checkSumAdjustment, magicNumber = read(">IIII")
flags, unitsPerEm, created, modified = read(">HHQQ")
xMin, yMin, xMax, yMax = read(">hhhh")
print(xMin, yMin, xMax, yMax)
macStyle, lowestRecPPEM, fontDirectionHint = read(">HHh")
indexToLocFormat, glyphDataFormat = read(">hh")
glyf_offset, glyf_length = table_info[b"glyf"]
f.seek(glyf_offset)
while f.tell() < glyf_offset + glyf_length:
numberOfContours, xMin, yMin, xMax, yMax = read(">hhhhh")
if numberOfContours > 0: # Simple
print(numberOfContours)
ends = []
for _ in range(numberOfContours):
ends.append(read(">H"))
instructionLength = read(">h")[0]
instructions = read(">{}s".format(instructionLength))[0]
print(instructions)
break
else:
raise RuntimeError("Unsupported font")

View file

@ -1,7 +1,6 @@
import array
import sys
import click
from adafruit_bitmap_font import bitmap_font, Bitmap
@ -25,20 +24,15 @@ class OffsetBitmap:
x = x - self.glyph.dx
y = y - (7 - self.glyph.height) + self.glyph.dy
print(pos, x, y)
if 0 <= x < self.glyph.bitmap.width and 0 <= y < self.glyph.bitmap.height:
return self.glyph.bitmap[x, y]
return 0
@click.command
@click.argument("bdf", type=click.Path(exists=True))
@click.argument("header", type=click.File(mode="w"), default=sys.stdout)
def main(bdf, header):
font = bitmap_font.load_font(bdf, Bitmap)
width, height, dx, dy = font.get_bounding_box()
print(width, height, dx, dy)
# if width != 5 or height != 9:
# raise SystemExit("sorry, only 5x9 monospace fonts supported")
@ -50,7 +44,6 @@ def main(bdf, header):
g = font.get_glyph(i)
if g is None:
continue
print(repr(chr(i)), g)
bitmap = OffsetBitmap(dx, dy, g)
for j in range(9):
d = extract_deposit_bits(
@ -61,8 +54,9 @@ def main(bdf, header):
(bitmap[0, j], 8, 9),
)
output_data[j * 256 + i] = d << 2
print(", ".join(f"0x{x:04x}" for x in output_data), file=header)
for x in output_data:
print(f"0x{x:04x},", file=header)
if __name__ == "__main__":
main()
main(sys.argv[1], open(sys.argv[2], "w", encoding="utf-8"))