From 46248d5ee65b42a9b616a736e98bef57a5a042d6 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 Jun 2022 11:21:26 -0700 Subject: [PATCH] Added simple bitmap interface --- src/bitmap/bitmap.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++ src/bitmap/bitmap.hpp | 47 +++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 src/bitmap/bitmap.cpp create mode 100644 src/bitmap/bitmap.hpp diff --git a/src/bitmap/bitmap.cpp b/src/bitmap/bitmap.cpp new file mode 100644 index 0000000..7eab19b --- /dev/null +++ b/src/bitmap/bitmap.cpp @@ -0,0 +1,133 @@ +#include "bitmap.hpp" + +Bitmap::Bitmap(size_t w, size_t h) { + this->width = w; + this->height = h; + + this->data.reserve(h); + for (size_t r = 0; r < h; r++) { + data[r].reserve(w); + } + + clear(); +} + + + +void Bitmap::dump_int_to_bytes( + uint64_t a, + uint8_t *array, + size_t index, + size_t num_bytes + ) { + // Dump bytes of i into array starting at index. + // least-significant byte goes first. + + if (num_bytes > 4) { + throw std::invalid_argument("Cannot dump more than 4 bytes."); + } + + for (size_t i = 0; i < num_bytes; i++) { + array[index + i] = (a >> (8 * i)) & 0xFF; + } +} + + + +void Bitmap::clear() { + // Fill with white pixels + for (size_t r = 0; r < height; r++) { + for (size_t i = 0; i < width; i++) { + data[r][i] = std::make_tuple( + 0xFF, 0xFF, 0xFF + ); + } + } +} + + + +void Bitmap::setpixel( + size_t row, + size_t col, + uint8_t r, + uint8_t g, + uint8_t b + ) { + data[row][col] = std::make_tuple(r, g, b); +} + + + +void Bitmap::save(const char *filename) const { + + uint8_t header[54] = { + // Universal 14-byte header + 0x42, 0x4D, // Bitmap standard header + 0x00, 0x00, 0x00, 0x00, // file size (bit 2, overwritten) + 0x00, 0x00, 0x00, 0x00, // Reserved (leave as zero) + 0x36, 0x00, 0x00, 0x00, // Index of first byte of pixmap + + // 40-byte BITMAPINFOHEADER + 0x28, 0x00, 0x00, 0x00, // Length of DIB + 0x00, 0x00, 0x00, 0x00, // width (px, bit 18, overwritten) + 0x00, 0x00, 0x00, 0x00, // height (px, bit 22, overwritten) + 0x01, 0x00, // Number of color planes (always 1) + 0x18, 0x00, // Number of bits per pixel (0x18 = 24) + 0x00, 0x00, 0x00, 0x00, // BI_RGB, no pixel array compression + 0x00, 0x00, 0x00, 0x00, // Size of raw bitmap data, incl. padding (bit 34, overwritten) + 0xFF, 0x0A, 0x00, 0x00, // Size of horizontal print resolution (px/m) + 0xFF, 0x0A, 0x00, 0x00, // Size of vertical print resolution (px/m) + 0x00, 0x00, 0x00, 0x00, // Size of colors in palette + 0x00, 0x00, 0x00, 0x00 // 0 important colors => all colors are important + }; + + + // How many bytes we need to store a row, including padding + size_t row_size = ((24 * width + 31) / 32) * 4; + // Total size of pixmap + uint64_t pixmap_size = row_size * height; + // Total size of file + uint64_t file_size = 54 + pixmap_size; + + // Set values in header + dump_int_to_bytes(file_size, header, 2, 4); + dump_int_to_bytes(width, header, 18, 4); + dump_int_to_bytes(height, header, 22, 4); + dump_int_to_bytes(pixmap_size, header, 34, 4); + + + FILE *fp = fopen(filename, "wb"); + fwrite(header, sizeof(header), 1, fp); + + uint8_t r, g, b; + for (size_t row = 0; row < height; row++) { + size_t i = 0; + + // Pixel data + while (i < width) { + std::tie(r, g, b) = data[height - row - 1][i]; + fwrite(&b, sizeof(uint8_t), 1, fp); + fwrite(&g, sizeof(uint8_t), 1, fp); + fwrite(&r, sizeof(uint8_t), 1, fp); + + i += 1; + } + + i *= 3; + // Row Padding + r = 0; + while (i < row_size) { + fwrite(&r, sizeof(uint8_t), 1, fp); + i += 1; + } + } + fclose(fp); +} + +/* +int main() { + Bitmap b = Bitmap(200, 200); + b.save("file.bmp"); +} +*/ \ No newline at end of file diff --git a/src/bitmap/bitmap.hpp b/src/bitmap/bitmap.hpp new file mode 100644 index 0000000..00fe569 --- /dev/null +++ b/src/bitmap/bitmap.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +class Bitmap { + public: + Bitmap(size_t w, size_t h); + + + void clear(); + void setpixel( + size_t row, + size_t col, + uint8_t r, + uint8_t g, + uint8_t b + ); + + void save(const char *filename) const; + + private: + size_t width; + size_t height; + + // Pixel data. + // First is a vector of rows, + // Second is a vector of pixels. + // RGB format. + std::vector< + std::vector< + std::tuple< + uint8_t, + uint8_t, + uint8_t + >> + > data; + + static void dump_int_to_bytes( + uint64_t a, + uint8_t* bytes, + size_t index, + size_t num_bytes + ); +}; \ No newline at end of file