Support GIMP bmp files.

Change-Id: I7380ceeaf696b67e1641d24e7b932e3d74770932
This commit is contained in:
Thomas Martitz 2013-12-21 17:12:21 +01:00
parent 21ff83295e
commit ef92ed4a6a
2 changed files with 67 additions and 44 deletions

View file

@ -92,35 +92,35 @@ struct bmp_header {
uint32_t clr_important; /* important color count */ uint32_t clr_important; /* important color count */
} STRUCT_PACKED; } STRUCT_PACKED;
union rgb_union {
struct { /* Little endian */
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
};
uint32_t raw;
};
/* masks for supported BI_BITFIELDS encodings (16/32 bit) */ /* masks for supported BI_BITFIELDS encodings (16/32 bit) */
static const struct uint8_rgb bitfields[3][3] = { static const struct uint8_rgb bitfields[][4] = {
/* 15bit */ /* 15bit */
{ {
{ .blue = 0x00, .green = 0x7c, .red = 0x00 }, { .blue = 0x00, .green = 0x7c, .red = 0x00, .alpha = 0x00 },
{ .blue = 0xe0, .green = 0x03, .red = 0x00 }, { .blue = 0xe0, .green = 0x03, .red = 0x00, .alpha = 0x00 },
{ .blue = 0x1f, .green = 0x00, .red = 0x00 }, { .blue = 0x1f, .green = 0x00, .red = 0x00, .alpha = 0x00 },
{ .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0x00 },
}, },
/* 16bit */ /* 16bit */
{ {
{ .blue = 0x00, .green = 0xf8, .red = 0x00 }, { .blue = 0x00, .green = 0xf8, .red = 0x00, .alpha = 0x00 },
{ .blue = 0xe0, .green = 0x07, .red = 0x00 }, { .blue = 0xe0, .green = 0x07, .red = 0x00, .alpha = 0x00 },
{ .blue = 0x1f, .green = 0x00, .red = 0x00 }, { .blue = 0x1f, .green = 0x00, .red = 0x00, .alpha = 0x00 },
{ .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0x00 },
}, },
/* 32bit */ /* 32bit BGRA */
{ {
{ .blue = 0x00, .green = 0x00, .red = 0xff }, { .blue = 0x00, .green = 0x00, .red = 0xff, .alpha = 0x00 },
{ .blue = 0x00, .green = 0xff, .red = 0x00 }, { .blue = 0x00, .green = 0xff, .red = 0x00, .alpha = 0x00 },
{ .blue = 0xff, .green = 0x00, .red = 0x00 }, { .blue = 0xff, .green = 0x00, .red = 0x00, .alpha = 0x00 },
{ .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0xff },
},
/* 32bit ABGR */
{
{ .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0xff },
{ .blue = 0x00, .green = 0x00, .red = 0xff, .alpha = 0x00 },
{ .blue = 0x00, .green = 0xff, .red = 0x00, .alpha = 0x00 },
{ .blue = 0xff, .green = 0x00, .red = 0x00, .alpha = 0x00 },
}, },
}; };
@ -168,13 +168,11 @@ int read_bmp_file(const char* filename,
return ret; return ret;
} }
static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) enum color_order {
{ /* only used for different types of 32bpp images */
dst->red = src.red; BGRA, /* should be most common */
dst->green = src.green; ABGR /* generated by some GIMP versions */
dst->blue = src.blue; };
dst->alpha = 0xff;
}
struct bmp_args { struct bmp_args {
int fd; int fd;
@ -182,6 +180,7 @@ struct bmp_args {
short read_width; short read_width;
short width; short width;
short depth; short depth;
enum color_order order;
unsigned char buf[BM_MAX_WIDTH * 4]; unsigned char buf[BM_MAX_WIDTH * 4];
struct uint8_rgb *palette; struct uint8_rgb *palette;
#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
@ -203,7 +202,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
const int padded_width = ba->padded_width; const int padded_width = ba->padded_width;
const int read_width = ba->read_width; const int read_width = ba->read_width;
const int width = ba->width; const int width = ba->width;
const int depth = ba->depth; int depth = ba->depth;
#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
defined(HAVE_BMP_SCALING) || defined(PLUGIN) defined(HAVE_BMP_SCALING) || defined(PLUGIN)
int cur_row = ba->cur_row; int cur_row = ba->cur_row;
@ -250,6 +249,11 @@ static unsigned int read_part_line(struct bmp_args *ba)
if (depth == 32 && ba->first_alpha_byte == 0x80) if (depth == 32 && ba->first_alpha_byte == 0x80)
ba->first_alpha_byte = ibuf[3] ? 0xff : 0x0; ba->first_alpha_byte = ibuf[3] ? 0xff : 0x0;
/* select different color orders within the switch-case to avoid
* nested if/switch */
if (depth == 32)
depth += ba->order;
while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
{ {
switch (depth) switch (depth)
@ -302,7 +306,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
buf->alpha = 0xff; buf->alpha = 0xff;
buf++; buf++;
break; break;
case 32: case 32 + BGRA:
buf->blue = *ibuf++; buf->blue = *ibuf++;
buf->green = *ibuf++; buf->green = *ibuf++;
buf->red = *ibuf++; buf->red = *ibuf++;
@ -310,6 +314,14 @@ static unsigned int read_part_line(struct bmp_args *ba)
ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte); ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte);
buf++; buf++;
break; break;
case 32 + ABGR:
buf->alpha = *ibuf++;
buf->blue = *ibuf++;
buf->green = *ibuf++;
buf->red = *ibuf++;
ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte);
buf++;
break;
} }
} }
#if !defined(HAVE_LCD_COLOR) && \ #if !defined(HAVE_LCD_COLOR) && \
@ -365,14 +377,11 @@ static struct img_part *store_part_bmp(void *args)
} }
#endif #endif
static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) static inline int rgbcmp(const struct uint8_rgb *rgb1, const struct uint8_rgb *rgb2)
{ {
if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) && return memcmp(rgb1, rgb2, sizeof(struct uint8_rgb));
(rgb1.blue == rgb2.blue))
return 0;
else
return 1;
} }
#if LCD_DEPTH > 1 #if LCD_DEPTH > 1
#if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING) #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
static inline static inline
@ -504,6 +513,7 @@ int read_bmp_fd(int fd,
int ret; int ret;
bool return_size = format & FORMAT_RETURN_SIZE; bool return_size = format & FORMAT_RETURN_SIZE;
bool read_alpha = format & FORMAT_TRANSPARENT; bool read_alpha = format & FORMAT_TRANSPARENT;
enum color_order order = BGRA;
unsigned char *bitmap = bm->data; unsigned char *bitmap = bm->data;
struct uint8_rgb palette[256]; struct uint8_rgb palette[256];
@ -668,19 +678,27 @@ int read_bmp_fd(int fd,
numcolors = letoh32(bmph.clr_used); numcolors = letoh32(bmph.clr_used);
if (numcolors == 0) if (numcolors == 0)
numcolors = BIT_N(depth); numcolors = BIT_N(depth);
} else } else {
numcolors = (compression == 3) ? 3 : 0; int hdr_size = letoh32(bmph.struct_size);
numcolors = 0;
if (compression == 3) {
if (hdr_size >= 56)
numcolors = 4;
else /* hdr_size == 52 */
numcolors = 3;
}
}
/* read color tables. for BI_BITFIELDS this actually
* reads the color masks */
if (numcolors > 0 && numcolors <= 256) { if (numcolors > 0 && numcolors <= 256) {
int i; int i;
union rgb_union pal;
for (i = 0; i < numcolors; i++) { for (i = 0; i < numcolors; i++) {
if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal)) if (read(fd, &palette[i], sizeof(struct uint8_rgb))
{ != (int)sizeof(struct uint8_rgb)) {
DEBUGF("read_bmp_fd: Can't read color palette\n"); DEBUGF("read_bmp_fd: Can't read color palette\n");
return -7; return -7;
} }
set_rgb_union(&palette[i], pal);
} }
} }
@ -705,8 +723,9 @@ int read_bmp_fd(int fd,
/* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */ /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
for (i = 0; i < ARRAY_SIZE(bitfields); i++) { for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) { /* for 15bpp and higher numcolors has the number of color masks */
if (!rgbcmp(palette[j], bitfields[i][j])) { for (j = 0; j < numcolors; j++) {
if (!rgbcmp(&palette[j], &bitfields[i][j])) {
found = true; found = true;
} else { } else {
found = false; found = false;
@ -716,6 +735,8 @@ int read_bmp_fd(int fd,
if (found) { if (found) {
if (i == 0) /* 15bit */ if (i == 0) /* 15bit */
depth = 15; depth = 15;
else if (i == 3) /* 32bit, ABGR bitmap */
order = ABGR;
break; break;
} }
} }
@ -752,6 +773,7 @@ int read_bmp_fd(int fd,
.cur_row = 0, .cur_col = 0, .part = {0,0}, .cur_row = 0, .cur_col = 0, .part = {0,0},
#endif #endif
.alpha_detected = false, .first_alpha_byte = 0x80, .alpha_detected = false, .first_alpha_byte = 0x80,
.order = order,
}; };
#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \

View file

@ -36,6 +36,7 @@
#define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7) #define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7)
struct uint8_rgb { struct uint8_rgb {
/* Little endian */
uint8_t blue; uint8_t blue;
uint8_t green; uint8_t green;
uint8_t red; uint8_t red;