Learn R Programming

bittermelon

Table of Contents

Please note this README is best viewed elsewhere than github.com. github.com's default line-height setting causes distracting extraneous horizontal lines to appear when "printing" bitmaps and github.com does not allow using CSS to set a more reasonable line-height value.

Overview

  • {bittermelon} features over a dozen functions that can modify individual bitmaps or every bitmap within a "bitmap list" or "bitmap font".
  • There is a special emphasis on bitmap fonts and their glyphs. It provides native read/write support for the 'hex' and 'yaff' bitmap font formats and if monobit is also installed then it can read/write several more bitmap font formats.
  • It can print bitmaps to the R terminal.
  • Besides supporting the builtin bm_bitmap() and bm_pixmap() objects it also supports modifying {magick}'s "magick-image" objects and base R's "nativeRaster" and "raster" objects.

Installation

remotes::install_github("trevorld/bittermelon")
  • The functions read_monobit() and write_monobit() require that monobit is installed (i.e. pip3 install monobit).
  • The function bm_distort() requires the suggested package magick.
  • Support for "nativeRaster" objects requires the suggested package farver.

Examples

Bitmap font glyphs

library("bittermelon") # remotes::install_github("trevorld/bittermelon")
font_file <- system.file("fonts/spleen/spleen-8x16.hex.gz", package = "bittermelon")
font <- read_hex(font_file)
bml <- as_bm_list("RSTATS", font = font)
# With vertical compression
bm <- bml |> bm_call(cbind) |> bm_compress("vertical")
print(bm)

██▀▀▀█▄ ▄█▀▀▀▀▀ ▀▀▀██▀▀▀▄█▀▀▀█▄ ▀▀▀██▀▀▀▄█▀▀▀▀▀
██   ██ ██         ██   ██   ██    ██   ██
██▀▀▀█▄  ▀▀▀▀█▄    ██   ██▀▀▀██    ██    ▀▀▀▀█▄
██   ██      ██    ██   ██   ██    ██        ██
██   ██ ▄▄▄▄▄█▀    ██   ██   ██    ██   ▄▄▄▄▄█▀

# Upside down with ASCII characters
bm <- bml |>
    bm_flip("both") |>
    bm_call(cbind, direction = "RTL")
print(bm, px = px_ascii)
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
--@@@@@@---@@----@@---@@---@@-----@@@@@@-@@---@@
-@@--------@@----@@---@@---@@----@@------@@---@@
-@@--------@@----@@---@@---@@----@@------@@---@@
-@@--------@@----@@---@@---@@----@@------@@---@@
-@@--------@@----@@---@@---@@----@@------@@---@@
--@@@@@----@@----@@@@@@@---@@-----@@@@@---@@@@@@
------@@---@@----@@---@@---@@---------@@-@@---@@
------@@---@@----@@---@@---@@---------@@-@@---@@
------@@---@@----@@---@@---@@---------@@-@@---@@
-@@@@@@-@@@@@@@@--@@@@@-@@@@@@@@-@@@@@@---@@@@@@
------------------------------------------------
------------------------------------------------
# With a shadow effect and borders
bm <- bml |>
    bm_pad(sides = 2L) |>
    bm_shadow() |>
    bm_extend(sides = c(2L, 1L), value = 3L) |>
    bm_call(cbind) |>
    bm_pad(sides = 2L, value = 3L)
