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