save-bmp.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #ifndef _CRT_SECURE_NO_WARNINGS
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #include "save-bmp.h"
  5. #include <cstdio>
  6. #ifdef MSDFGEN_USE_CPP11
  7. #include <cstdint>
  8. #else
  9. namespace msdfgen {
  10. typedef int int32_t;
  11. typedef unsigned uint32_t;
  12. typedef unsigned short uint16_t;
  13. }
  14. #endif
  15. #include "pixel-conversion.hpp"
  16. namespace msdfgen {
  17. static const byte BMP_LINEAR_COLOR_SPACE_SPECIFICATION[48] = {
  18. 0xf8, 0xc2, 0x64, 0x1a, 0x08, 0x3d, 0x9b, 0x0d, 0x11, 0x36, 0x3c, 0x01,
  19. 0x1c, 0xeb, 0xe2, 0x16, 0x39, 0xd6, 0xc5, 0x2d, 0x09, 0xf9, 0xa0, 0x07,
  20. 0xdf, 0x4f, 0x8d, 0x0b, 0xc0, 0xec, 0x9e, 0x04, 0xf4, 0xfd, 0xd4, 0x3c,
  21. 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
  22. };
  23. template <typename T>
  24. bool writeLE(FILE *file, T value);
  25. template <>
  26. bool writeLE(FILE *f, uint16_t value) {
  27. byte bytes[2] = { byte(value), byte(value>>8) };
  28. return fwrite(bytes, 1, 2, f) == 2;
  29. }
  30. template <>
  31. bool writeLE(FILE *f, uint32_t value) {
  32. byte bytes[4] = { byte(value), byte(value>>8), byte(value>>16), byte(value>>24) };
  33. return fwrite(bytes, 1, 4, f) == 4;
  34. }
  35. template <>
  36. bool writeLE(FILE *f, int32_t value) {
  37. byte bytes[4] = { byte(value), byte(value>>8), byte(value>>16), byte(value>>24) };
  38. return fwrite(bytes, 1, 4, f) == 4;
  39. }
  40. static bool writeBmpHeader(FILE *file, int bytesPerPixel, int width, int height, int &paddedWidth) {
  41. paddedWidth = (bytesPerPixel*width+3)&~3; // Ceil to multiple of 4 bytes
  42. uint32_t colorTableEntries = bytesPerPixel == 1 ? 256 : 0;
  43. uint32_t bitmapStart = 14+108+4*colorTableEntries;
  44. uint32_t bitmapSize = paddedWidth*height;
  45. uint32_t fileSize = bitmapStart+bitmapSize;
  46. // BMP file header
  47. writeLE<uint16_t>(file, 0x4d42u); // "BM"
  48. writeLE<uint32_t>(file, fileSize);
  49. writeLE<uint16_t>(file, 0);
  50. writeLE<uint16_t>(file, 0);
  51. writeLE<uint32_t>(file, bitmapStart);
  52. // DIB header (BITMAPV4HEADER)
  53. writeLE<uint32_t>(file, 108);
  54. writeLE<int32_t>(file, width);
  55. writeLE<int32_t>(file, height);
  56. writeLE<uint16_t>(file, 1); // planes
  57. writeLE<uint16_t>(file, uint16_t(8*bytesPerPixel));
  58. writeLE<uint32_t>(file, bytesPerPixel == 4 ? 3 : 0); // 0 = BI_RGB, 3 = BI_BITFIELDS
  59. writeLE<uint32_t>(file, bitmapSize);
  60. writeLE<uint32_t>(file, 2835); // 72 dpi as pixels/meter
  61. writeLE<uint32_t>(file, 2835);
  62. writeLE<uint32_t>(file, colorTableEntries);
  63. writeLE<uint32_t>(file, colorTableEntries);
  64. writeLE<uint32_t>(file, 0x00ff0000u); // Red channel bit mask
  65. writeLE<uint32_t>(file, 0x0000ff00u); // Green channel bit mask
  66. writeLE<uint32_t>(file, 0x000000ffu); // Blue channel bit mask
  67. writeLE<uint32_t>(file, bytesPerPixel == 4 ? 0xff000000u : 0u); // Alpha channel bit mask
  68. writeLE<uint32_t>(file, 0); // LCS_CALIBRATED_RGB
  69. fwrite(BMP_LINEAR_COLOR_SPACE_SPECIFICATION, 1, 48, file);
  70. // Use indexed color for single channel - color table just lists grayscale colors (#000000, #010101, ... #FFFFFF)
  71. if (bytesPerPixel == 1) {
  72. for (uint32_t grayColor = 0; grayColor < 0x01000000u; grayColor += 0x00010101u)
  73. writeLE<uint32_t>(file, grayColor|0xff000000u);
  74. }
  75. return true;
  76. }
  77. bool saveBmp(BitmapConstSection<byte, 1> bitmap, const char *filename) {
  78. FILE *file = fopen(filename, "wb");
  79. if (!file)
  80. return false;
  81. int paddedWidth;
  82. bitmap.reorient(Y_UPWARD);
  83. writeBmpHeader(file, 1, bitmap.width, bitmap.height, paddedWidth);
  84. byte padding[4] = { };
  85. int padLength = paddedWidth-bitmap.width;
  86. for (int y = 0; y < bitmap.height; ++y) {
  87. fwrite(bitmap(0, y), sizeof(byte), bitmap.width, file);
  88. fwrite(padding, 1, padLength, file);
  89. }
  90. return !fclose(file);
  91. }
  92. bool saveBmp(BitmapConstSection<byte, 3> bitmap, const char *filename) {
  93. FILE *file = fopen(filename, "wb");
  94. if (!file)
  95. return false;
  96. int paddedWidth;
  97. bitmap.reorient(Y_UPWARD);
  98. writeBmpHeader(file, 3, bitmap.width, bitmap.height, paddedWidth);
  99. byte padding[4] = { };
  100. int padLength = paddedWidth-3*bitmap.width;
  101. for (int y = 0; y < bitmap.height; ++y) {
  102. for (int x = 0; x < bitmap.width; ++x) {
  103. byte bgr[3] = {
  104. bitmap(x, y)[2],
  105. bitmap(x, y)[1],
  106. bitmap(x, y)[0]
  107. };
  108. fwrite(bgr, sizeof(byte), 3, file);
  109. }
  110. fwrite(padding, 1, padLength, file);
  111. }
  112. return !fclose(file);
  113. }
  114. bool saveBmp(BitmapConstSection<byte, 4> bitmap, const char *filename) {
  115. FILE *file = fopen(filename, "wb");
  116. if (!file)
  117. return false;
  118. int dummyPaddedWidth;
  119. bitmap.reorient(Y_UPWARD);
  120. writeBmpHeader(file, 4, bitmap.width, bitmap.height, dummyPaddedWidth);
  121. for (int y = 0; y < bitmap.height; ++y) {
  122. for (int x = 0; x < bitmap.width; ++x) {
  123. byte bgra[4] = {
  124. bitmap(x, y)[2],
  125. bitmap(x, y)[1],
  126. bitmap(x, y)[0],
  127. bitmap(x, y)[3]
  128. };
  129. fwrite(bgra, sizeof(byte), 4, file);
  130. }
  131. }
  132. return !fclose(file);
  133. }
  134. bool saveBmp(BitmapConstSection<float, 1> bitmap, const char *filename) {
  135. FILE *file = fopen(filename, "wb");
  136. if (!file)
  137. return false;
  138. int paddedWidth;
  139. bitmap.reorient(Y_UPWARD);
  140. writeBmpHeader(file, 1, bitmap.width, bitmap.height, paddedWidth);
  141. byte padding[4] = { };
  142. int padLength = paddedWidth-bitmap.width;
  143. for (int y = 0; y < bitmap.height; ++y) {
  144. for (int x = 0; x < bitmap.width; ++x) {
  145. byte px = pixelFloatToByte(*bitmap(x, y));
  146. fwrite(&px, sizeof(byte), 1, file);
  147. }
  148. fwrite(padding, 1, padLength, file);
  149. }
  150. return !fclose(file);
  151. }
  152. bool saveBmp(BitmapConstSection<float, 3> bitmap, const char *filename) {
  153. FILE *file = fopen(filename, "wb");
  154. if (!file)
  155. return false;
  156. int paddedWidth;
  157. bitmap.reorient(Y_UPWARD);
  158. writeBmpHeader(file, 3, bitmap.width, bitmap.height, paddedWidth);
  159. byte padding[4] = { };
  160. int padLength = paddedWidth-3*bitmap.width;
  161. for (int y = 0; y < bitmap.height; ++y) {
  162. for (int x = 0; x < bitmap.width; ++x) {
  163. byte bgr[3] = {
  164. pixelFloatToByte(bitmap(x, y)[2]),
  165. pixelFloatToByte(bitmap(x, y)[1]),
  166. pixelFloatToByte(bitmap(x, y)[0])
  167. };
  168. fwrite(bgr, sizeof(byte), 3, file);
  169. }
  170. fwrite(padding, 1, padLength, file);
  171. }
  172. return !fclose(file);
  173. }
  174. bool saveBmp(BitmapConstSection<float, 4> bitmap, const char *filename) {
  175. FILE *file = fopen(filename, "wb");
  176. if (!file)
  177. return false;
  178. int dummyPaddedWidth;
  179. bitmap.reorient(Y_UPWARD);
  180. writeBmpHeader(file, 4, bitmap.width, bitmap.height, dummyPaddedWidth);
  181. for (int y = 0; y < bitmap.height; ++y) {
  182. for (int x = 0; x < bitmap.width; ++x) {
  183. byte bgra[4] = {
  184. pixelFloatToByte(bitmap(x, y)[2]),
  185. pixelFloatToByte(bitmap(x, y)[1]),
  186. pixelFloatToByte(bitmap(x, y)[0]),
  187. pixelFloatToByte(bitmap(x, y)[3])
  188. };
  189. fwrite(bgra, sizeof(byte), 4, file);
  190. }
  191. }
  192. return !fclose(file);
  193. }
  194. }