summaryrefslogtreecommitdiff
path: root/bmp.cpp
blob: 329049c86750d8e1923d17f284048525ae36ef92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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;
}