diff options
author | Adrian Lees <adrian@aemulor.com> | 2008-03-24 01:35:13 +0000 |
---|---|---|
committer | Adrian Lees <adrian@aemulor.com> | 2008-03-24 01:35:13 +0000 |
commit | aefa03aed9333906dd0f3db794b79dcf41796729 (patch) | |
tree | ba8b71617ad33ac9dd35a782b6d162cfe6590d4f | |
parent | 175395b52dcd9f1cbae2f27ef7066fda731083f4 (diff) | |
download | netsurf-aefa03aed9333906dd0f3db794b79dcf41796729.tar.gz netsurf-aefa03aed9333906dd0f3db794b79dcf41796729.tar.bz2 |
Save non-opaque images with a proper mask/full alpha channel
svn path=/trunk/netsurf/; revision=4047
-rw-r--r-- | gtk/gtk_bitmap.c | 3 | ||||
-rw-r--r-- | image/bitmap.h | 4 | ||||
-rw-r--r-- | riscos/bitmap.c | 172 | ||||
-rw-r--r-- | riscos/save.c | 7 | ||||
-rw-r--r-- | riscos/wimp.c | 2 |
5 files changed, 172 insertions, 16 deletions
diff --git a/gtk/gtk_bitmap.c b/gtk/gtk_bitmap.c index 533159c23..2f4e1085c 100644 --- a/gtk/gtk_bitmap.c +++ b/gtk/gtk_bitmap.c @@ -171,10 +171,11 @@ void bitmap_destroy(struct bitmap *bitmap) * * \param bitmap a bitmap, as returned by bitmap_create() * \param path pathname for file + * \param flags modify the behaviour of the save * \return true on success, false on error and error reported */ -bool bitmap_save(struct bitmap *bitmap, const char *path) +bool bitmap_save(struct bitmap *bitmap, const char *path, unsigned flags) { GError *err = NULL; diff --git a/image/bitmap.h b/image/bitmap.h index c4c132935..7ef1e9c93 100644 --- a/image/bitmap.h +++ b/image/bitmap.h @@ -39,6 +39,8 @@ #define BITMAP_SUSPENDED (1 << 4) /** currently suspended */ #define BITMAP_READY (1 << 5) /** fully initialised */ +#define BITMAP_SAVE_FULL_ALPHA (1 << 0) /** save with full alpha channel (if not opaque) */ + struct content; /** An opaque image. */ @@ -51,7 +53,7 @@ bool bitmap_get_opaque(struct bitmap *bitmap); char *bitmap_get_buffer(struct bitmap *bitmap); size_t bitmap_get_rowstride(struct bitmap *bitmap); void bitmap_destroy(struct bitmap *bitmap); -bool bitmap_save(struct bitmap *bitmap, const char *path); +bool bitmap_save(struct bitmap *bitmap, const char *path, unsigned flags); void bitmap_modified(struct bitmap *bitmap); void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word, void (*invalidate)(struct bitmap *bitmap, void *private_word)); diff --git a/riscos/bitmap.c b/riscos/bitmap.c index eddd155be..edfa90c2c 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -1,6 +1,7 @@ /* * Copyright 2004 James Bursa <bursa@users.sourceforge.net> * Copyright 2005 Richard Wilson <info@tinct.net> + * Copyright 2008 Adrian Lees <adrianl@users.sourceforge.net> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -30,7 +31,9 @@ #include <swis.h> #include <unixlib/local.h> #include "oslib/osfile.h" -#include <oslib/osspriteop.h> +#include "oslib/osfind.h" +#include "oslib/osgbpb.h" +#include "oslib/osspriteop.h" #include "content/content.h" #include "image/bitmap.h" #include "riscos/bitmap.h" @@ -48,6 +51,9 @@ #define MAINTENANCE_THRESHOLD 32 +/** Size of buffer used when constructing mask data to be saved */ +#define SAVE_CHUNK_SIZE 4096 + /** The head of the bitmap list */ struct bitmap *bitmap_head = NULL; @@ -97,7 +103,6 @@ struct bitmap_compressed_header { char bitmap_unixname[256]; char bitmap_filename[256]; - static bool bitmap_initialise(struct bitmap *bitmap); static void bitmap_decompress(struct bitmap *bitmap); static void bitmap_compress(struct bitmap *bitmap); @@ -564,25 +569,170 @@ void bitmap_destroy(struct bitmap *bitmap) * * \param bitmap a bitmap, as returned by bitmap_create() * \param path pathname for file + * \param flags modify the behaviour of the save * \return true on success, false on error and error reported */ -bool bitmap_save(struct bitmap *bitmap, const char *path) +bool bitmap_save(struct bitmap *bitmap, const char *path, unsigned flags) { os_error *error; + if (!bitmap->sprite_area) bitmap_get_buffer(bitmap); if (!bitmap->sprite_area) return false; - error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, - (bitmap->sprite_area), path); - if (error) { - LOG(("xosspriteop_save_sprite_file: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("SaveError", error->errmess); - return false; + + if (bitmap_get_opaque(bitmap)) { + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + (bitmap->sprite_area), path); + if (error) { + LOG(("xosspriteop_save_sprite_file: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("SaveError", error->errmess); + return false; + } + return true; + } else { + /* to make the saved sprite useful we must convert from 'Tinct' + format to either a bi-level mask or a Select-style full + alpha channel */ + osspriteop_area *area = bitmap->sprite_area; + osspriteop_header *hdr = (osspriteop_header*)((char*)area+area->first); + unsigned width = hdr->width + 1, height = hdr->height + 1; + unsigned image_size = height * width * 4; + unsigned char *chunk_buf; + unsigned *p, *elp, *eip; + unsigned mask_size; + size_t chunk_pix; + struct { + osspriteop_area area; + osspriteop_header hdr; + } file_hdr; + os_fw fw; + + /* we only support 32bpp sprites */ + if ((((unsigned)hdr->mode >> 27)&15) != 6) { + assert(!"Unsupported sprite format in bitmap_save"); + return false; + } + + chunk_buf = malloc(SAVE_CHUNK_SIZE); + if (!chunk_buf) { + warn_user("NoMemory", NULL); + return false; + } + + file_hdr.area = *area; + file_hdr.hdr = *hdr; + + if (flags & BITMAP_SAVE_FULL_ALPHA) { + mask_size = ((width + 3) & ~3) * height; + chunk_pix = SAVE_CHUNK_SIZE; + file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode + | (1U<<31)); + } else { + mask_size = (((width + 31) & ~31)/8) * height; + chunk_pix = SAVE_CHUNK_SIZE<<3; + file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode + & ~(1U<<31)); + } + + file_hdr.area.sprite_count = 1; + file_hdr.area.first = sizeof(file_hdr.area); + file_hdr.area.used = sizeof(file_hdr) + image_size + mask_size; + + file_hdr.hdr.image = sizeof(file_hdr.hdr); + file_hdr.hdr.mask = file_hdr.hdr.image + image_size; + file_hdr.hdr.size = file_hdr.hdr.mask + mask_size; + + error = xosfind_openoutw(0, path, NULL, &fw); + if (error) { + LOG(("xosfind_openoutw: 0x%x: %s", + error->errnum, error->errmess)); + free(chunk_buf); + warn_user("SaveError", error->errmess); + return false; + } + + p = (unsigned*)((char*)hdr + hdr->image); + + /* write out the area header, sprite header and image data */ + error = xosgbpb_writew(fw, (byte*)&file_hdr + 4, + sizeof(file_hdr)-4, NULL); + if (!error) + error = xosgbpb_writew(fw, (byte*)p, image_size, NULL); + if (error) { + LOG(("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess)); + free(chunk_buf); + xosfind_closew(fw); + warn_user("SaveError", error->errmess); + return false; + } + + /* then write out the mask data in chunks */ + eip = p + (width * height); /* end of image */ + elp = p + width; /* end of line */ + + while (p < eip) { + unsigned char *dp = chunk_buf; + unsigned *ep = p + chunk_pix; + if (ep > elp) ep = elp; + + if (flags & BITMAP_SAVE_FULL_ALPHA) { + while (p < ep) { + *dp++ = ((unsigned char*)p)[3]; + p++; + } + } + else { + unsigned char mb = 0; + int msh = 0; + while (p < ep) { + if (((unsigned char*)p)[3]) mb |= (1 << msh); + if (++msh >= 8) { + *dp++ = mb; + msh = 0; + mb = 0; + } + p++; + } + if (msh > 0) *dp++ = mb; + } + + if (p >= elp) { /* end of line yet? */ + /* align to word boundary */ + while ((int)dp & 3) *dp++ = 0; + /* advance end of line pointer */ + elp += width; + } + error = xosgbpb_writew(fw, (byte*)chunk_buf, dp-chunk_buf, NULL); + if (error) { + LOG(("xosgbpb_writew: 0x%x: %s", + error->errnum, error->errmess)); + free(chunk_buf); + xosfind_closew(fw); + warn_user("SaveError", error->errmess); + return false; + } + } + + error = xosfind_closew(fw); + if (error) { + LOG(("xosfind_closew: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("SaveError", error->errmess); + } + + error = xosfile_set_type(path, osfile_TYPE_SPRITE); + if (error) { + LOG(("xosfile_set_type: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("SaveError", error->errmess); + } + + free(chunk_buf); + return true; } - return true; } diff --git a/riscos/save.c b/riscos/save.c index e73e55aeb..3ded30684 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -841,8 +841,11 @@ void ro_gui_save_object_native(struct content *c, char *path) case CONTENT_BMP: case CONTENT_ICO: #endif - bitmap_save(c->bitmap, path); - break; + { + unsigned flags = (os_version == 0xA9) ? BITMAP_SAVE_FULL_ALPHA : 0; + bitmap_save(c->bitmap, path, flags); + } + break; #ifdef WITH_SPRITE case CONTENT_SPRITE: { diff --git a/riscos/wimp.c b/riscos/wimp.c index a45454606..cc22c1091 100644 --- a/riscos/wimp.c +++ b/riscos/wimp.c @@ -424,7 +424,7 @@ void ro_gui_set_icon_decimal(wimp_w w, wimp_i i, int value, int decimal_places) sprintf(buffer, "%.2f", (float)value / 100); break; default: - assert("Unsupported decimal format"); + assert(!"Unsupported decimal format"); break; } ro_gui_set_icon_string(w, i, buffer); |