#define BMP_COLORS_NUM 16
class CFileBMP {
U16 type;
U32 file_size;
U32 reserved;
U32 data_offset;
U32 header_size;
U32 width;
U32 height;
U16 planes;
U16 bit_cnt;
U32 compression;
U32 image_size;
U32 x_pixs_per_meter;
U32 y_pixs_per_meter;
U32 colors_used;
U32 important_colors;
U0 end;
CBGR24 palette[BMP_COLORS_NUM];
};
public
CFileBMP *BMP4To(CDC *dc) {
U8 *src, *ptr;
CBGR48 palette[COLORS_NUM];
I64 i, x, y, w = dc->width >> 1,
size = sizeof(CFileBMP) + dc->width * dc->height >> 1;
CFileBMP *bmp = CAlloc(size);
bmp->type = 'BM';
bmp->planes = 1;
bmp->file_size = size;
bmp->data_offset = sizeof(CFileBMP);
bmp->header_size = offset(CFileBMP.end) - offset(CFileBMP.header_size);
bmp->width = dc->width;
bmp->height = dc->height;
bmp->bit_cnt = 4;
bmp->image_size = dc->width * dc->height >> 1;
GrPaletteGet(palette);
#assert COLORS_NUM == BMP_COLORS_NUM
for (i = 0; i < BMP_COLORS_NUM; i++) {
bmp->palette[i].b = palette[i].b >> 8;
bmp->palette[i].g = palette[i].g >> 8;
bmp->palette[i].r = palette[i].r >> 8;
bmp->palette[i].pad = 0;
}
ptr = bmp(U8 *) + bmp->data_offset;
for (y = dc->height - 1; y >= 0; y--) {
src = y * dc->width_internal + dc->body;
for (x = 0; x < w; x++) {
*ptr |= (*src++ & 15) << 4;
*ptr |= *src++ & 15;
ptr++;
}
}
return bmp;
}
public
CFileBMP *BMPRLE4To(CDC *dc) {
U8 *src, *ptr, *start;
I64 i, x, y, w = dc->width, cnt, pattern;
CBGR48 palette[COLORS_NUM];
CFileBMP *bmp = CAlloc(sizeof(CFileBMP) + 2 * (dc->width + 1) * dc->height);
bmp->type = 'BM';
bmp->planes = 1;
bmp->data_offset = sizeof(CFileBMP);
bmp->header_size = offset(CFileBMP.end) - offset(CFileBMP.header_size);
bmp->width = dc->width;
bmp->height = dc->height;
bmp->bit_cnt = 4;
bmp->compression = 2;
GrPaletteGet(palette);
#assert COLORS_NUM == BMP_COLORS_NUM
for (i = 0; i < BMP_COLORS_NUM; i++) {
bmp->palette[i].b = palette[i].b >> 8;
bmp->palette[i].g = palette[i].g >> 8;
bmp->palette[i].r = palette[i].r >> 8;
bmp->palette[i].pad = 0;
}
start = ptr = bmp(U8 *) + bmp->data_offset;
for (y = dc->height - 1; y >= 0; y--) {
src = y * dc->width_internal + dc->body;
x = 0;
while (x < w) {
pattern = (src[0] & 15) << 4 + src[1] & 15;
if (x + 1 < w && src[0] & 15 == src[1] & 15) {
src += 2;
cnt = 2;
x += 2;
while (x < w && cnt < U8_MAX) {
if (*src & 15 == pattern & 15) {
src++;
cnt++;
x++;
} else
break;
}
} else {
src += 2;
if (x + 1 < w)
cnt = 2;
else
cnt = 1;
x += 2;
}
*ptr++ = cnt;
*ptr++ = pattern;
}
*ptr(U16 *)++ = 0;
}
bmp->image_size = ptr - start;
bmp->file_size = sizeof(CFileBMP) + bmp->image_size;
return bmp;
}
public
CFileBMP *BMP24To(CDC *dc) {
U8 *src;
I64 i, x, y,
size = offset(CFileBMP.end) + dc->width * dc->height * sizeof(CBGR24);
CBGR24 *bgr;
CFileBMP *bmp = CAlloc(size);
bmp->type = 'BM';
bmp->planes = 1;
bmp->file_size = size;
bmp->data_offset = offset(CFileBMP.end);
bmp->header_size = offset(CFileBMP.end) - offset(CFileBMP.header_size);
bmp->width = dc->width;
bmp->height = dc->height;
bmp->bit_cnt = 32;
bmp->image_size = dc->width * dc->height << 2;
bgr = bmp(U8 *) + bmp->data_offset;
for (y = dc->height - 1; y >= 0; y--) {
src = y * dc->width_internal + dc->body;
for (x = 0; x < dc->width; x++) {
i = *src++;
if (i & BLUE)
bgr->b = 0x7F;
if (i & GREEN)
bgr->g = 0x7F;
if (i & RED)
bgr->r = 0x7F;
if (i & 8) {
if (bgr->b)
bgr->b = 0xFF;
if (bgr->g)
bgr->g = 0xFF;
if (bgr->r)
bgr->r = 0xFF;
}
bgr(U8 *) += 4;
}
}
return bmp;
}
public
I64 BMPWrite(U8 *filename, CDC *dc, I64 bits = 4) {
I64 size;
CFileBMP *bmp;
if (bits == 4) {
if (IsDotZ(filename))
bmp = BMP4To(dc);
else {
bmp = BMPRLE4To(dc);
if (bmp->file_size > sizeof(CFileBMP) + dc->width * dc->height >> 1) {
Free(bmp);
bmp = BMP4To(dc);
}
}
} else if (bits == 24)
bmp = BMP24To(dc);
else {
"Format Not Supported.\n";
return 0;
}
size = bmp->file_size;
FileWrite(filename, bmp, bmp->file_size);
Free(bmp);
return size;
}
U8 *BMPPaletteNew(CFileBMP *bmp) {
I64 i, j, best, score, best_score;
CBGR48 palette[COLORS_NUM];
U8 *res = CAlloc(BMP_COLORS_NUM * sizeof(U8));
GrPaletteGet(palette);
#assert COLORS_NUM == BMP_COLORS_NUM
for (i = 0; i < BMP_COLORS_NUM; i++) {
best = i;
best_score = I64_MAX;
for (j = 0; j < BMP_COLORS_NUM; j++) {
score = SqrI64(bmp->palette[i].r - palette[j].r >> 8) +
SqrI64(bmp->palette[i].g - palette[j].g >> 8) +
SqrI64(bmp->palette[i].b - palette[j].b >> 8);
if (score < best_score) {
best = j;
best_score = score;
}
}
res[i] = best;
}
return res;
}
U8 ms_paint_palette[BMP_COLORS_NUM] = {0, 4, 2, 6, 1, 5, 3, 8,
7, 12, 10, 14, 9, 13, 11, 15};
I64 BMP24Color(CBGR24 *ptr, Bool dither_probability) {
I64 res, k;
if (dither_probability) {
k = RandU32;
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= 3 * SqrI64(k.u8[0]))
res = 8;
else
res = 0;
if (ptr->r >= k.u8[1])
res |= RED;
if (ptr->g >= k.u8[2])
res |= GREEN;
if (ptr->b >= k.u8[3])
res |= BLUE;
} else {
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= SqrI64(0x80)) {
res = WHITE;
if (ptr->r >= 0x80)
res |= RED;
if (ptr->g >= 0x80)
res |= GREEN;
if (ptr->b >= 0x80)
res |= BLUE;
} else {
res = BLACK;
if (ptr->r >= 0x40)
res |= RED;
if (ptr->g >= 0x40)
res |= GREEN;
if (ptr->b >= 0x40)
res |= BLUE;
}
}
return res;
}
public
CDC *BMPRead(U8 *filename, Bool dither_probability = FALSE,
Bool use_ms_paint_palette = FALSE) {
I64 i, j, cnt;
U8 *palette_map, *ptr;
Bool rle;
CFileBMP *bmp;
CDC *res = NULL;
if (ptr = FileRead(filename)) {
bmp = ptr;
if (0 < bmp->width < I32_MAX && 0 < bmp->height < I32_MAX) {
res = DCNew(bmp->width, bmp->height);
ptr += bmp->data_offset;
if (bmp->compression == 2)
rle = TRUE;
else
rle = FALSE;
if (use_ms_paint_palette)
palette_map = ms_paint_palette;
else
palette_map = BMPPaletteNew(bmp);
if (bmp->bit_cnt == 4) {
for (i = bmp->height - 1; i >= 0; i--)
if (rle) {
j = 0;
while (cnt = *ptr++) {
if (cnt == 1) {
res->color = palette_map[*ptr++ & 15];
GrPlot(res, j++, i);
} else {
if (cnt == 2 && *ptr >> 4 != *ptr & 15) {
res->color = palette_map[*ptr & 15];
GrPlot(res, j + 1, i);
res->color = palette_map[*ptr >> 4];
GrPlot(res, j, i);
ptr++;
j += 2;
} else {
res->color = palette_map[*ptr++ & 15];
while (cnt--)
GrPlot(res, j++, i);
}
}
}
ptr++;
} else
for (j = 0; j < (bmp->width + 7) & ~7;) {
res->color = palette_map[*ptr & 15];
GrPlot(res, j + 1, i);
res->color = palette_map[*ptr >> 4];
GrPlot(res, j, i);
ptr++;
j += 2;
}
if (!use_ms_paint_palette)
Free(palette_map);
} else if (bmp->bit_cnt == 24) {
for (i = bmp->height - 1; i >= 0; i--) {
for (j = 0; j < bmp->width; j++, ptr += 3) {
res->color = BMP24Color(ptr, dither_probability);
GrPlot(res, j, i);
}
ptr += bmp->width & 3;
}
if (!use_ms_paint_palette)
Free(palette_map);
} else if (bmp->bit_cnt >= 32) {
for (i = bmp->height - 1; i >= 0; i--)
for (j = 0; j < bmp->width; j++, ptr += 4) {
res->color = BMP24Color(ptr, dither_probability);
GrPlot(res, j, i);
}
if (!use_ms_paint_palette)
Free(palette_map);
} else {
"Format Not Supported.\n";
DCDel(res);
res = NULL;
}
} else
"Invalid BMP File\n";
Free(bmp);
}
return res;
}
U0 BESplash() {
CDC *dc = DCAlias;
CDC *bmp_dc;
WinMax;
DocClear;
if (bmp_dc = BMPRead("T:/BeforeEcbatana/Splash.BMP", TRUE, FALSE)) {
GrBlot(dc, (GR_WIDTH - bmp_dc->width) / 2, (GR_HEIGHT - bmp_dc->height) / 2,
bmp_dc);
DCDel(bmp_dc);
} else {
dc->color = YELLOW;
GrPrint(dc, GR_WIDTH / 2 - 100, 50, "BeforeEcbatana");
}
DCDel(dc);
}
BESplash;