#include #include #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; }