CImageLoaderBMP.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #include "CImageLoaderBMP.h"
  5. #ifdef _IRR_COMPILE_WITH_BMP_LOADER_
  6. #include "IReadFile.h"
  7. #include "SColor.h"
  8. #include "CColorConverter.h"
  9. #include "CImage.h"
  10. #include "os.h"
  11. #include "irrString.h"
  12. namespace irr
  13. {
  14. namespace video
  15. {
  16. //! constructor
  17. CImageLoaderBMP::CImageLoaderBMP()
  18. {
  19. #ifdef _DEBUG
  20. setDebugName("CImageLoaderBMP");
  21. #endif
  22. }
  23. //! returns true if the file maybe is able to be loaded by this class
  24. //! based on the file extension (e.g. ".tga")
  25. bool CImageLoaderBMP::isALoadableFileExtension(const io::path& filename) const
  26. {
  27. return core::hasFileExtension ( filename, "bmp" );
  28. }
  29. //! returns true if the file maybe is able to be loaded by this class
  30. bool CImageLoaderBMP::isALoadableFileFormat(io::IReadFile* file) const
  31. {
  32. u16 headerID;
  33. file->read(&headerID, sizeof(u16));
  34. #ifdef __BIG_ENDIAN__
  35. headerID = os::Byteswap::byteswap(headerID);
  36. #endif
  37. return headerID == 0x4d42;
  38. }
  39. void CImageLoaderBMP::decompress8BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const
  40. {
  41. u8* p = bmpData;
  42. u8* newBmp = new u8[(width+pitch)*height];
  43. u8* d = newBmp;
  44. u8* destEnd = newBmp + (width+pitch)*height;
  45. s32 line = 0;
  46. while (bmpData - p < size && d < destEnd)
  47. {
  48. if (*p == 0)
  49. {
  50. ++p;
  51. switch(*p)
  52. {
  53. case 0: // end of line
  54. ++p;
  55. ++line;
  56. d = newBmp + (line*(width+pitch));
  57. break;
  58. case 1: // end of bmp
  59. delete [] bmpData;
  60. bmpData = newBmp;
  61. return;
  62. case 2:
  63. ++p; d +=(u8)*p; // delta
  64. ++p; d += ((u8)*p)*(width+pitch);
  65. ++p;
  66. break;
  67. default:
  68. {
  69. // absolute mode
  70. s32 count = (u8)*p; ++p;
  71. s32 readAdditional = ((2-(count%2))%2);
  72. s32 i;
  73. for (i=0; i<count; ++i)
  74. {
  75. *d = *p;
  76. ++p;
  77. ++d;
  78. }
  79. for (i=0; i<readAdditional; ++i)
  80. ++p;
  81. }
  82. }
  83. }
  84. else
  85. {
  86. s32 count = (u8)*p; ++p;
  87. u8 color = *p; ++p;
  88. for (s32 i=0; i<count; ++i)
  89. {
  90. *d = color;
  91. ++d;
  92. }
  93. }
  94. }
  95. delete [] bmpData;
  96. bmpData = newBmp;
  97. }
  98. void CImageLoaderBMP::decompress4BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const
  99. {
  100. s32 lineWidth = (width+1)/2+pitch;
  101. u8* p = bmpData;
  102. u8* newBmp = new u8[lineWidth*height];
  103. u8* d = newBmp;
  104. u8* destEnd = newBmp + lineWidth*height;
  105. s32 line = 0;
  106. s32 shift = 4;
  107. while (bmpData - p < size && d < destEnd)
  108. {
  109. if (*p == 0)
  110. {
  111. ++p;
  112. switch(*p)
  113. {
  114. case 0: // end of line
  115. ++p;
  116. ++line;
  117. d = newBmp + (line*lineWidth);
  118. shift = 4;
  119. break;
  120. case 1: // end of bmp
  121. delete [] bmpData;
  122. bmpData = newBmp;
  123. return;
  124. case 2:
  125. {
  126. ++p;
  127. s32 x = (u8)*p; ++p;
  128. s32 y = (u8)*p; ++p;
  129. d += x/2 + y*lineWidth;
  130. shift = x%2==0 ? 4 : 0;
  131. }
  132. break;
  133. default:
  134. {
  135. // absolute mode
  136. s32 count = (u8)*p; ++p;
  137. s32 readAdditional = ((2-((count)%2))%2);
  138. s32 readShift = 4;
  139. s32 i;
  140. for (i=0; i<count; ++i)
  141. {
  142. s32 color = (((u8)*p) >> readShift) & 0x0f;
  143. readShift -= 4;
  144. if (readShift < 0)
  145. {
  146. ++*p;
  147. readShift = 4;
  148. }
  149. u8 mask = 0x0f << shift;
  150. *d = (*d & (~mask)) | ((color << shift) & mask);
  151. shift -= 4;
  152. if (shift < 0)
  153. {
  154. shift = 4;
  155. ++d;
  156. }
  157. }
  158. for (i=0; i<readAdditional; ++i)
  159. ++p;
  160. }
  161. }
  162. }
  163. else
  164. {
  165. s32 count = (u8)*p; ++p;
  166. s32 color1 = (u8)*p; color1 = color1 & 0x0f;
  167. s32 color2 = (u8)*p; color2 = (color2 >> 4) & 0x0f;
  168. ++p;
  169. for (s32 i=0; i<count; ++i)
  170. {
  171. u8 mask = 0x0f << shift;
  172. u8 toSet = (shift==0 ? color1 : color2) << shift;
  173. *d = (*d & (~mask)) | (toSet & mask);
  174. shift -= 4;
  175. if (shift < 0)
  176. {
  177. shift = 4;
  178. ++d;
  179. }
  180. }
  181. }
  182. }
  183. delete [] bmpData;
  184. bmpData = newBmp;
  185. }
  186. //! creates a surface from the file
  187. IImage* CImageLoaderBMP::loadImage(io::IReadFile* file, bool skip_checking) const
  188. {
  189. SBMPHeader header;
  190. file->read(&header, sizeof(header));
  191. #ifdef __BIG_ENDIAN__
  192. header.Id = os::Byteswap::byteswap(header.Id);
  193. header.FileSize = os::Byteswap::byteswap(header.FileSize);
  194. header.BitmapDataOffset = os::Byteswap::byteswap(header.BitmapDataOffset);
  195. header.BitmapHeaderSize = os::Byteswap::byteswap(header.BitmapHeaderSize);
  196. header.Width = os::Byteswap::byteswap(header.Width);
  197. header.Height = os::Byteswap::byteswap(header.Height);
  198. header.Planes = os::Byteswap::byteswap(header.Planes);
  199. header.BPP = os::Byteswap::byteswap(header.BPP);
  200. header.Compression = os::Byteswap::byteswap(header.Compression);
  201. header.BitmapDataSize = os::Byteswap::byteswap(header.BitmapDataSize);
  202. header.PixelPerMeterX = os::Byteswap::byteswap(header.PixelPerMeterX);
  203. header.PixelPerMeterY = os::Byteswap::byteswap(header.PixelPerMeterY);
  204. header.Colors = os::Byteswap::byteswap(header.Colors);
  205. header.ImportantColors = os::Byteswap::byteswap(header.ImportantColors);
  206. #endif
  207. s32 pitch = 0;
  208. //! return if the header is false
  209. if (header.Id != 0x4d42)
  210. return 0;
  211. if (header.Compression > 2) // we'll only handle RLE-Compression
  212. {
  213. os::Printer::log("Compression mode not supported.", ELL_ERROR);
  214. return 0;
  215. }
  216. // adjust bitmap data size to dword boundary
  217. header.BitmapDataSize += (4-(header.BitmapDataSize%4))%4;
  218. // read palette
  219. long pos = file->getPos();
  220. s32 paletteSize = (header.BitmapDataOffset - pos) / 4;
  221. s32* paletteData = 0;
  222. if (paletteSize)
  223. {
  224. paletteData = new s32[paletteSize];
  225. file->read(paletteData, paletteSize * sizeof(s32));
  226. #ifdef __BIG_ENDIAN__
  227. for (s32 i=0; i<paletteSize; ++i)
  228. paletteData[i] = os::Byteswap::byteswap(paletteData[i]);
  229. #endif
  230. }
  231. // read image data
  232. if (!header.BitmapDataSize)
  233. {
  234. // okay, lets guess the size
  235. // some tools simply don't set it
  236. header.BitmapDataSize = static_cast<u32>(file->getSize()) - header.BitmapDataOffset;
  237. }
  238. file->seek(header.BitmapDataOffset);
  239. f32 t = (header.Width) * (header.BPP / 8.0f);
  240. s32 widthInBytes = (s32)t;
  241. t -= widthInBytes;
  242. if (t!=0.0f)
  243. ++widthInBytes;
  244. s32 lineData = widthInBytes + ((4-(widthInBytes%4)))%4;
  245. pitch = lineData - widthInBytes;
  246. u8* bmpData = new u8[header.BitmapDataSize];
  247. file->read(bmpData, header.BitmapDataSize);
  248. // decompress data if needed
  249. switch(header.Compression)
  250. {
  251. case 1: // 8 bit rle
  252. decompress8BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch);
  253. break;
  254. case 2: // 4 bit rle
  255. decompress4BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch);
  256. break;
  257. }
  258. // create surface
  259. // no default constructor from packed area! ARM problem!
  260. core::dimension2d<u32> dim;
  261. dim.Width = header.Width;
  262. dim.Height = header.Height;
  263. IImage* image = 0;
  264. switch(header.BPP)
  265. {
  266. case 1:
  267. image = new CImage(ECF_A1R5G5B5, dim);
  268. if (image)
  269. CColorConverter::convert1BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true);
  270. break;
  271. case 4:
  272. image = new CImage(ECF_A1R5G5B5, dim);
  273. if (image)
  274. CColorConverter::convert4BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true);
  275. break;
  276. case 8:
  277. image = new CImage(ECF_A1R5G5B5, dim);
  278. if (image)
  279. CColorConverter::convert8BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true);
  280. break;
  281. case 16:
  282. image = new CImage(ECF_A1R5G5B5, dim);
  283. if (image)
  284. CColorConverter::convert16BitTo16Bit((s16*)bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true);
  285. break;
  286. case 24:
  287. image = new CImage(ECF_R8G8B8, dim);
  288. if (image)
  289. CColorConverter::convert24BitTo24Bit(bmpData, (u8*)image->lock(), header.Width, header.Height, pitch, true, true);
  290. break;
  291. case 32: // thx to Reinhard Ostermeier
  292. image = new CImage(ECF_A8R8G8B8, dim);
  293. if (image)
  294. CColorConverter::convert32BitTo32Bit((s32*)bmpData, (s32*)image->lock(), header.Width, header.Height, pitch, true);
  295. break;
  296. };
  297. if (image)
  298. image->unlock();
  299. // clean up
  300. delete [] paletteData;
  301. delete [] bmpData;
  302. return image;
  303. }
  304. //! creates a loader which is able to load windows bitmaps
  305. IImageLoader* createImageLoaderBMP()
  306. {
  307. return new CImageLoaderBMP;
  308. }
  309. } // end namespace video
  310. } // end namespace irr
  311. #endif