Added simple bitmap interface
commit
46248d5ee6
|
@ -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");
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
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
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue