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