bdftools
provides some tools for reading, manipulating and outputting BDF bitmap fonts.
read_bdf(filename)
reads a BDF pixel font file into an R representation i.e. an object of class bdf
print.bdf()
prints meta information and a font sample.bdf_create_df(bdf, text)
Create a data.frame of points for the given stringbdf_create_mat(bdf, text)
Create a matrix representation for the given stringbdfGrob(bdf, text, ...)
create a simple grob representation of the given string using squares for pixelsgeom_text_bdf()
renders text in a bitmap font - simlar interface to ggplot2::geom_text()
as.data.frame.bdf(bdf)
converts the full bdf
font into a rectangular data.frame of all characters and their (x, y) coordinates.read_bdf_builtin()
to read in a font included with this package:
You can install from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/bdftools')
library(grid)
library(ggplot2)
library(bdftools)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Load a BDF font
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fontfile <- system.file("spleen-5x8.bdf", package = "bdftools", mustWork = TRUE)
myfont <- read_bdf(fontfile)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# By default, printing a font will print some header info, and a text
# sample rendered in that font in the console
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myfont
=8, bbox=5, pixel_size=8, font_descent=0, font_ascent=-1, default_char=8, line_height=1, bitmap=7, size=32, bbox=8, pixel_size=
size
# #
# # # #
# # ## ### ### ### # ## # # ### ###
#### # # # # # # # # # # # # # # #
# # ### # # # # # # # # # # # #### ##
# # # # # # # # ## # # # ## # #
# # ### # # ### # ## ## ## ### ###
###
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generate some sample text in the console
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bdf_print_sample(myfont, "Hello RStats", wrap = FALSE)
# # # #
# # # # ### ### # #
# # ### # # ## # # # ### ## ### ###
#### # # # # # # # # ## # # # #
# # #### # # # # ### # # ### # ##
# # # # # # # # # # # # # # #
# # ### ## ## ## # # ### ## ### ## ###
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# To compensate for many terminal fonts having a 2:1 ratio, it is possible
# to customize the characters used for each pixel
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bdf_print_sample(myfont, "Hello RStats", wrap = FALSE, zero = ' ', one = '@@')
@@ @@
@@ @@ @@ @@ @@@@@@ @@@@@@
@@ @@ @@@@@@ @@ @@ @@@@ @@ @@ @@
@@@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@@@
@@ @@ @@@@@@@@ @@ @@ @@ @@ @@@@@@ @@
@@ @@ @@ @@ @@ @@ @@ @@ @@ @@
@@ @@ @@@@@@ @@@@ @@@@ @@@@ @@ @@ @@@@@@
bdf_print_sample(myfont, "Hello RStats", wrap = FALSE, zero = ' ', one = '\u2588\u2588')
██ ██
██ ██ ██ ██ ██████ ██████
██ ██ ██████ ██ ██ ████ ██ ██ ██
████████ ██ ██ ██ ██ ██ ██ ██ ██ ████
██ ██ ████████ ██ ██ ██ ██ ██████ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ████ ████ ████ ██ ██ ██████
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Print using compact unicode block characters
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bdf_print_sample_compact(myfont, 'Hello #RStats')
▄ ▄ ▄ ▄
█ █ ▄▄▄ █ █ ▄▄ ▄█▄█▄█▀▀▄ ▄▀▀▀ ▄█▄ ▄▄ ▄█▄ ▄▄▄
█▀▀█ █▄▄█ █ █ █ █ █ █ █▄▄▀ ▀▀▄ █ ▄▄█ █ ▀▄▄ █ █ ▀▄▄▄ ▀▄▄ ▀▄▄ ▀▄▄▀ ▀█▀█▀█ █ ▄▄▄▀ ▀▄▄ ▀▄▄█ ▀▄▄ ▄▄▄▀
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generate a graphics grob and draw it
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grob <- bdfGrob(myfont, "Hello\nRStats", size = 10, shrink = 0.8, fill = 'lightblue', col = 'blue')
grid.newpage(); grid.draw(grob)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# View the entire font as a data.frame of coordiantes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
as.data.frame(myfont)
# A tibble: 2,385 x 10
encoding desc dwidth x y size pixel_size font_ascent font_descent* <int> <chr> <int> <dbl> <dbl> <int> <int> <int> <int>
1 32 SPACE 5 NA NA 8 8 7 1
2 33 EXCLAM… 5 3 7 8 8 7 1
3 33 EXCLAM… 5 3 6 8 8 7 1
4 33 EXCLAM… 5 3 5 8 8 7 1
5 33 EXCLAM… 5 3 4 8 8 7 1
6 33 EXCLAM… 5 3 3 8 8 7 1
7 33 EXCLAM… 5 3 1 8 8 7 1
8 34 QUOTAT… 5 4 7 8 8 7 1
9 34 QUOTAT… 5 2 7 8 8 7 1
10 34 QUOTAT… 5 4 6 8 8 7 1
# … with 2,375 more rows, and 1 more variable: line_height <int>
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# View the coordinates of a string rendered in this font
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bdf_create_df(myfont, "abc")
# A tibble: 34 x 3
x y idx<dbl> <dbl> <int>
1 3 5 1
2 2 5 1
3 4 4 1
4 4 3 1
5 3 3 1
6 2 3 1
7 4 2 1
8 1 2 1
9 4 1 1
10 3 1 1
# … with 24 more rows
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# View the coordinates of a string rendered in this font
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bdf_create_mat(myfont, "abc")
1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[,1,] 0 0 0 0 0 1 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 1 0 0 0 0 0 0 0 0
[3,] 0 1 1 0 0 1 1 1 0 0 0 1 1 1
[4,] 0 0 0 1 0 1 0 0 1 0 1 0 0 0
[5,] 0 1 1 1 0 1 0 0 1 0 1 0 0 0
[6,] 1 0 0 1 0 1 0 0 1 0 1 0 0 0
[7,] 0 1 1 1 0 1 1 1 0 0 0 1 1 1 [
myfont <- bdftools::read_bdf_builtin("spleen-16x32.bdf")
bdf_print_sample(myfont, "Frak")
########## ##
########### ##
### ##
## ##
## ##
## ##
## ########## ######### ## ##
## ########### ########## ## ###
## ### ## ### ## ###
######### ## ## ## ## ###
######### ## ## ## ###
## ## ########## #####
## ## ########### #####
## ## ### ## ## ###
## ## ## ## ## ###
## ## ## ## ## ###
## ## ## ## ## ###
## ## ### ## ## ###
## ## ########### ## ###
## ## ########## ## ##
geom_text_bdf()
geom_text_bdf()
works very similar to geom_text()
but text is rendered from a bitmap font as a collection of large square pixels. Key things to note:
colour
and a fill
shrink
argument determines the size of the square pixel. shrink = 1
is the default. shrink = 0.9
will make the square pixels smaller and not touching each other.
library(ggplot2)
library(bdftools)
fontfile <- system.file("spleen-5x8.bdf", package = "bdftools", mustWork = TRUE)
plot_df <- head(mtcars)
plot_df$car <- rownames(plot_df)
plot_df$cyl <- as.factor(plot_df$cyl)
ggplot(plot_df, aes(mpg, wt)) +
geom_point(col = 'red') +
geom_text_bdf(
aes(mpg, wt, label=car, fill = cyl),
col = NA,
linewidth = 0.5,
bdf_filename = fontfile,
shrink = 1,
size = 9,
hjust = -0.1
) +
theme_bw() +
scale_fill_brewer(palette = 'Dark2') +
labs(title = "geom_text_bdf() - bitmap font rendering in ggplot2")
An example of how the data.frame representation of the font can be plotted in ggplot2
.
library(ggplot2)
library(bdftools)
myfont <- read_bdf_builtin("cozette.bdf")
plot_df <- as.data.frame(myfont)
plot_df <- plot_df[plot_df$encoding >= 65 & plot_df$encoding <= 124,]
ggplot(plot_df) +
geom_tile(aes(x, y), width=0.9, height = 0.9, na.rm = TRUE) +
facet_wrap(~encoding + desc, ncol = 12)+
theme_void(10) +
coord_equal()
How the header for this page was created.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Choose some fonts
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
font1 <- bdftools::read_bdf_builtin("spleen-16x32.bdf")
font2 <- bdftools::read_bdf_builtin("spleen-5x8.bdf")
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main header
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
txt1 <- bdfGrob(
font1, "bdftools",
lwd = 0.5,
fill = '#3D428B',
col = 'darkblue',
size = 8,
shrink = 0.8
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Subtitle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
txt2 <- bdfGrob(
font2, "bitmap fonts in R",
lwd = 0.5,
col = 'darkblue',
size = 11,
shrink = 0.8,
fill = viridisLite::inferno(151),
y = unit(0.5, 'npc') - unit(50, 'mm')
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Plot it
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage();
grid.draw(txt1)
grid.draw(txt2)
U+0000
to U+FFFF
. (License: Dual licensed SIL Open Font License (OFL) version 1.1 and the GNU GPL 2+ with the GNU font embedding exception)