1 #include <msp/core/inttypes.h>
8 void read_full(Msp::IO::Base &io, char *buffer, unsigned size)
10 unsigned len = io.read(buffer, size);
12 throw Msp::Graphics::bad_image_data("premature end of file");
16 T decode(const char *data)
18 const Msp::UInt8 *udata = reinterpret_cast<const Msp::UInt8 *>(data);
20 for(unsigned i=0; i<sizeof(T); ++i)
21 result |= udata[i]<<(i*8);
30 BmpLoader::BmpLoader(IO::Base &i, unsigned sb):
33 invert_row_order(false)
35 // Image data location is stored at offset 10 and can't be skipped
37 throw invalid_argument("BmpLoader::BmpLoader");
40 bool BmpLoader::detect(const std::string &sig)
42 static const char bmp_sig[] = { 'B', 'M' };
43 if(sig.size()<sizeof(bmp_sig))
45 return !sig.compare(0, sizeof(bmp_sig), bmp_sig, sizeof(bmp_sig));
48 void BmpLoader::load_headers_(Image::Data &data)
51 read_full(io, bm_header+sig_bytes, sizeof(bm_header)-sig_bytes);
53 if(!sig_bytes && (bm_header[0]!='B' || bm_header[1]!='M'))
54 throw bad_image_data("bitmap header mismatch");
56 unsigned data_offset = decode<UInt32>(bm_header+10);
59 read_full(io, dib_header, 12);
60 unsigned dib_length = min<unsigned>(decode<UInt32>(dib_header), sizeof(dib_header));
62 throw bad_image_data("DIB header too short (very old bmp file?)");
64 read_full(io, dib_header+12, dib_length-12);
66 data.width = decode<UInt32>(dib_header+4);
67 Int32 height = decode<UInt32>(dib_header+8);
68 data.height = abs(height);
70 unsigned color_planes = decode<UInt16>(dib_header+12);
72 throw bad_image_data("color_planes!=1");
73 unsigned bits_per_pixel = decode<UInt16>(dib_header+14);
74 unsigned compression = decode<UInt32>(dib_header+16);
76 throw unsupported_image_format("compression not supported");
78 data.stride = (data.width*bits_per_pixel+31)/32*4;
79 switch(bits_per_pixel)
81 case 8: data.fmt = COLOR_INDEX; break;
82 case 24: data.fmt = BGR; break;
83 case 32: data.fmt = BGRX; break; // TODO is it BGRX or XBGR?
84 default: throw unsupported_image_format("bits per pixel value not supported");
87 unsigned skip = data_offset-sizeof(bm_header)-dib_length;
91 unsigned size = min<unsigned>(sizeof(buffer), skip);
92 read_full(io, buffer, size);
96 invert_row_order = (height<0);
99 void BmpLoader::load_pixels_(Image::Data &data)
103 for(unsigned y=0; y<data.height; ++y)
104 read_full(io, data.pixels+(data.height-1-y)*data.stride, data.stride);
108 for(unsigned y=0; y<data.height; ++y)
109 read_full(io, data.pixels+y*data.stride, data.stride);
113 } // namespace Graphics