Document handling of bitmapped font files.

pull/45/head
Peter Hinch 2021-01-31 17:53:24 +00:00
rodzic 0b253aa68a
commit 4e07ed605b
4 zmienionych plików z 84 dodań i 62 usunięć

Wyświetl plik

@ -1,15 +1,20 @@
# font_to_py.py
# 1. font_to_py.py
Convert a font file to Python source code. Python font files provide a much
faster way to access glyphs than the principal alternative which is a random
access file on the filesystem.
This PC utility converts an industry standard font file to Python source code.
Another benefit is that they can save large amounts of RAM on resource-limited
targets: the font file may be incorporated into a firmware build such that it
occupies flash memory rather than scarce RAM. Python code built into firmware
is known as frozen bytecode.
Python font files offer advantages on microcontroller platforms running
MicroPython. They provide a much faster way to render glyphs than the principal
alternative which is a random access binary file on the filesystem.
## Recent revisions
The format of the Python font file is designed to save large amounts of RAM on
resource-limited targets: the font file may be incorporated into a firmware
build such that it occupies flash memory rather than scarce RAM. Python code
built into firmware is known as frozen bytecode.
## 1.1 Recent revisions
1 Feb 2021 V0.4 With thanks to @enigmaniac for the suggestion and code ideas.
1. Now supports `bdf` and `pcf` font files for better results at small sizes.
17 Oct 2019 V0.33 With thanks to Stephen Irons (@ironss).
1. Fix bug where input rather than output filename was checked.
@ -32,7 +37,7 @@ API is unchanged.
###### [Main README](./README.md)
# Dependencies
# 2. Dependencies
The utility requires Python 3.2 or greater, also `freetype` which may be
installed using `pip3`. On Linux (you may need a root prompt):
@ -42,13 +47,15 @@ installed using `pip3`. On Linux (you may need a root prompt):
# pip3 install freetype-py
```
# Usage
# 3. Usage
`font_to_py.py` is a command line utility written in Python 3. It is run on a
PC. It takes as input a font file with a `ttf` or `otf` extension and a
required height in pixels and outputs a Python 3 source file. The pixel layout
is determined by command arguments. By default fonts are stored in variable
pitch form. This may be overidden by a command line argument.
required height in pixels and outputs a Python 3 source file. Alternatively it
will accept a `bdf` or `pcf` source file (which includes a height definition).
The pixel layout is determined by command arguments. By default fonts are
stored in variable pitch form. This may be overidden by a command line
argument.
By default the printable ASCII character set (ordinal values 32 to 126
inclusive) is supported (i.e. not including control characters). Command line
@ -65,16 +72,18 @@ Examples of usage to produce Python fonts with a height of 23 pixels:
$ font_to_py.py FreeSans.ttf 23 myfont.py
$ font_to_py.py -k extended FreeSans.ttf 23 my_extended_font.py
```
## Arguments
## 3.1 Arguments
### Mandatory positional arguments:
### 3.1.1 Mandatory positional arguments:
1. Font file path. Must be a ttf or otf file.
2. Height in pixels.
2. Height in pixels. In the case of `bdf` or `pcf` files a height of 0 should
be specified as the height is retrieved from the file.
3. Output file path. Filename must have a .py extension (unless writing a
binary font).
binary font). 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.
### Optional arguments:
### 3.1.2 Optional arguments:
* -f or --fixed If specified, all characters will have the same width. By
default fonts are assumed to be variable pitch.
@ -121,29 +130,32 @@ pitch result. A better apearance would be achieved by using a font designed as
monospaced.
There have been reports that producing fonts with Unicode characters outside
the ASCII set from ttf files is unreliable. If expected results are not
achieved, use an otf font. I have successfully created Cyrillic and extended
the ASCII set from `ttf` files is unreliable. If expected results are not
achieved, use an `otf` font. I have successfully created Cyrillic and extended
fonts from a `ttf`, so I suspect the issue may be source fonts lacking the
required glyphs.
The `-i` or `--iterate` argument. For specialist applications. Specifying this
causes a generator function `glyphs` to be included in the Python font file. A
generator instantiated with this will yield `bitmap`, `height`, and `width` for
every glyph in the font.
### 3.1.3 The -i or --iterate arg
### Output
This is for specialist applications; it causes a generator function `glyphs` to
be included in the Python font file. A generator instantiated with this will
yield `bitmap`, `height`, and `width` for every glyph in the font.
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, along with the width of the widest character.
### 3.1.4 The height arg
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.
In the case of scalable `ttf` or `otf` source files 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, along
with the width of the widest character.
## The font file
If a `bdf` or `pcf` bitmapped font is specified, the `height` arg should be 0.
A nonzero value will cause a warning message to be printed and the value will
be ignored.
## 3.2 The font file
Assume that the you have employed the utility to create a file `myfont.py`. In
your code you will issue
your code you will issue:
```python
import myfont
@ -154,9 +166,14 @@ to render strings on demand. A practical example may be studied
[here](./writer/writer_demo.py).
The detailed layout of the Python file may be seen [here](./writer/DRIVERS.md).
### Python font files
# 4. Python font files
These start with a comment which is the command line used to create the font.
Users of the `Writer` or `CWriter` classes or of
[nano-gui](https://github.com/peterhinch/micropython-nano-gui) do not need to
study the file format. These details are provided for those wishing to access
Python font files directly.
Files start with a comment which is the command line used to create the font.
They include the following functions:
1. `height()` Height of bitmaps in pixels (all are the same height).
@ -177,7 +194,7 @@ They include the following functions:
See [this link](https://stackoverflow.com/questions/27631736/meaning-of-top-ascent-baseline-descent-bottom-and-leading-in-androids-font)
for an explanation of `baseline`.
### Binary font files
# 5. Binary font files
There is an option to create a binary font file, specified with a `-b` or
`--binary` command line argument. In this instance the output filename must
@ -197,7 +214,7 @@ Only the following optional arguments are valid:
* -x or --xmap.
* -r or --reverse.
# Dependencies, links and licence
# 6. Dependencies, links and licence
The code is released under the MIT licence. The `font_to_py.py` utility
requires Python 3.2 or later.

Wyświetl plik

@ -4,9 +4,11 @@ This repository defines a method of creating and deploying fonts for use with
MicroPython display drivers. A PC utility renders industry standard font files
as a bitmap in the form of Python sourcecode. A MicroPython module enables such
files to be displayed on devices with suitable device drivers. These include
OLED displays using the SSD1306 chip and the official device driver.
OLED displays using the SSD1306 chip and the official device driver. Compatible
drivers for a variety of display technologies are available as part of the
[nano-gui repository](https://github.com/peterhinch/micropython-nano-gui).
# Introduction
# 1. Introduction
MicroPython platforms generally have limited RAM, but more abundant storage in
the form of flash memory. Font files tend to be relatively large. The
@ -29,7 +31,7 @@ The resultant file is usable with two varieties of display device drivers:
2. Drivers for displays where the frame buffer is implemented in the display
device hardware.
# Solution
# 2. Solution
This comprises three components, links to docs below:
@ -41,12 +43,13 @@ This comprises three components, links to docs below:
device drivers. Provides details of the font file format and information on
ensuring comptibility with the `Writer` classes.
# font_to_py.py
# 3. font_to_py.py
This command line utility is written in Python 3 and runs on a PC. It takes
as input a font file in `ttf` or `otf` form together with a height in pixels
and outputs a Python source file containing the font as a bitmap. Fixed and
variable pitch rendering are supported. The design has the following aims:
This command line utility is written in Python 3 and runs on a PC. To convert
a scalable font to Python the utility takes input a font file in `ttf` or `otf`
form together with a height in pixels and outputs a Python source file
containing the font as a bitmap. Fixed and variable pitch rendering are
supported. The design has the following aims:
* Independence of specific display hardware.
* The path from font file to Python code to be fully open source.
@ -58,24 +61,26 @@ The second is achieved by using Freetype and the Freetype Python bindings. Its
use is documented [here](./FONT_TO_PY.md). This also details measurements of
RAM usage when importing fonts stored as frozen bytecode.
# Limitations
## 3.1 Small fonts
Converting scalable `ttf` or `otf` files programmatically works best for larger
fonts. For small fonts it is best to use hand-designed bitmapped font files.
These are now supported: `bdf` or `pcf` font files may be converted to Python
source in the same format as files originating from scalable fonts.
## 3.2 Limitations
Kerning is not supported. Fonts are one bit per pixel. Colour displays are
supported by the `CWriter` class which adds colour information at the rendering
stage. This assumes that all pixels of a character are coloured identically.
Converting font files programmatically works best for larger fonts. For small
fonts, like the 8*8 default used by the SSD1306 driver, it is best to use
hand-designed binary font files: these are optiised for rendering at a specific
size.
By default the `font_to_py.py` utility produces the ASCII character set from
`chr(32)` to `chr(126)` inclusive. Command line options enable the character
set to be modified to include arbitrary Unicode characters. Alternative sets
may be specified such as for non-English languages. Efficient support is now
provided for sparse character sets.
# Font file interface
# 4. Font file interface
A font file is imported in the usual way e.g. `import font14`. Python font
files contain the following functions. These return values defined by the
@ -103,6 +108,6 @@ The `font_to_py.py` utility allows a default glyph to be specified (typically
The `min_ch` and `max_ch` functions are mainly relevant to contiguous character
sets.
# Licence
# 5. Licence
All code is released under the MIT licence.

Wyświetl plik

@ -6,11 +6,12 @@
# Some code adapted from Daniel Bader's work at the following URL
# http://dbader.org/blog/monochrome-font-rendering-with-freetype-and-python
# With thanks to Stephen Irons @ironss for various improvements.
# With thanks to Stephen Irons @ironss for various improvements, also to
# @enigmaniac for ideas around handling `bdf` and `pcf` files.
# The MIT License (MIT)
#
# Copyright (c) 2016-2019 Peter Hinch
# Copyright (c) 2016-2021 Peter Hinch
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -46,7 +47,7 @@ MAXCHAR = 126 # 94 chars
# Lines are broken with \ for readability.
class ByteWriter(object):
class ByteWriter:
bytes_per_line = 16
def __init__(self, stream, varname):
@ -92,7 +93,7 @@ def var_write(stream, name, value):
# FONT HANDLING
class Bitmap(object):
class Bitmap:
"""
A 2D bitmap image represented as a list of byte values. Each byte indicates
the state of a single pixel in the bitmap. A value of 0 indicates that the
@ -166,7 +167,7 @@ class Bitmap(object):
row += 1
class Glyph(object):
class Glyph:
def __init__(self, pixels, width, height, top, left, advance_width):
self.bitmap = Bitmap(width, height, pixels)
@ -495,7 +496,6 @@ def write_func(stream, name, arg):
def write_font(op_path, font_path, height, monospaced, hmap, reverse, minchar,
maxchar, defchar, charset, iterate, bitmapped):
# fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar, charset, bitmapped)
try:
fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar, charset, bitmapped)
except freetype.ft_errors.FT_Exception:
@ -576,8 +576,8 @@ def quit(msg):
print(msg)
sys.exit(1)
DESC = """font_to_py.py
Utility to convert ttf or otf font files to Python source.
DESC = """font_to_py.py V0.4.0
Utility to convert ttf, otf, bdf and pcf font files to Python source.
Sample usage:
font_to_py.py FreeSans.ttf 23 freesans.py

Wyświetl plik

@ -6,7 +6,7 @@
# V0.35 Sept 2020 Fast rendering option for color displays
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2019-2020 Peter Hinch
# Copyright (c) 2019-2021 Peter Hinch
# A Writer supports rendering text to a Display instance in a given font.
# Multiple Writer instances may be created, each rendering a font to the