ares-openbsd/nall/decode/bmp.hpp

77 行
2.0 KiB
C++

#pragma once
namespace nall::Decode {
struct BMP {
BMP() = default;
BMP(const string& filename) { load(filename); }
BMP(const u8* data, u32 size) { load(data, size); }
explicit operator bool() const { return _data; }
auto reset() -> void {
if(_data) { delete[] _data; _data = nullptr; }
}
auto data() -> u32* { return _data; }
auto data() const -> const u32* { return _data; }
auto width() const -> u32 { return _width; }
auto height() const -> u32 { return _height; }
auto load(const string& filename) -> bool {
auto buffer = file::read(filename);
return load(buffer.data(), buffer.size());
}
auto load(const u8* data, u32 size) -> bool {
if(size < 0x36) return false;
const u8* p = data;
if(read(p, 2) != 0x4d42) return false; //signature
read(p, 8);
u32 offset = read(p, 4);
if(read(p, 4) != 40) return false; //DIB size
s32 width = (s32)read(p, 4);
if(width < 0) width = -width;
s32 height = (s32)read(p, 4);
bool flip = height >= 0;
if(height < 0) height = -height;
read(p, 2);
u32 bitsPerPixel = read(p, 2);
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
if(read(p, 4) != 0) return false; //compression type
_width = width;
_height = height;
_data = new u32[width * height];
u32 bytesPerPixel = bitsPerPixel / 8;
u32 alignedWidth = width * bytesPerPixel;
u32 paddingLength = 0;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
p = data + offset;
for(auto y : range(height)) {
u32* output = flip ? _data + (height - 1 - y) * width : _data + y * width;
for(auto x : range(width)) {
*output++ = read(p, bytesPerPixel) | (bitsPerPixel == 24 ? 255u << 24 : 0);
}
if(paddingLength) read(p, paddingLength);
}
return true;
}
private:
u32* _data = nullptr;
u32 _width = 0;
u32 _height = 0;
auto read(const u8*& buffer, u32 length) -> u64 {
u64 result = 0;
for(u32 n : range(length)) result |= (u64)*buffer++ << (n << 3);
return result;
}
};
}