18 void BmpInitializeBuffer(
BmpBuffer *buffer, FILE *file)
23 buffer->real_pos = ftell(file);
26 static inline void AdvanceBuffer(
BmpBuffer *buffer)
28 if (buffer->read < 0)
return;
30 buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
34 static inline bool EndOfBuffer(
BmpBuffer *buffer)
36 if (buffer->read < 0)
return false;
38 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
39 return buffer->pos == buffer->read;
42 static inline byte ReadByte(
BmpBuffer *buffer)
44 if (buffer->read < 0)
return 0;
46 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
48 return buffer->data[buffer->pos++];
51 static inline uint16 ReadWord(
BmpBuffer *buffer)
53 uint16 var = ReadByte(buffer);
54 return var | (ReadByte(buffer) << 8);
57 static inline uint32 ReadDword(
BmpBuffer *buffer)
59 uint32 var = ReadWord(buffer);
60 return var | (ReadWord(buffer) << 16);
63 static inline void SkipBytes(
BmpBuffer *buffer,
int bytes)
66 for (i = 0; i < bytes; i++) ReadByte(buffer);
69 static inline void SetStreamOffset(
BmpBuffer *buffer,
int offset)
71 if (fseek(buffer->file, offset, SEEK_SET) < 0) {
75 buffer->real_pos = offset;
76 AdvanceBuffer(buffer);
86 byte pad =
GB(4 - info->
width / 8, 0, 2);
89 for (y = info->
height; y > 0; y--) {
91 pixel_row = &data->bitmap[(y - 1) * info->
width];
92 while (x < info->width) {
93 if (EndOfBuffer(buffer))
return false;
95 for (i = 8; i > 0; i--) {
96 if (x < info->width) *pixel_row++ =
GB(b, i - 1, 1);
101 SkipBytes(buffer, pad);
113 byte pad =
GB(4 - info->
width / 2, 0, 2);
116 for (y = info->
height; y > 0; y--) {
118 pixel_row = &data->bitmap[(y - 1) * info->
width];
119 while (x < info->width) {
120 if (EndOfBuffer(buffer))
return false;
121 b = ReadByte(buffer);
122 *pixel_row++ =
GB(b, 4, 4);
124 if (x < info->width) {
125 *pixel_row++ =
GB(b, 0, 4);
130 SkipBytes(buffer, pad);
142 uint y = info->
height - 1;
143 byte *pixel = &data->bitmap[y * info->
width];
144 while (y != 0 || x < info->width) {
145 if (EndOfBuffer(buffer))
return false;
147 byte n = ReadByte(buffer);
148 byte c = ReadByte(buffer);
153 if (y == 0)
return false;
154 pixel = &data->bitmap[--y * info->
width];
161 if (EndOfBuffer(buffer))
return false;
162 byte dx = ReadByte(buffer);
163 byte dy = ReadByte(buffer);
166 if (x + dx >= info->
width || x + dx < x || dy > y)
return false;
170 pixel = &data->bitmap[y * info->
width + x];
177 if (EndOfBuffer(buffer) || x >= info->
width)
return false;
178 byte b = ReadByte(buffer);
179 *pixel++ =
GB(b, 4, 4);
182 if (x >= info->
width)
return false;
183 *pixel++ =
GB(b, 0, 4);
188 SkipBytes(buffer, ((c + 1) / 2) % 2);
197 while (x < info->width && i++ < n) {
198 *pixel++ =
GB(c, 4, 4);
200 if (x < info->width && i++ < n) {
201 *pixel++ =
GB(c, 0, 4);
217 byte pad =
GB(4 - info->
width, 0, 2);
219 for (y = info->
height; y > 0; y--) {
220 if (EndOfBuffer(buffer))
return false;
221 pixel = &data->bitmap[(y - 1) * info->
width];
222 for (i = 0; i < info->
width; i++) *pixel++ = ReadByte(buffer);
224 SkipBytes(buffer, pad);
235 uint y = info->
height - 1;
236 byte *pixel = &data->bitmap[y * info->
width];
237 while (y != 0 || x < info->width) {
238 if (EndOfBuffer(buffer))
return false;
240 byte n = ReadByte(buffer);
241 byte c = ReadByte(buffer);
246 if (y == 0)
return false;
247 pixel = &data->bitmap[--y * info->
width];
254 if (EndOfBuffer(buffer))
return false;
255 byte dx = ReadByte(buffer);
256 byte dy = ReadByte(buffer);
259 if (x + dx >= info->
width || x + dx < x || dy > y)
return false;
263 pixel = &data->bitmap[y * info->
width + x];
268 for (uint i = 0; i < c; i++) {
269 if (EndOfBuffer(buffer) || x >= info->
width)
return false;
270 *pixel++ = ReadByte(buffer);
274 SkipBytes(buffer, c % 2);
282 for (uint i = 0; x < info->
width && i < n; i++) {
297 byte pad =
GB(4 - info->
width * 3, 0, 2);
299 for (y = info->
height; y > 0; y--) {
300 pixel_row = &data->bitmap[(y - 1) * info->
width * 3];
301 for (x = 0; x < info->
width; x++) {
302 if (EndOfBuffer(buffer))
return false;
303 *(pixel_row + 2) = ReadByte(buffer);
304 *(pixel_row + 1) = ReadByte(buffer);
305 *pixel_row = ReadByte(buffer);
309 SkipBytes(buffer, pad);
320 assert(info !=
nullptr);
324 if (ReadWord(buffer) != 0x4D42)
return false;
325 SkipBytes(buffer, 8);
326 info->
offset = ReadDword(buffer);
329 header_size = ReadDword(buffer);
330 if (header_size < 12)
return false;
332 info->
os2_bmp = (header_size == 12);
335 info->
width = ReadWord(buffer);
336 info->
height = ReadWord(buffer);
339 info->
width = ReadDword(buffer);
340 info->
height = ReadDword(buffer);
344 if (ReadWord(buffer) != 1)
return false;
346 info->
bpp = ReadWord(buffer);
347 if (info->
bpp != 1 && info->
bpp != 4 && info->
bpp != 8 && info->
bpp != 24) {
353 if ((header_size -= 4) >= 4) {
361 if (info->
bpp <= 8) {
365 if (header_size >= 16) {
366 SkipBytes(buffer, 12);
368 SkipBytes(buffer, header_size - 16);
375 data->palette[i].b = ReadByte(buffer);
376 data->palette[i].g = ReadByte(buffer);
377 data->palette[i].r = ReadByte(buffer);
378 if (!info->
os2_bmp) SkipBytes(buffer, 1);
382 return buffer->real_pos <= info->
offset;
391 assert(info !=
nullptr && data !=
nullptr);
393 data->bitmap = CallocT<byte>(info->
width * info->
height * ((info->
bpp == 24) ? 3 : 1));
396 SetStreamOffset(buffer, info->
offset);
400 case 1:
return BmpRead1(buffer, info, data);
401 case 4:
return BmpRead4(buffer, info, data);
402 case 8:
return BmpRead8(buffer, info, data);
403 case 24:
return BmpRead24(buffer, info, data);
404 default: NOT_REACHED();
408 default: NOT_REACHED();
412 void BmpDestroyData(
BmpData *data)
414 assert(data !=
nullptr);