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 uint8_t *udata = reinterpret_cast<const uint8_t *>(data);
20 for(unsigned i=0; i<sizeof(T); ++i)
21 result |= udata[i]<<(i*8);
30 BmpLoader::BmpLoader(IO::Base &i, unsigned sb):
34 // Image data location is stored at offset 10 and can't be skipped
36 throw invalid_argument("BmpLoader::BmpLoader");
39 bool BmpLoader::detect(const string &sig)
41 static const char bmp_sig[] = { 'B', 'M' };
42 if(sig.size()<sizeof(bmp_sig))
44 return !sig.compare(0, sizeof(bmp_sig), bmp_sig, sizeof(bmp_sig));
47 void BmpLoader::load_headers_(Image::Data &data)
50 read_full(io, bm_header+sig_bytes, sizeof(bm_header)-sig_bytes);
52 if(!sig_bytes && (bm_header[0]!='B' || bm_header[1]!='M'))
53 throw bad_image_data("bitmap header mismatch");
55 unsigned data_offset = decode<uint32_t>(bm_header+10);
58 read_full(io, dib_header, 12);
59 unsigned dib_length = min<unsigned>(decode<uint32_t>(dib_header), sizeof(dib_header));
61 throw bad_image_data("DIB header too short (very old bmp file?)");
63 read_full(io, dib_header+12, dib_length-12);
65 data.width = decode<uint32_t>(dib_header+4);
66 int32_t height = decode<uint32_t>(dib_header+8);
67 data.height = abs(height);
69 unsigned color_planes = decode<uint16_t>(dib_header+12);
71 throw bad_image_data("color_planes!=1");
72 unsigned bits_per_pixel = decode<uint16_t>(dib_header+14);
73 unsigned compression = decode<uint32_t>(dib_header+16);
75 throw unsupported_image_format("compression not supported");
77 data.stride = (data.width*bits_per_pixel+31)/32*4;
78 switch(bits_per_pixel)
80 case 8: data.fmt = COLOR_INDEX; break;
81 case 24: data.fmt = BGR; break;
82 case 32: data.fmt = BGRX; break; // TODO is it BGRX or XBGR?
83 default: throw unsupported_image_format("bits per pixel value not supported");
86 unsigned skip = data_offset-sizeof(bm_header)-dib_length;
90 unsigned size = min<unsigned>(sizeof(buffer), skip);
91 read_full(io, buffer, size);
95 invert_row_order = (height<0);
98 void BmpLoader::load_pixels_(Image::Data &data)
102 for(unsigned y=0; y<data.height; ++y)
103 read_full(io, data.pixels+(data.height-1-y)*data.stride, data.stride);
107 for(unsigned y=0; y<data.height; ++y)
108 read_full(io, data.pixels+y*data.stride, data.stride);
112 } // namespace Graphics