summaryrefslogtreecommitdiff
path: root/bmp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bmp.cpp')
-rw-r--r--bmp.cpp68
1 files changed, 68 insertions, 0 deletions
diff --git a/bmp.cpp b/bmp.cpp
new file mode 100644
index 0000000..329049c
--- /dev/null
+++ b/bmp.cpp
@@ -0,0 +1,68 @@
+#include <cstdio>
+#include <cassert>
+#include "bmp.h"
+
+
+int64_t bmp_rgb_encoded_size(int width, int height) {
+ return 54 + (3 * (int64_t)width + 3) / 4 * 4 * (int64_t)height;
+}
+
+static void write_le32(uint8_t *dst, uint32_t value) {
+ dst[0] = value & 0xff;
+ dst[1] = (value >> 8) & 0xff;
+ dst[2] = (value >> 16) & 0xff;
+ dst[3] = value >> 24;
+}
+
+static void write_le16(uint8_t *dst, uint16_t value) {
+ dst[0] = value & 0xff;
+ dst[1] = value >> 8;
+}
+
+void bmp_rgb_encode_memory(uint8_t *dst, const uint8_t *src, int width, int height) {
+ const int64_t size = bmp_rgb_encoded_size(width, height);
+ const int padding = (4 - 3 * width % 4) % 4;
+ dst[0] = 'B';
+ dst[1] = 'M';
+ write_le32(&dst[2], size);
+ dst[6] = dst[7] = dst[8] = dst[9] = 0;
+ write_le32(&dst[10], 54);
+ write_le32(&dst[14], 40); // this is a BITMAPINFOHEADER
+ write_le32(&dst[18], width);
+ write_le32(&dst[22], height);
+ write_le16(&dst[26], 1);
+ write_le16(&dst[28], 24);
+ write_le32(&dst[30], 0);
+ write_le32(&dst[34], size - 54);
+ write_le32(&dst[38], 0); // pixels/metre; imagemagick sets this to 0
+ write_le32(&dst[42], 0); // and if they can, we can
+ write_le32(&dst[46], 0);
+ write_le32(&dst[50], 0);
+ int off = 54;
+ for (int y = height - 1; y >= 0; y--) {
+ for (int x = 0; x < width; x++) {
+ dst[off+0] = src[3 * (width * y + x) + 2];
+ dst[off+1] = src[3 * (width * y + x) + 1];
+ dst[off+2] = src[3 * (width * y + x) + 0];
+ off += 3;
+ }
+ for (int i = 0; i < padding; i++) dst[off++] = 0;
+ }
+ assert(off == size);
+}
+
+uint8_t* bmp_rgb_encode_memory_alloc(const uint8_t *src, int width, int height) {
+ const int64_t size = bmp_rgb_encoded_size(width, height);
+ uint8_t *dst = new uint8_t[size];
+ bmp_rgb_encode_memory(dst, src, width, height);
+ return dst;
+}
+
+void bmp_rgb_encode_file(const char *fname, const uint8_t *src, int width, int height) {
+ const int64_t size = bmp_rgb_encoded_size(width, height);
+ uint8_t *data = bmp_rgb_encode_memory_alloc(src, width, height);
+ FILE *f = fopen(fname, "w");
+ fwrite(data, 1, size, f);
+ fclose(f);
+ delete[] data;
+}