API Reference¶
Read, manipulate and write bitmap fonts in the Bitmap Distribution Format.
To get started, use bdflib.reader.read_bdf() to load a BDF file and
create a bdflib.model.Font object, or just create one yourself from
scratch.
Modify the font by tinkering with it directly, or by using the helpers in
bdflib.effects and bdflib.glyph_combining.
If you’re making a font intended for use with the X11 windowing system,
check out the helpers in bdflib.xlfd.
When you’re done, you can use bdflib.writer.write_bdf() to write your
font back out to a BDF file.
bdflib.model¶
Classes that represent a bitmap font, with its glyphs and metadata.
- class bdflib.model.Font(name: bytes, ptSize: int, xdpi: int, ydpi: int)[source]¶
Bases:
objectRepresents the entire font and font-global properties.
- Parameters:
Instances of this class can be used like
dictinstances.byteskeys refer to the font’s properties and are associated withbytesinstances, whileintkeys refer to the code-points the font supports, and are associated withGlyphinstances.>>> myfont = Font( ... b"My Font", ... ptSize=12, ... xdpi=96, ... ydpi=96, ... ) >>> myfont.ptSize 12 >>> a_glyph = myfont.new_glyph_from_data( ... b"capital A", ... codepoint=65, ... ) >>> a_glyph == myfont[65] True
Note
Some properties (the name, point-size and resolutions) are required, and although they can be examined via the
dictinterface, they cannot be removed with thedelstatement.- add_comment(comment: bytes) None[source]¶
Add one or more lines of text to the font’s comment field.
- Parameters:
comment – Human-readable text to add to the comment, ASCII encoded. It may include newline characters.
The added text will begin on a new line.
- codepoints() Iterable[int][source]¶
Returns the codepoints that this font has glyphs for.
These codepoints can be used with the regular dict syntax to retrieve the associated glyphs
- Returns:
Supported codepoints
- copy() Font[source]¶
Returns a deep copy of this font.
The new font, along with all of its properties and glyphs, may be modified without affecting this font.
- Returns:
A new, independent copy of this Font
- get_comments() List[bytes][source]¶
Retrieve the lines of the font’s comment field.
- Returns:
The comment text, ASCII encoded.
- new_glyph_from_data(name: bytes, data: List[int] | None = None, bbX: int = 0, bbY: int = 0, bbW: int = 0, bbH: int = 0, advance: int = 0, codepoint: int | None = None) Glyph[source]¶
Add a new
Glyphto this font.This method’s arguments are passed to the
Glyphconstructor.If you include the
codepointparameter, the codepoint will be included in the result ofcodepoints()and you will be able to look up the glyph by codepoint later. Otherwise, the glyph will only be available via theglyphsproperty.- Returns:
the newly-created Glyph
- Raises:
GlyphExists – if an existing glyph is already associated with the requested codepoint.
- property_names() Iterable[bytes][source]¶
Returns the names of this font’s properties.
These names can be used with the regular dict syntax to retrieve the associated value.
- Returns:
Property names
- ptSize: int¶
The font’s nominal size in PostScript points (1/72 of an inch), the first value in the SIZE field in the BDF file
- class bdflib.model.Glyph(name: bytes, data: List[int] | None = None, bbX: int = 0, bbY: int = 0, bbW: int = 0, bbH: int = 0, advance: int = 0, codepoint: int | None = None)[source]¶
Bases:
objectRepresents a font glyph and associated properties.
- Parameters:
name – The name of this glyph, ASCII encoded.
data – If provided, gives the initial bitmap for the glyph, see the
dataattribute below.bbX – The left-most edge of the glyph’s bounding box, in pixels.
bbY – The bottom-most edge of the glyph’s bounding box, in pixels.
bbW – The glyph’s bounding-box extends this many pixels right of
bbX(must be >= 0). If data is provided, each integer should be at most this many bits wide.bbH – The glyph’s bounding-box extends this many pixels upward from
bbY(must be >= 0). If data is provided, it should yield this many rows.advance – After drawing this glyph, the next glyph will be drawn this many pixels to the right.
codepoint – The Unicode codepoint that this glyph represents.
- data: List[int]¶
Each item of the
.dataproperty is aintbbW bits wide, representing the pixels of a single row. the first item in.datais the lowest row in the glyph, so that list indices increase in the same direction as pixel coordinates.>>> my_glyph = Glyph( ... name=b"capital A", ... data=[ ... 0b10001, ... 0b11111, ... 0b10001, ... 0b01110, ... ], ... bbW=5, ... bbH=4, ... ) >>> for row in reversed(my_glyph.data): ... print("{:05b}".format(row)) 01110 10001 11111 10001
If you want to get the actual coordinates of the glyph’s drawn pixels, look at the
iter_pixels()method.
- get_ascent() int[source]¶
Returns the distance from the Y axis to the highest point of the glyph.
This is zero if no part of the glyph is above the Y axis.
- Returns:
The ascent of this glyph.
- get_bounding_box() Tuple[int, int, int, int][source]¶
Returns the position and dimensions of the glyph’s bounding box.
- Returns:
The left, bottom, width and height of the bounding box, as passed to the constructor.
- get_descent() int[source]¶
Returns the distance from the Y axis to the lowest point of the glyph.
This is zero if no part of the glyph is below the Y axis.
- Returns:
The descent of this glyph.
- iter_pixels() Iterable[Iterable[bool]][source]¶
Yields the state of pixels within the bounding box.
This method returns an iterable of
bbHrows, from the top of the glyph (large X values) to the bottom (small X values). Each row is an iterable ofbbWbooleans, from left to right. Each boolean isTrueif that pixel should be drawn, and otherwiseFalse.Alternatively, you can obtain the glyph data in BDF format with
get_data(), or access the raw bitmap via thedataproperty.- Returns:
the state of each pixel
- merge_glyph(other: Glyph, atX: int, atY: int) None[source]¶
Draw another glyph onto this one at the given coordinates.
- Parameters:
other – The other glyph to draw onto this one.
atX – The other glyph’s origin will be placed at this X offset in this glyph.
atY – The other glyph’s origin will be placed at this Y offset in this glyph.
This glyph’s bounding box will be stretch to include the area of the added glyph, but the
advancewill not be modified.
bdflib.reader¶
- exception bdflib.reader.ParseError(lineno: int, message: str)[source]¶
Bases:
ExceptionAn error encountered by
read_bdf()- add_note()¶
Exception.add_note(note) – add a note to the exception
- args¶
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- bdflib.reader.WarningCallback¶
The signature of a function for reporting parser warnings
- bdflib.reader.read_bdf(raw_iterable: Iterable[bytes], report_warning: Callable[[int, str], None] | None = None) Font[source]¶
Read a BDF-format font from the given source.
- Parameters:
raw_iterable – Each item should be a single line of the BDF file, ASCII encoded.
report_warning – A callback that will be invoked to report problems encountered during parsing the file. These problems do not prevent the file being interpreted as BDF, but may indicate misunderstandings or corruption. If not provided, warnings will be discarded.
- Returns:
the resulting font object
- Raises:
ParseError – if the font cannot be meaningfully interpreted as a BDF file.
If you want to read an actual file, make sure you use the ‘b’ flag so you get bytes instead of text:
def report_warning(lineno: int, message: str) -> None: print("Problem on line {}: {}".format(lineno, message)) font = bdflib.reader.read_bdf(open(path, 'rb'), report_warning)
bdflib.writer¶
- bdflib.writer.write_bdf(font: Font, stream: IOBase) None[source]¶
Write a BDF-format font to the given stream.
- Parameters:
font – The font to write to the given stream.
stream – The stream that will receive the font.
streammust be an object with at.write()method that takes abytes. If you want to write to an actual file, make sure you use the ‘b’ flag:bdflib.writer.write_bdf(font, open(path, 'wb'))
bdflib.effects¶
Automatically generate visual variants of a font.
- bdflib.effects.embolden(font: Font, maintain_spacing: bool = True) Font[source]¶
Create a bold version of a font by widening each glyph.
- Parameters:
font – The font to embolden.
maintain_spacing – If true, each glyph’s advance width will be incremented, because a wider glyph needs more room.
- Returns:
A copy of
font, with each glyph emboldened.
To embolden a glyph, it is drawn over itself one pixel to the right, making each vertical stroke one pixel wider.
- bdflib.effects.expand(font: Font, x_factor: int, y_factor: int) Font[source]¶
Create a font with greater resolution by duplicating glyph rows and columns.
- Parameters:
font – The font to expand.
x_factor – The number of times to increase the font’s horizontal resolution. Must be > 0.
y_factor – The number of times to increase the font’s vertical resolution. Must be > 0.
- Returns:
A copy of
font, with the resolution adjusted.
If
fonthas a horizontal resolution of 72dpi, andx_factoris 2, the resulting font will have the same vertical metrics, but the horizontal resolution will be doubled to 144dpi. The new columns will be created by duplicating existing columns (“Nearest Neighbour”), so each column of a source glyph will appear twice in the resulting glyph.Vertical increases work the same way, except duplicating rows instead of columns. Because the resolution is increased, rather than making the glyph bigger, the point size stays the same.
- bdflib.effects.merge(base: Font, custom: Font) Font[source]¶
Create a new font by choosing glyphs from two other fonts.
- Parameters:
base – The lower-priority font.
custom – The higher-priority font.
- Returns:
A font where each glyph comes from
baseorcustom.
For any given codepoint, the resulting font will use the corresponding glyph from
customif there is one, falling back to the glyph frombase. The new font’s properties and other metadata are all copied fromcustom.
bdflib.glyph_combining¶
Tools for building glyphs by combining other glyphs.
Unicode has a lot of “pre-combined” code-points that are the combination of a normal code-point and a combining code-point, like how U+014D LATIN SMALL LETTER O WITH MACRON is the combination of U+006F LATIN SMALL LETTER O with U+0304 COMBINING MACRON. Given glyphs for their individual components, glyphs for pre-combined code-points can be automatically generated.
An example of using this module to generate pre-combined glyphs:
decompositions = build_unicode_decompositions()
filler = FontFiller(myfont, decompositions)
filler.add_decomposable_glyphs_to_font()
- class bdflib.glyph_combining.FontFiller(font: Font, decompositions: Dict[str, List[Tuple[str, int]]])[source]¶
Bases:
objectBuild pre-combined glyphs from available component glyphs.
- Parameters:
font (Font) – Any pre-combined glyphs will be added to this font.
decompositions – A dict mapping pre-combined characters to their components, as returned by
build_unicode_decompositions().
Call
add_decomposable_glyphs_to_font()on an instance of this class to add as many pre-combined glyphs as possible.- add_decomposable_glyphs_to_font() None[source]¶
Adds all the glyphs that can be built to the given font.
This calls
add_glyph_to_font()for each key in the decompositions passed to the class constructor.
- add_glyph_to_font(char: str) bool[source]¶
Add the glyph representing char to the given font, if it can be built.
- Parameters:
char – A single-codepoint Unicode string, whose glyph should be generated (if possible) and added to the font passed to the class constructor.
- Returns:
Trueif the font now contains a glyph for that character,Falseotherwise.
This method may return
Trueif a glyph was generated, or if the font already contained the required glyph.This method may return
Falseif:the decompositions passed to the class constructor do not include any components for
charthe font passed to the class constructor is missing glyphs for one or more of
char’s components, and they could not be generatedone of
char’s components uses a combining class this code doesn’t understand
- missing_chars: Counter[str]¶
After calling
add_decomposable_glyphs_to_font(), this attribute will record characters that could be used in combining sequences, but were missing from the input font. Adding the character with the highest count to the font will give you the biggest increase in Unicode coverage.
- unknown_classes: Counter[int]¶
After calling
add_decomposable_glyphs_to_font(), this attribute will record Unicode combining classes included in the decompositions paramater that bdflib does not yet support. If bdflib were extended to support these Unicode combining classes, we might be able to use them to create new glyphs.
- bdflib.glyph_combining.build_unicode_decompositions() Dict[str, List[Tuple[str, int]]][source]¶
Returns a dictionary mapping unicode characters to their components.
- Returns:
a mapping from pre-combined characters to their components.
Each key in the resulting dict is a single-character Unicode string, and each value is a list of single-character Unicode strings and their combining classes, the components of the key. For example, one of the items in the result should be:
u"\N{LATIN SMALL LETTER O WITH MACRON}": [ (u"o", 0), (u"\N{COMBINING MACRON}", 230), ]
(where 0 indicates a regular base character, and 230 means the glyph is drawn above the base glyph. See https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values for details.)
This function obtains information about combining characters from Python’s
unicodedatastandard library module. It also properly handles “soft-dotted” characters “i” and “j” where pre-combined glyphs should be built from the dotless versions of those characters.
bdflib.xlfd¶
Check fonts against the X Logical Font Descriptor conventions.
Fonts in the BDF format can be used for all kinds of things, but commonly they are used with the traditional X11 font APIs, built around X Logical Font Descriptors, which require certain custom properties be set.
To check a BDF font against the XLFD conventions,
use validate(),
which returns a (hopefully empty) list of problems,
represented as subclasses of ValidationError.
If the font is missing properties that can be automatically calculated,
fix() will update the font as required.
For more information about these issues, see the official X Logical Font Description Conventions specification.
Helpful constants¶
Names for XLFD properties:
- bdflib.xlfd.FOUNDRY¶
The organisation responsible for making the font, a namespace for
FAMILY_NAME
- bdflib.xlfd.FAMILY_NAME¶
The human-readable name of the font, like “Times New” or “Helvetica”
- bdflib.xlfd.WEIGHT_NAME¶
The human-readable name of the font’s weight, like “Bold” or “Thin”
- bdflib.xlfd.SLANT¶
A code describing the slant style of the font, one of the values in
SLANT_VALUES
- bdflib.xlfd.SETWIDTH_NAME¶
The human-reaadable name of the font’s width, like “Expanded” or “Ultracondensed”
- bdflib.xlfd.ADD_STYLE_NAME¶
A human-readable name that further distinguishes this font from other similar fonts; an “additional style” if you will, like “Sans Serif” or “Outline”
- bdflib.xlfd.PIXEL_SIZE¶
The vertical space required for a line of type, in pixels, usually (but not always) the sum of
FONT_ASCENTandFONT_DESCENT
- bdflib.xlfd.POINT_SIZE¶
The vertical space required for a line of type, in deci-points
- bdflib.xlfd.RESOLUTION_X¶
The horizontal output resolution this font is intended for, in dots-per-inch
- bdflib.xlfd.RESOLUTION_Y¶
The horizontal output resolution this font is intended for, in dots-per-inch
- bdflib.xlfd.SPACING¶
A code describing the spacing of this font, one of the values in
SPACING_VALUESbelow
- bdflib.xlfd.AVERAGE_WIDTH¶
The average width of all the characters in this font, in deci-pixels.
- bdflib.xlfd.CHARSET_REGISTRY¶
The organisation responsible for defining the character set encoding used by this font, a namespace for
CHARSET_ENCODING
- bdflib.xlfd.CHARSET_ENCODING¶
The identifier for the character set encoding used by this font
- bdflib.xlfd.FONT_ASCENT¶
The maxium height above the baseline that any glyph in this font touches, in pixels
- bdflib.xlfd.FONT_DESCENT¶
The maxium depth below the baseline that any glyph in this font touches, in pixels
- bdflib.xlfd.DEFAULT_CHAR¶
If the software using this font wants to draw a glyph that the font does not contain, the glyph with this encoding will be drawn instead
Values for the SLANT property:
- bdflib.xlfd.SLANT_ROMAN¶
This font is drawn with upright strokes
- bdflib.xlfd.SLANT_ITALIC¶
This font is drawn leaning forward, often with curves or flourishes
- bdflib.xlfd.SLANT_OBLIQUE¶
This font is the Roman variant, tilted forward
- bdflib.xlfd.SLANT_REVERSE_ITALIC¶
This font is drawn leaning backward, often with curves or flourishes
- bdflib.xlfd.SLANT_REVERSE_OBLIQUE¶
This font is the Roman variant, tilted backward
- bdflib.xlfd.SLANT_OTHER¶
This font has a tilt that’s not any of the above
Values for the SPACING property:
- bdflib.xlfd.SPACING_PROPORTIONAL¶
Each glyph in this font takes space proportional to its natural width, so a character like “i” is narrow while “m” is wide
- bdflib.xlfd.SPACING_MONOSPACED¶
Each glyph in this font takes exactly the same space, regardless of its natural width
- bdflib.xlfd.SPACING_CHARCELL¶
Like
SPACING_MONOSPACED, but in addition, no part of any glyph sticks out of the space allocated to it
Classes and functions¶
- exception bdflib.xlfd.Contradiction(name: bytes, prop_value: bytes | int, xlfd_value: bytes | int)[source]¶
Bases:
ValidationErrorA value in the XLFD name contradicts a BDF property value
- exception bdflib.xlfd.ExpectedBytestring(name: bytes, value: int)[source]¶
Bases:
ValidationErrorThe value of a property should be a bytestring
- exception bdflib.xlfd.ExpectedEnumeratedValue(name: bytes, value: bytes | int, expected: Set[bytes | int])[source]¶
Bases:
ValidationErrorThe value of a property should be one of a fixed set of values
- exception bdflib.xlfd.ExpectedInteger(name: bytes, value: bytes)[source]¶
Bases:
ValidationErrorThe value of a property should be an integer
- exception bdflib.xlfd.MissingProperty[source]¶
Bases:
ValidationErrorThe font is missing a property required by the XLFD conventions
- exception bdflib.xlfd.NotAnXlfd[source]¶
Bases:
ValidationErrorThe font’s name is not a valid XLFD string
- exception bdflib.xlfd.ValidationError[source]¶
Bases:
ValueErrorSuperclass of all problems detected by
validate()
- bdflib.xlfd.fix(font: Font) None[source]¶
Add missing XLFD properties to a font, with default or calculated values
Any properties already present will be preserved, even if their values seem to be incorrect.
- bdflib.xlfd.validate(font: Font) List[ValidationError][source]¶
Validate a font against the XLFD conventions
This function checks for missing, required properties, properties with the wrong type, the syntax of the font’s XLFD name and conflicts between the XLFD name and its properties.
All problems detected (not just the first) are returned in a list.