From f61d7fe881c3cac0de02733738c1694d638282cf Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Sat, 10 Apr 2004 18:19:35 +0000 Subject: [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 --- riscos/thumbnail.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++------- riscos/thumbnail.h | 1 + 2 files changed, 322 insertions(+), 46 deletions(-) (limited to 'riscos') diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c index 704ef51a8..72e0b8ce3 100644 --- a/riscos/thumbnail.c +++ b/riscos/thumbnail.c @@ -1,8 +1,9 @@ /* * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license + * http://www.opensource.org/licenses/gpl-license * Copyright 2004 James Bursa + * Copyright 2004 Richard Wilson */ /** \file @@ -12,80 +13,354 @@ * page at a small scale. */ +#include +#include #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. * * \param content content structure to thumbnail - * \param area sprite area containing thumbnail sprite + * \param area sprite area containing thumbnail sprite * \param sprite pointer to sprite * \param width sprite width / pixels * \param height sprite height / pixels * * 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; - scale = (float) width / (float) content->width; + /* 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(); - /* 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; + /* 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; + + /* 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); + +/* 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; } - save_area = malloc((unsigned) size); - if (!save_area) { - LOG(("malloc failed")); - return; + + /* 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); } - 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)); +/* 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); +} - /* clear background to white */ - colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG, - os_ACTION_OVERWRITE, 0); - os_clg(); - /* render content */ - content_redraw(content, 0, height * 2, width * 2, height * 2, - 0, 0, width * 2, height * 2, scale); +/* 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; + } - /* 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)); + /* 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); } diff --git a/riscos/thumbnail.h b/riscos/thumbnail.h index 7482b3c39..429e14fa8 100644 --- a/riscos/thumbnail.h +++ b/riscos/thumbnail.h @@ -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); -- cgit v1.2.3