Bmp.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "stdafx.h"
  19. #include <stdio.h>
  20. #include <malloc.h>
  21. #include <string.h>
  22. #include "bmp.h"
  23. void Error(char *fmt, ...);
  24. static int GetColorCount(int nbits)
  25. {
  26. int ncolors = 0;
  27. if (nbits < 24)
  28. {
  29. ncolors = 1 << nbits;
  30. }
  31. return(ncolors);
  32. }
  33. static void BMPLineNone(FILE *f, char *sline, int pixbytes, int width)
  34. {
  35. int nbytes, i, k, j;
  36. switch (pixbytes)
  37. {
  38. case 1 :
  39. nbytes = (width + 3) / 4;
  40. nbytes *= 4;
  41. fread(sline, width, 1, f);
  42. nbytes -= width;
  43. while (nbytes-- > 0) fgetc(f);
  44. return;
  45. case 3 :
  46. nbytes = ((width * 3) + 3) / 4;
  47. nbytes *= 4;
  48. fread(sline, width, 3, f);
  49. nbytes -= width * 3;
  50. while (nbytes-- > 0) fgetc(f);
  51. // reorder bgr to rgb
  52. for (i = 0, j = 0; i < width; i++, j += 3)
  53. {
  54. k = sline[j];
  55. sline[j] = sline[j+2];
  56. sline[j+2] = k;
  57. }
  58. return;
  59. }
  60. Error("BMPLineNone failed.");
  61. }
  62. static void BMPLineRLE8(FILE *f, char *sline, int pixbytes, int width)
  63. {
  64. Error("RLE8 not yet supported.");
  65. }
  66. static void BMPLineRLE4(FILE *f, char *sline, int pixbytes, int width)
  67. {
  68. Error("RLE4 not yet supported.");
  69. }
  70. static void BMPLine(FILE *f, char *scanline, int pixbytes, int width, int rle)
  71. {
  72. switch (rle)
  73. {
  74. case xBI_NONE : BMPLineNone(f, scanline, pixbytes, width); return;
  75. case xBI_RLE8 : BMPLineRLE8(f, scanline, pixbytes, width); return;
  76. case xBI_RLE4 : BMPLineRLE4(f, scanline, pixbytes, width); return;
  77. }
  78. Error("Unknown compression type.");
  79. }
  80. static void PrintHeader(binfo_t *b)
  81. {
  82. printf("biSize : %ld\n", b->biSize);
  83. printf("biWidth : %ld\n", b->biWidth);
  84. printf("biHeight : %ld\n", b->biHeight);
  85. printf("biPlanes : %d\n", b->biPlanes);
  86. printf("biBitCount : %d\n", b->biBitCount);
  87. printf("biCompression : %ld\n", b->biCompression);
  88. printf("biSizeImage : %ld\n", b->biSizeImage);
  89. printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter);
  90. printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter);
  91. printf("biClrUsed : %ld\n", b->biClrUsed);
  92. printf("biClrImportant : %ld\n", b->biClrImportant);
  93. }
  94. void LoadBMP(char *filename, bitmap_t *bit)
  95. {
  96. FILE *f;
  97. bmphd_t bhd;
  98. binfo_t info;
  99. int pxlsize = 1;
  100. int rowbytes, i, pixbytes;
  101. char *scanline;
  102. // open file
  103. if ((f = fopen(filename, "rb")) == NULL)
  104. {
  105. Error("Unable to open %s.", filename);
  106. }
  107. // read in bitmap header
  108. if (fread(&bhd, sizeof(bhd), 1, f) != 1)
  109. {
  110. fclose(f);
  111. Error("Unable to read in bitmap header.");
  112. }
  113. // make sure we have a valid bitmap file
  114. if (bhd.bfType != BMP_SIGNATURE_WORD)
  115. {
  116. fclose(f);
  117. Error("Invalid BMP file: %s", filename);
  118. }
  119. // load in info header
  120. if (fread(&info, sizeof(info), 1, f) != 1)
  121. {
  122. fclose(f);
  123. Error("Unable to read bitmap info header.");
  124. }
  125. // make sure this is an info type of bitmap
  126. if (info.biSize != sizeof(binfo_t))
  127. {
  128. fclose(f);
  129. Error("We only support the info bitmap type.");
  130. }
  131. // PrintHeader(&info);
  132. bit->bpp = info.biBitCount;
  133. bit->width = info.biWidth;
  134. bit->height = info.biHeight;
  135. bit->data = NULL;
  136. bit->palette = NULL;
  137. //currently we only read in 8 and 24 bit bmp files
  138. if (info.biBitCount == 8) pixbytes = 1;
  139. else if (info.biBitCount == 24) pixbytes = 3;
  140. else
  141. {
  142. Error("BPP %d not supported.", info.biBitCount);
  143. }
  144. // if this is an eight bit image load palette
  145. if (pixbytes == 1)
  146. {
  147. drgb_t q;
  148. bit->palette = reinterpret_cast<rgb_t*>(malloc(sizeof(rgb_t) * 256));
  149. for (i = 0; i < 256; i++)
  150. {
  151. if (fread(&q, sizeof(drgb_t), 1, f) != 1)
  152. {
  153. fclose(f); free(bit->palette);
  154. Error("Unable to read palette.");
  155. }
  156. bit->palette[i].r = q.red;
  157. bit->palette[i].g = q.green;
  158. bit->palette[i].b = q.blue;
  159. }
  160. }
  161. // position to start of bitmap
  162. fseek(f, bhd.bfOffBits, SEEK_SET);
  163. // create scanline to read data into
  164. rowbytes = ((info.biWidth * pixbytes) + 3) / 4;
  165. rowbytes *= 4;
  166. scanline = reinterpret_cast<char*>(malloc(rowbytes));
  167. // alloc space for new bitmap
  168. bit->data = reinterpret_cast<unsigned char*>(malloc(info.biWidth * pixbytes * info.biHeight));
  169. // read in image
  170. for (i = 0; i < info.biHeight; i++)
  171. {
  172. BMPLine(f, scanline, pixbytes, info.biWidth, info.biCompression);
  173. // store line
  174. memcpy(&bit->data[info.biWidth * pixbytes * (info.biHeight - i - 1)], scanline, info.biWidth * pixbytes);
  175. }
  176. free(scanline);
  177. fclose(f);
  178. }
  179. static void BMPEncodeLine(FILE *f, unsigned char *data, int npxls, int pixbytes)
  180. {
  181. int nbytes, i, j, k;
  182. switch (pixbytes)
  183. {
  184. case 1 :
  185. nbytes = (npxls + 3) / 4;
  186. nbytes *= 4;
  187. fwrite(data, npxls, 1, f);
  188. nbytes -= npxls;
  189. while (nbytes-- > 0) fputc(0, f);
  190. return;
  191. case 3 :
  192. // reorder rgb to bgr
  193. for (i = 0, j = 0; i < npxls; i++, j+= 3)
  194. {
  195. k = data[j];
  196. data[j] = data[j + 2];
  197. data[j + 2] = k;
  198. }
  199. nbytes = ((npxls * 3) + 3) / 4;
  200. nbytes *= 4;
  201. fwrite(data, npxls, 3, f);
  202. nbytes -= npxls * 3;
  203. while (nbytes-- > 0) fputc(0, f);
  204. return;
  205. }
  206. Error("BMPEncodeLine Failed.");
  207. }
  208. void WriteBMP(char *filename, bitmap_t *bit)
  209. {
  210. FILE *f;
  211. bmphd_t header;
  212. binfo_t info;
  213. drgb_t q; // palette that gets written
  214. long bmofs;
  215. int w, h, i;
  216. int pixbytes;
  217. if (bit->bpp == 8) pixbytes = 1;
  218. else if (bit->bpp == 24) pixbytes = 3;
  219. else
  220. {
  221. Error("BPP %d not supported.", bit->bpp);
  222. }
  223. if ((f = fopen(filename, "wb")) == NULL)
  224. {
  225. Error("Unable to open %s.", filename);
  226. }
  227. // write out an empty header as a place holder
  228. if (fwrite(&header, sizeof(header), 1, f) != 1)
  229. {
  230. Error("Unable to fwrite.");
  231. }
  232. // init and write info header
  233. info.biSize = sizeof(binfo_t);
  234. info.biWidth = bit->width;
  235. info.biHeight = bit->height;
  236. info.biPlanes = 1;
  237. info.biBitCount = bit->bpp;
  238. info.biCompression = xBI_NONE;
  239. info.biSizeImage = bit->width * bit->height;
  240. info.biXPelsPerMeter = 0;
  241. info.biYPelsPerMeter = 0;
  242. info.biClrUsed = 256;
  243. info.biClrImportant = 256;
  244. if (fwrite(&info, sizeof(binfo_t), 1, f) != 1)
  245. {
  246. Error("fwrite failed.");
  247. }
  248. // write out palette if we need to
  249. if (bit->bpp == 8)
  250. {
  251. for (i = 0; i < 256; i++)
  252. {
  253. q.red = bit->palette[i].r;
  254. q.green = bit->palette[i].g;
  255. q.blue = bit->palette[i].b;
  256. fwrite(&q, sizeof(q), 1, f);
  257. }
  258. }
  259. // save offset to start of bitmap
  260. bmofs = ftell(f);
  261. // output bitmap
  262. w = bit->width;
  263. h = bit->height;
  264. for (i = h - 1; i >= 0; i--)
  265. {
  266. BMPEncodeLine(f, &bit->data[w * pixbytes * i], w, pixbytes);
  267. }
  268. // update and rewrite file header
  269. header.bfType = BMP_SIGNATURE_WORD;
  270. header.bfSize = ftell(f);
  271. header.bfOffBits = bmofs;
  272. fseek(f, 0L, SEEK_SET);
  273. fwrite(&header, sizeof(header), 1, f);
  274. fclose(f);
  275. }
  276. void NewBMP(int width, int height, int bpp, bitmap_t *bit)
  277. {
  278. int pixbytes;
  279. if (bpp == 8) pixbytes = 1;
  280. else if (bpp == 24) pixbytes = 3;
  281. else
  282. {
  283. Error("NewBMP: 8 or 24 bit only.");
  284. }
  285. bit->bpp = bpp;
  286. bit->width = width;
  287. bit->height = height;
  288. bit->data = reinterpret_cast<unsigned char*>(malloc(width * height * pixbytes));
  289. if (bit->data == NULL)
  290. {
  291. Error("NewBMP: malloc failed.");
  292. }
  293. // see if we need to create a palette
  294. if (pixbytes == 1)
  295. {
  296. bit->palette = (rgb_t *) malloc(768);
  297. if (bit->palette == NULL)
  298. {
  299. Error("NewBMP: unable to malloc palette.");
  300. }
  301. }
  302. else
  303. {
  304. bit->palette = NULL;
  305. }
  306. }
  307. void FreeBMP(bitmap_t *bitmap)
  308. {
  309. if (bitmap->palette)
  310. {
  311. free(bitmap->palette);
  312. bitmap->palette = NULL;
  313. }
  314. if (bitmap->data)
  315. {
  316. free(bitmap->data);
  317. bitmap->data = NULL;
  318. }
  319. }