bmp.hpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #pragma once
  2. namespace nall::Decode {
  3. struct BMP {
  4. BMP() = default;
  5. BMP(const string& filename) { load(filename); }
  6. BMP(const uint8_t* data, uint size) { load(data, size); }
  7. explicit operator bool() const { return _data; }
  8. auto reset() -> void {
  9. if(_data) { delete[] _data; _data = nullptr; }
  10. }
  11. auto data() -> uint32_t* { return _data; }
  12. auto data() const -> const uint32_t* { return _data; }
  13. auto width() const -> uint { return _width; }
  14. auto height() const -> uint { return _height; }
  15. auto load(const string& filename) -> bool {
  16. auto buffer = file::read(filename);
  17. return load(buffer.data(), buffer.size());
  18. }
  19. auto load(const uint8_t* data, uint size) -> bool {
  20. if(size < 0x36) return false;
  21. const uint8_t* p = data;
  22. if(read(p, 2) != 0x4d42) return false; //signature
  23. read(p, 8);
  24. uint offset = read(p, 4);
  25. if(read(p, 4) != 40) return false; //DIB size
  26. int width = read(p, 4);
  27. if(width < 0) return false;
  28. int height = read(p, 4);
  29. bool flip = height < 0;
  30. if(flip) height = -height;
  31. read(p, 2);
  32. uint bitsPerPixel = read(p, 2);
  33. if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
  34. if(read(p, 4) != 0) return false; //compression type
  35. _width = width;
  36. _height = height;
  37. _data = new uint32_t[width * height];
  38. uint bytesPerPixel = bitsPerPixel / 8;
  39. uint alignedWidth = width * bytesPerPixel;
  40. uint paddingLength = 0;
  41. while(alignedWidth % 4) alignedWidth++, paddingLength++;
  42. p = data + offset;
  43. for(auto y : range(height)) {
  44. uint32_t* output = flip ? _data + (height - 1 - y) * width : _data + y * width;
  45. for(auto x : range(width)) {
  46. *output++ = read(p, bytesPerPixel) | (bitsPerPixel == 24 ? 255u << 24 : 0);
  47. }
  48. if(paddingLength) read(p, paddingLength);
  49. }
  50. return true;
  51. }
  52. private:
  53. uint32_t* _data = nullptr;
  54. uint _width = 0;
  55. uint _height = 0;
  56. auto read(const uint8_t*& buffer, uint length) -> uintmax {
  57. uintmax result = 0;
  58. for(auto n : range(length)) result |= (uintmax)*buffer++ << (n << 3);
  59. return result;
  60. }
  61. };
  62. }