Bitmap

Bitmap is the low-level pixel container used throughout the library whenever a boolean mask needs to be rendered, copied, or transformed.

A bitmap stores only on/off pixels. The actual terminal representation is chosen later by Buffer::drawBitmap() together with BitmapDrawOptions.

You will mostly encounter this class indirectly during glyph rendering and other pixel-based operations. That said, it is also a great tool when you want to build your own rendering helpers—such as icons, line maps, or small procedural effects.

Usage

Preparing a Small Pixel Mask

A Bitmap represents a two-dimensional grid of pixels. You can set or query each pixel individually and copy regions between bitmaps.

This makes it straightforward to construct reusable masks or generate small procedural patterns.

auto bitmap = Bitmap{Size{8, 8}};
bitmap.setPixel({1, 1}, true);
bitmap.setPixel({2, 2}, true);
bitmap.setPixel({3, 3}, true);

auto copy = Bitmap{Size{8, 8}};
copy.draw(Position{2, 1}, bitmap);

if (copy.pixelQuad({1, 1}) != 0) {
    // Use the encoded 2x2 mask for custom rendering.
}

Use draw() to copy one bitmap into another at a given position.

The pixelQuad() function reads a 2×2 group of pixels and encodes them as a small integer. This is especially useful when translating bitmap data into terminal cell representations (for example, when working with half-block characters).

Building Bitmaps from Text Patterns

For small icons or handcrafted masks, Bitmap::fromPattern() is usually the fastest and most readable way to define pixels.

Each input string represents one row. Dots and spaces are treated as cleared pixels, while every other character sets a pixel.

const auto rocket = Bitmap::fromPattern({
    ".....#.....",
    "....###....",
    "...#####...",
    "....###....",
    "...#####...",
    "..#######..",
    "...#####...",
    "..#######..",
    ".#########.",
    ".....#.....",
    ".....#.....",
});

Rows may have different lengths. fromPattern() automatically uses the longest row as the bitmap width and pads shorter rows with cleared pixels on the right.

Rendering a Bitmap to a Buffer

Once your bitmap is prepared, you can render it using Buffer::drawBitmap().

The BitmapDrawOptions control how pixels are translated into terminal cells—this includes scaling, block characters, colors, and optional neighbor-aware line styles.

auto bitmap = Bitmap{Size{8, 8}};
bitmap.setPixel({1, 1}, true);
bitmap.setPixel({2, 2}, true);
bitmap.setPixel({3, 3}, true);
bitmap.setPixel({4, 4}, true);

auto options = BitmapDrawOptions{};
options.setColorSequence(
    ColorSequence{
        Color{fg::BrightBlue, bg::Black},
        Color{fg::BrightCyan, bg::Black},
        Color{fg::BrightMagenta, bg::Black},
    },
    BitmapColorMode::ForwardDiagonalStripes);

buffer.drawBitmap(bitmap, Rectangle{2, 2, 20, 8}, Alignment::Center, options, animationCycle);

When using the rectangle overload, the rendered bitmap is aligned inside the target rectangle. If it exceeds the available space, it is cropped according to the selected alignment.

Choosing the Scale Mode

BitmapScaleMode determines how bitmap pixels are mapped to terminal cells:

  • HalfBlock Groups pixels into 2×2 blocks per character. This is the default mode and allows even empty cells to be colored, because the zero entry in halfBlocks() is rendered.

  • FullBlock Uses one character per set bitmap pixel.

  • DoubleBlock Also uses one character per set pixel, but doubles the width in terminal cells to better match typical terminal aspect ratios.

If you enable char16Style(), it overrides the scale mode entirely. In this mode, each set pixel becomes one terminal cell, and the selected Char16Style determines the character based on the pixel’s east, south, west, and north neighbors.

This is particularly useful for rendering circuit diagrams, line art, or bitmap-derived frame structures.

Color and Animation Rules

The base color is defined by BitmapDrawOptions::color().

If you provide a color sequence, it is applied depending on the selected BitmapColorMode. Stripe modes derive their color from the rendered bitmap coordinates, combined with animationCycle and colorAnimationOffset().

