00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <string.h>
00010 #include "corona.h"
00011 #include "SimpleImage.h"
00012 #include "Utility.h"
00013
00014
00015 namespace corona {
00016
00017 struct Header {
00018 bool os2;
00019
00020 int file_size;
00021 int data_offset;
00022 int width;
00023 int height;
00024 int bpp;
00025 int compression;
00026
00027 int pitch;
00028 int image_size;
00029
00030 auto_array<BGR> palette;
00031 int palette_size;
00032
00033
00034
00035 u32 bf_red_mask, bf_red_shift, bf_red_rshift;
00036 u32 bf_green_mask, bf_green_shift, bf_green_rshift;
00037 u32 bf_blue_mask, bf_blue_shift, bf_blue_rshift;
00038 };
00039
00040
00041 bool ReadHeader(File* file, Header& h);
00042 bool ReadInfoHeader(File* file, Header& h);
00043 bool ReadPalette(File* file, Header& h);
00044 Image* DecodeBitmap(File* file, const Header& h);
00045
00046
00047 Image* OpenBMP(File* file) {
00048 Header h;
00049 if (ReadHeader(file, h) &&
00050 ReadInfoHeader(file, h) &&
00051 ReadPalette(file, h)) {
00052
00053 return DecodeBitmap(file, h);
00054
00055 } else {
00056
00057 return 0;
00058
00059 }
00060 }
00061
00062
00063 bool ReadHeader(File* file, Header& h) {
00064 byte header[14];
00065 if (file->read(header, 14) != 14) {
00066 return false;
00067 }
00068
00069
00070 if (header[0] != 'B' || header[1] != 'M') {
00071 return false;
00072 }
00073
00074 h.file_size = read32_le(header + 2);
00075 h.data_offset = read32_le(header + 10);
00076 return true;
00077 }
00078
00079
00080 bool ReadInfoHeader(File* file, Header& h) {
00081
00082 const int HEADER_READ_SIZE = 24;
00083
00084
00085 byte header[HEADER_READ_SIZE];
00086 if (file->read(header, HEADER_READ_SIZE) != HEADER_READ_SIZE) {
00087 return false;
00088 }
00089
00090 int size = read32_le(header + 0);
00091 int width;
00092 int height;
00093 int planes;
00094 int bpp;
00095 int compression;
00096 int image_size;
00097
00098 if (size < 40) {
00099 if (size < 12) {
00100 return false;
00101 }
00102
00103 h.os2 = true;
00104 width = read16_le(header + 4);
00105 height = read16_le(header + 6);
00106 planes = read16_le(header + 8);
00107 bpp = read16_le(header + 10);
00108 compression = 0;
00109 image_size = 0;
00110
00111 } else {
00112
00113 h.os2 = false;
00114 width = read32_le(header + 4);
00115 height = read32_le(header + 8);
00116 planes = read16_le(header + 12);
00117 bpp = read16_le(header + 14);
00118 compression = read32_le(header + 16);
00119 image_size = read32_le(header + 20);
00120
00121 }
00122
00123
00124 if (planes != 1) {
00125 return false;
00126 }
00127
00128
00129
00130 int line_size = 0;
00131 if (compression == 0 || compression == 3) {
00132 line_size = (width * bpp + 7) / 8;
00133 line_size = (line_size + 3) / 4 * 4;
00134 image_size = line_size * height;
00135 }
00136
00137 h.width = width;
00138 h.height = height;
00139 h.bpp = bpp;
00140 h.compression = compression;
00141 h.pitch = line_size;
00142 h.image_size = image_size;
00143
00144
00145 file->seek(size - HEADER_READ_SIZE, File::CURRENT);
00146
00147 return true;
00148 }
00149
00150
00151
00152
00153 int count_right_zeroes(u32 n) {
00154 int total = 0;
00155 u32 c = 1;
00156 while ((total < 32) && ((n & c) == 0)) {
00157 c <<= 1;
00158 ++total;
00159 }
00160 return total;
00161 }
00162
00163
00164
00165 int count_ones(u32 n) {
00166 int total = 0;
00167 u32 c = 1;
00168 for (int i = 0; i < 32; ++i) {
00169 if (n & c) {
00170 ++total;
00171 }
00172 c <<= 1;
00173 }
00174 return total;
00175 }
00176
00177 bool ReadPalette(File* file, Header& h) {
00178
00179
00180 h.bf_red_mask = h.bf_red_shift = h.bf_red_rshift = 0;
00181 h.bf_green_mask = h.bf_green_shift = h.bf_green_rshift = 0;
00182 h.bf_blue_mask = h.bf_blue_shift = h.bf_blue_rshift = 0;
00183
00184
00185 if (h.bpp > 8) {
00186 h.palette_size = 0;
00187
00188
00189 if (h.compression == 3) {
00190
00191 auto_array<byte> bitfields(new byte[12]);
00192 if (file->read(bitfields, 12) != 12) {
00193 return false;
00194 }
00195
00196 h.bf_red_mask = read32_le((byte*)bitfields);
00197 h.bf_green_mask = read32_le((byte*)bitfields + 4);
00198 h.bf_blue_mask = read32_le((byte*)bitfields + 8);
00199
00200
00201 h.bf_red_shift = count_right_zeroes(h.bf_red_mask);
00202 h.bf_green_shift = count_right_zeroes(h.bf_green_mask);
00203 h.bf_blue_shift = count_right_zeroes(h.bf_blue_mask);
00204 h.bf_red_rshift = 8 - count_ones(h.bf_red_mask);
00205 h.bf_green_rshift = 8 - count_ones(h.bf_green_mask);
00206 h.bf_blue_rshift = 8 - count_ones(h.bf_blue_mask);
00207
00208
00209 } else {
00210
00211 if (h.bpp == 16) {
00212
00213 h.bf_red_mask = 0x7C00;
00214 h.bf_red_shift = 10;
00215 h.bf_red_rshift = 3;
00216
00217 h.bf_green_mask = 0x03E0;
00218 h.bf_green_shift = 5;
00219 h.bf_green_rshift = 3;
00220
00221 h.bf_blue_mask = 0x001F;
00222 h.bf_blue_shift = 0;
00223 h.bf_blue_rshift = 3;
00224
00225 } else if (h.bpp == 32) {
00226
00227
00228 h.bf_red_mask = 0x00FF0000; h.bf_red_shift = 16;
00229 h.bf_green_mask = 0x0000FF00; h.bf_green_shift = 8;
00230 h.bf_blue_mask = 0x000000FF; h.bf_blue_shift = 0;
00231
00232 }
00233 }
00234
00235 return true;
00236 }
00237
00238 if (h.bpp <= 8) {
00239 h.palette_size = 1 << h.bpp;
00240 } else {
00241 h.palette_size = 0;
00242 return true;
00243 }
00244 h.palette = new BGR[h.palette_size];
00245
00246
00247 const int buffer_size = h.palette_size * (h.os2 ? 3 : 4);
00248 auto_array<byte> buffer(new byte[buffer_size]);
00249 if (file->read(buffer, buffer_size) != buffer_size) {
00250 return false;
00251 }
00252
00253 byte* in = buffer;
00254 BGR* out = h.palette;
00255 for (int i = 0; i < h.palette_size; ++i) {
00256 out->blue = *in++;
00257 out->green = *in++;
00258 out->red = *in++;
00259 if (!h.os2) {
00260 ++in;
00261 }
00262 ++out;
00263 }
00264
00265 return true;
00266 }
00267
00268
00269 bool advance(int& x, int& y, const Header& h) {
00270 if (++x >= h.width) {
00271 x = 0;
00272 if (++y >= h.height) {
00273 return false;
00274 }
00275 }
00276 return true;
00277 }
00278
00279 Image* ReadBitmap1(const byte* raster_data, const Header& h) {
00280 auto_array<byte> pixels(new byte[h.width * h.height]);
00281
00282 auto_array<BGR> palette(new BGR[256]);
00283 memset(palette, 0, 256 * sizeof(BGR));
00284 memcpy(palette, h.palette, h.palette_size * sizeof(BGR));
00285
00286 for (int i = 0; i < h.height; ++i) {
00287 const byte* in = raster_data + i * h.pitch;
00288 byte* out = pixels + (h.height - i - 1) * h.width;
00289
00290 int mask = 128;
00291 for (int j = 0; j < h.width; ++j) {
00292 *out++ = (*in & mask) > 0;
00293
00294 mask >>= 1;
00295 if (mask == 0) {
00296 ++in;
00297 mask = 128;
00298 }
00299 }
00300 }
00301
00302 return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
00303 (byte*)palette.release(), 256, PF_B8G8R8);
00304 }
00305
00306 Image* ReadBitmap4(const byte* raster_data, const Header& h) {
00307 auto_array<byte> pixels(new byte[h.width * h.height]);
00308
00309 auto_array<BGR> palette(new BGR[256]);
00310 memset(palette, 0, 256 * sizeof(BGR));
00311 memcpy(palette, h.palette, h.palette_size * sizeof(BGR));
00312
00313 for (int i = 0; i < h.height; ++i) {
00314 const byte* in = raster_data + i * h.pitch;
00315 byte* out = pixels + (h.height - i - 1) * h.width;
00316
00317 for (int j = 0; j < h.width / 2; ++j) {
00318 *out++ = (*in >> 4);
00319 *out++ = (*in & 0x0F);
00320
00321 ++in;
00322 }
00323
00324 if (h.width % 2) {
00325 *out++ = (*in >> 4);
00326 }
00327 }
00328
00329 return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
00330 (byte*)palette.release(), 256, PF_B8G8R8);
00331 }
00332
00333 Image* ReadBitmapRLE4(const byte* raster_data, const Header& h) {
00334 auto_array<byte> pixels(new byte[h.width * h.height]);
00335
00336 auto_array<BGR> palette(new BGR[256]);
00337 memset(palette, 0, 256 * sizeof(BGR));
00338 memcpy(palette, h.palette, h.palette_size * sizeof(BGR));
00339
00340
00341 memset(pixels, 0, h.width * h.height);
00342
00343
00344
00345 int x = 0;
00346 int y = 0;
00347
00348 const byte* in = raster_data;
00349 while (in - raster_data < h.image_size - 1) {
00350 byte n = *in++;
00351 byte c = *in++;
00352
00353 if (n == 0) {
00354
00355 if (c == 0) {
00356 x = 0;
00357
00358
00359
00360 if (y >= h.height) {
00361
00362 break;
00363 }
00364 } else if (c == 1) {
00365 break;
00366 } else if (c == 2) {
00367
00368
00369 if (in - raster_data >= h.image_size - 1) {
00370 break;
00371 }
00372
00373
00374
00375 int dx = *in++;
00376 int dy = *in++;
00377 x = (x + dx) % h.width;
00378 y += dy + (x + dx) / h.width;
00379 if (y >= h.height) {
00380
00381 break;
00382 }
00383
00384 } else {
00385
00386
00387
00388 int num_bytes = (c + 3) / 4 * 2;
00389
00390
00391 if (in - raster_data > h.image_size - num_bytes) {
00392 break;
00393 }
00394
00395
00396 int i = 0;
00397 int j = 0;
00398 while (true) {
00399 byte l = (in[j] & 0xF0) >> 4;
00400 byte r = (in[j] & 0x0F);
00401 ++j;
00402
00403 pixels[y * h.width + x] = l;
00404 if (!advance(x, y, h) || ++i >= c) {
00405 break;
00406 }
00407
00408 pixels[y * h.width + x] = r;
00409 if (!advance(x, y, h) || ++i >= c) {
00410 break;
00411 }
00412 }
00413
00414 in += num_bytes;
00415 }
00416
00417 } else {
00418
00419
00420 byte lc = (c & 0xF0) >> 4;
00421 byte rc = c & 0x0F;
00422
00423 int i = 0;
00424 while (true) {
00425 pixels[y * h.width + x] = lc;
00426 if (!advance(x, y, h) || ++i >= n) {
00427 break;
00428 }
00429
00430 pixels[y * h.width + x] = rc;
00431 if (!advance(x, y, h) || ++i >= n) {
00432 break;
00433 }
00434 }
00435
00436 }
00437 }
00438
00439
00440 int pitch = h.width;
00441 auto_array<byte> row(new byte[pitch]);
00442 for (int i = 0; i < h.height / 2; ++i) {
00443 int j = h.height - i - 1;
00444 memcpy((byte*)row, pixels + i * pitch, pitch);
00445 memcpy(pixels + i * pitch, pixels + j * pitch, pitch);
00446 memcpy(pixels + j * pitch, (byte*)row, pitch);
00447 }
00448
00449 return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
00450 (byte*)palette.release(), 256, PF_B8G8R8);
00451 }
00452
00453 Image* ReadBitmap8(const byte* raster_data, const Header& h) {
00454 auto_array<byte> pixels(new byte[h.width * h.height]);
00455
00456 auto_array<BGR> palette(new BGR[256]);
00457 memset(palette, 0, 256 * sizeof(BGR));
00458 memcpy(palette, h.palette, h.palette_size * sizeof(BGR));
00459
00460 for (int i = 0; i < h.height; ++i) {
00461 const byte* in = raster_data + i * h.pitch;
00462 byte* out = pixels + (h.height - i - 1) * h.width;
00463
00464 for (int j = 0; j < h.width; ++j) {
00465 *out++ = *in++;
00466 }
00467 }
00468
00469 return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
00470 (byte*)palette.release(), 256, PF_B8G8R8);
00471 }
00472
00473 Image* ReadBitmapRLE8(const byte* raster_data, const Header& h) {
00474 auto_array<byte> pixels(new byte[h.width * h.height]);
00475
00476 auto_array<BGR> palette(new BGR[256]);
00477 memset(palette, 0, 256 * sizeof(BGR));
00478 memcpy(palette, h.palette, h.palette_size * sizeof(BGR));
00479
00480
00481 memset(pixels, 0, h.width * h.height);
00482
00483
00484
00485 int x = 0;
00486 int y = 0;
00487
00488 const byte* in = raster_data;
00489 while (in - raster_data < h.image_size - 1) {
00490 byte n = *in++;
00491 byte c = *in++;
00492
00493 if (n == 0) {
00494
00495 if (c == 0) {
00496 x = 0;
00497
00498
00499
00500 if (y >= h.height) {
00501
00502 break;
00503 }
00504 } else if (c == 1) {
00505 break;
00506 } else if (c == 2) {
00507
00508
00509 if (in - raster_data >= h.image_size - 1) {
00510 break;
00511 }
00512
00513
00514
00515 int dx = *in++;
00516 int dy = *in++;
00517 x = (x + dx) % h.width;
00518 y += dy + (x + dx) / h.width;
00519 if (y >= h.height) {
00520
00521 break;
00522 }
00523
00524 } else {
00525
00526
00527 int num_bytes = (c + 1) / 2 * 2;
00528
00529
00530 if (in - raster_data > h.image_size - num_bytes) {
00531 break;
00532 }
00533
00534
00535 int i = 0;
00536 int j = 0;
00537 while (true) {
00538 pixels[y * h.width + x] = in[j++];
00539 if (!advance(x, y, h) || ++i >= c) {
00540 break;
00541 }
00542 }
00543
00544 in += num_bytes;
00545 }
00546
00547 } else {
00548
00549 int i = 0;
00550 while (true) {
00551 pixels[y * h.width + x] = c;
00552 if (!advance(x, y, h) || ++i >= n) {
00553 break;
00554 }
00555 }
00556
00557 }
00558 }
00559
00560
00561 int pitch = h.width;
00562 auto_array<byte> row(new byte[pitch]);
00563 for (int i = 0; i < h.height / 2; ++i) {
00564 int j = h.height - i - 1;
00565 memcpy((byte*)row, pixels + i * pitch, pitch);
00566 memcpy(pixels + i * pitch, pixels + j * pitch, pitch);
00567 memcpy(pixels + j * pitch, (byte*)row, pitch);
00568 }
00569
00570 return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
00571 (byte*)palette.release(), 256, PF_B8G8R8);
00572 }
00573
00574 Image* ReadBitmap16(const byte* raster_data, const Header& h) {
00575 auto_array<RGB> pixels(new RGB[h.width * h.height]);
00576
00577 for (int i = 0; i < h.height; ++i) {
00578 const byte* in = raster_data + i * h.pitch;
00579 RGB* out = pixels + (h.height - i - 1) * h.width;
00580
00581 for (int j = 0; j < h.width; ++j) {
00582 int clr = read16_le(in);
00583 in += 2;
00584
00585 #define C16(C) \
00586 (byte)( ((clr & h.bf_##C##_mask) >> h.bf_##C##_shift) << h.bf_##C##_rshift);
00587
00588 out->red = C16(red);
00589 out->green = C16(green);
00590 out->blue = C16(blue);
00591 ++out;
00592
00593 #undef C16
00594 }
00595 }
00596
00597 return new SimpleImage(h.width, h.height, PF_R8G8B8,
00598 (byte*)pixels.release());
00599 }
00600
00601 Image* ReadBitmap24(const byte* raster_data, const Header& h) {
00602 auto_array<BGR> pixels(new BGR[h.width * h.height]);
00603
00604 for (int i = 0; i < h.height; ++i) {
00605 const byte* in = raster_data + i * h.pitch;
00606 BGR* out = pixels + (h.height - i - 1) * h.width;
00607
00608 for (int j = 0; j < h.width; ++j) {
00609 out->blue = *in++;
00610 out->green = *in++;
00611 out->red = *in++;
00612 ++out;
00613 }
00614 }
00615
00616 return new SimpleImage(h.width, h.height, PF_B8G8R8,
00617 (byte*)pixels.release());
00618 }
00619
00620 Image* ReadBitmap32(const byte* raster_data, const Header& h) {
00621 auto_array<RGB> pixels(new RGB[h.width * h.height]);
00622
00623 for (int i = 0; i < h.height; ++i) {
00624 const byte* in = raster_data + i * h.pitch;
00625 RGB* out = pixels + (h.height - i - 1) * h.width;
00626
00627 for (int j = 0; j < h.width; ++j) {
00628 u32 pixel = read32_le(in);
00629 in += 4;
00630 out->red = (byte)((pixel & h.bf_red_mask) >> h.bf_red_shift);
00631 out->green = (byte)((pixel & h.bf_green_mask) >> h.bf_green_shift);
00632 out->blue = (byte)((pixel & h.bf_blue_mask) >> h.bf_blue_shift);
00633 ++out;
00634 }
00635 }
00636
00637 return new SimpleImage(h.width, h.height, PF_R8G8B8,
00638 (byte*)pixels.release());
00639 }
00640
00641 Image* DecodeBitmap(File* file, const Header& h) {
00642
00643 if (!file->seek(h.data_offset, File::BEGIN)) {
00644 return 0;
00645 }
00646
00647
00648 auto_array<byte> raster_data(new byte[h.image_size]);
00649 if (file->read(raster_data, h.image_size) != h.image_size) {
00650 return 0;
00651 }
00652
00653
00654 auto_array<byte> pixels(new byte[h.width * h.height * 3]);
00655
00656 typedef Image* (*Decoder)(const byte* raster_data, const Header& h);
00657
00658 Decoder decoder = 0;
00659
00660 if (h.bpp == 1 && h.compression == 0) { decoder = ReadBitmap1; }
00661 else if (h.bpp == 4 && h.compression == 0) { decoder = ReadBitmap4; }
00662 else if (h.bpp == 4 && h.compression == 2) { decoder = ReadBitmapRLE4; }
00663 else if (h.bpp == 8 && h.compression == 0) { decoder = ReadBitmap8; }
00664 else if (h.bpp == 8 && h.compression == 1) { decoder = ReadBitmapRLE8; }
00665 else if (h.bpp == 16 && (h.compression == 0 ||
00666 h.compression == 3)) { decoder = ReadBitmap16; }
00667 else if (h.bpp == 24 && h.compression == 0) { decoder = ReadBitmap24; }
00668 else if (h.bpp == 32 && (h.compression == 0 ||
00669 h.compression == 3)) { decoder = ReadBitmap32; }
00670
00671 if (decoder) {
00672 return decoder(raster_data.get(), h);
00673 } else {
00674 return 0;
00675 }
00676 }
00677
00678 }