Bmp.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*************************************************************************
  2. file created on: 2002/08/30 19:33
  3. filename: Bmp.c
  4. author: Andreas Hartl<andy@runicsoft.com>
  5. visit http://www.runicsoft.com for updates and more information
  6. purpose: functions to load raw bmp data,
  7. to save raw bmp data,
  8. to convert RGB data to raw bmp data,
  9. to convert raw bmp data to RGB data
  10. and to use the WinAPI to select
  11. a bitmap into a device context
  12. The code in this file is subject to the RunicSoft source code licence
  13. ( http://www.runicsoft.com/sourcelicence.txt )
  14. **************************************************************************/
  15. #include <stdio.h> // for memset
  16. #include "3d_all.h"
  17. /*******************************************************************
  18. char* ConvertRGBToBMPBuffer ( char* Buffer, int width,
  19. int height, long* newsize )
  20. This function takes as input an array of RGB values, it's width
  21. and height.
  22. The buffer gets then transformed to an array that can be used
  23. to write to a windows bitmap file. The size of the array
  24. is returned in newsize, the array itself is the
  25. return value of the function.
  26. Both input and output buffers must be deleted by the
  27. calling function.
  28. The input buffer is expected to consist of width * height
  29. RGB triplets. Thus the total size of the buffer is taken as
  30. width * height * 3.
  31. The function then transforms this buffer so that it can be written
  32. to a windows bitmap file:
  33. First the RGB triplets are converted to BGR.
  34. Then the buffer is swapped around since .bmps store
  35. images uside-down.
  36. Finally the buffer gets DWORD ( 32bit ) aligned,
  37. meaning that each scanline ( 3 * width chars ) gets
  38. padded with 0x00 chars up to the next DWORD boundary
  39. *******************************************************************/
  40. byte *ConvertRGBToBMPBuffer(byte * Buffer, int width, int height,
  41. int *newsize)
  42. {
  43. int padding = 0;
  44. int scanlinebytes = width * 3;
  45. int psw;
  46. long bufpos = 0;
  47. long newpos = 0;
  48. byte *newbuf;
  49. int x, y;
  50. // first make sure the parameters are valid
  51. if ((NULL == Buffer) || (width == 0) || (height == 0))
  52. return NULL;
  53. // now we have to find with how many bytes
  54. // we have to pad for the next DWORD boundary
  55. while ((scanlinebytes + padding) % 4 != 0) // DWORD = 4 bytes
  56. padding++;
  57. // get the padded scanline width
  58. psw = scanlinebytes + padding;
  59. // we can already store the size of the new padded buffer
  60. *newsize = height * psw;
  61. // and create new buffer
  62. newbuf = (byte *) malloc(sizeof(byte) * (*newsize));
  63. // fill the buffer with zero bytes then we dont have to add
  64. // extra padding zero bytes later on
  65. memset(newbuf, 0, *newsize);
  66. // now we loop trough all bytes of the original buffer,
  67. // swap the R and B bytes and the scanlines
  68. for (y = 0; y < height; y++)
  69. for (x = 0; x < 3 * width; x += 3) {
  70. bufpos = y * 3 * width + x; // position in original buffer
  71. newpos = y * psw + x; // position in padded buffer
  72. newbuf[newpos] = Buffer[bufpos]; // swap r and b
  73. newbuf[newpos + 1] = Buffer[bufpos + 1]; // g stays
  74. newbuf[newpos + 2] = Buffer[bufpos + 2]; // swap b and r
  75. }
  76. return newbuf;
  77. }
  78. /***************************************************************
  79. byte* ConvertBMPToRGBBuffer ( byte* Buffer,
  80. int width, int height )
  81. This function takes as input the data array
  82. from a bitmap and its width and height.
  83. It then converts the bmp data into an RGB array.
  84. The calling function must delete both the input
  85. and output arrays.
  86. The size of the returned array will be
  87. width * height * 3
  88. On error the returb value is NULL, else the
  89. RGB array.
  90. The Buffer is expected to be the exact data read out
  91. from a .bmp file.
  92. The function will swap it around, since images
  93. are stored upside-down in bmps.
  94. The BGR triplets from the image data will
  95. be converted to RGB.
  96. And finally the function removes padding bytes.
  97. The returned arraay consits then of
  98. width * height RGB triplets.
  99. *****************************************************************/
  100. byte *ConvertBMPToRGBBuffer(byte * Buffer, int width, int height)
  101. {
  102. int padding = 0;
  103. int scanlinebytes = width * 3;
  104. int psw;
  105. byte *newbuf;
  106. byte *p_p1, *p_p2;
  107. int x, y;
  108. // first make sure the parameters are valid
  109. if ((NULL == Buffer) || (width == 0) || (height == 0))
  110. return NULL;
  111. // find the number of padding bytes
  112. while ((scanlinebytes + padding) % 4 != 0) // DWORD = 4 bytes
  113. padding++;
  114. // get the padded scanline width
  115. psw = scanlinebytes + padding;
  116. // create new buffer
  117. newbuf = (byte *) malloc(sizeof(byte) * width * height * 3);
  118. for (y = 0; y < height; y++) {
  119. p_p1 = newbuf + y * scanlinebytes;
  120. p_p2 = Buffer + y * psw;
  121. for (x = 0; x < width; x++, p_p1 += 3, p_p2 += 3) {
  122. p_p1[0] = p_p2[0];
  123. p_p1[1] = p_p2[1];
  124. p_p1[2] = p_p2[2];
  125. }
  126. }
  127. return newbuf;
  128. }
  129. /***************************************************************
  130. int SaveBMP ( byte* Buffer, int width, int height,
  131. long paddedsize, char* bmpfile )
  132. Function takes a buffer of size <paddedsize>
  133. and saves it as a <width> * <height> sized bitmap
  134. under the supplied filename.
  135. On error the return value is FALSE.
  136. ***************************************************************/
  137. int SaveBMP(FILE * file, byte * Buffer, int width, int height, int paddedsize)
  138. {
  139. // declare bmp structures
  140. BITMAPFILEHEADER bmfh;
  141. BITMAPINFOHEADER info;
  142. // andinitialize them to zero
  143. memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
  144. memset(&info, 0, sizeof(BITMAPINFOHEADER));
  145. // fill the fileheader with data
  146. bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
  147. bmfh.bfReserved1 = 0;
  148. bmfh.bfReserved2 = 0;
  149. bmfh.bfSize =
  150. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + paddedsize;
  151. bmfh.bfOffBits = 0x36; // number of bytes to start of bitmap bits
  152. // fill the infoheader
  153. info.biSize = sizeof(BITMAPINFOHEADER);
  154. info.biWidth = width;
  155. info.biHeight = height;
  156. info.biPlanes = 1; // we only have one bitplane
  157. info.biBitCount = 24; // RGB mode is 24 bits
  158. info.biCompression = BI_RGB;
  159. info.biSizeImage = 0; // can be 0 for 24 bit images
  160. info.biXPelsPerMeter = 0x0ec4; // paint and PSP use this values
  161. info.biYPelsPerMeter = 0x0ec4;
  162. info.biClrUsed = 0; // we are in RGB mode and have no palette
  163. info.biClrImportant = 0; // all colors are important
  164. // write file header
  165. if (!fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, file)) {
  166. return FALSE;
  167. }
  168. // write infoheader
  169. if (!fwrite(&info, sizeof(BITMAPINFOHEADER), 1, file)) {
  170. return FALSE;
  171. }
  172. // write image data
  173. if (!fwrite(Buffer, paddedsize, 1, file)) {
  174. return FALSE;
  175. }
  176. return TRUE;
  177. }
  178. /*******************************************************************
  179. byte* LoadBMP ( int* width, int* height, long* size
  180. char* bmpfile )
  181. The function loads a 24 bit bitmap from bmpfile,
  182. stores it's width and height in the supplied variables
  183. and the whole size of the data (padded) in <size>
  184. and returns a buffer of the image data
  185. On error the return value is NULL.
  186. NOTE: make sure you [] delete the returned array at end of
  187. program!!!
  188. *******************************************************************/
  189. byte *LoadBMP(KFILE * file, int *width, int *height, int *size)
  190. {
  191. // declare bitmap structures
  192. BITMAPFILEHEADER bmpheader;
  193. BITMAPINFOHEADER bmpinfo;
  194. byte *Buffer;
  195. kread(&bmpheader, sizeof(BITMAPFILEHEADER), 1, file);
  196. kread(&bmpinfo, sizeof(BITMAPINFOHEADER), 1, file);
  197. // check if file is actually a bmp
  198. if (bmpheader.bfType != 'MB') {
  199. return (NULL);
  200. }
  201. // get image measurements
  202. *width = bmpinfo.biWidth;
  203. *height = abs(bmpinfo.biHeight);
  204. // check if bmp is uncompressed
  205. if (bmpinfo.biCompression != BI_RGB) {
  206. return (NULL);
  207. }
  208. // check if we have 24 bit bmp
  209. if (bmpinfo.biBitCount != 24) {
  210. return (NULL);
  211. }
  212. // create buffer to hold the data
  213. *size = bmpheader.bfSize - bmpheader.bfOffBits;
  214. Buffer = (byte *) mmalloc(sizeof(byte) * (*size));
  215. // move file pointer to start of bitmap data
  216. //aseek(1,file, start+bmpheader.bfOffBits, SEEK_SET);
  217. // read bmp data
  218. if (!kread(Buffer, *size, 1, file)) {
  219. free(Buffer);
  220. return (NULL);
  221. }
  222. // everything successful here: close file and return buffer
  223. return (Buffer);
  224. }