From ef92ed4a6a997524944f42aa7abffddca7bef05e Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 21 Dec 2013 17:12:21 +0100 Subject: Support GIMP bmp files. Change-Id: I7380ceeaf696b67e1641d24e7b932e3d74770932 --- apps/recorder/bmp.c | 110 +++++++++++++++++++++++++++++++--------------------- apps/recorder/bmp.h | 1 + 2 files changed, 67 insertions(+), 44 deletions(-) diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index 011a4d60fe..75d82b449f 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -92,35 +92,35 @@ struct bmp_header { uint32_t clr_important; /* important color count */ } 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) */ -static const struct uint8_rgb bitfields[3][3] = { +static const struct uint8_rgb bitfields[][4] = { /* 15bit */ { - { .blue = 0x00, .green = 0x7c, .red = 0x00 }, - { .blue = 0xe0, .green = 0x03, .red = 0x00 }, - { .blue = 0x1f, .green = 0x00, .red = 0x00 }, + { .blue = 0x00, .green = 0x7c, .red = 0x00, .alpha = 0x00 }, + { .blue = 0xe0, .green = 0x03, .red = 0x00, .alpha = 0x00 }, + { .blue = 0x1f, .green = 0x00, .red = 0x00, .alpha = 0x00 }, + { .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0x00 }, }, /* 16bit */ { - { .blue = 0x00, .green = 0xf8, .red = 0x00 }, - { .blue = 0xe0, .green = 0x07, .red = 0x00 }, - { .blue = 0x1f, .green = 0x00, .red = 0x00 }, + { .blue = 0x00, .green = 0xf8, .red = 0x00, .alpha = 0x00 }, + { .blue = 0xe0, .green = 0x07, .red = 0x00, .alpha = 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 = 0xff, .red = 0x00 }, - { .blue = 0xff, .green = 0x00, .red = 0x00 }, + { .blue = 0x00, .green = 0x00, .red = 0xff, .alpha = 0x00 }, + { .blue = 0x00, .green = 0xff, .red = 0x00, .alpha = 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; } -static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) -{ - dst->red = src.red; - dst->green = src.green; - dst->blue = src.blue; - dst->alpha = 0xff; -} +enum color_order { + /* only used for different types of 32bpp images */ + BGRA, /* should be most common */ + ABGR /* generated by some GIMP versions */ +}; struct bmp_args { int fd; @@ -182,6 +180,7 @@ struct bmp_args { short read_width; short width; short depth; + enum color_order order; unsigned char buf[BM_MAX_WIDTH * 4]; struct uint8_rgb *palette; #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 read_width = ba->read_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)) && \ defined(HAVE_BMP_SCALING) || defined(PLUGIN) 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) 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)) { switch (depth) @@ -302,7 +306,7 @@ static unsigned int read_part_line(struct bmp_args *ba) buf->alpha = 0xff; buf++; break; - case 32: + case 32 + BGRA: buf->blue = *ibuf++; buf->green = *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); buf++; 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) && \ @@ -365,14 +377,11 @@ static struct img_part *store_part_bmp(void *args) } #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) && - (rgb1.blue == rgb2.blue)) - return 0; - else - return 1; + return memcmp(rgb1, rgb2, sizeof(struct uint8_rgb)); } + #if LCD_DEPTH > 1 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING) static inline @@ -504,6 +513,7 @@ int read_bmp_fd(int fd, int ret; bool return_size = format & FORMAT_RETURN_SIZE; bool read_alpha = format & FORMAT_TRANSPARENT; + enum color_order order = BGRA; unsigned char *bitmap = bm->data; struct uint8_rgb palette[256]; @@ -668,19 +678,27 @@ int read_bmp_fd(int fd, numcolors = letoh32(bmph.clr_used); if (numcolors == 0) numcolors = BIT_N(depth); - } else - numcolors = (compression == 3) ? 3 : 0; + } else { + 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) { int i; - union rgb_union pal; 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"); 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 */ for (i = 0; i < ARRAY_SIZE(bitfields); i++) { - for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) { - if (!rgbcmp(palette[j], bitfields[i][j])) { + /* for 15bpp and higher numcolors has the number of color masks */ + for (j = 0; j < numcolors; j++) { + if (!rgbcmp(&palette[j], &bitfields[i][j])) { found = true; } else { found = false; @@ -716,6 +735,8 @@ int read_bmp_fd(int fd, if (found) { if (i == 0) /* 15bit */ depth = 15; + else if (i == 3) /* 32bit, ABGR bitmap */ + order = ABGR; break; } } @@ -752,6 +773,7 @@ int read_bmp_fd(int fd, .cur_row = 0, .cur_col = 0, .part = {0,0}, #endif .alpha_detected = false, .first_alpha_byte = 0x80, + .order = order, }; #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index 3ddc3b66df..610ec29f21 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h @@ -36,6 +36,7 @@ #define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7) struct uint8_rgb { + /* Little endian */ uint8_t blue; uint8_t green; uint8_t red; -- cgit v1.2.3