print(bm)
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓
▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓
▓▓░░██████░░░░▓▓░░░██████░░░▓▓░░████████░░░▓▓░░░█████░░░░▓▓░░████████░░░▓▓░░░██████░░░▓▓
▓▓░░██▒▒▒██░░░▓▓░░██▒▒▒▒▒▒░░▓▓░░░▒▒██▒▒▒▒░░▓▓░░██▒▒▒██░░░▓▓░░░▒▒██▒▒▒▒░░▓▓░░██▒▒▒▒▒▒░░▓▓
▓▓░░██▒░░██▒░░▓▓░░██▒░░░░░░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░░░░░░▓▓
▓▓░░██▒░░██▒░░▓▓░░██▒░░░░░░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░░░░░░▓▓
▓▓░░██████▒▒░░▓▓░░░█████░░░░▓▓░░░░░██▒░░░░░▓▓░░███████▒░░▓▓░░░░░██▒░░░░░▓▓░░░█████░░░░▓▓
▓▓░░██▒▒▒██░░░▓▓░░░░▒▒▒██░░░▓▓░░░░░██▒░░░░░▓▓░░██▒▒▒██▒░░▓▓░░░░░██▒░░░░░▓▓░░░░▒▒▒██░░░▓▓
▓▓░░██▒░░██▒░░▓▓░░░░░░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░░░░░░██▒░░▓▓
▓▓░░██▒░░██▒░░▓▓░░░░░░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░░░░░░██▒░░▓▓
▓▓░░██▒░░██▒░░▓▓░░░░░░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░░░░░░██▒░░▓▓
▓▓░░██▒░░██▒░░▓▓░░██████▒▒░░▓▓░░░░░██▒░░░░░▓▓░░██▒░░██▒░░▓▓░░░░░██▒░░░░░▓▓░░██████▒▒░░▓▓
▓▓░░░▒▒░░░▒▒░░▓▓░░░▒▒▒▒▒▒░░░▓▓░░░░░░▒▒░░░░░▓▓░░░▒▒░░░▒▒░░▓▓░░░░░░▒▒░░░░░▓▓░░░▒▒▒▒▒▒░░░▓▓
▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓
▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓░░░░░░░░░░░░░▓▓░░░░░░░░░░░░▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

We can also print colored terminal output with help of {cli}:

if (cli::num_ansi_colors() >= 16L)
    print(bm, px = " ",
          bg = c(cli::bg_br_white, cli::bg_blue, cli::bg_cyan, cli::bg_red))
plot(bm, col = c("white", "blue3", "cyan3", "red3"))

{gridpattern} matrices

# Also supports {gridpattern} matrices
gridpattern::pattern_weave("twill_herringbone", nrow=14L, ncol = 50L) |>
    as_bm_bitmap() |>
    print(compress = "vertical")
 █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█
  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█
█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█  █▄ ▀█
▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀▀▄▄▀▄▄▀
 ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀
██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ █
█ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██ ▄█▀ ██
gridpattern::pattern_square(subtype=8L, nrow=8L, ncol = 50L) |>
    as_bm_pixmap(s, col = grDevices::rainbow(8L)) |>
    plot()

{mazing} mazes

# Also supports {mazing} mazes
set.seed(42)
m <- mazing::maze(16L, 32L)
m |> as_bm_bitmap(walls = TRUE) |>
    print(compress = "vertical")
