Gitweb links:
...log
http://git.netsurf-browser.org/libnsbmp.git/shortlog/911072bc0312a1a0f7eeac01fdf861c02a34a313
...commit
http://git.netsurf-browser.org/libnsbmp.git/commit/911072bc0312a1a0f7eeac01fdf861c02a34a313
...tree
http://git.netsurf-browser.org/libnsbmp.git/tree/911072bc0312a1a0f7eeac01fdf861c02a34a313
The branch, master has been updated
via 911072bc0312a1a0f7eeac01fdf861c02a34a313 (commit)
via 1eff62bd9d4a97bab3973aaf55f64aabc9ec9876 (commit)
via 822b394b677054d9d2314bb4a0013e600fd9266a (commit)
via 135c1700bfeff8d69ed2fb8c181f75c422a7d887 (commit)
from 8cdf3858127bbe1a23bd68546ddcb5b350a03904 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=911072bc0312a1a0f7eeac01fdf861c02a34a313
commit 911072bc0312a1a0f7eeac01fdf861c02a34a313
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
add previously failing icon with transparancy as test
diff --git a/test/icons/liberation.fr.favicon.ico
b/test/icons/liberation.fr.favicon.ico
new file mode 100644
index 0000000..0b670bb
Binary files /dev/null and b/test/icons/liberation.fr.favicon.ico differ
diff --git a/test/icons/liberation.fr.favicon.ppm
b/test/icons/liberation.fr.favicon.ppm
new file mode 100644
index 0000000..ddd5aa5
Binary files /dev/null and b/test/icons/liberation.fr.favicon.ppm differ
diff --git a/test/runtest.sh b/test/runtest.sh
index 28196c5..8e2b33c 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -40,8 +40,15 @@ bmpdecode()
icodecode()
{
OUTF=$(basename ${1} .ico)
+ CMPF=$(dirname ${1})/${OUTF}.ppm
echo "Icon:${1}" >> ${TEST_LOG}
${TEST_PATH}/test_decode_ico ${1} > ${TEST_OUT}/${OUTF}.ppm 2>> ${TEST_LOG}
+ if [ -f "${CMPF}" ]; then
+ cmp ${CMPF} ${TEST_OUT}/${OUTF}.ppm >> ${TEST_LOG} 2>> ${TEST_LOG}
+ if [ "$?" -ne 0 ]; then
+ return 128
+ fi
+ fi
}
# bitmap tests
@@ -54,7 +61,7 @@ for BMP in $(ls ${BMPTESTS});do
BMPTESTTOTC=$((BMPTESTTOTC+1))
bmpdecode ${BMP}
ECODE=$?
- if [ "${ECODE}" -gt 128 ];then
+ if [ "${ECODE}" -gt 127 ];then
BMPTESTERRC=$((BMPTESTERRC+1))
else
BMPTESTPASSC=$((BMPTESTPASSC+1))
@@ -76,7 +83,7 @@ for ICO in $(ls ${ICOTESTS});do
ICOTESTTOTC=$((ICOTESTTOTC+1))
icodecode ${ICO}
ECODE=$?
- if [ "${ECODE}" -gt 128 ];then
+ if [ "${ECODE}" -gt 127 ];then
ICOTESTERRC=$((ICOTESTERRC+1))
else
ICOTESTPASSC=$((ICOTESTPASSC+1))
commitdiff
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=1eff62bd9d4a97bab3973aaf55f64aabc9ec9876
commit 1eff62bd9d4a97bab3973aaf55f64aabc9ec9876
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
allow icons with transparaency to be saved in P7 format
diff --git a/test/decode_ico.c b/test/decode_ico.c
index 935001c..266b3bb 100644
--- a/test/decode_ico.c
+++ b/test/decode_ico.c
@@ -7,6 +7,11 @@
* http://www.opensource.org/licenses/mit-license.php
*/
+/**
+ * \file
+ * Use libnsbmp to decode icons into ppm or pam files for testing
+ */
+
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
@@ -32,172 +37,216 @@ size_t bitmap_get_bpp(void *bitmap);
void bitmap_destroy(void *bitmap);
+static void write_pam(FILE* fh, const char *name, struct bmp_image *bmp)
+{
+ uint16_t row, col;
+ uint8_t *image;
+
+ fprintf(fh, "P7\n");
+ fprintf(fh, "# %s\n", name);
+ fprintf(fh, "WIDTH %u\n", bmp->width);
+ fprintf(fh, "HEIGHT %u\n", bmp->height);
+ fprintf(fh, "DEPTH 4\n");
+ fprintf(fh, "MAXVAL 255\n");
+ fprintf(fh, "TUPLTYPE RGB_ALPHA\n");
+ fprintf(fh, "ENDHDR\n");
+
+
+ image = (uint8_t *) bmp->bitmap;
+ for (row = 0; row != bmp->height; row++) {
+ for (col = 0; col != bmp->width; col++) {
+ size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
+ putc(image[z], fh);
+ putc(image[z + 1], fh);
+ putc(image[z + 2], fh);
+ putc(image[z + 3], fh);
+ }
+ }
+
+}
+
+static void write_ppm(FILE* fh, const char *name, struct bmp_image *bmp)
+{
+ uint16_t row, col;
+ uint8_t *image;
+
+ fprintf(fh, "P3\n");
+ fprintf(fh, "# %s\n", name);
+ fprintf(fh, "# width %u \n", bmp->width);
+ fprintf(fh, "# height %u \n", bmp->height);
+ fprintf(fh, "%u %u 256\n", bmp->width, bmp->height);
+
+ image = (uint8_t *) bmp->bitmap;
+ for (row = 0; row != bmp->height; row++) {
+ for (col = 0; col != bmp->width; col++) {
+ size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
+ fprintf(fh, "%u %u %u ",
+ image[z],
+ image[z + 1],
+ image[z + 2]);
+ }
+ fprintf(fh, "\n");
+ }
+}
+
int main(int argc, char *argv[])
{
- bmp_bitmap_callback_vt bitmap_callbacks = {
- bitmap_create,
- bitmap_destroy,
- bitmap_get_buffer,
- bitmap_get_bpp
- };
- uint16_t width, height;
- ico_collection ico;
- bmp_result code;
- struct bmp_image *bmp;
- size_t size;
- unsigned short res = 0;
-
- if ((argc < 2) || (argc > 4)) {
- fprintf(stderr, "Usage: %s collection.ico [width=255]
[height=255]\n", argv[0]);
- return 1;
- }
- width = (argc >= 3) ? atoi(argv[2]) : 255;
- height = (argc == 4) ? atoi(argv[3]) : 255;
-
- /* create our bmp image */
- ico_collection_create(&ico, &bitmap_callbacks);
-
- /* load file into memory */
- unsigned char *data = load_file(argv[1], &size);
-
- /* analyse the BMP */
- code = ico_analyse(&ico, size, data);
- if (code != BMP_OK) {
- warning("ico_analyse", code);
- res = 1;
- goto cleanup;
- }
-
- /* decode the image */
- bmp = ico_find(&ico, width, height);
- assert(bmp);
-
- code = bmp_decode(bmp);
- /* code = bmp_decode_trans(bmp, TRANSPARENT_COLOR); */
- if (code != BMP_OK) {
- warning("bmp_decode", code);
- /* allow partially decoded images */
- if (code != BMP_INSUFFICIENT_DATA) {
- res = 1;
- goto cleanup;
- }
- }
-
- printf("P3\n");
- printf("# %s\n", argv[1]);
- printf("# width %u \n", bmp->width);
- printf("# height %u \n", bmp->height);
- printf("%u %u 256\n", bmp->width, bmp->height);
-
- {
- uint16_t row, col;
- uint8_t *image;
- image = (uint8_t *) bmp->bitmap;
- for (row = 0; row != bmp->height; row++) {
- for (col = 0; col != bmp->width; col++) {
- size_t z = (row * bmp->width + col) *
BYTES_PER_PIXEL;
- printf("%u %u %u ", image[z],
- image[z + 1],
- image[z + 2]);
- }
- printf("\n");
- }
- }
+ bmp_bitmap_callback_vt bitmap_callbacks = {
+ bitmap_create,
+ bitmap_destroy,
+ bitmap_get_buffer,
+ bitmap_get_bpp
+ };
+ uint16_t width, height;
+ ico_collection ico;
+ bmp_result code;
+ struct bmp_image *bmp;
+ size_t size;
+ unsigned short res = 0;
+ unsigned char *data;
+
+ if ((argc < 2) || (argc > 4)) {
+ fprintf(stderr, "Usage: %s collection.ico [width=255]
[height=255]\n", argv[0]);
+ return 1;
+ }
+ width = (argc >= 3) ? atoi(argv[2]) : 255;
+ height = (argc == 4) ? atoi(argv[3]) : 255;
+
+ /* create our bmp image */
+ ico_collection_create(&ico, &bitmap_callbacks);
+
+ /* load file into memory */
+ data = load_file(argv[1], &size);
+
+ /* analyse the BMP */
+ code = ico_analyse(&ico, size, data);
+ if (code != BMP_OK) {
+ warning("ico_analyse", code);
+ res = 1;
+ goto cleanup;
+ }
+
+ /* decode the image */
+ bmp = ico_find(&ico, width, height);
+ assert(bmp);
+
+ code = bmp_decode(bmp);
+ /* code = bmp_decode_trans(bmp, TRANSPARENT_COLOR); */
+ if (code != BMP_OK) {
+ warning("bmp_decode", code);
+ /* allow partially decoded images */
+ if ((code != BMP_INSUFFICIENT_DATA) &&
+ (code != BMP_DATA_ERROR)) {
+ res = 1;
+ goto cleanup;
+ }
+
+ /* skip if the decoded image would be ridiculously large */
+ if ((bmp->width * bmp->height) > 200000) {
+ res = 1;
+ goto cleanup;
+ }
+ }
+
+ if (bmp->opaque) {
+ write_ppm(stdout, argv[1], bmp);
+ } else {
+ write_pam(stdout, argv[1], bmp);
+ }
cleanup:
- /* clean up */
- ico_finalise(&ico);
- free(data);
+ /* clean up */
+ ico_finalise(&ico);
+ free(data);
- return res;
+ return res;
}
unsigned char *load_file(const char *path, size_t *data_size)
{
- FILE *fd;
- struct stat sb;
- unsigned char *buffer;
- size_t size;
- size_t n;
-
- fd = fopen(path, "rb");
- if (!fd) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- if (stat(path, &sb)) {
- perror(path);
- exit(EXIT_FAILURE);
- }
- size = sb.st_size;
-
- buffer = malloc(size);
- if (!buffer) {
- fprintf(stderr, "Unable to allocate %lld bytes\n",
- (long long) size);
- exit(EXIT_FAILURE);
- }
-
- n = fread(buffer, 1, size, fd);
- if (n != size) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- fclose(fd);
-
- *data_size = size;
- return buffer;
+ FILE *fd;
+ struct stat sb;
+ unsigned char *buffer;
+ size_t size;
+ size_t n;
+
+ fd = fopen(path, "rb");
+ if (!fd) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(path, &sb)) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+ size = sb.st_size;
+
+ buffer = malloc(size);
+ if (!buffer) {
+ fprintf(stderr, "Unable to allocate %lld bytes\n",
+ (long long) size);
+ exit(EXIT_FAILURE);
+ }
+
+ n = fread(buffer, 1, size, fd);
+ if (n != size) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(fd);
+
+ *data_size = size;
+ return buffer;
}
void warning(const char *context, bmp_result code)
{
- fprintf(stderr, "%s failed: ", context);
- switch (code) {
- case BMP_INSUFFICIENT_MEMORY:
- fprintf(stderr, "BMP_INSUFFICIENT_MEMORY");
- break;
- case BMP_INSUFFICIENT_DATA:
- fprintf(stderr, "BMP_INSUFFICIENT_DATA");
- break;
- case BMP_DATA_ERROR:
- fprintf(stderr, "BMP_DATA_ERROR");
- break;
- default:
- fprintf(stderr, "unknown code %i", code);
- break;
- }
- fprintf(stderr, "\n");
+ fprintf(stderr, "%s failed: ", context);
+ switch (code) {
+ case BMP_INSUFFICIENT_MEMORY:
+ fprintf(stderr, "BMP_INSUFFICIENT_MEMORY");
+ break;
+ case BMP_INSUFFICIENT_DATA:
+ fprintf(stderr, "BMP_INSUFFICIENT_DATA");
+ break;
+ case BMP_DATA_ERROR:
+ fprintf(stderr, "BMP_DATA_ERROR");
+ break;
+ default:
+ fprintf(stderr, "unknown code %i", code);
+ break;
+ }
+ fprintf(stderr, "\n");
}
void *bitmap_create(int width, int height, unsigned int state)
{
- (void) state; /* unused */
- return calloc(width * height, BYTES_PER_PIXEL);
+ (void) state; /* unused */
+ return calloc(width * height, BYTES_PER_PIXEL);
}
unsigned char *bitmap_get_buffer(void *bitmap)
{
- assert(bitmap);
- return bitmap;
+ assert(bitmap);
+ return bitmap;
}
size_t bitmap_get_bpp(void *bitmap)
{
- (void) bitmap; /* unused */
- return BYTES_PER_PIXEL;
+ (void) bitmap; /* unused */
+ return BYTES_PER_PIXEL;
}
void bitmap_destroy(void *bitmap)
{
- assert(bitmap);
- free(bitmap);
+ assert(bitmap);
+ free(bitmap);
}
-
commitdiff
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=822b394b677054d9d2314bb4a0013e600fd9266a
commit 822b394b677054d9d2314bb4a0013e600fd9266a
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
allow 32bpp icon to use their alpha channel for opacity
modified patch from François Revol
diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index 7318347..0e241a1 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -555,6 +555,8 @@ static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t
**start, int bytes)
}
if (bmp->opaque) {
scanline[x] |= (0xff << 24);
+ } else {
+ scanline[x] |= data[3] << 24;
}
data += 4;
scanline[x] = read_uint32((uint8_t
*)&scanline[x],0);
@@ -816,6 +818,11 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t
*data, int bytes)
uint32_t x, y, swidth;
uint32_t cur_byte = 0;
+ if (bmp->bpp == 32) {
+ /* should already have proper alpha */
+ return BMP_OK;
+ }
+
swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
if (!top)
commitdiff
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=135c1700bfeff8d69ed2fb8c181f75c422a7d887
commit 135c1700bfeff8d69ed2fb8c181f75c422a7d887
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
separate 24bpp decoder from 32bpp
diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index b4747f6..7318347 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -483,7 +483,7 @@ static bmp_result ico_header_parse(ico_collection *ico,
uint8_t *data)
/**
- * Decode BMP data stored in 24bpp colour.
+ * Decode BMP data stored in 32bpp colour.
*
* \param bmp the BMP image to decode
* \param start the data to decode, updated to last byte read on success
@@ -492,16 +492,18 @@ static bmp_result ico_header_parse(ico_collection *ico,
uint8_t *data)
* BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
* in this case, the image may be partially viewable
*/
-static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
+static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes)
{
uint8_t *top, *bottom, *end, *data;
uint32_t *scanline;
uint32_t x, y;
- uint32_t swidth, skip;
+ uint32_t swidth;
intptr_t addr;
uint8_t i;
uint32_t word;
+ assert(bmp->bpp == 32);
+
data = *start;
swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
@@ -510,12 +512,11 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp,
uint8_t **start, int bytes)
bottom = top + (uint64_t)swidth * (bmp->height - 1);
end = data + bytes;
addr = ((intptr_t)data) & 3;
- skip = bmp->bpp >> 3;
bmp->decoded = true;
/* Determine transparent index */
if (bmp->limited_trans) {
- if ((data + skip) > end)
+ if ((data + 4) > end)
return BMP_INSUFFICIENT_DATA;
if (bmp->encoding == BMP_ENCODING_BITFIELDS)
bmp->transparent_index = read_uint32(data, 0);
@@ -526,7 +527,7 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t
**start, int bytes)
for (y = 0; y < bmp->height; y++) {
while (addr != (((intptr_t)data) & 3))
data++;
- if ((data + (skip * bmp->width)) > end)
+ if ((data + (4 * bmp->width)) > end)
return BMP_INSUFFICIENT_DATA;
if (bmp->reversed)
scanline = (void *)(top + (y * swidth));
@@ -543,17 +544,19 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp,
uint8_t **start, int bytes)
/* 32-bit BMPs have alpha masks, but sometimes
they're not utilized */
if (bmp->opaque)
scanline[x] |= (0xff << 24);
- data += skip;
+ data += 4;
scanline[x] = read_uint32((uint8_t
*)&scanline[x],0);
}
} else {
for (x = 0; x < bmp->width; x++) {
scanline[x] = data[2] | (data[1] << 8) |
(data[0] << 16);
- if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index))
+ if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index)) {
scanline[x] = bmp->trans_colour;
- if (bmp->opaque)
+ }
+ if (bmp->opaque) {
scanline[x] |= (0xff << 24);
- data += skip;
+ }
+ data += 4;
scanline[x] = read_uint32((uint8_t
*)&scanline[x],0);
}
}
@@ -564,6 +567,80 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t
**start, int bytes)
/**
+ * Decode BMP data stored in 24bpp colour.
+ *
+ * \param bmp the BMP image to decode
+ * \param start the data to decode, updated to last byte read on success
+ * \param bytes the number of bytes of data available
+ * \return BMP_OK on success
+ * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ * in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
+{
+ uint8_t *top, *bottom, *end, *data;
+ uint32_t *scanline;
+ uint32_t x, y;
+ uint32_t swidth;
+ intptr_t addr;
+
+ assert(bmp->encoding == BMP_ENCODING_RGB);
+ assert(bmp->bpp == 24);
+
+ data = *start;
+ swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
+ top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+ if (!top) {
+ return BMP_INSUFFICIENT_MEMORY;
+ }
+
+ bottom = top + (uint64_t)swidth * (bmp->height - 1);
+ end = data + bytes;
+ addr = ((intptr_t)data) & 3;
+ bmp->decoded = true;
+
+ /* Determine transparent index */
+ if (bmp->limited_trans) {
+ if ((data + 3) > end) {
+ return BMP_INSUFFICIENT_DATA;
+ }
+
+ bmp->transparent_index = data[2] | (data[1] << 8) | (data[0]
<< 16);
+ }
+
+ for (y = 0; y < bmp->height; y++) {
+ while (addr != (((intptr_t)data) & 3)) {
+ data++;
+ }
+
+ if ((data + (3 * bmp->width)) > end) {
+ return BMP_INSUFFICIENT_DATA;
+ }
+
+ if (bmp->reversed) {
+ scanline = (void *)(top + (y * swidth));
+ } else {
+ scanline = (void *)(bottom - (y * swidth));
+ }
+
+ for (x = 0; x < bmp->width; x++) {
+ scanline[x] = data[2] | (data[1] << 8) | (data[0] <<
16);
+ if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index)) {
+ scanline[x] = bmp->trans_colour;
+ } else {
+ scanline[x] |= (0xff << 24);
+ }
+ data += 3;
+ scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+ }
+
+ }
+ *start = data;
+ return BMP_OK;
+}
+
+
+/**
* Decode BMP data stored in 16bpp colour.
*
* \param bmp the BMP image to decode
@@ -1167,12 +1244,22 @@ bmp_result bmp_decode(bmp_image *bmp)
switch (bmp->encoding) {
case BMP_ENCODING_RGB:
- if ((bmp->bpp == 24) || (bmp->bpp == 32)) {
+ switch (bmp->bpp) {
+ case 32:
+ result = bmp_decode_rgb32(bmp, &data, bytes);
+ break;
+
+ case 24:
result = bmp_decode_rgb24(bmp, &data, bytes);
- } else if (bmp->bpp == 16) {
+ break;
+
+ case 16:
result = bmp_decode_rgb16(bmp, &data, bytes);
- } else {
+ break;
+
+ default:
result = bmp_decode_rgb(bmp, &data, bytes);
+ break;
}
break;
@@ -1185,12 +1272,18 @@ bmp_result bmp_decode(bmp_image *bmp)
break;
case BMP_ENCODING_BITFIELDS:
- if (bmp->bpp == 32) {
- result = bmp_decode_rgb24(bmp, &data, bytes);
- } else if (bmp->bpp == 16) {
+ switch (bmp->bpp) {
+ case 32:
+ result = bmp_decode_rgb32(bmp, &data, bytes);
+ break;
+
+ case 16:
result = bmp_decode_rgb16(bmp, &data, bytes);
- } else {
+ break;
+
+ default:
result = BMP_DATA_ERROR;
+ break;
}
break;
}
-----------------------------------------------------------------------
Summary of changes:
src/libnsbmp.c | 134 +++++++++++++--
test/decode_ico.c | 315 ++++++++++++++++++++--------------
test/icons/liberation.fr.favicon.ico | Bin 0 -> 18094 bytes
test/icons/liberation.fr.favicon.ppm | Bin 0 -> 9322 bytes
test/runtest.sh | 11 +-
5 files changed, 308 insertions(+), 152 deletions(-)
create mode 100644 test/icons/liberation.fr.favicon.ico
create mode 100644 test/icons/liberation.fr.favicon.ppm
diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index b4747f6..0e241a1 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -483,7 +483,7 @@ static bmp_result ico_header_parse(ico_collection *ico,
uint8_t *data)
/**
- * Decode BMP data stored in 24bpp colour.
+ * Decode BMP data stored in 32bpp colour.
*
* \param bmp the BMP image to decode
* \param start the data to decode, updated to last byte read on success
@@ -492,16 +492,18 @@ static bmp_result ico_header_parse(ico_collection *ico,
uint8_t *data)
* BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
* in this case, the image may be partially viewable
*/
-static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
+static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes)
{
uint8_t *top, *bottom, *end, *data;
uint32_t *scanline;
uint32_t x, y;
- uint32_t swidth, skip;
+ uint32_t swidth;
intptr_t addr;
uint8_t i;
uint32_t word;
+ assert(bmp->bpp == 32);
+
data = *start;
swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
@@ -510,12 +512,11 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp,
uint8_t **start, int bytes)
bottom = top + (uint64_t)swidth * (bmp->height - 1);
end = data + bytes;
addr = ((intptr_t)data) & 3;
- skip = bmp->bpp >> 3;
bmp->decoded = true;
/* Determine transparent index */
if (bmp->limited_trans) {
- if ((data + skip) > end)
+ if ((data + 4) > end)
return BMP_INSUFFICIENT_DATA;
if (bmp->encoding == BMP_ENCODING_BITFIELDS)
bmp->transparent_index = read_uint32(data, 0);
@@ -526,7 +527,7 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t
**start, int bytes)
for (y = 0; y < bmp->height; y++) {
while (addr != (((intptr_t)data) & 3))
data++;
- if ((data + (skip * bmp->width)) > end)
+ if ((data + (4 * bmp->width)) > end)
return BMP_INSUFFICIENT_DATA;
if (bmp->reversed)
scanline = (void *)(top + (y * swidth));
@@ -543,17 +544,21 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp,
uint8_t **start, int bytes)
/* 32-bit BMPs have alpha masks, but sometimes
they're not utilized */
if (bmp->opaque)
scanline[x] |= (0xff << 24);
- data += skip;
+ data += 4;
scanline[x] = read_uint32((uint8_t
*)&scanline[x],0);
}
} else {
for (x = 0; x < bmp->width; x++) {
scanline[x] = data[2] | (data[1] << 8) |
(data[0] << 16);
- if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index))
+ if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index)) {
scanline[x] = bmp->trans_colour;
- if (bmp->opaque)
+ }
+ if (bmp->opaque) {
scanline[x] |= (0xff << 24);
- data += skip;
+ } else {
+ scanline[x] |= data[3] << 24;
+ }
+ data += 4;
scanline[x] = read_uint32((uint8_t
*)&scanline[x],0);
}
}
@@ -564,6 +569,80 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t
**start, int bytes)
/**
+ * Decode BMP data stored in 24bpp colour.
+ *
+ * \param bmp the BMP image to decode
+ * \param start the data to decode, updated to last byte read on success
+ * \param bytes the number of bytes of data available
+ * \return BMP_OK on success
+ * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ * in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
+{
+ uint8_t *top, *bottom, *end, *data;
+ uint32_t *scanline;
+ uint32_t x, y;
+ uint32_t swidth;
+ intptr_t addr;
+
+ assert(bmp->encoding == BMP_ENCODING_RGB);
+ assert(bmp->bpp == 24);
+
+ data = *start;
+ swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
+ top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+ if (!top) {
+ return BMP_INSUFFICIENT_MEMORY;
+ }
+
+ bottom = top + (uint64_t)swidth * (bmp->height - 1);
+ end = data + bytes;
+ addr = ((intptr_t)data) & 3;
+ bmp->decoded = true;
+
+ /* Determine transparent index */
+ if (bmp->limited_trans) {
+ if ((data + 3) > end) {
+ return BMP_INSUFFICIENT_DATA;
+ }
+
+ bmp->transparent_index = data[2] | (data[1] << 8) | (data[0]
<< 16);
+ }
+
+ for (y = 0; y < bmp->height; y++) {
+ while (addr != (((intptr_t)data) & 3)) {
+ data++;
+ }
+
+ if ((data + (3 * bmp->width)) > end) {
+ return BMP_INSUFFICIENT_DATA;
+ }
+
+ if (bmp->reversed) {
+ scanline = (void *)(top + (y * swidth));
+ } else {
+ scanline = (void *)(bottom - (y * swidth));
+ }
+
+ for (x = 0; x < bmp->width; x++) {
+ scanline[x] = data[2] | (data[1] << 8) | (data[0] <<
16);
+ if ((bmp->limited_trans) && (scanline[x] ==
bmp->transparent_index)) {
+ scanline[x] = bmp->trans_colour;
+ } else {
+ scanline[x] |= (0xff << 24);
+ }
+ data += 3;
+ scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+ }
+
+ }
+ *start = data;
+ return BMP_OK;
+}
+
+
+/**
* Decode BMP data stored in 16bpp colour.
*
* \param bmp the BMP image to decode
@@ -739,6 +818,11 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t
*data, int bytes)
uint32_t x, y, swidth;
uint32_t cur_byte = 0;
+ if (bmp->bpp == 32) {
+ /* should already have proper alpha */
+ return BMP_OK;
+ }
+
swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) *
bmp->width;
top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
if (!top)
@@ -1167,12 +1251,22 @@ bmp_result bmp_decode(bmp_image *bmp)
switch (bmp->encoding) {
case BMP_ENCODING_RGB:
- if ((bmp->bpp == 24) || (bmp->bpp == 32)) {
+ switch (bmp->bpp) {
+ case 32:
+ result = bmp_decode_rgb32(bmp, &data, bytes);
+ break;
+
+ case 24:
result = bmp_decode_rgb24(bmp, &data, bytes);
- } else if (bmp->bpp == 16) {
+ break;
+
+ case 16:
result = bmp_decode_rgb16(bmp, &data, bytes);
- } else {
+ break;
+
+ default:
result = bmp_decode_rgb(bmp, &data, bytes);
+ break;
}
break;
@@ -1185,12 +1279,18 @@ bmp_result bmp_decode(bmp_image *bmp)
break;
case BMP_ENCODING_BITFIELDS:
- if (bmp->bpp == 32) {
- result = bmp_decode_rgb24(bmp, &data, bytes);
- } else if (bmp->bpp == 16) {
+ switch (bmp->bpp) {
+ case 32:
+ result = bmp_decode_rgb32(bmp, &data, bytes);
+ break;
+
+ case 16:
result = bmp_decode_rgb16(bmp, &data, bytes);
- } else {
+ break;
+
+ default:
result = BMP_DATA_ERROR;
+ break;
}
break;
}
diff --git a/test/decode_ico.c b/test/decode_ico.c
index 935001c..266b3bb 100644
--- a/test/decode_ico.c
+++ b/test/decode_ico.c
@@ -7,6 +7,11 @@
* http://www.opensource.org/licenses/mit-license.php
*/
+/**
+ * \file
+ * Use libnsbmp to decode icons into ppm or pam files for testing
+ */
+
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
@@ -32,172 +37,216 @@ size_t bitmap_get_bpp(void *bitmap);
void bitmap_destroy(void *bitmap);
+static void write_pam(FILE* fh, const char *name, struct bmp_image *bmp)
+{
+ uint16_t row, col;
+ uint8_t *image;
+
+ fprintf(fh, "P7\n");
+ fprintf(fh, "# %s\n", name);
+ fprintf(fh, "WIDTH %u\n", bmp->width);
+ fprintf(fh, "HEIGHT %u\n", bmp->height);
+ fprintf(fh, "DEPTH 4\n");
+ fprintf(fh, "MAXVAL 255\n");
+ fprintf(fh, "TUPLTYPE RGB_ALPHA\n");
+ fprintf(fh, "ENDHDR\n");
+
+
+ image = (uint8_t *) bmp->bitmap;
+ for (row = 0; row != bmp->height; row++) {
+ for (col = 0; col != bmp->width; col++) {
+ size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
+ putc(image[z], fh);
+ putc(image[z + 1], fh);
+ putc(image[z + 2], fh);
+ putc(image[z + 3], fh);
+ }
+ }
+
+}
+
+static void write_ppm(FILE* fh, const char *name, struct bmp_image *bmp)
+{
+ uint16_t row, col;
+ uint8_t *image;
+
+ fprintf(fh, "P3\n");
+ fprintf(fh, "# %s\n", name);
+ fprintf(fh, "# width %u \n", bmp->width);
+ fprintf(fh, "# height %u \n", bmp->height);
+ fprintf(fh, "%u %u 256\n", bmp->width, bmp->height);
+
+ image = (uint8_t *) bmp->bitmap;
+ for (row = 0; row != bmp->height; row++) {
+ for (col = 0; col != bmp->width; col++) {
+ size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
+ fprintf(fh, "%u %u %u ",
+ image[z],
+ image[z + 1],
+ image[z + 2]);
+ }
+ fprintf(fh, "\n");
+ }
+}
+
int main(int argc, char *argv[])
{
- bmp_bitmap_callback_vt bitmap_callbacks = {
- bitmap_create,
- bitmap_destroy,
- bitmap_get_buffer,
- bitmap_get_bpp
- };
- uint16_t width, height;
- ico_collection ico;
- bmp_result code;
- struct bmp_image *bmp;
- size_t size;
- unsigned short res = 0;
-
- if ((argc < 2) || (argc > 4)) {
- fprintf(stderr, "Usage: %s collection.ico [width=255]
[height=255]\n", argv[0]);
- return 1;
- }
- width = (argc >= 3) ? atoi(argv[2]) : 255;
- height = (argc == 4) ? atoi(argv[3]) : 255;
-
- /* create our bmp image */
- ico_collection_create(&ico, &bitmap_callbacks);
-
- /* load file into memory */
- unsigned char *data = load_file(argv[1], &size);
-
- /* analyse the BMP */
- code = ico_analyse(&ico, size, data);
- if (code != BMP_OK) {
- warning("ico_analyse", code);
- res = 1;
- goto cleanup;
- }
-
- /* decode the image */
- bmp = ico_find(&ico, width, height);
- assert(bmp);
-
- code = bmp_decode(bmp);
- /* code = bmp_decode_trans(bmp, TRANSPARENT_COLOR); */
- if (code != BMP_OK) {
- warning("bmp_decode", code);
- /* allow partially decoded images */
- if (code != BMP_INSUFFICIENT_DATA) {
- res = 1;
- goto cleanup;
- }
- }
-
- printf("P3\n");
- printf("# %s\n", argv[1]);
- printf("# width %u \n", bmp->width);
- printf("# height %u \n", bmp->height);
- printf("%u %u 256\n", bmp->width, bmp->height);
-
- {
- uint16_t row, col;
- uint8_t *image;
- image = (uint8_t *) bmp->bitmap;
- for (row = 0; row != bmp->height; row++) {
- for (col = 0; col != bmp->width; col++) {
- size_t z = (row * bmp->width + col) *
BYTES_PER_PIXEL;
- printf("%u %u %u ", image[z],
- image[z + 1],
- image[z + 2]);
- }
- printf("\n");
- }
- }
+ bmp_bitmap_callback_vt bitmap_callbacks = {
+ bitmap_create,
+ bitmap_destroy,
+ bitmap_get_buffer,
+ bitmap_get_bpp
+ };
+ uint16_t width, height;
+ ico_collection ico;
+ bmp_result code;
+ struct bmp_image *bmp;
+ size_t size;
+ unsigned short res = 0;
+ unsigned char *data;
+
+ if ((argc < 2) || (argc > 4)) {
+ fprintf(stderr, "Usage: %s collection.ico [width=255]
[height=255]\n", argv[0]);
+ return 1;
+ }
+ width = (argc >= 3) ? atoi(argv[2]) : 255;
+ height = (argc == 4) ? atoi(argv[3]) : 255;
+
+ /* create our bmp image */
+ ico_collection_create(&ico, &bitmap_callbacks);
+
+ /* load file into memory */
+ data = load_file(argv[1], &size);
+
+ /* analyse the BMP */
+ code = ico_analyse(&ico, size, data);
+ if (code != BMP_OK) {
+ warning("ico_analyse", code);
+ res = 1;
+ goto cleanup;
+ }
+
+ /* decode the image */
+ bmp = ico_find(&ico, width, height);
+ assert(bmp);
+
+ code = bmp_decode(bmp);
+ /* code = bmp_decode_trans(bmp, TRANSPARENT_COLOR); */
+ if (code != BMP_OK) {
+ warning("bmp_decode", code);
+ /* allow partially decoded images */
+ if ((code != BMP_INSUFFICIENT_DATA) &&
+ (code != BMP_DATA_ERROR)) {
+ res = 1;
+ goto cleanup;
+ }
+
+ /* skip if the decoded image would be ridiculously large */
+ if ((bmp->width * bmp->height) > 200000) {
+ res = 1;
+ goto cleanup;
+ }
+ }
+
+ if (bmp->opaque) {
+ write_ppm(stdout, argv[1], bmp);
+ } else {
+ write_pam(stdout, argv[1], bmp);
+ }
cleanup:
- /* clean up */
- ico_finalise(&ico);
- free(data);
+ /* clean up */
+ ico_finalise(&ico);
+ free(data);
- return res;
+ return res;
}
unsigned char *load_file(const char *path, size_t *data_size)
{
- FILE *fd;
- struct stat sb;
- unsigned char *buffer;
- size_t size;
- size_t n;
-
- fd = fopen(path, "rb");
- if (!fd) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- if (stat(path, &sb)) {
- perror(path);
- exit(EXIT_FAILURE);
- }
- size = sb.st_size;
-
- buffer = malloc(size);
- if (!buffer) {
- fprintf(stderr, "Unable to allocate %lld bytes\n",
- (long long) size);
- exit(EXIT_FAILURE);
- }
-
- n = fread(buffer, 1, size, fd);
- if (n != size) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- fclose(fd);
-
- *data_size = size;
- return buffer;
+ FILE *fd;
+ struct stat sb;
+ unsigned char *buffer;
+ size_t size;
+ size_t n;
+
+ fd = fopen(path, "rb");
+ if (!fd) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(path, &sb)) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+ size = sb.st_size;
+
+ buffer = malloc(size);
+ if (!buffer) {
+ fprintf(stderr, "Unable to allocate %lld bytes\n",
+ (long long) size);
+ exit(EXIT_FAILURE);
+ }
+
+ n = fread(buffer, 1, size, fd);
+ if (n != size) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(fd);
+
+ *data_size = size;
+ return buffer;
}
void warning(const char *context, bmp_result code)
{
- fprintf(stderr, "%s failed: ", context);
- switch (code) {
- case BMP_INSUFFICIENT_MEMORY:
- fprintf(stderr, "BMP_INSUFFICIENT_MEMORY");
- break;
- case BMP_INSUFFICIENT_DATA:
- fprintf(stderr, "BMP_INSUFFICIENT_DATA");
- break;
- case BMP_DATA_ERROR:
- fprintf(stderr, "BMP_DATA_ERROR");
- break;
- default:
- fprintf(stderr, "unknown code %i", code);
- break;
- }
- fprintf(stderr, "\n");
+ fprintf(stderr, "%s failed: ", context);
+ switch (code) {
+ case BMP_INSUFFICIENT_MEMORY:
+ fprintf(stderr, "BMP_INSUFFICIENT_MEMORY");
+ break;
+ case BMP_INSUFFICIENT_DATA:
+ fprintf(stderr, "BMP_INSUFFICIENT_DATA");
+ break;
+ case BMP_DATA_ERROR:
+ fprintf(stderr, "BMP_DATA_ERROR");
+ break;
+ default:
+ fprintf(stderr, "unknown code %i", code);
+ break;
+ }
+ fprintf(stderr, "\n");
}
void *bitmap_create(int width, int height, unsigned int state)
{
- (void) state; /* unused */
- return calloc(width * height, BYTES_PER_PIXEL);
+ (void) state; /* unused */
+ return calloc(width * height, BYTES_PER_PIXEL);
}
unsigned char *bitmap_get_buffer(void *bitmap)
{
- assert(bitmap);
- return bitmap;
+ assert(bitmap);
+ return bitmap;
}
size_t bitmap_get_bpp(void *bitmap)
{
- (void) bitmap; /* unused */
- return BYTES_PER_PIXEL;
+ (void) bitmap; /* unused */
+ return BYTES_PER_PIXEL;
}
void bitmap_destroy(void *bitmap)
{
- assert(bitmap);
- free(bitmap);
+ assert(bitmap);
+ free(bitmap);
}
-
diff --git a/test/icons/liberation.fr.favicon.ico
b/test/icons/liberation.fr.favicon.ico
new file mode 100644
index 0000000..0b670bb
Binary files /dev/null and b/test/icons/liberation.fr.favicon.ico differ
diff --git a/test/icons/liberation.fr.favicon.ppm
b/test/icons/liberation.fr.favicon.ppm
new file mode 100644
index 0000000..ddd5aa5
Binary files /dev/null and b/test/icons/liberation.fr.favicon.ppm differ
diff --git a/test/runtest.sh b/test/runtest.sh
index 28196c5..8e2b33c 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -40,8 +40,15 @@ bmpdecode()
icodecode()
{
OUTF=$(basename ${1} .ico)
+ CMPF=$(dirname ${1})/${OUTF}.ppm
echo "Icon:${1}" >> ${TEST_LOG}
${TEST_PATH}/test_decode_ico ${1} > ${TEST_OUT}/${OUTF}.ppm 2>> ${TEST_LOG}
+ if [ -f "${CMPF}" ]; then
+ cmp ${CMPF} ${TEST_OUT}/${OUTF}.ppm >> ${TEST_LOG} 2>> ${TEST_LOG}
+ if [ "$?" -ne 0 ]; then
+ return 128
+ fi
+ fi
}
# bitmap tests
@@ -54,7 +61,7 @@ for BMP in $(ls ${BMPTESTS});do
BMPTESTTOTC=$((BMPTESTTOTC+1))
bmpdecode ${BMP}
ECODE=$?
- if [ "${ECODE}" -gt 128 ];then
+ if [ "${ECODE}" -gt 127 ];then
BMPTESTERRC=$((BMPTESTERRC+1))
else
BMPTESTPASSC=$((BMPTESTPASSC+1))
@@ -76,7 +83,7 @@ for ICO in $(ls ${ICOTESTS});do
ICOTESTTOTC=$((ICOTESTTOTC+1))
icodecode ${ICO}
ECODE=$?
- if [ "${ECODE}" -gt 128 ];then
+ if [ "${ECODE}" -gt 127 ];then
ICOTESTERRC=$((ICOTESTERRC+1))
else
ICOTESTPASSC=$((ICOTESTPASSC+1))
--
NetSurf BMP Decoder
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org