From: Tony Cook Date: Mon, 23 Apr 2012 12:05:32 +0000 (+1000) Subject: [rt #76736] fix BI_BITFIELDS handling X-Git-Tag: v0.90~18 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/1cd4eef39a02cf926503eabde30bd27157b835ec [rt #76736] fix BI_BITFIELDS handling I didn't have any test images when I wrote the BI_BITFIELDS code, unfortunately it was completely broken. Updated and tested (with some unshipped images for now.) --- diff --git a/bmp.c b/bmp.c index ed134b2e..8b55d3fe 100644 --- a/bmp.c +++ b/bmp.c @@ -1256,23 +1256,42 @@ read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, struct bm_masks { unsigned masks[3]; int shifts[3]; + int bits[3]; }; static struct bm_masks std_masks[] = { { /* 16-bit */ - { 0770000, 00007700, 00000077, }, - { 10, 4, -2, }, + { 0076000, 00001740, 00000037, }, + { 10, 5, 0, }, + { 5, 5, 5, } }, { /* 24-bit */ { 0xFF0000, 0x00FF00, 0x0000FF, }, { 16, 8, 0, }, + { 8, 8, 8, }, }, { /* 32-bit */ { 0xFF0000, 0x00FF00, 0x0000FF, }, { 16, 8, 0, }, + { 8, 8, 8, }, }, }; +/* multiplier and shift for converting from N bits to 8 bits */ +struct bm_sampconverts { + int mult; + int shift; +}; +static struct bm_sampconverts samp_converts[] = { + { 0xff, 0 }, /* 1 bit samples */ + { 0x55, 0 }, + { 0111, 1 }, + { 0x11, 0 }, + { 0x21, 2 }, + { 0x41, 4 }, + { 0x81, 6 } /* 7 bit samples */ +}; + /* =item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression, allow_incomplete) @@ -1334,7 +1353,8 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, } } else if (compression == BI_BITFIELDS) { - int pos, bit; + int pos; + unsigned bits; compression_name = "BI_BITFIELDS"; for (i = 0; i < 3; ++i) { @@ -1343,17 +1363,29 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, i_push_error(0, "reading pixel masks"); return 0; } + if (rmask == 0) { + i_push_errorf(0, "Zero mask for channel %d", i); + return NULL; + } masks.masks[i] = rmask; /* work out a shift for the mask */ pos = 0; - bit = masks.masks[i] & -masks.masks[i]; - while (bit) { + bits = masks.masks[i]; + while (!(bits & 1)) { ++pos; - bit >>= 1; + bits >>= 1; } - masks.shifts[i] = pos - 8; + masks.shifts[i] = pos; + pos = 0; + while (bits & 1) { + ++pos; + bits >>= 1; + } + masks.bits[i] = pos; + /*fprintf(stderr, "%d: mask %08x shift %d bits %d\n", i, masks.masks[i], masks.shifts[i], masks.bits[i]);*/ } - base_offset += 4 * 4; + /* account for the masks */ + base_offset += 3 * 4; } else { i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression); @@ -1411,10 +1443,15 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, } } for (i = 0; i < 3; ++i) { - if (masks.shifts[i] > 0) - p->channel[i] = (pixel & masks.masks[i]) >> masks.shifts[i]; - else - p->channel[i] = (pixel & masks.masks[i]) << -masks.shifts[i]; + int sample = (pixel & masks.masks[i]) >> masks.shifts[i]; + int bits = masks.bits[i]; + if (bits < 8) { + sample = (sample * samp_converts[bits-1].mult) >> samp_converts[bits-1].shift; + } + else if (bits) { + sample >>= bits - 8; + } + p->channel[i] = sample; } ++p; }