█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█▀▀▀█▀▀▀▀▀█▀▀▀▀▀▀▀▀▀▀▀█▀▀▀▀▀█▀▀▀▀▀▀▀█▀▀▀▀▀▀▀█▀▀▀█
█ █▀▀▀▀▀▀▀▀▀█ ▀▀▀ █ ▀ █ █ █ █ ▀▀█▀▀▀▀ ▀ █▀▀ █ █▀▀ █ ▀ █▀▀▀█ █ █ █
█ █ ▀▀▀▀█▀▀ ▀▀▀▀█▀█▀▀▀▀ █ █ █▀▀ █▀▀▀█▀█▀▀ █▀▀▀▀ █▀▀▀▀▀█ ▀▀▀ █ █ █
█ █▀▀ █▀▀ █▀▀▀▀ █ █ ▀▀█▀█ ▀▀█ █▀▀ █ █ ▀ ▀▀▀ █▀▀▀▀▀▀▀▀ █ ▀▀█▀▀▀▀ █
█ ▀▀▀▀█ █▀█ █▀▀▀▀ █▀▀ █ █▀▀ █ █ █▀█ ▀▀█▀▀▀▀▀█ █▀█ ▀▀▀▀▀▀▀ █ █ ▀▀█
█▀▀▀▀ █ █ ▀ █ █▀█ █ █▀▀ █ █▀▀ █ ▀ ▀▀█ █ █ ▀▀█ █ ▀▀▀▀▀▀█▀▀▀▀ ▀▀█ █
█ █▀▀▀▀ █ ▀▀█ █ ▀ █ █▀▀ █ █ █ ▀▀▀ █▀▀ █ █▀▀ █ ▀ █▀▀▀█ █▀▀▀▀▀▀▀█ █
█ ▀ █▀█▀▀▀▀ █ ▀▀▀▀█ █ █ █ ▀▀▀▀█ ▀▀█ ▀▀▀▀█ ▀▀▀▀▀▀▀ █ █ ▀ █▀▀▀█ ▀ █
█▀▀▀▀ █ █▀▀▀▀ ▀▀█ █ █ ▀▀▀▀▀▀█ █ █▀▀▀█▀▀ █ █▀▀▀▀ █▀▀▀█▀▀▀█ █ ▀▀█ █
█ ▀▀█ ▀ █ ▀▀█▀▀▀▀ █ ▀▀█ █ ▀▀▀ █ █ █ █ ▀▀█ █ █ █▀▀ █ ▀ █ ▀ ▀▀█ █ █
█▀▀ ▀▀▀▀▀▀█▀▀ █▀▀ █▀▀ █ █▀▀▀█ ▀▀▀ █ ▀▀▀ █▀▀ █▀▀ █▀▀▀█▀▀▀▀▀▀▀▀ █ █
█ █▀▀▀▀▀█ ▀ █▀▀ ▀▀█ ▀▀▀▀▀ █ █▀█▀▀▀▀▀▀▀▀▀▀ ▀▀█ █▀▀ █▀▀ █▀▀▀█ █▀▀ █
█ █ ▀▀█ █▀▀▀▀▀▀▀█ █▀▀▀▀▀█▀█ █ ▀ █▀▀▀█▀▀▀▀▀█ ▀ █▀▀ █ █▀▀ █ ▀▀█ █▀█
█ █▀█ █ ▀ █▀▀▀█ █ ▀▀█ █ ▀ █ █ ▀▀█ ▀▀▀ █ ▀▀▀▀▀▀▀ █ █ ▀ █▀▀▀█ █ █ █
█ █ █ █▀▀▀▀ █ █ ▀▀█ ▀ █ █▀▀ █▀█ █▀▀▀█ █▀▀ █▀▀▀█▀▀ █▀▀▀▀▀▀ █ ▀ █ █
█ ▀ █ ▀▀▀▀█ ▀▀▀▀▀ ▀▀▀▀▀▀▀ █▀▀ ▀ ▀ █ ▀▀▀ █▀▀ ▀▀▀ ▀▀▀▀▀▀▀ █ ▀▀▀▀▀ █
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# Can also visualize the maze solutions
pal <- grDevices::palette.colors()
m |> as_bm_pixmap(start = "top", end = "bottom",
                  col = c(pal[6L], "white", pal[7L], pal[5L])) |>
   bm_pad(sides = 1L) |>
   plot()

Sprites

# Contains some built-in farming crops sprites
crops <- farming_crops_16x16()
names(crops)
 [1] "avocado"    "cassava"    "coffee"     "corn"       "cucumber"
 [6] "eggplant"   "grapes"     "lemon"      "melon"      "orange"
[11] "pineapple"  "potato"     "rice"       "rose"       "strawberry"
[16] "sunflower"  "tomato"     "tulip"      "turnip"     "wheat"
corn <- crops$corn$portrait
grapes <- crops$grapes$portrait
orange <- crops$orange$stage5
tulip <- crops$tulip$portrait
pm <- cbind(corn, grapes, orange, tulip)

We can pretty print sprites to the terminal with help of {cli}:

if (cli::is_utf8_output() && cli::num_ansi_colors() >= 256L)
    print(pm, compress = "v", bg = "white")
plot(pm)

Builtin Fonts

{bittermelon} has a builtin versions of the 8x16 Spleen font as well as 4x6 and 6x13 Fixed fonts.

spleen_8x16 <- read_hex(system.file("fonts/spleen/spleen-8x16.hex.gz",
                                    package = "bittermelon"))
