Reads bitmap fonts in Adobe's Glyph Bitmap Distribution Format.
A BDF file is plain text, which makes it the most approachable font format there is. A header describes the font, and then each glyph is a block naming its codepoint, its box, how far the pen advances, and its rows of pixels in hexadecimal:
STARTCHAR A
ENCODING 65
DWIDTH 4 0
BBX 4 6 0 -1
BITMAP
40
A0
E0
A0
A0
00
ENDCHARENCODING is a real codepoint, which is a step up on the Hershey fonts, where
the mapping from character to glyph is positional and has to be supplied
separately.
Rows are listed from the top of the glyph down, and each is padded to a whole
number of bytes, so a glyph 4 pixels wide still spends 8 bits per row and uses
only the high 4. BBX gives the size of the box and where it sits relative to
the origin, and its vertical offset is normally negative, since it starts below
the baseline to leave room for descenders. Vivid's Y axis points up, so rows
are read in reverse.
Examples
iex> Path.join(:code.priv_dir(:vivid), "fonts/misc-fixed-4x6.bdf")
...> |> Vivid.BDF.load!()
...> |> Vivid.Font.glyph(?A)
...> |> Vivid.BDF.Glyph.pixels()
[{1, 4}, {0, 3}, {2, 3}, {0, 2}, {1, 2}, {2, 2}, {0, 1}, {2, 1}, {0, 0}, {2, 0}]A bitmap font's em is its pixel size, so asking for that size draws it at one pixel per pixel - which for this font, drawn to be six pixels tall, is a size of six.
iex> Path.join(:code.priv_dir(:vivid), "fonts/misc-fixed-4x6.bdf")
...> |> Vivid.BDF.load!()
...> |> Vivid.Font.line("Hi!", 6)
...> |> to_string()
"@@@@@@@@@@@@\n" <>
"@ @ @@ @@@ @\n" <>
"@ @ @@@@@@ @\n" <>
"@ @ @@@ @\n" <>
"@ @ @@ @@@@@\n" <>
"@ @ @ @@ @\n" <>
"@@@@@@@@@@@@\n"Twice that size is blocks of four pixels rather than the same pixels twice as
far apart, because a glyph is drawn as a Vivid.Bitmap, whose cells cover an
area.
iex> Path.join(:code.priv_dir(:vivid), "fonts/misc-fixed-4x6.bdf")
...> |> Vivid.BDF.load!()
...> |> Vivid.Font.line("Hi!", 12)
...> |> to_string()
"@@@@@@@@@@@@@@@@@@@@@@\n" <>
"@ @@ @@@@ @@@@@@ @\n" <>
"@ @@ @@@@ @@@@@@ @\n" <>
"@ @@ @@@@@@@@@@@@ @\n" <>
"@ @@ @@@@@@@@@@@@ @\n" <>
"@ @@ @@@@@@ @\n" <>
"@ @@ @@@@@@ @\n" <>
"@ @@ @@@@ @@@@@@@@@\n" <>
"@ @@ @@@@ @@@@@@@@@\n" <>
"@ @@ @@ @@@@ @\n" <>
"@ @@ @@ @@@@ @\n" <>
"@@@@@@@@@@@@@@@@@@@@@@\n"
Summary
Functions
Read the BDF font at path.
Read the BDF font at path, raising ArgumentError if it can't be read.
Functions
@spec load(Path.t()) :: {:ok, Vivid.Font.t()} | {:error, String.t()}
Read the BDF font at path.
Returns {:error, reason} with a reason worth showing a user rather than
raising.
Examples
iex> {:ok, font} = Vivid.BDF.load(Path.join(:code.priv_dir(:vivid), "fonts/misc-fixed-4x6.bdf"))
...> {font.units_per_em, map_size(font.glyphs)}
{6, 95}
iex> Vivid.BDF.load("/no/such/font.bdf")
{:error, "couldn't read /no/such/font.bdf: no such file or directory"}
iex> Vivid.BDF.load(Path.join(:code.priv_dir(:vivid), "fonts/roboto-subset.ttf"))
{:error, "not a BDF font"}
@spec load!(Path.t()) :: Vivid.Font.t()
Read the BDF font at path, raising ArgumentError if it can't be read.
Example
iex> Path.join(:code.priv_dir(:vivid), "fonts/misc-fixed-4x6.bdf")
...> |> Vivid.BDF.load!()
...> |> Vivid.Font.glyph(?A)
...> |> Vivid.BDF.Glyph.advance()
4