The Bitmap Font (BMF) Format
The BMF font format is based on a group of glyphs drawn inside text files (much like ASCII art), and a set of JSON configuration files to set their parameters.
The Bitmap Font Builder tool can be used to convert BMF fonts into outline formats (such as OpenType).
This format was devised by Lasse Fister as part of the original Bitmap Font Builder package. This page is an attempt to document the format based on the builder's source code.
Font components
A font's directory structure is made out of three main parts:
- the glyphs directory (
glyphs/
by default) - font specification files, one per desired weight, in JSON format
(
FontName-Regular.json
by default) - other option files inside the
options/
directory
The BMF format is rather flexible in what it allows, so in this page we also indicate some sensible defaults. There are two good examples for understanding how a font is structured:
- the font-skeleton repository, with a minimal set of options
- the
graphicoreBMFB
font included in the Bitmap Font Builder, which uses advanced features such as kerning and ligatures.
Glyphs
Glyphs are in a folder called glyphs
. Inside the folder, glyphs are stored in
simple text files. For example, the capital A from the Graphicore font looks
like this:
...........
........###
.......###.
......####.
.....##.##.
....##..##.
.. #######.
..##....##.
.##.....###
##.........
...........
...........
The options/glyphs.json
file contains the list of characters and their
respective files.
Options
The font's metadata, options and generation parameters are all stored in options files, which are specified according to the JSON format.
The recommended structure for options files would be:
- a specifications file (
Fontname-Regular.json
), for font metadata and base features - an options file (
options/options.json
) - a list of characters and corresponding glyphs (
options/glyphs.json
) - a list of kerning pairs (
options/kerning.json
, optional) - a list of ligatures (
options/ligatures.json
, optional)
Multiple options files and inheritance
While all of the font's options could fit into one single option file, this would be somewhat clunky beyond the most basic uses, so BMF supports multiple option files, with an inheritance system that allows us to specify more than one file.
Options can inherit from one another, and the last defined JSON file takes priority. They must specify their ancestors in their root object like this:
{
"inherit": ["glyphs.json", "kerning.json", "ligatures.json"]
}
This will load ligatures.json
first and all its ancestors, then
kerning.json
and all its ancestors, and finally the glyphs.
If an option is already set, it will not be overwritten by the ancestors. Options are only set in the root element and in its direct children if these are dicts, there is no deeper copying.
Side bearing values
A glyph contains no side bearing values. That information is stored inside the
features.distances
table that you can find in options.
Available options and defaults
This is a work in progress effort to document all available fields and values,
but not yet complete. In the meantime, the graphicoreBitmapFont included in the
Bitmap Font Builder is a great example of how to use BMF options. The defaults
dict in ./graphicoreBMFB/__init__.py
has some comments and the default
values.
Option sets:
- font
fileName
: "unnamed",featureFile
: A.fea
file to be merged directly. Default: falseglyphFolder
: Name of the folder where glyph files are contained. Default: "glyphs",lineCount
: Height of all glyphs. Glyphs with a different number of lines will be cropped or padded as needed. Default: 12descent
: Count of lines below the baseline. Default: 2upos
: Underline position from the baseline. Default: 3uwidth
: Underline height. Default: 1filled
: Character to use for filled pixels inside glyph files. Default:"#"
empty
: Character to use for empty pixels inside glyph files. Default:"."
classRightIndicator
: Default: u"@_1R",classLeftIndicator
: Default: u"@_2L"
- metadata
- generator
- glyphs
- features
TODO: incorporate below code into the list
{
"metadata": {
# postscript names, as used in fontforge
"fontname": "unnamed-medium",
"weight": "Medium",
"fullname": "unnamed medium",
"familyname": "unnamed",
"copyright": "Copyright (c), put your notice here.",
"version": "0",
"more": {
"English": {
"Manufacturer": "unnamed",
"Designer": "unnamed",
"Designer URL": "http://unnamed",
"Vendor URL": "http://unnamed",
"License": "no text",
"License URL": "http://unnamed",
"Trademark": "",
"Descriptor": "Built with graphicore Boolean Matrix Font Building and fontforge. http://graphicore.de",
}
}
},
"generator": {
"unit": 125, # one raster unit in em
"offset": 5, # the x and y offset of the final pixel shape
"width": 115, # the width (diameter) of the final pixel shape
"em": 1000, # the fonts em height usually 1000 for postscript font and for truetyoe a power of 2, such as 2048
"emDescent": 200, # if set here the descent is not beeing calculated, thus givin some control over it
"contextualShape": False, # magical thing
# a value biger than 0 will turn on contextualShapes for outside
# corners. i.e. corners where otherwise nothing would have been drawn
# the combination: offset > 0 and width < unit and itself
# outsideCornerRadius = 0.5 fontforge has problems removing the
# overlaps in some chars making outsideCornerRadius (width/2) -1 is the
# best solution I know so far
"outsideCornerRadius": 0,
"insideCornerRadius": 0,
"generatedFeatureFile": False, # a .fea file that will be generated (and then merged)
"generatedClassesFile": "classes.json",
"generatedKerningFile": "kerning.json",
"fileFormats": ['otf', 'sfd'],
"ffGenerateFlags": ["opentype", "old-kern", "dummy-dsig"],
"removeOverlap": True,
"autoHint": True, # an either good idea, but slow
"invertOutside": False
},
"glyphs": {}, # dict of glyphsNames: glyphFiles.txt
"features": {
"kerningClasses": {}, # dict of "kerningclassname": ["list of space separated glyphnames a b c comma"]
"distances": {}, # dict of "keringclassname": int(always ad on this side) #this is not the dist table
# distances stores the left and right sidebearing of the characters in the kerning class
"kern": [], # list of ["rightEdgeKerningClass", "leftEdgeKerningKlass", int(distance)[, bool enum]]
"liga": [], # list of ligatures ["replace space separated like f f i", "by_a_single_glyph_like_f_f_i"]
"dlig": [],
# all features here are made for all the following languagesystems: pairs of cryptic 4 letter words ["script", "language"]
# for real good international magic some work would be required
"languagesystems": [["DFLT", "dflt"], ["latn", "dflt"]]
}
}
List of default character mappings
TODO: Convert to Markdown table
A : aCap.txt
B : bCap.txt
C : cCap.txt
D : dCap.txt
E : eCap.txt
F : fCap.txt
G : gCap.txt
H : hCap.txt
I : iCap.txt
J : jCap.txt
K : kCap.txt
L : lCap.txt
M : mCap.txt
N : nCap.txt
O : oCap.txt
P : pCap.txt
Q : qCap.txt
R : rCap.txt
S : sCap.txt
T : tCap:.txt
U : uCap.txt
V : vCap.txt
W : wCap.txt
X : xCap.txt
Y : yCap.txt
Z : zCap.txt
-----
1.txt
2.txt
3.txt
4.txt
5.txt
6.txt
7.txt
8.txt
9.txt
0.txt
-----
interrogación - ? : _questionmark.txt
exclamación - ! : _exclamationmark.txt
paréntesis izquierdo - ( : _leftparenthesis.txt
paréntesis derecho - ) : _rightparenthesis.txt
llave izquierda - { : _leftcurlybracket.txt
llave derecha - } : _rightcurlybracket.txt
corchete izquierdo - [ : _leftsquarebracket.txt
corchete derecho - ] : _rightsquarebracket.txt
arroba - @ : _commercialat.txt
dólar - $ : _dollarsign.txt
euro - € : _euro.txt
almohadilla - # : _numbersign.txt
et - & : _ampersand.txt
comillas - " : _quotationmark.txt
asterisco - * : _asterisk.txt
guion/menos - - : _hyphenminus.txt
más - + : _plussign.txt
barra - / : _solidus.txt
punto - . : _fullstop.txt
coma - , : _comma.txt
dos puntos - : : _colon.txt
punto y coma - ; : _semicolon.txt
porcentaje - % : _percentsign.txt