If the sequence is empty, the bitmap inherits the color from the underlying buffer.

After selecting the base color, the color defined in fullBlock(), doubleBlocks(), halfBlocks(), or the chosen Char16Style is applied on top.

To explore all combinations interactively, run the bitmap-showcase demo.

Interface

class Bitmap

A mutable bitmap storing boolean pixels in row-major order.

Subclassed by erbsland::cterm::FontGlyph

Public Functions

Bitmap() = default

Create an empty bitmap with the size (0,0).

inline explicit Bitmap(const Size size)

Create a bitmap with the given size and all pixels cleared.

Parameters:

size – The bitmap dimensions.

inline Size size() const noexcept

Get the bitmap dimensions.

inline Rectangle rect() const noexcept

Get a rectangle that represents the bitmap bounds.

inline const std::vector<bool> &data() const noexcept

Access the raw pixel storage.

inline std::vector<bool> &data() noexcept

Access the raw pixel storage for modification.

bool pixel(Position pos) const noexcept

Read one pixel.

Parameters:

pos – The pixel position.

Returns:

The pixel state, or false if pos is outside the bitmap.

uint8_t pixelQuad(Position pos) const noexcept

Read a 2x2 pixel block encoded as four bits.

Parameters:

pos – The quad position in half-resolution coordinates.

Returns:

Bit mask with top-left/top-right/bottom-left/bottom-right pixels in bits 0..3.

uint8_t pixelCardinal(Position pos) const noexcept

Read the four cardinal pixels as a bit-mask.

Clockwise bit-order: right, down, left, up

Parameters:

pos – The center pixel position.

Returns:

The bit mask, where bits 0..3 represent the pixels in clockwise order starting from the right.

uint8_t pixelRing(Position pos) const noexcept

Read the ring of eight pixels surrounding the given position as a bitmask.

Clockwise bit-order: 0:E, 1:SE, 2:S, 3:SW, 4:W, 5:NW, 6:N, 7:NE

Parameters:

pos – The center pixel position.

Returns:

The bit mask, where bits 0..7 represent the pixels in clockwise order starting from the right.

Rectangle boundingRect(bool value = true) const noexcept

Get a rectangle around all set/cleared pixels.

Parameters:

value – If true, return the bounding box of set pixels, otherwise cleared pixels.

Returns:

The bounding rectangle of the specified pixels or an empty rectangle if none are set/cleared.

std::size_t pixelCount(bool value = true) const noexcept

Get the number of set/cleared pixels in this bitmap.

Parameters:

value – The pixel type to count.

void setPixel(Position pos, bool value) noexcept

Set one pixel in the bitmap.

Note

Positions outside the bitmap are ignored.

Parameters:
  • pos – The pixel position.

  • value – The new pixel state.

void flipHorizontal() noexcept

Mirror the bitmap horizontally in-place.

void invert() noexcept

Invert the bitmap in-place.

Bitmap inverted() const noexcept

Get an inverted version of this bitmap.

Returns:

The inverted bitmap.

Bitmap outlined() const noexcept

Convert this bitmap to an outlined version.

The bitmap needs to have a margin large enough for the outline. Algorithm: If at a cleared source pixel is surrounded by at least one set pixel, the target pixel is set.

Bitmap expanded(Margins margins, bool value) const noexcept

Create a new bitmap expanded with a given margin.

Negative margins cut sections from the bitmap.

Parameters:
  • margins – The margins for the expansion.

  • value – The value to fill the expanded area with.

Returns:

The expanded/shrunk bitmap. If the new width or height is zero, an empty bitmap is returned.

template<typename T>
void draw(Position position, const std::vector<T> &data) noexcept

Draw pixels from a numeric bit mask.

Template Parameters:

T – The unsigned integer type.

Parameters:
  • position – The top left corner where to draw the bit mask.

  • data – The array with the data.

inline void draw(const Position position, const Bitmap &bitmap) noexcept

Draw another bitmap to the given position.

Parameters:
  • position – The top left corner of the bitmap to draw.

  • bitmap – The bitmap to draw.

