20 void BmpInitializeBuffer(
BmpBuffer *buffer, FILE *file)
25 buffer->real_pos = ftell(file);
28 static inline void AdvanceBuffer(
BmpBuffer *buffer)
30 if (buffer->read < 0)
return;
32 buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
36 static inline bool EndOfBuffer(
BmpBuffer *buffer)
38 if (buffer->read < 0)
return false;
40 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
41 return buffer->pos == buffer->read;
44 static inline byte ReadByte(
BmpBuffer *buffer)
46 if (buffer->read < 0)
return 0;
48 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
50 return buffer->data[buffer->pos++];
53 static inline uint16 ReadWord(
BmpBuffer *buffer)
55 uint16 var = ReadByte(buffer);
56 return var | (ReadByte(buffer) << 8);
59 static inline uint32 ReadDword(
BmpBuffer *buffer)
61 uint32 var = ReadWord(buffer);
62 return var | (ReadWord(buffer) << 16);
65 static inline void SkipBytes(
BmpBuffer *buffer,
int bytes)
68 for (i = 0; i < bytes; i++) ReadByte(buffer);
71 static inline void SetStreamOffset(
BmpBuffer *buffer,
int offset)
73 if (fseek(buffer->file, offset, SEEK_SET) < 0) {
77 buffer->real_pos = offset;
78 AdvanceBuffer(buffer);
88 byte pad =
GB(4 - info->
width / 8, 0, 2);
91 for (y = info->
height; y > 0; y--) {
93 pixel_row = &data->bitmap[(y - 1) * info->
width];
94 while (x < info->width) {
95 if (EndOfBuffer(buffer))
return false;
97 for (i = 8; i > 0; i--) {
98 if (x < info->width) *pixel_row++ =
GB(b, i - 1, 1);
103 SkipBytes(buffer, pad);
115 byte pad =
GB(4 - info->
width / 2, 0, 2);
118 for (y = info->
height; y > 0; y--) {
120 pixel_row = &data->bitmap[(y - 1) * info->
width];
121 while (x < info->width) {
122 if (EndOfBuffer(buffer))
return false;
123 b = ReadByte(buffer);
124 *pixel_row++ =
GB(b, 4, 4);
126 if (x < info->width) {
127 *pixel_row++ =
GB(b, 0, 4);
132 SkipBytes(buffer, pad);
144 uint y = info->
height - 1;
145 byte *pixel = &data->bitmap[y * info->
width];
146 while (y != 0 || x < info->width) {
147 if (EndOfBuffer(buffer))
return false;
149 byte n = ReadByte(buffer);
150 byte c = ReadByte(buffer);
155 if (y == 0)
return false;
156 pixel = &data->bitmap[--y * info->
width];
163 if (EndOfBuffer(buffer))
return false;
164 byte dx = ReadByte(buffer);
165 byte dy = ReadByte(buffer);
168 if (x + dx >= info->
width || x + dx < x || dy > y)
return false;
172 pixel = &data->bitmap[y * info->
width + x];
179 if (EndOfBuffer(buffer) || x >= info->
width)
return false;
180 byte b = ReadByte(buffer);
181 *pixel++ =
GB(b, 4, 4);
184 if (x >= info->
width)
return false;
185 *pixel++ =
GB(b, 0, 4);
190 SkipBytes(buffer, ((c + 1) / 2) % 2);
199 while (x < info->width && i++ < n) {
200 *pixel++ =
GB(c, 4, 4);
202 if (x < info->width && i++ < n) {
203 *pixel++ =
GB(c, 0, 4);
219 byte pad =
GB(4 - info->
width, 0, 2);
221 for (y = info->
height; y > 0; y--) {
222 if (EndOfBuffer(buffer))
return false;
223 pixel = &data->bitmap[(y - 1) * info->
width];
224 for (i = 0; i < info->
width; i++) *pixel++ = ReadByte(buffer);
226 SkipBytes(buffer, pad);
237 uint y = info->
height - 1;
238 byte *pixel = &data->bitmap[y * info->
width];
239 while (y != 0 || x < info->width) {
240 if (EndOfBuffer(buffer))
return false;
242 byte n = ReadByte(buffer);
243 byte c = ReadByte(buffer);
248 if (y == 0)
return false;
249 pixel = &data->bitmap[--y * info->
width];
256 if (EndOfBuffer(buffer))
return false;
257 byte dx = ReadByte(buffer);
258 byte dy = ReadByte(buffer);
261 if (x + dx >= info->
width || x + dx < x || dy > y)
return false;
265 pixel = &data->bitmap[y * info->
width + x];
270 for (uint i = 0; i < c; i++) {
271 if (EndOfBuffer(buffer) || x >= info->
width)
return false;
272 *pixel++ = ReadByte(buffer);
276 SkipBytes(buffer, c % 2);
284 for (uint i = 0; x < info->
width && i < n; i++) {
299 byte pad =
GB(4 - info->
width * 3, 0, 2);
301 for (y = info->
height; y > 0; y--) {
302 pixel_row = &data->bitmap[(y - 1) * info->
width * 3];
303 for (x = 0; x < info->
width; x++) {
304 if (EndOfBuffer(buffer))
return false;
305 *(pixel_row + 2) = ReadByte(buffer);
306 *(pixel_row + 1) = ReadByte(buffer);
307 *pixel_row = ReadByte(buffer);
311 SkipBytes(buffer, pad);
322 assert(info != NULL);
326 if (ReadWord(buffer) != 0x4D42)
return false;
327 SkipBytes(buffer, 8);
328 info->
offset = ReadDword(buffer);
331 header_size = ReadDword(buffer);
332 if (header_size < 12)
return false;
334 info->
os2_bmp = (header_size == 12);
337 info->
width = ReadWord(buffer);
338 info->
height = ReadWord(buffer);
341 info->
width = ReadDword(buffer);
342 info->
height = ReadDword(buffer);
346 if (ReadWord(buffer) != 1)
return false;
348 info->
bpp = ReadWord(buffer);
349 if (info->
bpp != 1 && info->
bpp != 4 && info->
bpp != 8 && info->
bpp != 24) {
355 if ((header_size -= 4) >= 4) {
363 if (info->
bpp <= 8) {
367 if (header_size >= 16) {
368 SkipBytes(buffer, 12);
370 SkipBytes(buffer, header_size - 16);
377 data->palette[i].b = ReadByte(buffer);
378 data->palette[i].g = ReadByte(buffer);
379 data->palette[i].r = ReadByte(buffer);
380 if (!info->
os2_bmp) SkipBytes(buffer, 1);
384 return buffer->real_pos <= info->
offset;
393 assert(info != NULL && data != NULL);
395 data->bitmap = CallocT<byte>(info->
width * info->
height * ((info->
bpp == 24) ? 3 : 1));
398 SetStreamOffset(buffer, info->
offset);
402 case 1:
return BmpRead1(buffer, info, data);
403 case 4:
return BmpRead4(buffer, info, data);
404 case 8:
return BmpRead8(buffer, info, data);
405 case 24:
return BmpRead24(buffer, info, data);
406 default: NOT_REACHED();
410 default: NOT_REACHED();
414 void BmpDestroyData(
BmpData *data)
416 assert(data != NULL);