fixed_4x6 <- read_yaff(system.file("fonts/fixed/4x6.yaff.gz",
                                   package = "bittermelon"))
fixed_5x8 <- read_yaff(system.file("fonts/fixed/5x8.yaff.gz",
                                   package = "bittermelon"))
fixed_6x13 <- read_yaff(system.file("fonts/fixed/6x13.yaff.gz",
                                    package = "bittermelon"))
as_bm_bitmap("RSTATS", font = spleen_8x16) |> bm_compress("v")

██▀▀▀█▄ ▄█▀▀▀▀▀ ▀▀▀██▀▀▀▄█▀▀▀█▄ ▀▀▀██▀▀▀▄█▀▀▀▀▀
██   ██ ██         ██   ██   ██    ██   ██
██▀▀▀█▄  ▀▀▀▀█▄    ██   ██▀▀▀██    ██    ▀▀▀▀█▄
██   ██      ██    ██   ██   ██    ██        ██
██   ██ ▄▄▄▄▄█▀    ██   ██   ██    ██   ▄▄▄▄▄█▀

as_bm_bitmap("RSTATS", font = fixed_4x6) |> bm_compress("v")
█▀▄ ▄▀▀ ▀█▀ ▄▀▄ ▀█▀ ▄▀▀
█▀▄  ▀▄  █  █▀█  █   ▀▄
▀ ▀ ▀▀   ▀  ▀ ▀  ▀  ▀▀
as_bm_bitmap("RSTATS", font = fixed_5x8) |> bm_compress("v")
▄▄▄   ▄▄   ▄▄▄  ▄▄   ▄▄▄  ▄▄
█  █ ▀▄ ▀   █  █  █   █  ▀▄ ▀
█▀▀▄ ▄ ▀▄   █  █▀▀█   █  ▄ ▀▄
▀  ▀  ▀▀    ▀  ▀  ▀   ▀   ▀▀
as_bm_bitmap("RSTATS", font = fixed_6x13) |> bm_compress("v")

█▀▀▀▄ ▄▀▀▀▄ ▀▀█▀▀  ▄▀▄  ▀▀█▀▀ ▄▀▀▀▄
█   █ █       █   █   █   █   █
█▀█▀   ▀▀▀▄   █   █▄▄▄█   █    ▀▀▀▄
█  ▀▄ ▄   █   █   █   █   █   ▄   █
▀   ▀  ▀▀▀    ▀   ▀   ▀   ▀    ▀▀▀

GNU Unifont via {hexfont}

The {hexfont} package includes a helper function unifont() which loads several GNU Unifont hex fonts as a single {bittermelon} bm_font() object. GNU Unifont is a monoscale bitmap font (8x16 and 16x16 glyphs) that pretty much covers all of the official Unicode glyphs plus several of the artificial scripts in the (Under-)ConScript Unicode Registry.

library("hexfont")
system.time(font <- unifont()) # Unifont is a **big** font
   user  system elapsed
104.772   0.196 104.999
length(font) |> prettyNum(big.mark = ",") # number of glyphs
[1] "125,472"
object.size(font) |> format(units = "MB") # memory used
[1] "198.7 Mb"
# Faster to load from a cache
system.time(font <- unifont(cache = TRUE))
   user  system elapsed
  0.700   0.012   0.712
# Or just load the subset of GNU Unifont you need
s <- "R很棒!"
system.time(font_s <- unifont(ucp = str2ucp(s)))
   user  system elapsed
  0.648   0.004   0.652
# Mandarin Chinese
as_bm_bitmap(s, font = font_s) |> bm_compress("v")
                    █ ▄▄▄▄▄▄▄      █      █
   ▄▄▄▄▄▄▄        ▄▀  █     █      █  ▀▀▀▀█▀▀▀▀      ▄█▄
    █     ▀▄     ▀  █ █▀▀▀▀▀█   ▀▀▀█▀▀ ▀▀█▀▀▀▀       ███
    █     ▄▀      ▄█  █▄▄▄▄▄█     ██▄ ▀▀█▀▀▀█▀▀      ▀█▀
    █▀▀▀█▀      ▄▀ █  █  █  ▄▀   █ █ ▀▄▀  █  ▀▄       █
    █    ▀▄        █  █   █▀    ▀  █    ▀▀█▀▀
   ▄█▄    ▄█▄      █  █ ▄  ▀▄      █  ▀▀▀▀█▀▀▀▀       █
                   █  █▀     ▀▀    █      █
