bmp.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. Copyright (C) 2001-2006, William Joseph.
  3. All Rights Reserved.
  4. This file is part of GtkRadiant.
  5. GtkRadiant is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. GtkRadiant is distributed in the hope that it will be useful,
  10. 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 GtkRadiant; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. #include "bmp.h"
  18. #include "ifilesystem.h"
  19. typedef unsigned char byte;
  20. #include "imagelib.h"
  21. #include "bytestreamutils.h"
  22. typedef unsigned char PaletteEntry[4];
  23. typedef struct
  24. {
  25. char id[2];
  26. unsigned long fileSize;
  27. unsigned long reserved0;
  28. unsigned long bitmapDataOffset;
  29. unsigned long bitmapHeaderSize;
  30. unsigned long width;
  31. unsigned long height;
  32. unsigned short planes;
  33. unsigned short bitsPerPixel;
  34. unsigned long compression;
  35. unsigned long bitmapDataSize;
  36. unsigned long hRes;
  37. unsigned long vRes;
  38. unsigned long colors;
  39. unsigned long importantColors;
  40. PaletteEntry palette[256];
  41. } BMPHeader_t;
  42. class ReadPixel8
  43. {
  44. PaletteEntry* m_palette;
  45. public:
  46. ReadPixel8(PaletteEntry* palette) : m_palette(palette)
  47. {
  48. }
  49. void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
  50. {
  51. byte palIndex;
  52. inputStream.read(&palIndex, 1);
  53. *pixbuf++ = m_palette[palIndex][2];
  54. *pixbuf++ = m_palette[palIndex][1];
  55. *pixbuf++ = m_palette[palIndex][0];
  56. *pixbuf++ = 0xff;
  57. }
  58. };
  59. class ReadPixel16
  60. {
  61. public:
  62. void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
  63. {
  64. unsigned short shortPixel;
  65. inputStream.read(reinterpret_cast<byte*>(&shortPixel), sizeof(unsigned short)); //!\todo Is this endian safe?
  66. *pixbuf++ = static_cast<byte>(shortPixel & (31 << 10)) >> 7;
  67. *pixbuf++ = static_cast<byte>(shortPixel & (31 << 5)) >> 2;
  68. *pixbuf++ = static_cast<byte>(shortPixel & (31)) << 3;
  69. *pixbuf++ = 0xff;
  70. }
  71. };
  72. class ReadPixel24
  73. {
  74. public:
  75. void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
  76. {
  77. byte bgr[3];
  78. inputStream.read(bgr, 3);
  79. *pixbuf++ = bgr[2];
  80. *pixbuf++ = bgr[1];
  81. *pixbuf++ = bgr[0];
  82. *pixbuf++ = 255;
  83. }
  84. };
  85. class ReadPixel32
  86. {
  87. public:
  88. void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
  89. {
  90. byte bgra[4];
  91. inputStream.read(bgra, 4);
  92. *pixbuf++ = bgra[2];
  93. *pixbuf++ = bgra[1];
  94. *pixbuf++ = bgra[0];
  95. *pixbuf++ = bgra[3];
  96. }
  97. };
  98. template<typename ReadPixel>
  99. void ReadBMP(PointerInputStream& inputStream, byte* bmpRGBA, int rows, int columns, ReadPixel readPixel)
  100. {
  101. for (int row = rows - 1; row >= 0; row--)
  102. {
  103. byte* pixbuf = bmpRGBA + row * columns * 4;
  104. for (int column = 0; column < columns; column++)
  105. {
  106. readPixel(inputStream, pixbuf);
  107. }
  108. }
  109. }
  110. Image* LoadBMPBuff(PointerInputStream& inputStream, std::size_t length)
  111. {
  112. BMPHeader_t bmpHeader;
  113. inputStream.read(reinterpret_cast<byte*>(bmpHeader.id), 2);
  114. bmpHeader.fileSize = istream_read_uint32_le(inputStream);
  115. bmpHeader.reserved0 = istream_read_uint32_le(inputStream);
  116. bmpHeader.bitmapDataOffset = istream_read_uint32_le(inputStream);
  117. bmpHeader.bitmapHeaderSize = istream_read_uint32_le(inputStream);
  118. bmpHeader.width = istream_read_uint32_le(inputStream);
  119. bmpHeader.height = istream_read_uint32_le(inputStream);
  120. bmpHeader.planes = istream_read_uint16_le(inputStream);
  121. bmpHeader.bitsPerPixel = istream_read_uint16_le(inputStream);
  122. bmpHeader.compression = istream_read_uint32_le(inputStream);
  123. bmpHeader.bitmapDataSize = istream_read_uint32_le(inputStream);
  124. bmpHeader.hRes = istream_read_uint32_le(inputStream);
  125. bmpHeader.vRes = istream_read_uint32_le(inputStream);
  126. bmpHeader.colors = istream_read_uint32_le(inputStream);
  127. bmpHeader.importantColors = istream_read_uint32_le(inputStream);
  128. if (bmpHeader.bitsPerPixel == 8)
  129. {
  130. int paletteSize = bmpHeader.colors * 4;
  131. inputStream.read(reinterpret_cast<byte*>(bmpHeader.palette), paletteSize);
  132. }
  133. if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M')
  134. {
  135. globalErrorStream() << "LoadBMP: only Windows-style BMP files supported\n";
  136. return 0;
  137. }
  138. if (bmpHeader.fileSize != length)
  139. {
  140. globalErrorStream() << "LoadBMP: header size does not match file size (" << Unsigned(bmpHeader.fileSize) << " vs. " << Unsigned(length) << ")\n";
  141. return 0;
  142. }
  143. if (bmpHeader.compression != 0)
  144. {
  145. globalErrorStream() << "LoadBMP: only uncompressed BMP files supported\n";
  146. return 0;
  147. }
  148. if (bmpHeader.bitsPerPixel < 8)
  149. {
  150. globalErrorStream() << "LoadBMP: monochrome and 4-bit BMP files not supported\n";
  151. return 0;
  152. }
  153. int columns = bmpHeader.width;
  154. int rows = bmpHeader.height;
  155. if (rows < 0)
  156. rows = -rows;
  157. RGBAImage* image = new RGBAImage(columns, rows);
  158. switch(bmpHeader.bitsPerPixel)
  159. {
  160. case 8:
  161. ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel8(bmpHeader.palette));
  162. break;
  163. case 16:
  164. ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel16());
  165. break;
  166. case 24:
  167. ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel24());
  168. break;
  169. case 32:
  170. ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel32());
  171. break;
  172. default:
  173. globalErrorStream() << "LoadBMP: illegal pixel_size '" << bmpHeader.bitsPerPixel << "'\n";
  174. image->release();
  175. return 0;
  176. }
  177. return image;
  178. }
  179. Image* LoadBMP(ArchiveFile& file)
  180. {
  181. ScopedArchiveBuffer buffer(file);
  182. PointerInputStream inputStream(buffer.buffer);
  183. return LoadBMPBuff(inputStream, buffer.length);
  184. }