[project @ 2004-04-10 18:19:35 by rjw]
Thumnails now created with a palette to fix incorrect colour rendition. Thumnails output to a 32bpp sprite where possible. Thumnails oversampled to improve display if desired. svn path=/import/netsurf/; revision=744
This commit is contained in:
parent
4934762dd6
commit
f61d7fe881
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
|
@ -12,13 +13,41 @@
|
|||
* page at a small scale.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <swis.h>
|
||||
#include "oslib/colourtrans.h"
|
||||
#include "oslib/osfile.h"
|
||||
#include "oslib/osspriteop.h"
|
||||
#include "netsurf/content/content.h"
|
||||
#include "netsurf/riscos/options.h"
|
||||
#include "netsurf/riscos/thumbnail.h"
|
||||
#include "netsurf/riscos/tinct.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
|
||||
|
||||
/* Whether we can use 32bpp sprites
|
||||
*/
|
||||
static int thumbnail_32bpp_available = -1;
|
||||
|
||||
|
||||
/* Sprite output context saving
|
||||
*/
|
||||
struct thumbnail_save_area {
|
||||
osspriteop_save_area *save_area;
|
||||
int context1;
|
||||
int context2;
|
||||
int context3;
|
||||
};
|
||||
|
||||
|
||||
/* Internal prototypes
|
||||
*/
|
||||
static void thumbnail_test(void);
|
||||
static struct thumbnail_save_area* thumbnail_switch_output(osspriteop_area *sprite_area,
|
||||
osspriteop_header *sprite_header);
|
||||
static void thumbnail_restore_output(struct thumbnail_save_area *save_area);
|
||||
|
||||
|
||||
/**
|
||||
* Create a thumbnail of a page.
|
||||
*
|
||||
|
@ -30,62 +59,308 @@
|
|||
*
|
||||
* The thumbnail is rendered in the given sprite.
|
||||
*/
|
||||
|
||||
void thumbnail_create(struct content *content, osspriteop_area *area,
|
||||
osspriteop_header *sprite, int width, int height)
|
||||
{
|
||||
int size;
|
||||
int context1, context2, context3;
|
||||
osspriteop_header *sprite, int width, int height) {
|
||||
float scale;
|
||||
osspriteop_save_area *save_area;
|
||||
os_error *error;
|
||||
osspriteop_area *oversampled_area = NULL;
|
||||
struct thumbnail_save_area *save_area;
|
||||
|
||||
/* Check for 32bpp support in case we've been called for a sprite
|
||||
we didn't set up.
|
||||
*/
|
||||
if (thumbnail_32bpp_available == -1) thumbnail_test();
|
||||
|
||||
/* Check our oversampling is within a usable range
|
||||
*/
|
||||
if (option_thumbnail_oversampling < 0) option_thumbnail_oversampling = 0;
|
||||
if (option_thumbnail_oversampling > 4) option_thumbnail_oversampling = 4;
|
||||
|
||||
/* Get the oversampled sprite holder. We perform oversamling if either we
|
||||
want to oversample, or the output sprite is 8bpp and we can do 32bpp and
|
||||
thus improve the final rendition via dithering.
|
||||
*/
|
||||
if ((thumbnail_32bpp_available == 1) &&
|
||||
((option_thumbnail_oversampling > 0) || (sprite->mode != (os_mode)0x301680b5))) {
|
||||
oversampled_area = thumbnail_initialise(
|
||||
width << option_thumbnail_oversampling,
|
||||
height << option_thumbnail_oversampling,
|
||||
(os_mode)0x301680b5);
|
||||
}
|
||||
|
||||
/* Oversample if we have an oversampled sprite, don't otherwise
|
||||
*/
|
||||
if (oversampled_area != NULL) {
|
||||
/* Scale up for oversampling
|
||||
*/
|
||||
width = width << option_thumbnail_oversampling;
|
||||
height = height << option_thumbnail_oversampling;
|
||||
|
||||
/* Calculate the scale
|
||||
*/
|
||||
scale = (float) width / (float) content->width;
|
||||
|
||||
/* allocate save area */
|
||||
error = xosspriteop_read_save_area_size(osspriteop_PTR, area,
|
||||
(osspriteop_id) sprite, &size);
|
||||
if (error) {
|
||||
LOG(("xosspriteop_read_save_area_size failed: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
return;
|
||||
}
|
||||
save_area = malloc((unsigned) size);
|
||||
if (!save_area) {
|
||||
LOG(("malloc failed"));
|
||||
return;
|
||||
}
|
||||
save_area->a[0] = 0;
|
||||
|
||||
/* switch output to sprite */
|
||||
error = xosspriteop_switch_output_to_sprite(osspriteop_PTR, area,
|
||||
(osspriteop_id) sprite, save_area,
|
||||
0, &context1, &context2, &context3);
|
||||
if (error) {
|
||||
LOG(("xosspriteop_switch_output_to_sprite failed: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear background to white */
|
||||
colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG,
|
||||
os_ACTION_OVERWRITE, 0);
|
||||
os_clg();
|
||||
|
||||
/* render content */
|
||||
/* Switch output and redraw oversampled
|
||||
*/
|
||||
save_area = thumbnail_switch_output(oversampled_area,
|
||||
(osspriteop_header *)(oversampled_area + 1));
|
||||
if (save_area == NULL) return;
|
||||
content_redraw(content, 0, height * 2, width * 2, height * 2,
|
||||
0, 0, width * 2, height * 2, scale);
|
||||
thumbnail_restore_output(save_area);
|
||||
|
||||
/* switch output back to screen */
|
||||
error = xosspriteop_switch_output_to_sprite(osspriteop_PTR,
|
||||
(osspriteop_area *) context1,
|
||||
(osspriteop_id) context2,
|
||||
(osspriteop_save_area *) context3,
|
||||
0, 0, 0, 0);
|
||||
if (error) {
|
||||
LOG(("xosspriteop_switch_output_to_sprite failed: %s",
|
||||
error->errmess));
|
||||
/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
|
||||
oversampled_area, "oversample");
|
||||
*/
|
||||
/* Scale back
|
||||
*/
|
||||
width = width >> option_thumbnail_oversampling;
|
||||
height = height >> option_thumbnail_oversampling;
|
||||
|
||||
/* Switch output to the final sprite
|
||||
*/
|
||||
save_area = thumbnail_switch_output(area, sprite);
|
||||
if (save_area == NULL) {
|
||||
free(oversampled_area);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get Tinct to dither and bilinear filter back to what we want.
|
||||
*/
|
||||
_swix(Tinct_PlotScaled, _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7),
|
||||
(char *)(oversampled_area + 1), 0, 0, width * 2, height * 2,
|
||||
(1<<1) | (1<<2));
|
||||
|
||||
/* Restore output
|
||||
*/
|
||||
thumbnail_restore_output(save_area);
|
||||
|
||||
/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
|
||||
area, "thumb_scaled");
|
||||
*/
|
||||
|
||||
} else {
|
||||
/* Calculate the scale
|
||||
*/
|
||||
scale = (float) width / (float) content->width;
|
||||
|
||||
/* Switch output and redraw
|
||||
*/
|
||||
save_area = thumbnail_switch_output(area, sprite);
|
||||
if (save_area == NULL) return;
|
||||
content_redraw(content, 0, height * 2, width * 2, height * 2,
|
||||
0, 0, width * 2, height * 2, scale);
|
||||
thumbnail_restore_output(save_area);
|
||||
|
||||
/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
|
||||
area, "thumb");
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialises a sprite.
|
||||
*
|
||||
* The sprite background cleared to white.
|
||||
* Any necessary palette data is set up to the default palette.
|
||||
* The sprite name is set to "thumbnail".
|
||||
*
|
||||
* @param width The sprite width
|
||||
* @param height The sprite height
|
||||
* @param mode The preferred mode (0x301680b5 or os_MODE8BPP90X90)
|
||||
* @return
|
||||
*/
|
||||
osspriteop_area* thumbnail_initialise(int width, int height, os_mode mode) {
|
||||
unsigned int area_size;
|
||||
unsigned int remaining_bytes;
|
||||
osspriteop_area *sprite_area;
|
||||
osspriteop_header *sprite_header;
|
||||
char *sprite_image;
|
||||
|
||||
/* Check if we can use 32bpp sprites if we haven't already. By
|
||||
doing it this way we don't need to allocate lot of memory
|
||||
first which will probably not be available on machines that
|
||||
can't handle such sprites..
|
||||
*/
|
||||
if (thumbnail_32bpp_available == -1) thumbnail_test();
|
||||
|
||||
/* If we can't handle 32bpp then we get 8bpp.
|
||||
*/
|
||||
if (thumbnail_32bpp_available != 1) mode = os_MODE8BPP90X90;
|
||||
|
||||
/* Calculate our required memory
|
||||
*/
|
||||
area_size = sizeof(osspriteop_area) + sizeof(osspriteop_header);
|
||||
if (mode == (os_mode)0x301680b5) {
|
||||
area_size += width * height * 4;
|
||||
} else {
|
||||
area_size += ((width + 3) & ~3) * height + 2048;
|
||||
}
|
||||
|
||||
/* Try to get enough memory
|
||||
*/
|
||||
if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
|
||||
LOG(("Insufficient memory to create thumbnail."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialise the sprite area
|
||||
*/
|
||||
sprite_area->size = area_size;
|
||||
sprite_area->sprite_count = 1;
|
||||
sprite_area->first = 16;
|
||||
sprite_area->used = area_size;
|
||||
|
||||
/* Initialise the sprite header. We can't trust OS_SpriteOp to
|
||||
set up our palette properly due to insane legacy 8bpp palettes,
|
||||
so we do it all manually.
|
||||
*/
|
||||
sprite_header = (osspriteop_header *)(sprite_area + 1);
|
||||
sprite_header->size = area_size - sizeof(osspriteop_area);
|
||||
memset(sprite_header->name, 0x00, 12);
|
||||
strcpy(sprite_header->name, "thumbnail");
|
||||
sprite_header->left_bit = 0;
|
||||
sprite_header->height = height - 1;
|
||||
sprite_header->mode = mode;
|
||||
if (mode == (os_mode)0x301680b5) {
|
||||
sprite_header->right_bit = 31;
|
||||
sprite_header->width = width - 1;
|
||||
sprite_header->image = sizeof(osspriteop_header);
|
||||
sprite_header->mask = sizeof(osspriteop_header);
|
||||
|
||||
/* Clear to white, full opacity
|
||||
*/
|
||||
sprite_image = ((char *)sprite_header) + sprite_header->image;
|
||||
memset(sprite_image, 0xff, area_size - sizeof(osspriteop_area) -
|
||||
sizeof(osspriteop_header));
|
||||
} else {
|
||||
sprite_header->right_bit = ((width << 3) - 1) & 31;
|
||||
sprite_header->width = ((width + 3) >> 2) - 1;
|
||||
sprite_header->image = sizeof(osspriteop_header) + 2048;
|
||||
sprite_header->mask = sizeof(osspriteop_header) + 2048;
|
||||
|
||||
/* Create the palette. We don't read the necessary size
|
||||
like we really should as we know it's going to have
|
||||
256 entries of 8 bytes = 2048.
|
||||
*/
|
||||
xcolourtrans_read_palette((osspriteop_area *)mode, (osspriteop_id)0,
|
||||
(os_palette *)(sprite_header + 1), 2048,
|
||||
(colourtrans_palette_flags)(1 << 1), &remaining_bytes);
|
||||
|
||||
/* Clear to white
|
||||
*/
|
||||
sprite_image = ((char *)sprite_header) + sprite_header->image;
|
||||
memset(sprite_image, 0xff, area_size - sizeof(osspriteop_area) -
|
||||
sizeof(osspriteop_header) - 2048);
|
||||
}
|
||||
/* xosfile_save_stamped("thumb", 0xff9,
|
||||
((char *)sprite_area) + 4,
|
||||
((char *)sprite_area) + area_size);
|
||||
|
||||
*/
|
||||
/* Return our sprite area
|
||||
*/
|
||||
return sprite_area;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to see whether 32bpp sprites are available. Rather than
|
||||
* using Wimp_ReadSysInfo we test if 32bpp sprites are available in
|
||||
* case the user has a 3rd party patch to enable them.
|
||||
*/
|
||||
static void thumbnail_test(void) {
|
||||
unsigned int area_size;
|
||||
osspriteop_area *sprite_area;
|
||||
|
||||
/* Get enough memory for a 1x1 32bpp sprite
|
||||
*/
|
||||
area_size = sizeof(osspriteop_area) +
|
||||
sizeof(osspriteop_header) + sizeof(int);
|
||||
if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
|
||||
LOG(("Insufficient memory to perform sprite test."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialise the sprite area
|
||||
*/
|
||||
sprite_area->size = area_size + 1;
|
||||
sprite_area->sprite_count = 0;
|
||||
sprite_area->first = 16;
|
||||
sprite_area->used = 16;
|
||||
|
||||
/* Try to create a 32bpp sprite
|
||||
*/
|
||||
if (xosspriteop_create_sprite(osspriteop_NAME, sprite_area,
|
||||
"test", false, 1, 1, (os_mode)0x301680b5)) {
|
||||
thumbnail_32bpp_available = 0;
|
||||
} else {
|
||||
thumbnail_32bpp_available = 1;
|
||||
}
|
||||
|
||||
/* Free our memory
|
||||
*/
|
||||
free(sprite_area);
|
||||
}
|
||||
|
||||
|
||||
/* Switches output to the specified sprite and returns the previous context.
|
||||
*/
|
||||
static struct thumbnail_save_area* thumbnail_switch_output(osspriteop_area *sprite_area,
|
||||
osspriteop_header *sprite_header) {
|
||||
struct thumbnail_save_area *save_area;
|
||||
int size;
|
||||
|
||||
/* Create a save area
|
||||
*/
|
||||
save_area = calloc(sizeof(struct thumbnail_save_area), 1);
|
||||
if (save_area == NULL) return NULL;
|
||||
|
||||
/* Allocate OS_SpriteOp save area
|
||||
*/
|
||||
if (xosspriteop_read_save_area_size(osspriteop_PTR, sprite_area,
|
||||
(osspriteop_id)sprite_header, &size)) {
|
||||
free(save_area);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the save area
|
||||
*/
|
||||
save_area->save_area = malloc((unsigned)size);
|
||||
if (save_area->save_area == NULL) {
|
||||
free(save_area);
|
||||
return NULL;
|
||||
}
|
||||
save_area->save_area->a[0] = 0;
|
||||
|
||||
/* Switch output to sprite
|
||||
*/
|
||||
if (xosspriteop_switch_output_to_sprite(osspriteop_PTR, sprite_area,
|
||||
(osspriteop_id)sprite_header, save_area->save_area,
|
||||
0, &save_area->context1, &save_area->context2,
|
||||
&save_area->context3)) {
|
||||
free(save_area->save_area);
|
||||
free(save_area);
|
||||
return NULL;
|
||||
}
|
||||
return save_area;
|
||||
}
|
||||
|
||||
|
||||
/* Restores output to the specified context, and destroys it.
|
||||
*/
|
||||
static void thumbnail_restore_output(struct thumbnail_save_area *save_area) {
|
||||
|
||||
/* We don't care if we err, as there's nothing we can do about it
|
||||
*/
|
||||
xosspriteop_switch_output_to_sprite(osspriteop_PTR,
|
||||
(osspriteop_area *)save_area->context1,
|
||||
(osspriteop_id)save_area->context2,
|
||||
(osspriteop_save_area *)save_area->context3,
|
||||
0, 0, 0, 0);
|
||||
|
||||
/* Free our workspace
|
||||
*/
|
||||
free(save_area->save_area);
|
||||
free(save_area);
|
||||
}
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
|
||||
void thumbnail_create(struct content *content, osspriteop_area *area,
|
||||
osspriteop_header *sprite, int width, int height);
|
||||
osspriteop_area* thumbnail_initialise(int width, int height, os_mode mode);
|
||||
|
|
Loading…
Reference in New Issue