From 312b2a2de7a35f8c4b0dc355b7b291085a9a5ea4 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 11 Nov 2011 19:05:11 +0000 Subject: Document the internal alpha channel format better, and fixes for 32bit alpha bitmaps. For images, rows need to be even (this is not true for anti-aliased font files). Fix stride and size calculation. This makes images that have odd pixel rows display properly and fixes buffer overflows. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30966 a1c6a512-1295-4272-9138-f99709370657 --- apps/recorder/bmp.c | 12 +++++++----- apps/recorder/resize.c | 4 ++-- firmware/drivers/lcd-16bit-common.c | 30 ++++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index 26be4e48cf..75165528e7 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -438,7 +438,7 @@ void output_row_8_native(uint32_t row, void * row_in, if (ctx->bm->alpha_offset > 0) bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; if (bm_alpha) - bm_alpha += ctx->bm->width*row/2; + bm_alpha += ALIGN_UP(ctx->bm->width, 2) * row/2; for (col = 0; col < ctx->bm->width; col++) { if (ctx->dither) @@ -453,7 +453,7 @@ void output_row_8_native(uint32_t row, void * row_in, dest += STRIDE_MAIN(1, ctx->bm->height); if (bm_alpha) { /* pack alpha channel for 2 pixels into 1 byte */ - unsigned alpha = 255-qp->alpha; + unsigned alpha = qp->alpha; if (col%2) *bm_alpha++ |= alpha&0xf0; else @@ -612,6 +612,8 @@ int read_bmp_fd(int fd, rset.rowstop = -1; } + /* need even rows (see lcd-16bit-common.c for details) */ + int alphasize = ALIGN_UP(bm->width, 2) * bm->height / 2; if (cformat) totalsize = cformat->get_size(bm); else { @@ -620,7 +622,7 @@ int read_bmp_fd(int fd, if (!remote) #endif if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */ - totalsize += bm->width * bm->height / 2; + totalsize += alphasize; } if(return_size) @@ -718,7 +720,7 @@ int read_bmp_fd(int fd, #ifdef HAVE_LCD_COLOR if (read_alpha && depth == 32) - bm->alpha_offset = totalsize - (bm->width * bm->height / 2); + bm->alpha_offset = totalsize - alphasize; else bm->alpha_offset = 0; #endif @@ -882,7 +884,7 @@ int read_bmp_fd(int fd, { /* if this has an alpha channel, totalsize accounts for it as well * subtract if no actual alpha information was found */ if (bm->alpha_offset > 0) - totalsize -= bm->width*bm->height/2; + totalsize -= alphasize; bm->alpha_offset = 0; } #endif diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c index a68a5f2e9f..dd1f3edf88 100644 --- a/apps/recorder/resize.c +++ b/apps/recorder/resize.c @@ -775,7 +775,7 @@ static void output_row_32_native(uint32_t row, void * row_in, if (ctx->bm->alpha_offset > 0) bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; if (bm_alpha) - bm_alpha += ctx->bm->width*row/2; + bm_alpha += ALIGN_UP(ctx->bm->width, 2)*row/2; for (col = 0; col < ctx->bm->width; col++) { if (ctx->dither) @@ -791,7 +791,7 @@ static void output_row_32_native(uint32_t row, void * row_in, dest += STRIDE_MAIN(1, ctx->bm->height); if (bm_alpha) { /* pack alpha channel for 2 pixels into 1 byte */ - unsigned alpha = 255-SC_OUT(q0.a, ctx); + unsigned alpha = SC_OUT(q0.a, ctx); if (col%2) *bm_alpha++ |= alpha&0xf0; else diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c index 7b37bf7c30..47f5968228 100644 --- a/firmware/drivers/lcd-16bit-common.c +++ b/firmware/drivers/lcd-16bit-common.c @@ -229,6 +229,25 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); } + +/* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2) + * + * For each pixel, 4bit of alpha information is stored in a byte-stream, + * so two pixels are packed into one byte. + * The lower nibble is the first pixel, the upper one the second. The stride is + * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],... + * The format is independant of the internal display orientation, as to + * support the same font files on + * The values go linear from 0 (fully transparent) to 15 (fully opaque). + * + * This might suggest that rows need to have an even number of pixels. + * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal + * with uneven colums (i.e. two rows can share one byte). And font files do + * exploit this. + * However, this is difficult to do for image files, especially bottom-up bitmaps, + * so lcd_bmp() do expect even rows. + */ + #define ALPHA_COLOR_FONT_DEPTH 2 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) @@ -357,17 +376,16 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, dmask = 0xffffffff; drmode &= DRMODE_SOLID; /* mask out inversevid */ } - if (drmode == DRMODE_BG) - { - dmask = ~dmask; - } /* sourcing from an image ignore drawmode. * Set to DRMODE_BG as we use its code path in the switch below */ if (image != NULL) { - dmask = 0; drmode = DRMODE_BG; } + if (drmode == DRMODE_BG) + { + dmask = ~dmask; + } dst_row = LCDADDR(x, y); @@ -560,7 +578,7 @@ void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, else if (bm->alpha_offset > 0) lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset, src_x, src_y, x, y, width, height, - bitmap_stride, bm->width); + bitmap_stride, ALIGN_UP(bm->width, 2)); else lcd_bitmap_transparent_part((fb_data*)bm->data, src_x, src_y, bitmap_stride, x, y, width, height); -- cgit v1.2.3