diff options
author | Richard Wilson <rjw@netsurf-browser.org> | 2006-02-26 02:25:19 +0000 |
---|---|---|
committer | Richard Wilson <rjw@netsurf-browser.org> | 2006-02-26 02:25:19 +0000 |
commit | 60ea34ad48f604c96f228d8f7942c5527e8a5b15 (patch) | |
tree | 81afbe5a766c42b7cc1b3036be990c8fcda299c5 /image | |
parent | da4a9313f1260531ec3dde07b32c122f120f695c (diff) | |
download | netsurf-60ea34ad48f604c96f228d8f7942c5527e8a5b15.tar.gz netsurf-60ea34ad48f604c96f228d8f7942c5527e8a5b15.tar.bz2 |
[project @ 2006-02-26 02:25:19 by rjw]
Add support for ICO files.
svn path=/import/netsurf/; revision=2096
Diffstat (limited to 'image')
-rw-r--r-- | image/bmp.c | 12 | ||||
-rw-r--r-- | image/bmpread.c | 268 | ||||
-rw-r--r-- | image/bmpread.h | 18 | ||||
-rw-r--r-- | image/ico.c | 118 | ||||
-rw-r--r-- | image/ico.h | 33 |
5 files changed, 403 insertions, 46 deletions
diff --git a/image/bmp.c b/image/bmp.c index b2fc59f86..1eaef0592 100644 --- a/image/bmp.c +++ b/image/bmp.c @@ -11,8 +11,6 @@ #include <stdlib.h> #include "netsurf/utils/config.h" #include "netsurf/content/content.h" -#include "netsurf/desktop/browser.h" -#include "netsurf/desktop/options.h" #include "netsurf/desktop/plotters.h" #include "netsurf/image/bitmap.h" #include "netsurf/image/bmp.h" @@ -23,8 +21,6 @@ #ifdef WITH_BMP -static void nsbmp_invalidate(struct bitmap *bitmap, void *private_word); - bool nsbmp_create(struct content *c, const char *params[]) { union content_msg_data msg_data; @@ -76,20 +72,12 @@ bool nsbmp_convert(struct content *c, int iwidth, int iheight) { c->height, c->source_size); c->size += (bmp->width * bmp->height * 4) + 16 + 44 + 100; - /* make so that the bitmap code can free our image quickly */ - bitmap_set_suspendable(bmp->bitmap, bmp, nsbmp_invalidate); - /* exit as a success */ c->bitmap = bmp->bitmap; c->status = CONTENT_STATUS_DONE; return true; } -void nsbmp_invalidate(struct bitmap *bitmap, void *private_word) { - struct bmp_image *bmp = (struct bmp_image *)private_word; - - bmp->decoded = false; -} bool nsbmp_redraw(struct content *c, int x, int y, int width, int height, diff --git a/image/bmpread.c b/image/bmpread.c index 15c103ae0..89f30789e 100644 --- a/image/bmpread.c +++ b/image/bmpread.c @@ -18,9 +18,12 @@ #define READ_SHORT(a, o) (a[o]|(a[o+1]<<8)) #define READ_INT(a, o) (a[o]|(a[o+1]<<8)|(a[o+2]<<16)|(a[o+3]<<24)) -bmp_result bmp_decode_rgb24(struct bmp_image *bmp, char *data, int bytes); -bmp_result bmp_decode_rgb(struct bmp_image *bmp, char *data, int bytes); +bmp_result bmp_analyse_header(struct bmp_image *bmp, char *data); +bmp_result bmp_decode_rgb24(struct bmp_image *bmp, char **start, int bytes); +bmp_result bmp_decode_rgb(struct bmp_image *bmp, char **start, int bytes); +bmp_result bmp_decode_mask(struct bmp_image *bmp, char *data, int bytes); bmp_result bmp_decode_rle(struct bmp_image *bmp, char *data, int bytes, int size); +void bmp_invalidate(struct bitmap *bitmap, void *private_word); /** @@ -37,10 +40,6 @@ bmp_result bmp_decode_rle(struct bmp_image *bmp, char *data, int bytes, int size */ bmp_result bmp_analyse(struct bmp_image *bmp) { char *data = bmp->bmp_data; - unsigned int header_size; - unsigned int i; - int width, height; - int palette_size; /* ensure we aren't already initialised */ if (bmp->bitmap) @@ -59,9 +58,85 @@ bmp_result bmp_analyse(struct bmp_image *bmp) { if ((data[0] != 'B') || (data[1] != 'M')) return BMP_DATA_ERROR; bmp->bitmap_offset = READ_INT(data, 10); - data += 14; + + /* decode the BMP header */ + return bmp_analyse_header(bmp, data + 14); +} + + +/** + * Analyse an ICO prior to decoding. + * + * This function will scan the data provided and perform simple checks to + * ensure the data is a valid ICO. + * + * This function must be called before ico_find(). + * + * \param ico the ICO image to analyse + * \return BMP_OK on success + */ +bmp_result ico_analyse(struct ico_collection *ico) { + char *data = ico->ico_data; + unsigned int count, i; + bmp_result result; + struct ico_image *image; + int area, max_area = 0; + + /* ensure we aren't already initialised */ + if (ico->first) + return BMP_OK; + + /* standard 6-byte ICO file header is: + * + * +0 INT 0x00010000 + * +4 SHORT number of BMPs to follow + */ + if (ico->buffer_size < 6) + return BMP_INSUFFICIENT_DATA; + if (READ_INT(data, 0) != 0x00010000) + return BMP_DATA_ERROR; + count = READ_SHORT(data, 4); + if (count == 0) + return BMP_DATA_ERROR; + data += 6; + + /* decode the BMP files */ + if (ico->buffer_size < 6 + (16 * count)) + return BMP_INSUFFICIENT_DATA; + for (i = 0; i < count; i++) { + image = calloc(1, sizeof(struct ico_image)); + if (!image) + return BMP_INSUFFICIENT_MEMORY; + image->next = ico->first; + ico->first = image; + image->bmp.width = data[0]; + image->bmp.height = data[1]; + image->bmp.buffer_size = READ_INT(data, 8) + 40; + image->bmp.bmp_data = ico->ico_data + READ_INT(data, 12); + image->bmp.ico = true; + data += 16; + result = bmp_analyse_header(&image->bmp, image->bmp.bmp_data); + if (result != BMP_OK) + return result; + area = image->bmp.width * image->bmp.height; + if (area > max_area) { + ico->width = image->bmp.width; + ico->height = image->bmp.height; + max_area = area; + } + } + return BMP_OK; +} + + +bmp_result bmp_analyse_header(struct bmp_image *bmp, char *data) { + unsigned int header_size; + unsigned int i; + int width, height; + int palette_size; + unsigned int flags; - /* a variety of different bitmap headers can now follow, depending + /* a variety of different bitmap headers can follow, depending * on the BMP variant. A full description of the various headers * can be found at http://www.fileformat.info/format/bmp/ */ @@ -127,19 +202,23 @@ bmp_result bmp_analyse(struct bmp_image *bmp) { * +100 INT gamma green coordinate scale value * +104 INT gamma blue coordinate scale value */ - width = READ_INT(data, 4); - height = READ_INT(data, 8); - if (width < 0) - return BMP_DATA_ERROR; - if (height < 0) { - bmp->reversed = true; - height = -height; + if (!bmp->ico) { + width = READ_INT(data, 4); + height = READ_INT(data, 8); + if (width < 0) + return BMP_DATA_ERROR; + if (height < 0) { + bmp->reversed = true; + height = -height; + } + bmp->width = width; + bmp->height = height; } - bmp->width = width; - bmp->height = height; if (READ_SHORT(data, 12) != 1) return BMP_DATA_ERROR; bmp->bpp = READ_SHORT(data, 14); + if (bmp->bpp == 0) + bmp->bpp = 8; bmp->encoding = READ_INT(data, 16); if (bmp->encoding >= BMP_ENCODING_BITFIELDS) /* unsupported so far */ return BMP_DATA_ERROR; @@ -169,25 +248,74 @@ bmp_result bmp_analyse(struct bmp_image *bmp) { if (!bmp->colour_table) return BMP_INSUFFICIENT_MEMORY; for (i = 0; i < bmp->colours; i++) { - bmp->colour_table[i] = (data[2] | (data[1] << 8) | - (data[0] << 16) | (0xff << 24)); + bmp->colour_table[i] = data[2] | (data[1] << 8) | + (data[0] << 16); data += palette_size; } } /* create our bitmap */ - bmp->bitmap = bitmap_create(bmp->width, bmp->height, - BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); + flags = BITMAP_NEW | BITMAP_CLEAR_MEMORY; + if (!bmp->ico) + flags |= BITMAP_OPAQUE; + bmp->bitmap = bitmap_create(bmp->width, bmp->height, flags); if (!bmp->bitmap) { if (bmp->colour_table) free(bmp->colour_table); bmp->colour_table = NULL; return BMP_INSUFFICIENT_MEMORY; } + bmp->bitmap_offset = (int)data - (int)bmp->bmp_data; + bitmap_set_suspendable(bmp->bitmap, bmp, bmp_invalidate); return BMP_OK; } +/* + * Finds the closest BMP within an ICO collection + * + * This function finds the BMP with dimensions as close to a specified set + * as possible from the images in the collection. + * + * \param ico the ICO collection to examine + * \param width the preferred width + * \param height the preferred height + */ +struct bmp_image *ico_find(struct ico_collection *ico, int width, int height) { + struct bmp_image *bmp = NULL; + struct ico_image *image; + int x, y, cur, distance = (1 << 24); + + for (image = ico->first; image; image = image->next) { + if (((int)image->bmp.width == width) && ((int)image->bmp.height == height)) + return &image->bmp; + x = image->bmp.width - width; + y = image->bmp.height - height; + cur = (x * x) + (y * y); + if (cur < distance) { + distance = cur; + bmp = &image->bmp; + } + } + return bmp; +} + + +/** + * Invalidates a BMP + * + * This function sets the BMP into a state such that the bitmap image data + * can be released from memory. + * + * \param bmp the BMP image to invalidate + */ +void bmp_invalidate(struct bitmap *bitmap, void *private_word) { + struct bmp_image *bmp = (struct bmp_image *)private_word; + + bmp->decoded = false; +} + + /** * Decode a BMP * @@ -201,6 +329,7 @@ bmp_result bmp_analyse(struct bmp_image *bmp) { bmp_result bmp_decode(struct bmp_image *bmp) { char *data; int bytes; + bmp_result result = BMP_OK; assert(bmp->bitmap); @@ -210,20 +339,27 @@ bmp_result bmp_decode(struct bmp_image *bmp) { switch (bmp->encoding) { case BMP_ENCODING_RGB: if (bmp->bpp >= 24) - return bmp_decode_rgb24(bmp, data, bytes); + result = bmp_decode_rgb24(bmp, &data, bytes); else if (bmp->bpp > 8) return BMP_DATA_ERROR; else - return bmp_decode_rgb(bmp, data, bytes); + result = bmp_decode_rgb(bmp, &data, bytes); + break; case BMP_ENCODING_RLE8: - return bmp_decode_rle(bmp, data, bytes, 8); + result = bmp_decode_rle(bmp, data, bytes, 8); + break; case BMP_ENCODING_RLE4: - return bmp_decode_rle(bmp, data, bytes, 4); - case BMP_ENCODING_BITFIELDS: - /* todo: implement me */ + result = bmp_decode_rle(bmp, data, bytes, 4); break; + case BMP_ENCODING_BITFIELDS: + return BMP_DATA_ERROR; } - return BMP_DATA_ERROR; + + if ((!bmp->ico) || (result != BMP_OK)) + return result; + + bytes = (int)bmp->bmp_data + bmp->buffer_size - (int)data; + return bmp_decode_mask(bmp, data, bytes); } @@ -231,16 +367,17 @@ bmp_result bmp_decode(struct bmp_image *bmp) { * Decode BMP data stored in 24bpp colour. * * \param bmp the BMP image to decode - * \param data the data 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_result bmp_decode_rgb24(struct bmp_image *bmp, char *data, int bytes) { - char *top, *bottom, *end; +bmp_result bmp_decode_rgb24(struct bmp_image *bmp, char **start, int bytes) { + char *top, *bottom, *end, *data; unsigned int *scanline; unsigned int x, y, swidth, skip; unsigned int addr; + data = *start; swidth = bitmap_get_rowstride(bmp->bitmap); top = bitmap_get_buffer(bmp->bitmap); bottom = top + swidth * (bmp->height - 1); @@ -263,6 +400,7 @@ bmp_result bmp_decode_rgb24(struct bmp_image *bmp, char *data, int bytes) { data += skip; } } + *start = data; return BMP_OK; } @@ -271,12 +409,12 @@ bmp_result bmp_decode_rgb24(struct bmp_image *bmp, char *data, int bytes) { * Decode BMP data stored with a palette and in 8bpp colour or less. * * \param bmp the BMP image to decode - * \param data the data 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_result bmp_decode_rgb(struct bmp_image *bmp, char *data, int bytes) { - char *top, *bottom, *end; +bmp_result bmp_decode_rgb(struct bmp_image *bmp, char **start, int bytes) { + char *top, *bottom, *end, *data; unsigned int *scanline; unsigned int addr; unsigned int x, y, swidth; @@ -289,6 +427,7 @@ bmp_result bmp_decode_rgb(struct bmp_image *bmp, char *data, int bytes) { for (i = 0; i < ppb; i++) bit_shifts[i] = 8 - ((i + 1) * bmp->bpp); + data = *start; swidth = bitmap_get_rowstride(bmp->bitmap); top = bitmap_get_buffer(bmp->bitmap); bottom = top + swidth * (bmp->height - 1); @@ -315,6 +454,46 @@ bmp_result bmp_decode_rgb(struct bmp_image *bmp, char *data, int bytes) { bit_shifts[bit++]) & bit_mask]; } } + *start = data; + return BMP_OK; +} + + +/** + * Decode a 1bpp mask for an ICO + * + * \param bmp the BMP image to decode + * \param data the data to decode + * \param bytes the number of bytes of data available + * \return BMP_OK on success + */ +bmp_result bmp_decode_mask(struct bmp_image *bmp, char *data, int bytes) { + char *top, *bottom, *end; + unsigned int *scanline; + unsigned int addr; + unsigned int x, y, swidth; + int cur_byte = 0; + + swidth = bitmap_get_rowstride(bmp->bitmap); + top = bitmap_get_buffer(bmp->bitmap); + bottom = top + swidth * (bmp->height - 1); + end = data + bytes; + addr = ((unsigned int)data) & 3; + + for (y = 0; y < bmp->height; y++) { + while (addr != (((unsigned int)data) & 3)) + data++; + if ((data + (bmp->width >> 3)) > end) + return BMP_INSUFFICIENT_DATA; + scanline = (unsigned int *)(bottom - (y * swidth)); + for (x = 0; x < bmp->width; x++) { + if ((x & 7) == 0) + cur_byte = *data++; + if ((cur_byte & 128) == 0) + scanline[x] |= (0xff << 24); + cur_byte = cur_byte << 1; + } + } return BMP_OK; } @@ -336,6 +515,9 @@ bmp_result bmp_decode_rle(struct bmp_image *bmp, char *data, int bytes, int size unsigned int x = 0, y = 0, last_y = 0; unsigned int pixel = 0, pixel2; + if (bmp->ico) + return BMP_DATA_ERROR; + swidth = bitmap_get_rowstride(bmp->bitmap); top = bitmap_get_buffer(bmp->bitmap); bottom = top + swidth * (bmp->height - 1); @@ -481,3 +663,21 @@ void bmp_finalise(struct bmp_image *bmp) { free(bmp->colour_table); bmp->colour_table = NULL; } + + +/** + * Finalise an ICO prior to destruction. + * + * \param ico the ICO image to finalise + */ +void ico_finalise(struct ico_collection *ico) { + struct ico_image *image; + + for (image = ico->first; image; image = image->next) + bmp_finalise(&image->bmp); + while (ico->first) { + image = ico->first; + ico->first = image->next; + free(image); + } +} diff --git a/image/bmpread.h b/image/bmpread.h index 45468a9ed..275374e5a 100644 --- a/image/bmpread.h +++ b/image/bmpread.h @@ -44,11 +44,29 @@ struct bmp_image { unsigned int *colour_table; /** colour table */ bool reversed; /** scanlines are top to bottom */ bool decoded; /** whether the image has been decoded */ + bool ico; /** image is part of an ICO, mask follows */ struct bitmap *bitmap; /** decoded image */ }; +struct ico_image { + struct bmp_image bmp; + struct ico_image *next; +}; + +struct ico_collection { + unsigned char *ico_data; /** pointer to ICO data */ + unsigned int buffer_size; /** total number of bytes of ICO data available */ + unsigned int width; /** width of largest BMP */ + unsigned int height; /** heigth of largest BMP */ + struct ico_image *first; +}; + bmp_result bmp_analyse(struct bmp_image *bmp); bmp_result bmp_decode(struct bmp_image *bmp); void bmp_finalise(struct bmp_image *bmp); +bmp_result ico_analyse(struct ico_collection *ico); +struct bmp_image *ico_find(struct ico_collection *ico, int width, int height); +void ico_finalise(struct ico_collection *ico); + #endif diff --git a/image/ico.c b/image/ico.c new file mode 100644 index 000000000..cdb21eb57 --- /dev/null +++ b/image/ico.c @@ -0,0 +1,118 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson <info@tinct.net> + */ + +#include <assert.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include "netsurf/utils/config.h" +#include "netsurf/content/content.h" +#include "netsurf/desktop/plotters.h" +#include "netsurf/image/bitmap.h" +#include "netsurf/image/bmpread.h" +#include "netsurf/image/ico.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/messages.h" +#include "netsurf/utils/utils.h" + +#ifdef WITH_BMP + +bool nsico_create(struct content *c, const char *params[]) { + union content_msg_data msg_data; + + c->data.ico.ico = calloc(sizeof(struct ico_collection), 1); + if (!c->data.ico.ico) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + return true; +} + + +bool nsico_convert(struct content *c, int iwidth, int iheight) { + struct bmp_image *bmp; + bmp_result res; + struct ico_collection *ico; + union content_msg_data msg_data; + + /* set our source data */ + ico = c->data.ico.ico; + ico->ico_data = c->source_data; + ico->buffer_size = c->source_size; + + /* analyse the BMP */ + res = ico_analyse(ico); + switch (res) { + case BMP_OK: + break; + case BMP_INSUFFICIENT_MEMORY: + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + case BMP_INSUFFICIENT_DATA: + case BMP_DATA_ERROR: + msg_data.error = messages_get("BadICO"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + /* Store our content width and description + */ + c->width = ico->width; + c->height = ico->height; + c->title = malloc(100); + if (c->title) + snprintf(c->title, 100, messages_get("ICOTitle"), c->width, + c->height, c->source_size); + c->size += (ico->width * ico->height * 4) + 16 + 44 + 100; + + /* exit as a success */ + bmp = ico_find(c->data.ico.ico, 255, 255); + assert(bmp); + c->bitmap = bmp->bitmap; + c->status = CONTENT_STATUS_DONE; + return true; +} + +bool nsico_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour) { + struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); + if (!bmp->decoded) + bmp_decode(bmp); + c->bitmap = bmp->bitmap; + return plot.bitmap(x, y, width, height, c->bitmap, + background_colour); +} + + +bool nsico_redraw_tiled(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour, + bool repeat_x, bool repeat_y) { + struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); + if (!bmp->decoded) + bmp_decode(bmp); + c->bitmap = bmp->bitmap; + return plot.bitmap_tile(x, y, width, height, c->bitmap, + background_colour, repeat_x, repeat_y); +} + + +void nsico_destroy(struct content *c) +{ + ico_finalise(c->data.ico.ico); + free(c->data.ico.ico); + free(c->title); +} + +#endif diff --git a/image/ico.h b/image/ico.h new file mode 100644 index 000000000..401962e96 --- /dev/null +++ b/image/ico.h @@ -0,0 +1,33 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson <info@tinct.net> + */ + +#ifndef _NETSURF_IMAGE_ICO_H_ +#define _NETSURF_IMAGE_ICO_H_ + +#include <stdbool.h> +#include "netsurf/image/bmpread.h" + +struct content; + +struct content_ico_data { + struct ico_collection *ico; /** ICO collection data */ +}; + +bool nsico_create(struct content *c, const char *params[]); +bool nsico_convert(struct content *c, int width, int height); +void nsico_destroy(struct content *c); +bool nsico_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour); +bool nsico_redraw_tiled(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour, + bool repeat_x, bool repeat_y); + +#endif |