Height determination improved. Better user feedback.

pull/3/merge
Peter Hinch 2016-11-20 17:12:32 +00:00
rodzic 4058de707a
commit 67ea344993
3 zmienionych plików z 62 dodań i 14 usunięć

Wyświetl plik

@ -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
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
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
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
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
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
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.
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.

Wyświetl plik

@ -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.
2. Height in pixels.
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:
@ -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
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
Assume that the you have employed the utility to create a file ``myfont.py``. In

Wyświetl plik

@ -280,18 +280,19 @@ class Font(dict):
max_ascent = 0
for char in self.charset:
glyph = self._glyph_for_character(char)
max_ascent = max(max_ascent, int(glyph.ascent))
max_descent = max(max_descent, int(glyph.descent))
max_ascent = max(max_ascent, glyph.ascent)
max_descent = max(max_descent, glyph.descent)
# for a few chars e.g. _ glyph.width > glyph.advance_width
max_width = int(max(max_width, glyph.advance_width,
glyph.width))
error = required_height - (max_ascent + max_descent)
if error == 0:
new_error = required_height - (max_ascent + max_descent)
if (new_error == 0) or (abs(new_error) - abs(error) == 0):
break
print('Height set in {} passes'.format(npass))
self.height = max_ascent + max_descent
self._max_descent = max_descent
error = new_error
self.height = int(max_ascent + max_descent)
print('Height set in {} passes. Actual height {} pixels'.format(npass + 1, self.height))
self._max_descent = int(max_descent)
return max_width
@ -332,8 +333,8 @@ class Font(dict):
index += (len(data)).to_bytes(2, byteorder='little')
return data, index
def build_binary_array(self, hmap, reverse):
data = bytearray((0x3f, 0xe7, self.max_width, self.height))
def build_binary_array(self, hmap, reverse, sig):
data = bytearray((0x3f + sig, 0xe7, self.max_width, self.height))
for char in self.charset:
width = self[char][2]
data += bytes((width,))
@ -401,16 +402,23 @@ def write_data(stream, fnt, font_path, monospaced, hmap, reverse):
stream.write(STR02.format(height, height))
# 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):
try:
fnt = Font(font_path, height, True) # All chars have same width
except freetype.ft_errors.FT_Exception:
print("Can't open", font_path)
return False
sig = 1 if hmap else 0
if reverse:
sig += 2
try:
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)
except OSError:
print("Can't open", op_path, 'for writing')