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 i;
00134 uint x = 0;
00135 uint y = info->height - 1;
00136 byte n, c, b;
00137 byte *pixel = &data->bitmap[y * info->width];
00138 while (y != 0 || x < info->width) {
00139 if (EndOfBuffer(buffer)) return false;
00140 n = ReadByte(buffer);
00141 c = ReadByte(buffer);
00142 if (n == 0) {
00143 switch (c) {
00144 case 0:
00145 x = 0;
00146 pixel = &data->bitmap[--y * info->width];
00147 break;
00148 case 1:
00149 x = info->width;
00150 y = 0;
00151 pixel = NULL;
00152 break;
00153 case 2:
00154 x += ReadByte(buffer);
00155 i = ReadByte(buffer);
00156 if (x >= info->width || (y == 0 && i > 0)) return false;
00157 y -= i;
00158 pixel = &data->bitmap[y * info->width + x];
00159 break;
00160 default:
00161 i = 0;
00162 while (i++ < c) {
00163 if (EndOfBuffer(buffer) || x >= info->width) return false;
00164 b = ReadByte(buffer);
00165 *pixel++ = GB(b, 4, 4);
00166 x++;
00167 if (x < info->width && i++ < c) {
00168 *pixel++ = GB(b, 0, 4);
00169 x++;
00170 }
00171 }
00172
00173 SkipBytes(buffer, ((c + 1) / 2) % 2);
00174 break;
00175 }
00176 } else {
00177 i = 0;
00178 while (i++ < n) {
00179 if (EndOfBuffer(buffer) || x >= info->width) return false;
00180 *pixel++ = GB(c, 4, 4);
00181 x++;
00182 if (x < info->width && i++ < n) {
00183 *pixel++ = GB(c, 0, 4);
00184 x++;
00185 }
00186 }
00187 }
00188 }
00189 return true;
00190 }
00191
00195 static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00196 {
00197 uint i;
00198 uint y;
00199 byte pad = GB(4 - info->width, 0, 2);
00200 byte *pixel;
00201 for (y = info->height; y > 0; y--) {
00202 if (EndOfBuffer(buffer)) return false;
00203 pixel = &data->bitmap[(y - 1) * info->width];
00204 for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer);
00205
00206 SkipBytes(buffer, pad);
00207 }
00208 return true;
00209 }
00210
00214 static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00215 {
00216 uint i;
00217 uint x = 0;
00218 uint y = info->height - 1;
00219 byte n, c;
00220 byte *pixel = &data->bitmap[y * info->width];
00221 while (y != 0 || x < info->width) {
00222 if (EndOfBuffer(buffer)) return false;
00223 n = ReadByte(buffer);
00224 c = ReadByte(buffer);
00225 if (n == 0) {
00226 switch (c) {
00227 case 0:
00228 x = 0;
00229 pixel = &data->bitmap[--y * info->width];
00230 break;
00231 case 1:
00232 x = info->width;
00233 y = 0;
00234 pixel = NULL;
00235 break;
00236 case 2:
00237 x += ReadByte(buffer);
00238 i = ReadByte(buffer);
00239 if (x >= info->width || (y == 0 && i > 0)) return false;
00240 y -= i;
00241 pixel = &data->bitmap[y * info->width + x];
00242 break;
00243 default:
00244 if ((x += c) > info->width) return false;
00245 for (i = 0; i < c; i++) *pixel++ = ReadByte(buffer);
00246
00247 SkipBytes(buffer, c % 2);
00248 break;
00249 }
00250 } else {
00251 for (i = 0; i < n; i++) {
00252 if (x >= info->width) return false;
00253 *pixel++ = c;
00254 x++;
00255 }
00256 }
00257 }
00258 return true;
00259 }
00260
00264 static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00265 {
00266 uint x, y;
00267 byte pad = GB(4 - info->width * 3, 0, 2);
00268 byte *pixel_row;
00269 for (y = info->height; y > 0; y--) {
00270 pixel_row = &data->bitmap[(y - 1) * info->width * 3];
00271 for (x = 0; x < info->width; x++) {
00272 if (EndOfBuffer(buffer)) return false;
00273 *(pixel_row + 2) = ReadByte(buffer);
00274 *(pixel_row + 1) = ReadByte(buffer);
00275 *pixel_row = ReadByte(buffer);
00276 pixel_row += 3;
00277 }
00278
00279 SkipBytes(buffer, pad);
00280 }
00281 return true;
00282 }
00283
00284
00285
00286
00287 bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00288 {
00289 uint32 header_size;
00290 assert(info != NULL);
00291 MemSetT(info, 0);
00292
00293
00294 if (ReadWord(buffer) != 0x4D42) return false;
00295 SkipBytes(buffer, 8);
00296 info->offset = ReadDword(buffer);
00297
00298
00299 header_size = ReadDword(buffer);
00300 if (header_size < 12) return false;
00301
00302 info->os2_bmp = (header_size == 12);
00303
00304 if (info->os2_bmp) {
00305 info->width = ReadWord(buffer);
00306 info->height = ReadWord(buffer);
00307 header_size -= 8;
00308 } else {
00309 info->width = ReadDword(buffer);
00310 info->height = ReadDword(buffer);
00311 header_size -= 12;
00312 }
00313
00314 if (ReadWord(buffer) != 1) return false;
00315
00316 info->bpp = ReadWord(buffer);
00317 if (info->bpp != 1 && info->bpp != 4 && info->bpp != 8 && info->bpp != 24) {
00318
00319 return false;
00320 }
00321
00322
00323 if ((header_size -= 4) >= 4) {
00324 info->compression = ReadDword(buffer);
00325 header_size -= 4;
00326 }
00327
00328
00329 if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false;
00330
00331 if (info->bpp <= 8) {
00332 uint i;
00333
00334
00335 if (header_size >= 16) {
00336 SkipBytes(buffer, 12);
00337 info->palette_size = ReadDword(buffer);
00338 SkipBytes(buffer, header_size - 16);
00339 }
00340 if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
00341
00342 data->palette = CallocT<Colour>(info->palette_size);
00343
00344 for (i = 0; i < info->palette_size; i++) {
00345 data->palette[i].b = ReadByte(buffer);
00346 data->palette[i].g = ReadByte(buffer);
00347 data->palette[i].r = ReadByte(buffer);
00348 if (!info->os2_bmp) SkipBytes(buffer, 1);
00349 }
00350 }
00351
00352 return buffer->real_pos <= info->offset;
00353 }
00354
00355
00356
00357
00358
00359 bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
00360 {
00361 assert(info != NULL && data != NULL);
00362
00363 data->bitmap = CallocT<byte>(info->width * info->height * ((info->bpp == 24) ? 3 : 1));
00364
00365
00366 SetStreamOffset(buffer, info->offset);
00367 switch (info->compression) {
00368 case 0:
00369 switch (info->bpp) {
00370 case 1: return BmpRead1(buffer, info, data);
00371 case 4: return BmpRead4(buffer, info, data);
00372 case 8: return BmpRead8(buffer, info, data);
00373 case 24: return BmpRead24(buffer, info, data);
00374 default: NOT_REACHED();
00375 }
00376 case 1: return BmpRead8Rle(buffer, info, data);
00377 case 2: return BmpRead4Rle(buffer, info, data);
00378 default: NOT_REACHED();
00379 }
00380 }
00381
00382 void BmpDestroyData(BmpData *data)
00383 {
00384 assert(data != NULL);
00385 free(data->palette);
00386 free(data->bitmap);
00387 }