Save non-opaque images with a proper mask/full alpha channel
svn path=/trunk/netsurf/; revision=4047
This commit is contained in:
parent
175395b52d
commit
aefa03aed9
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
156
riscos/bitmap.c
156
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,16 +569,20 @@ 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;
|
||||
|
||||
if (bitmap_get_opaque(bitmap)) {
|
||||
error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
|
||||
(bitmap->sprite_area), path);
|
||||
if (error) {
|
||||
|
@ -583,6 +592,147 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -841,7 +841,10 @@ void ro_gui_save_object_native(struct content *c, char *path)
|
|||
case CONTENT_BMP:
|
||||
case CONTENT_ICO:
|
||||
#endif
|
||||
bitmap_save(c->bitmap, path);
|
||||
{
|
||||
unsigned flags = (os_version == 0xA9) ? BITMAP_SAVE_FULL_ALPHA : 0;
|
||||
bitmap_save(c->bitmap, path, flags);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef WITH_SPRITE
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue