00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "bmp.h"
00014 #include "core/bitmath_func.hpp"
00015 #include "core/alloc_func.hpp"
00016 #include "core/mem_func.hpp"
00017
00018 void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file)
00019 {
00020 buffer->pos = -1;
00021 buffer->file = file;
00022 buffer->read = 0;
00023 buffer->real_pos = ftell(file);
00024 }
00025
00026 static inline void AdvanceBuffer(BmpBuffer *buffer)
00027 {
00028 if (buffer->read < 0) return;
00029
00030 buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
00031 buffer->pos = 0;
00032 }
00033
00034 static inline bool EndOfBuffer(BmpBuffer *buffer)
00035 {
00036 if (buffer->read < 0) return false;
00037
00038 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
00039 return buffer->pos == buffer->read;
00040 }
00041
00042 static inline byte ReadByte(BmpBuffer *buffer)
00043 {
00044 if (buffer->read < 0) return 0;
00045
00046 if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
00047 buffer->real_pos++;
00048 return buffer->data[buffer->pos++];
00049 }
00050
00051 static inline uint16 ReadWord(BmpBuffer *buffer)
00052 {
00053 uint16 var = ReadByte(buffer);
00054 return var | (ReadByte(buffer) << 8);
00055 }
00056
00057 static inline uint32 ReadDword(BmpBuffer *buffer)
00058 {
00059 uint32 var = ReadWord(buffer);
00060 return var | (ReadWord(buffer) << 16);
00061 }
00062
00063 static inline void SkipBytes(BmpBuffer *buffer, int bytes)
00064 {
00065 int i;
00066 for (i = 0; i < bytes; i++) ReadByte(buffer);
00067 }
00068
00069 static inline void SetStreamOffset(BmpBuffer *buffer, int offset)
00070 {
00071 if (fseek(buffer->file, offset, SEEK_SET) < 0) {
00072 buffer->read = -1;
00073 }
00074 buffer->pos = -1;
00075 buffer->real_pos = offset;
00076 AdvanceBuffer(buffer);
00077 }
00078
00083 static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00084 {
00085 uint x, y, i;
00086 byte pad = GB(4 - info->width / 8, 0, 2);
00087 byte *pixel_row;
00088 byte b;
00089 for (y = info->height; y > 0; y--) {
00090 x = 0;
00091 pixel_row = &data->bitmap[(y - 1) * info->width];
00092 while (x < info->width) {
00093 if (EndOfBuffer(buffer)) return false;
00094 b = ReadByte(buffer);
00095 for (i = 8; i > 0; i--) {
00096 if (x < info->width) *pixel_row++ = GB(b, i - 1, 1);
00097 x++;
00098 }
00099 }
00100
00101 SkipBytes(buffer, pad);
00102 }
00103 return true;
00104 }
00105
00110 static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00111 {
00112 uint x, y;
00113 byte pad = GB(4 - info->width / 2, 0, 2);
00114 byte *pixel_row;
00115 byte b;
00116 for (y = info->height; y > 0; y--) {
00117 x = 0;
00118 pixel_row = &data->bitmap[(y - 1) * info->width];
00119 while (x < info->width) {
00120 if (EndOfBuffer(buffer)) return false;
00121 b = ReadByte(buffer);
00122 *pixel_row++ = GB(b, 4, 4);
00123 x++;
00124 if (x < info->width) {
00125 *pixel_row++ = GB(b, 0, 4);
00126 x++;
00127 }
00128 }
00129
00130 SkipBytes(buffer, pad);
00131 }
00132 return true;
00133 }
00134
00139 static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00140 {
00141 uint x = 0;
00142 uint y = info->height - 1;
00143 byte *pixel = &data->bitmap[y * info->width];
00144 while (y != 0 || x < info->width) {
00145 if (EndOfBuffer(buffer)) return false;
00146
00147 byte n = ReadByte(buffer);
00148 byte c = ReadByte(buffer);
00149 if (n == 0) {
00150 switch (c) {
00151 case 0:
00152 x = 0;
00153 if (y == 0) return false;
00154 pixel = &data->bitmap[--y * info->width];
00155 break;
00156
00157 case 1:
00158 return true;
00159
00160 case 2: {
00161 if (EndOfBuffer(buffer)) return false;
00162 byte dx = ReadByte(buffer);
00163 byte dy = ReadByte(buffer);
00164
00165
00166 if (x + dx >= info->width || x + dx < x || dy > y) return false;
00167
00168 x += dx;
00169 y -= dy;
00170 pixel = &data->bitmap[y * info->width + x];
00171 break;
00172 }
00173
00174 default: {
00175 uint i = 0;
00176 while (i++ < c) {
00177 if (EndOfBuffer(buffer) || x >= info->width) return false;
00178 byte b = ReadByte(buffer);
00179 *pixel++ = GB(b, 4, 4);
00180 x++;
00181 if (i++ < c) {
00182 if (x >= info->width) return false;
00183 *pixel++ = GB(b, 0, 4);
00184 x++;
00185 }
00186 }
00187
00188 SkipBytes(buffer, ((c + 1) / 2) % 2);
00189 break;
00190 }
00191 }
00192 } else {
00193
00194
00195
00196 uint i = 0;
00197 while (x < info->width && i++ < n) {
00198 *pixel++ = GB(c, 4, 4);
00199 x++;
00200 if (x < info->width && i++ < n) {
00201 *pixel++ = GB(c, 0, 4);
00202 x++;
00203 }
00204 }
00205 }
00206 }
00207 return true;
00208 }
00209
00213 static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00214 {
00215 uint i;
00216 uint y;
00217 byte pad = GB(4 - info->width, 0, 2);
00218 byte *pixel;
00219 for (y = info->height; y > 0; y--) {
00220 if (EndOfBuffer(buffer)) return false;
00221 pixel = &data->bitmap[(y - 1) * info->width];
00222 for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer);
00223
00224 SkipBytes(buffer, pad);
00225 }
00226 return true;
00227 }
00228
00232 static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00233 {
00234 uint x = 0;
00235 uint y = info->height - 1;
00236 byte *pixel = &data->bitmap[y * info->width];
00237 while (y != 0 || x < info->width) {
00238 if (EndOfBuffer(buffer)) return false;
00239
00240 byte n = ReadByte(buffer);
00241 byte c = ReadByte(buffer);
00242 if (n == 0) {
00243 switch (c) {
00244 case 0:
00245 x = 0;
00246 if (y == 0) return false;
00247 pixel = &data->bitmap[--y * info->width];
00248 break;
00249
00250 case 1:
00251 return true;
00252
00253 case 2: {
00254 if (EndOfBuffer(buffer)) return false;
00255 byte dx = ReadByte(buffer);
00256 byte dy = ReadByte(buffer);
00257
00258
00259 if (x + dx >= info->width || x + dx < x || dy > y) return false;
00260
00261 x += dx;
00262 y -= dy;
00263 pixel = &data->bitmap[y * info->width + x];
00264 break;
00265 }
00266
00267 default: {
00268 for (uint i = 0; i < c; i++) {
00269 if (EndOfBuffer(buffer) || x >= info->width) return false;
00270 *pixel++ = ReadByte(buffer);
00271 x++;
00272 }
00273
00274 SkipBytes(buffer, c % 2);
00275 break;
00276 }
00277 }
00278 } else {
00279
00280
00281
00282 for (uint i = 0; x < info->width && i < n; i++) {
00283 *pixel++ = c;
00284 x++;
00285 }
00286 }
00287 }
00288 return true;
00289 }
00290
00294 static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00295 {
00296 uint x, y;
00297 byte pad = GB(4 - info->width * 3, 0, 2);
00298 byte *pixel_row;
00299 for (y = info->height; y > 0; y--) {
00300 pixel_row = &data->bitmap[(y - 1) * info->width * 3];
00301 for (x = 0; x < info->width; x++) {
00302 if (EndOfBuffer(buffer)) return false;
00303 *(pixel_row + 2) = ReadByte(buffer);
00304 *(pixel_row + 1) = ReadByte(buffer);
00305 *pixel_row = ReadByte(buffer);
00306 pixel_row += 3;
00307 }
00308
00309 SkipBytes(buffer, pad);
00310 }
00311 return true;
00312 }
00313
00314
00315
00316
00317 bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00318 {
00319 uint32 header_size;
00320 assert(info != NULL);
00321 MemSetT(info, 0);
00322
00323
00324 if (ReadWord(buffer) != 0x4D42) return false;
00325 SkipBytes(buffer, 8);
00326 info->offset = ReadDword(buffer);
00327
00328
00329 header_size = ReadDword(buffer);
00330 if (header_size < 12) return false;
00331
00332 info->os2_bmp = (header_size == 12);
00333
00334 if (info->os2_bmp) {
00335 info->width = ReadWord(buffer);
00336 info->height = ReadWord(buffer);
00337 header_size -= 8;
00338 } else {
00339 info->width = ReadDword(buffer);
00340 info->height = ReadDword(buffer);
00341 header_size -= 12;
00342 }
00343
00344 if (ReadWord(buffer) != 1) return false;
00345
00346 info->bpp = ReadWord(buffer);
00347 if (info->bpp != 1 && info->bpp != 4 && info->bpp != 8 && info->bpp != 24) {
00348
00349 return false;
00350 }
00351
00352
00353 if ((header_size -= 4) >= 4) {
00354 info->compression = ReadDword(buffer);
00355 header_size -= 4;
00356 }
00357
00358
00359 if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false;
00360
00361 if (info->bpp <= 8) {
00362 uint i;
00363
00364
00365 if (header_size >= 16) {
00366 SkipBytes(buffer, 12);
00367 info->palette_size = ReadDword(buffer);
00368 SkipBytes(buffer, header_size - 16);
00369 }
00370 if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
00371
00372 data->palette = CallocT<Colour>(info->palette_size);
00373
00374 for (i = 0; i < info->palette_size; i++) {
00375 data->palette[i].b = ReadByte(buffer);
00376 data->palette[i].g = ReadByte(buffer);
00377 data->palette[i].r = ReadByte(buffer);
00378 if (!info->os2_bmp) SkipBytes(buffer, 1);
00379 }
00380 }
00381
00382 return buffer->real_pos <= info->offset;
00383 }
00384
00385
00386
00387
00388
00389 bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00390 {
00391 assert(info != NULL && data != NULL);
00392
00393 data->bitmap = CallocT<byte>(info->width * info->height * ((info->bpp == 24) ? 3 : 1));
00394
00395
00396 SetStreamOffset(buffer, info->offset);
00397 switch (info->compression) {
00398 case 0:
00399 switch (info->bpp) {
00400 case 1: return BmpRead1(buffer, info, data);
00401 case 4: return BmpRead4(buffer, info, data);
00402 case 8: return BmpRead8(buffer, info, data);
00403 case 24: return BmpRead24(buffer, info, data);
00404 default: NOT_REACHED();
00405 }
00406 case 1: return BmpRead8Rle(buffer, info, data);
00407 case 2: return BmpRead4Rle(buffer, info, data);
00408 default: NOT_REACHED();
00409 }
00410 }
00411
00412 void BmpDestroyData(BmpData *data)
00413 {
00414 assert(data != NULL);
00415 free(data->palette);
00416 free(data->bitmap);
00417 }