| 48 | } |
| 49 | |
| 50 | static bool writeBmpHeader(FILE *file, int bytesPerPixel, int width, int height, int &paddedWidth) { |
| 51 | paddedWidth = (bytesPerPixel*width+3)&~3; // Ceil to multiple of 4 bytes |
| 52 | uint32_t colorTableEntries = bytesPerPixel == 1 ? 256 : 0; |
| 53 | uint32_t bitmapStart = 14+108+4*colorTableEntries; |
| 54 | uint32_t bitmapSize = paddedWidth*height; |
| 55 | uint32_t fileSize = bitmapStart+bitmapSize; |
| 56 | |
| 57 | // BMP file header |
| 58 | writeLE<uint16_t>(file, 0x4d42u); // "BM" |
| 59 | writeLE<uint32_t>(file, fileSize); |
| 60 | writeLE<uint16_t>(file, 0); |
| 61 | writeLE<uint16_t>(file, 0); |
| 62 | writeLE<uint32_t>(file, bitmapStart); |
| 63 | |
| 64 | // DIB header (BITMAPV4HEADER) |
| 65 | writeLE<uint32_t>(file, 108); |
| 66 | writeLE<int32_t>(file, width); |
| 67 | writeLE<int32_t>(file, height); |
| 68 | writeLE<uint16_t>(file, 1); // planes |
| 69 | writeLE<uint16_t>(file, uint16_t(8*bytesPerPixel)); |
| 70 | writeLE<uint32_t>(file, bytesPerPixel == 4 ? 3 : 0); // 0 = BI_RGB, 3 = BI_BITFIELDS |
| 71 | writeLE<uint32_t>(file, bitmapSize); |
| 72 | writeLE<uint32_t>(file, 2835); // 72 dpi as pixels/meter |
| 73 | writeLE<uint32_t>(file, 2835); |
| 74 | writeLE<uint32_t>(file, colorTableEntries); |
| 75 | writeLE<uint32_t>(file, colorTableEntries); |
| 76 | writeLE<uint32_t>(file, 0x00ff0000u); // Red channel bit mask |
| 77 | writeLE<uint32_t>(file, 0x0000ff00u); // Green channel bit mask |
| 78 | writeLE<uint32_t>(file, 0x000000ffu); // Blue channel bit mask |
| 79 | writeLE<uint32_t>(file, bytesPerPixel == 4 ? 0xff000000u : 0u); // Alpha channel bit mask |
| 80 | writeLE<uint32_t>(file, 0); // LCS_CALIBRATED_RGB |
| 81 | fwrite(BMP_LINEAR_COLOR_SPACE_SPECIFICATION, 1, 48, file); |
| 82 | |
| 83 | // Use indexed color for single channel - color table just lists grayscale colors (#000000, #010101, ... #FFFFFF) |
| 84 | if (bytesPerPixel == 1) { |
| 85 | for (uint32_t grayColor = 0; grayColor < 0x01000000u; grayColor += 0x00010101u) |
| 86 | writeLE<uint32_t>(file, grayColor|0xff000000u); |
| 87 | } |
| 88 | |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | bool saveBmp(BitmapConstSection<byte, 1> bitmap, const char *filename) { |
| 93 | FILE *file = fopen(filename, "wb"); |