kopia lustrzana https://github.com/peterhinch/micropython-font-to-py
Height determination improved. Better user feedback.
rodzic
4058de707a
commit
67ea344993
35
DRIVERS.md
35
DRIVERS.md
|
@ -78,6 +78,14 @@ Where the buffer is located on the display device the means of controlling the
|
||||||
text insertion point will be device dependent. The driver will need to
|
text insertion point will be device dependent. The driver will need to
|
||||||
implement the functionality of the ``Writer`` class itself.
|
implement the functionality of the ``Writer`` class itself.
|
||||||
|
|
||||||
|
## Fixed width fonts
|
||||||
|
|
||||||
|
If a Python font file is created with the ``-f`` argument, all characters will
|
||||||
|
be saved with the width of the widest. In general it is not necessary to
|
||||||
|
specify this option. The driver can perform fixed pich rendering by rendering
|
||||||
|
the character as variable pitch, then advancing the pixel column by the value
|
||||||
|
returned by ``font.max_width()``.
|
||||||
|
|
||||||
## Drivers with local buffers
|
## Drivers with local buffers
|
||||||
|
|
||||||
The writer of a device driver need not be concerned with the structure of a
|
The writer of a device driver need not be concerned with the structure of a
|
||||||
|
@ -127,7 +135,7 @@ things as the text insertion point. Consideration should be given to employing
|
||||||
the same interface as the ``Writer`` class to simplify the porting of user code
|
the same interface as the ``Writer`` class to simplify the porting of user code
|
||||||
between displays with differing hardware.
|
between displays with differing hardware.
|
||||||
|
|
||||||
## Font files
|
## Python Font files
|
||||||
|
|
||||||
Assume the user has run the utility to produce a file ``myfont.py`` This then
|
Assume the user has run the utility to produce a file ``myfont.py`` This then
|
||||||
has the following outline definition (in practice the bytes objects are large):
|
has the following outline definition (in practice the bytes objects are large):
|
||||||
|
@ -182,6 +190,28 @@ character check.
|
||||||
and contains all the bytes required to render the character including trailing
|
and contains all the bytes required to render the character including trailing
|
||||||
space.
|
space.
|
||||||
|
|
||||||
|
## Binary font files
|
||||||
|
|
||||||
|
These are unlikely to find application beyond the e-paper driver, but for
|
||||||
|
completeness the format is as follows. They are binary files with a four byte
|
||||||
|
header and 126 fixed length records. The header consists of two file identifiers
|
||||||
|
enabling the file format to be checked, followed by bytes specifying the width
|
||||||
|
and height. The length of each record is (width + 1) bytes.
|
||||||
|
|
||||||
|
The file indentifiers depend on the -x and -r arguments specified to ``font_to_py.py``
|
||||||
|
and are as follows:
|
||||||
|
|
||||||
|
hmap reverse byte
|
||||||
|
-x -r 0 1
|
||||||
|
0 0 0x3f 0xe7
|
||||||
|
1 0 0x40 0xe7
|
||||||
|
0 1 0x41 0xe7
|
||||||
|
1 1 0x42 0xe7
|
||||||
|
|
||||||
|
Each record starts with a width byte specifying the x dimension of the glyph if
|
||||||
|
rendered proportionally spaced, followed by the glyph data. This data includes
|
||||||
|
trailing space ensuring that all records have the size specified in the header.
|
||||||
|
|
||||||
## Mapping
|
## Mapping
|
||||||
|
|
||||||
A character occupies a space where (0, 0) represents the coordinates of the top
|
A character occupies a space where (0, 0) represents the coordinates of the top
|
||||||
|
@ -215,4 +245,5 @@ The approach has been tested on SSD1306 devices using both the pseudo-horizontal
|
||||||
and true vertical mapping.
|
and true vertical mapping.
|
||||||
|
|
||||||
The ``font_to_py`` utility has been extensively tested with each of the mapping
|
The ``font_to_py`` utility has been extensively tested with each of the mapping
|
||||||
options.
|
options. It has been used with drivers for SSD1306 OLEDs, SSD1963 LCD displays,
|
||||||
|
and the e-paper display.
|
||||||
|
|
|
@ -24,7 +24,7 @@ Example usage to produce a file ``myfont.py`` with height of 23 pixels:
|
||||||
1. Font file path. Must be a ttf or otf file.
|
1. Font file path. Must be a ttf or otf file.
|
||||||
2. Height in pixels.
|
2. Height in pixels.
|
||||||
3. Output file path. Must have a .py extension otherwise a binary font file
|
3. Output file path. Must have a .py extension otherwise a binary font file
|
||||||
will be created; in this instance a warning message is output.
|
will be created.
|
||||||
|
|
||||||
### Optional arguments:
|
### Optional arguments:
|
||||||
|
|
||||||
|
@ -36,6 +36,15 @@ Example usage to produce a file ``myfont.py`` with height of 23 pixels:
|
||||||
Optional arguments other than the fixed pitch argument will be specified in the
|
Optional arguments other than the fixed pitch argument will be specified in the
|
||||||
device driver documentation. Bit reversal is required by some display hardware.
|
device driver documentation. Bit reversal is required by some display hardware.
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
The specified height is a target. The algorithm gets as close to the target
|
||||||
|
height as possible (usually within one pixel). The actual height achieved is
|
||||||
|
displayed on completion.
|
||||||
|
|
||||||
|
A warning is output if the output filename does not have a .py extension as the
|
||||||
|
creation of a binary font file may not be intended.
|
||||||
|
|
||||||
## The font file
|
## The font file
|
||||||
|
|
||||||
Assume that the you have employed the utility to create a file ``myfont.py``. In
|
Assume that the you have employed the utility to create a file ``myfont.py``. In
|
||||||
|
|
|
@ -280,18 +280,19 @@ class Font(dict):
|
||||||
max_ascent = 0
|
max_ascent = 0
|
||||||
for char in self.charset:
|
for char in self.charset:
|
||||||
glyph = self._glyph_for_character(char)
|
glyph = self._glyph_for_character(char)
|
||||||
max_ascent = max(max_ascent, int(glyph.ascent))
|
max_ascent = max(max_ascent, glyph.ascent)
|
||||||
max_descent = max(max_descent, int(glyph.descent))
|
max_descent = max(max_descent, glyph.descent)
|
||||||
# for a few chars e.g. _ glyph.width > glyph.advance_width
|
# for a few chars e.g. _ glyph.width > glyph.advance_width
|
||||||
max_width = int(max(max_width, glyph.advance_width,
|
max_width = int(max(max_width, glyph.advance_width,
|
||||||
glyph.width))
|
glyph.width))
|
||||||
|
|
||||||
error = required_height - (max_ascent + max_descent)
|
new_error = required_height - (max_ascent + max_descent)
|
||||||
if error == 0:
|
if (new_error == 0) or (abs(new_error) - abs(error) == 0):
|
||||||
break
|
break
|
||||||
print('Height set in {} passes'.format(npass))
|
error = new_error
|
||||||
self.height = max_ascent + max_descent
|
self.height = int(max_ascent + max_descent)
|
||||||
self._max_descent = max_descent
|
print('Height set in {} passes. Actual height {} pixels'.format(npass + 1, self.height))
|
||||||
|
self._max_descent = int(max_descent)
|
||||||
return max_width
|
return max_width
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,8 +333,8 @@ class Font(dict):
|
||||||
index += (len(data)).to_bytes(2, byteorder='little')
|
index += (len(data)).to_bytes(2, byteorder='little')
|
||||||
return data, index
|
return data, index
|
||||||
|
|
||||||
def build_binary_array(self, hmap, reverse):
|
def build_binary_array(self, hmap, reverse, sig):
|
||||||
data = bytearray((0x3f, 0xe7, self.max_width, self.height))
|
data = bytearray((0x3f + sig, 0xe7, self.max_width, self.height))
|
||||||
for char in self.charset:
|
for char in self.charset:
|
||||||
width = self[char][2]
|
width = self[char][2]
|
||||||
data += bytes((width,))
|
data += bytes((width,))
|
||||||
|
@ -401,16 +402,23 @@ def write_data(stream, fnt, font_path, monospaced, hmap, reverse):
|
||||||
stream.write(STR02.format(height, height))
|
stream.write(STR02.format(height, height))
|
||||||
|
|
||||||
# BINARY OUTPUT
|
# BINARY OUTPUT
|
||||||
|
# hmap reverse magic bytes
|
||||||
|
# 0 0 0x3f 0xe7
|
||||||
|
# 1 0 0x40 0xe7
|
||||||
|
# 0 1 0x41 0xe7
|
||||||
|
# 1 1 0x42 0xe7
|
||||||
def write_binary_font(op_path, font_path, height, hmap, reverse):
|
def write_binary_font(op_path, font_path, height, hmap, reverse):
|
||||||
try:
|
try:
|
||||||
fnt = Font(font_path, height, True) # All chars have same width
|
fnt = Font(font_path, height, True) # All chars have same width
|
||||||
except freetype.ft_errors.FT_Exception:
|
except freetype.ft_errors.FT_Exception:
|
||||||
print("Can't open", font_path)
|
print("Can't open", font_path)
|
||||||
return False
|
return False
|
||||||
|
sig = 1 if hmap else 0
|
||||||
|
if reverse:
|
||||||
|
sig += 2
|
||||||
try:
|
try:
|
||||||
with open(op_path, 'wb') as stream:
|
with open(op_path, 'wb') as stream:
|
||||||
data = fnt.build_binary_array(hmap, reverse)
|
data = fnt.build_binary_array(hmap, reverse, sig)
|
||||||
stream.write(data)
|
stream.write(data)
|
||||||
except OSError:
|
except OSError:
|
||||||
print("Can't open", op_path, 'for writing')
|
print("Can't open", op_path, 'for writing')
|
||||||
|
|
Ładowanie…
Reference in New Issue