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