# Emoji
as_bm_bitmap("

Copy Link

Version

Install

install.packages('bittermelon')

Monthly Downloads

325

Version

2.2.1

License

MIT + file LICENSE

Maintainer

Trevor L Davis

Last Published

January 29th, 2026

Functions in bittermelon (2.2.1)

cbind.bm_bitmap

Combine bitmap/pixmap objects by rows or columns
bm_lapply

Modify bitmap lists
bm_gray

Gray a bitmap
bm_invert

Invert (negate) a bitmap
bm_pixel_picker

Bitmap pixel picker
bm_options

Get bittermelon options
bm_overlay

Merge bitmaps by overlaying one over another
bm_padding_lengths

Compute bitmap padding lengths
bm_pad

Adjust bitmap padding lengths
bm_pixmap

Bittermelon pixmap matrix object
bm_resize

Resize bitmaps by trimming and/or extending
bm_outline

Compute "outline" bitmap of a bitmap
bm_rotate

Rotate bitmaps 0, 90, 180, or 270 degrees
bm_extract

Extract part of a bitmap
bm_extend

Extend bitmaps on the sides with extra pixels
bm_mask

Modify bitmaps via masking with a 'mask' bitmap
bm_font

Bitmap font object
bm_flip

Flip (reflect) bitmaps
col2int

Color to (native) integer conversions
c.bm_bitmap

Combine bitmap objects
bm_list

Bitmap list object
col2hex

Colors to standardized hex strings
bm_trim

Trim bitmaps
bm_shift

Shift elements within bitmaps
bm_shadow

Bitmap shadow, bold, and glow effects
bm_replace

Replace a color in a bitmap with another color
bm_print

Print bitmap objects
bm_heights

Widths or heights of bitmaps
is_supported_bitmap

Test if the object is a bitmap object supported by the methods in this package
farming_crops_16x16

Sprites for twenty farming crops
read_hex

Read and write hex bitmap font files
plot.bm_matrix

Plot bitmap/pixmap objects
read_monobit

Read and write bitmap font files using monobit
is_bm_bitmap

Test if the object is a bitmap object
ucp2label

Other Unicode utilities
read_yaff

Read and write yaff bitmap font files
print.bm_pixmap

Print pixmap objects
is_bm_font

Test if the object is a bitmap font object
print.bm_bitmap

Print bitmap objects
hex2ucp

Get Unicode code points
is_bm_pixmap

Test if the object is a pixmap object
is_bm_list

Test if the object is a bitmap glyph list object
as.array.bm_bitmap

Cast bitmap/pixmap objects to an array
as_bm_font

Coerce to bitmap font objects
Summary.bm_list

max, min, and range for bitmap objects
as_bm_list

Coerce to bitmap list objects
as_bm_pixmap

Cast to a pixmap matrix object
as.matrix.bm_matrix

Cast bitmap/pixmap objects to a (normal) matrix
Ops.bm_bitmap

S3 Ops group generic methods for bitmap objects
as.data.frame.bm_bitmap

Convert to data frame with pixel (x,y) coordinates
as_bm_bitmap

Cast to a bitmap matrix object
[.bm_matrix

Extract or replace parts of a bitmap/pixmap matrix
bm_edit

Edit a bitmap via text editor
bm_clamp

Clamp bitmap values
bm_call

Execute a function call on bitmap objects
bm_expand

Expand bitmaps by repeating each row and/or column
bm_compose

Compose graphemes in a bitmap list by applying combining marks
bittermelon

bittermelon: Bitmap Tools
bm_bitmap

Bittermelon bitmap matrix object
bm_compress

Compress bitmaps by a factor of two
bm_distort

Resize bitmaps via distortion.