void fillRect(Rectangle rect, bool value) noexcept

Fill a rectangle with a given pixel state.

Positions outside this bitmap are ignored.

Parameters:
  • rect – The rectangle to fill.

  • value – The new pixel state.

void floodFill(Position pos, bool value) noexcept

Perform a flood fill from the given position.

If the pixel at the given position is already set to the given value, nothing happens. If the start position is outside the bitmap, nothing happens.

Parameters:
  • pos – The start position.

  • value – The new pixel state.

std::string toPattern() const

Convert this bitmap to a simple ASCII representation.

This function is meant for debugging and visualization. Use Buffer for a true character matrix. Cleared pixels are represented by dots (.), set pixels by a hash (#).

Public Static Functions

template<typename Fn>
static inline Bitmap fromFunction(const Size size, Fn fn) noexcept

Build a new bitmap using a function.

Parameters:
  • size – The size of the new bitmap.

  • fn – The function to use for building the bitmap. Takes a position and returns a boolean.

Returns:

The new bitmap.

static Bitmap fromPattern(std::initializer_list<std::string_view> rows)

Create a bitmap from an ASCII pattern.

Each input string becomes one row. Dots (.) and spaces create cleared pixels, every other character sets a pixel. Shorter rows are padded with cleared pixels to the maximum row width.

Parameters:

rows – The pattern rows to parse.

Returns:

The created bitmap.

class BitmapDrawOptions

The options to draw a bitmap.

These options define how Buffer::drawBitmap() converts bitmap pixels into terminal cells. For color animation and stripe modes, the color position is calculated in the rendered bitmap grid: FullBlock, DoubleBlock, and Char16Style use one logical position per bitmap pixel, while HalfBlock uses one logical position per 2x2 pixel cell. The rectangle overload of drawBitmap() aligns this rendered grid inside the target rectangle and crops it if needed.

Note

Creating custom option instances is expensive. For that reason, create them once and keep the instances for multiple drawBitmap calls.

Public Functions

BitmapDrawOptions() = default

Create default bitmap draw options.

template<typename tColor>
inline explicit BitmapDrawOptions(tColor color)

Create options for one fixed color.

Parameters:

color – The base color for the bitmap.

BitmapDrawOptions(ColorSequence colorSequence, BitmapColorMode colorMode = BitmapColorMode::OneColor)

Create options from a color sequence.

Parameters:
  • colorSequence – The base colors for the bitmap.

  • colorMode – The mode used to pick colors from the sequence.

const ColorSequence &color() const noexcept

The color to use for drawing the bitmap.

The color can be either a single color or a sequence of colors. If this is an empty sequence, the color is inherited from the buffer. Colors are applied using the colorMode(). If the characters in fullBlock(), doubleBlocks() or halfBlocks() have colors set, these colors are overlaid after calculating this base color.

Note

For full-block and double-block mode, the background color is only applied to set pixels. Fill the bitmap area if you need a custom background color for unset pixels.

void setColor(Color color) noexcept

Set a single color.

Replaces the current color sequence with one entry.

void setColor(Foreground foreground, Background background) noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void setColor(Foreground foreground) noexcept

Set only a foreground color.

The background remains inherited from the buffer below.

void setColor(Foreground::Hue foreground) noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void setColor(Background background) noexcept

Set only a background color.

The foreground remains inherited from the buffer below.

void setColor(Background::Hue background) noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void setColorSequence(ColorSequence colorSequence, BitmapColorMode colorMode = BitmapColorMode::OneColor) noexcept

Set a color sequence.

Pass an empty ColorSequence{} to inherit the complete color from the buffer below.

BitmapColorMode colorMode() const noexcept

The color mode.

This mode controls how colors are applied to the bitmap. See BitmapColorMode for more information.

void setColorMode(BitmapColorMode colorMode) noexcept

Set the color mode.

std::size_t colorAnimationOffset() const noexcept

The offset for color animations.

This offset is added to the animationCycle passed to drawBitmap. Animate animationCycle and keep this offset static.

void setColorAnimationOffset(std::size_t offset) noexcept

Set the offset for color animations.

const Char16StylePtr &char16Style() const noexcept

The Char16Style instance.

If a Char16Style instance is set, it overrides the scale mode and renders one terminal cell for each set bitmap pixel. The selected block depends on the four direct neighbors of the set pixel: east=bit 0, south=bit 1, west=bit 2, north=bit 3.

void setChar16Style(Char16StylePtr char16Style) noexcept

Set a Char16Style instance.

const CharCombinationStylePtr &combinationStyle() const noexcept

The combination style.

If a combination style is set, every block that is set in the buffer is first passed to this combination style. This happens for every mode used to draw the bitmap.

void setCombinationStyle(CharCombinationStylePtr combinationStyle) noexcept

Set the combination style.

const Char &fullBlock() const noexcept

The full block.

The full block is only used when the scale mode FullBlock is used and no Char16Style is set. Character colors are overlaid on the color from the color mode.

void setFullBlock(Char fullBlock)

Set the full block.

The full block must have a display width of 1.

const String &doubleBlocks() const noexcept

The double blocks.

The double blocks are only used when the scale mode DoubleBlock is used and no Char16Style is set. Character index 0 is used for the left half and index 1 for the right half of each set bitmap pixel. Character colors are overlaid on the color from the color mode.

void setDoubleBlocks(String doubleBlocks)

Set the double block String.

The string must have exactly two characters.

const String &halfBlocks() const noexcept

The string with the half-blocks.

The half-blocks are only used when the scale mode HalfBlock is used and no Char16Style is set. Entry 0 is used for an empty 2x2 block and entry 15 for a full 2x2 block. Character colors are overlaid on the color from the color mode.

void setHalfBlocks(String halfBlocks)

Set the half-blocks string.

The half-blocks string must have exactly 16 characters.

BitmapScaleMode scaleMode() const noexcept

The scale mode.

See BitmapScaleMode for more details.

void setScaleMode(BitmapScaleMode scaleMode) noexcept

Set the scale mode.

Public Static Functions

static const BitmapDrawOptions &defaultOptions() noexcept

Access the shared object with the default options.

Default options use default terminal colors, half-block rendering, and the standard Unicode half-block characters.

enum class erbsland::cterm::BitmapColorMode : uint8_t

The mode how color is applied to the bitmap.

Values:

enumerator OneColor

Uses one color from the sequence for the whole bitmap.

The selected sequence entry is animationCycle + colorAnimationOffset.

enumerator VerticalStripes

Uses the color sequence in vertical stripes.

The selected sequence entry is x + animationCycle + colorAnimationOffset.

enumerator HorizontalStripes

Uses the color sequence in horizontal stripes.

The selected sequence entry is y + animationCycle + colorAnimationOffset.

enumerator ForwardDiagonalStripes

Uses the color sequence in forward diagonal stripes.

The selected sequence entry is x + y + animationCycle + colorAnimationOffset.

enumerator BackwardDiagonalStripes

Uses the color sequence in backward diagonal stripes.

The selected sequence entry is -x + y + animationCycle + colorAnimationOffset.

enum class erbsland::cterm::BitmapScaleMode : uint8_t

The mode how the bitmap is scaled.

Values:

enumerator HalfBlock

Draw the bitmap with half-blocks.

This mode uses the 16 characters from halfBlocks(). Each 2x2 pixel block creates a 4-bit index in this order: bit 0 = top-left, bit 1 = top-right, bit 2 = bottom-left, bit 3 = bottom-right. This renders the bitmap at half width and half height, rounded up. Character colors are overlaid on the color from the color mode.

enumerator FullBlock

Draw the bitmap with full-blocks.

This mode uses fullBlock() to draw each set pixel of the bitmap. Character colors are overlaid on the color from the color mode. To color the unset pixels, you must fill the bitmap area first.

enumerator DoubleBlock

Draw the bitmap with double-blocks.

This mode uses doubleBlocks() to draw each set pixel of the bitmap. The bitmap is twice as large in the X axis, to compensate for the rectangular shape of terminal characters. Character colors are overlaid on the color from the color mode. To color the unset pixels, you must fill the bitmap area first.