/BitmapPlusPlus

Simple and Fast single header Bitmap (BMP) C++ library

Primary LanguageC++MIT LicenseMIT

Bitmap Plus Plus

Simple and Fast header only Bitmap (BMP) library

Bitmap Type Supported

  • 24 Bits Per Pixel (RGB)

Examples

Random Pixel Colors

#include "BitmapPlusPlus.hpp"
#include <random>
#include <iostream>

static bmp::Pixel random_color() {
  static std::random_device seed{};
  static std::default_random_engine engine{seed()};
  std::uniform_int_distribution<std::int32_t> dist(0, 255);
  bmp::Pixel color{};
  color.r = dist(engine);
  color.g = dist(engine);
  color.b = dist(engine);
  return color;
}

int main(void) {
  try {
    // Create a 512x512 bitmap
    bmp::Bitmap image(512, 512);

    // Assign a random color to each pixel in the image
    for (bmp::Pixel &pixel: image) {
      pixel = random_color();
    }

    // Save bitmap to new file image.bmp
    image.save("image.bmp");

    // And Voila!
    return EXIT_SUCCESS;
  }
  catch (const bmp::Exception &e) {
    std::cerr << "[BMP ERROR]: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
}

random

Draw Primitives

#include <iostream>
#include "BitmapPlusPlus.hpp"

using namespace bmp;

int main() {
  // Create a 512x240 blank image
  Bitmap image(512, 240);
  image.clear(Pixel(0x25292e));

  /** Line **/
  // Draw a yellow line from position (250, 50) to position (500, 50)
  image.draw_line(250, 50, 500, 50, Yellow);

  /** Rectangle **/
  // Draw a red rectangle in position (10, 10) with size 100x100
  image.draw_rect(10, 10, 100, 100, Red);
  // Draw a white filled rectangle in position (120, 10) with size 100x100
  image.fill_rect(120, 10, 100, 100, White);

  /** Triangle **/
  image.draw_triangle(60, 120, 10, 220, 120, 220, Cyan);
  image.fill_triangle(180, 120, 130, 220, 245, 220, Magenta);

  /** Circle **/
  // Draw a non-filled Gray circle in position (300, 170) with 50 pixels radius
  image.draw_circle(300, 170, 50, Gray);
  // Draw a filled Lime circle in position (300, 170) with 50 pixels radius
  image.fill_circle(420, 170, 50, Lime);

  // Save bitmap
  image.save("primitives.bmp");

  return EXIT_SUCCESS;
}

primitives



Mandelbrot Fractal Set

#include "BitmapPlusPlus.hpp"
#include "color_maps.inl"
#include <cmath>

int main(void) {
  bmp::Bitmap image(1280, 960);

  double cr, ci;
  double nextr, nexti;
  double prevr, previ;
  constexpr const std::uint16_t max_iterations = 3000;

  for (std::int32_t y = 0; y < image.height(); ++y) {
    for (std::int32_t x = 0; x < image.width(); ++x) {
      cr = 1.5 * (2.0 * x / image.width() - 1.0) - 0.5;
      ci = (2.0 * y / image.height() - 1.0);

      nextr = nexti = 0;
      prevr = previ = 0;

      for (std::uint16_t i = 0; i < max_iterations; ++i) {
        prevr = nextr;
        previ = nexti;

        nextr = prevr * prevr - previ * previ + cr;
        nexti = 2 * prevr * previ + ci;

        if (((nextr * nextr) + (nexti * nexti)) > 4) {
          const double z = sqrt(nextr * nextr + nexti * nexti);

          // https://en.wikipedia.org/wiki/Mandelbrot_set#Continuous_.28smooth.29_coloring
          const std::uint32_t index = static_cast<std::uint32_t>(1000.0 * log2(1.75 + i - log2(log2(z))) /
                                                                 log2(max_iterations));

          image.set(x, y, jet_colormap[index]);

          break;
        }
      }
    }
  }

  image.save("mandelbrot.bmp");

  return EXIT_SUCCESS;
}

mandelbrot



Julia Fractal Set

#include "BitmapPlusPlus.hpp"
#include "color_maps.inl"

int main(void) {
  bmp::Bitmap image(1280, 960);

  constexpr const std::uint16_t max_iterations = 300;

  constexpr const double cr = -0.70000;
  constexpr const double ci = 0.27015;

  double prevr, previ;

  for (std::int32_t y = 0; y < image.height(); ++y) {
    for (std::int32_t x = 0; x < image.width(); ++x) {
      double nextr = 1.5 * (2.0 * x / image.width() - 1.0);
      double nexti = (2.0 * y / image.height() - 1.0);

      for (std::uint16_t i = 0; i < max_iterations; ++i) {
        prevr = nextr;
        previ = nexti;

        nextr = prevr * prevr - previ * previ + cr;
        nexti = 2 * prevr * previ + ci;

        if (((nextr * nextr) + (nexti * nexti)) > 4) {
          const bmp::Pixel color = hsv_colormap[static_cast<std::size_t>((1000.0 * i) / max_iterations)];
          image.set(x, y, color);
          break;
        }
      }
    }
  }

  image.save("julia.bmp");

  return EXIT_SUCCESS;
}

julia



Modify The Penguin

#include "BitmapPlusPlus.hpp"

int main(void) {
  try {
    bmp::Bitmap image;

    // Load penguin.bmp bitmap
    image.load("penguin.bmp");

    // Modify loaded image (makes half of the image black)
    for (std::int32_t y = 0; y < image.height(); ++y) {
      for (std::int32_t x = 0; x < image.width() / 2; ++x) {
        image.set(x, y, bmp::Black);
      }
    }

    // Save
    image.save("modified-penguin.bmp");

    return EXIT_SUCCESS;
  }
  catch (const bmp::Exception &e) {
    return EXIT_FAILURE;
  }
}

penguin modified-penguin



Chess Board

#include <iostream>
#include "BitmapPlusPlus.hpp"

int main() {
  try {
    // 8x8 chess board
    bmp::Bitmap image(640, 640);
    const std::size_t board_dims = 8;
    const std::size_t rect_w = image.width() / board_dims;
    const std::size_t rect_h = image.height() / board_dims;

    // Iterate over rects
    bool is_white = true;
    for (std::size_t x = 0; x < image.width(); x += rect_w) {
      for (std::size_t y = 0; y < image.height(); y += rect_h) {
        bmp::Pixel color = is_white ? bmp::White : bmp::Black;
        // Fill rect
        image.fill_rect(x, y, rect_w, rect_h, color);
        // Next rect in will be the opposite color
        is_white = !is_white;
      }
      is_white = !is_white;
    }

    // Save bitmap to file
    image.save("chess_board.bmp");

    return EXIT_SUCCESS;
  }
  catch (const bmp::Exception &e) {
    std::cerr << "[BMP ERROR]: " << e.what() << '\n';
    return EXIT_FAILURE;
  }
}

chess_board



Draw multiple shapes using Polymorphism

#include <iostream>
#include "BitmapPlusPlus.hpp"

struct Shape {
  int x, y;
  bmp::Pixel color;

  Shape(int x, int y, bmp::Pixel color) : x(x), y(y), color(color) {}

  virtual void draw(bmp::Bitmap &image) = 0;
};

struct Rectangle : Shape {
  int width, height;

  Rectangle(int x, int y, int w, int h, bmp::Pixel color) : width(w), height(h), Shape(x, y, color) {}

  void draw(bmp::Bitmap &image) override {
    image.fill_rect(x, y, width, height, color);
  }
};

struct Triangle : Shape {
  int x2, y2, x3, y3;

  Triangle(int x1, int y1, int x2, int y2, int x3, int y3, bmp::Pixel color) : x2(x2), y2(y2), x3(x3), y3(y3),
                                                                               Shape(x1, y1, color) {}

  void draw(bmp::Bitmap &image) override {
    image.fill_triangle(x, y, x2, y2, x3, y3, color);
  }
};

struct Circle : Shape {
  int radius;

  Circle(int x, int y, int radius, bmp::Pixel color) : radius(radius), Shape(x, y, color) {}

  void draw(bmp::Bitmap &image) override {
    image.fill_circle(x, y, radius, color);
  }
};

int main() {
  try {
    bmp::Bitmap image(640, 256);
    bmp::Pixel background_color{bmp::Silver};
    image.clear(background_color);

    std::vector<Shape *> shapes
      {
        new Rectangle(20, 20, 180, 180, bmp::Pixel(0xa31d3a)),
        new Triangle(310, 20, 230, 200, 400, 200, bmp::Pixel(0x1a5096)),
        new Circle(500, 110, 90, bmp::Pixel(0x228035))
      };

    for (Shape *shape: shapes) {
      shape->draw(image);
      delete shape;
    }
    image.save("shapes.bmp");

    return EXIT_SUCCESS;
  }
  catch (const bmp::Exception &e) {
    std::cerr << "[BMP ERROR]: " << e.what() << '\n';
    return EXIT_FAILURE;
  }
}

shapes

Features and bugs

If you face any problems feel free to open an issue at the issue tracker. If you feel the library is missing a feature, please raise a ticket on Github. Pull request are also welcome.