From c3c1fb916bb6135ddbd61225b18f7778274bd0be Mon Sep 17 00:00:00 2001 From: James Bursa Date: Fri, 18 Jul 2003 21:02:29 +0000 Subject: [project @ 2003-07-18 21:02:29 by bursa] New GIF renderer using animlib (jmb). svn path=/import/netsurf/; revision=235 --- riscos/gif.c | 408 ++++++++++++++++++++++------------------------------------- 1 file changed, 150 insertions(+), 258 deletions(-) (limited to 'riscos') diff --git a/riscos/gif.c b/riscos/gif.c index d9848cb21..31b0963b0 100644 --- a/riscos/gif.c +++ b/riscos/gif.c @@ -2,25 +2,16 @@ * 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 2003 Philip Pemberton - */ -/******************* - * GIF loader for Netsurf - * Developed by Philip Pemberton for the Netsurf project - * - * Yes, this is an evil hack. You will not be tested on your understanding of - * this code. Beware - dragons lurketh here. - * - * TO-DO: - * Add support for GIF transparency - * Add better error handling - * - especially where bad GIFs are concerned. + * Copyright 2003 John M Bell + * Parts modified from IGviewer source by Peter Hartley + * http://utter.chaos.org/~pdh/software/intergif.htm */ #include #include +#include #include -#include "libungif/gif_lib.h" +#include "animlib/animlib.h" #include "oslib/colourtrans.h" #include "oslib/os.h" #include "oslib/osspriteop.h" @@ -29,265 +20,96 @@ #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" -// Constants for GIF interlacing -const int - InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */ - InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */ - +static osspriteop_area *create_buffer_sprite(struct content *c, anim a, int *bgc); void nsgif_init(void) { } -// Called when Netsurf wants us to prepare to decode a GIF -void nsgif_create(struct content *c) +void nsgif_create(struct content*c) { - // Clear the sprite area c->data.gif.sprite_area = 0; - - // Allocate some memory for the GIF file c->data.gif.data = xcalloc(0, 1); - // Set the length and buffer position to zero (we haven't loaded any data - // yet) c->data.gif.length = 0; c->data.gif.buffer_pos = 0; } -// Called when Netsurf has got some more data for us void nsgif_process_data(struct content *c, char *data, unsigned long size) { - // We've just been given some more data! - // Reallocate the memory block c->data.gif.data = xrealloc(c->data.gif.data, c->data.gif.length + size); - // Copy the new data into our buffer memcpy(c->data.gif.data + c->data.gif.length, data, size); - // Update the data length variables c->data.gif.length += size; c->size += size; } -// This is the callback for the GIF loader. It grabs some data from the buffer -// and hands it over to Libungif. -// Returns the number of bytes successfully read from the buffer -int nsgif_input_callback(GifFileType *giffile, GifByteType *data, int length) -{ - struct content *c; - - // We need to set up the content block pointer first - c = (struct content *)giffile->UserData; - - // Now check that there's enough data in the buffer - if ((c->data.gif.buffer_pos + length) > c->data.gif.length) - { - // We don't have enough data in the buffer. Give libungif the data we've - // got. - memcpy(data, &c->data.gif.data[c->data.gif.buffer_pos], (c->data.gif.length - c->data.gif.buffer_pos)); - c->data.gif.buffer_pos += length; - return (c->data.gif.length - c->data.gif.buffer_pos); - } - - // Well, we've got enough data. Give libungif as much as it wants. - memcpy(data, &c->data.gif.data[c->data.gif.buffer_pos], (unsigned int) length); - c->data.gif.buffer_pos += length; - - return length; -} - -// Called when Netsurf wants us to convert the image int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight) { - unsigned long i, j; - unsigned int sprite_size; - unsigned long width, height, left, top; - os_sprite_palette *sprite_palette; - osspriteop_area *sprite_area; - osspriteop_header *sprite; - // The next three lines are for vars. used by the gif decoding engine - GifRecordType recordtype; - int extcode, count, got_image_data; - int trancol = -1; - GifByteType *extension; - GifColorType *colormap; - - LOG(("Opening GIF file")); - - got_image_data = 0; // we haven't read any image data yet - - // Now decode the GIF - c->data.gif.giffile = DGifOpen(c, &nsgif_input_callback); - if (c->data.gif.giffile == NULL) - { - LOG(("ERROR: giffile is null! error %d", GifLastError())); - return 1; // more graceful exit + anim a; + frame f; + pixel *img, *mask; + int bg; + struct osspriteop_header *header; + struct osspriteop_area *area; + + a = Anim_FromData(c->data.gif.data, c->data.gif.length, NULL, false, false, false); + if (!a) { + + LOG(("Error creating anim object")); + return 1; } - // Start creating the sprite - width = c->data.gif.giffile->SWidth; - height = c->data.gif.giffile->SHeight; - - LOG(("gif image width = %lu, height = %lu", width, height)); - - sprite_size = sizeof(*sprite_area) + sizeof(*sprite); - - // GIFs can't be more than 256 colours (8 bits). - sprite_size += (8 * 256) + (height * ((width + 3) & ~3u) * 2); - - sprite_area = xcalloc((sprite_size) + 1000, 1); - sprite_area->size = sprite_size; - sprite_area->sprite_count = 1; - sprite_area->first = sizeof(*sprite_area); - sprite_area->used = sprite_size; - sprite = (osspriteop_header *) (sprite_area + 1); - sprite->size = sprite_size - sizeof(*sprite_area); - strcpy(sprite->name, "gif"); - sprite->height = height -1; - c->data.gif.sprite_area = sprite_area; - sprite->width = ((width + 3) & ~3u) / 4 - 1; - sprite->left_bit = 0; - sprite->right_bit = (8 * (((width - 1) % 4) + 1)) -1; - sprite->image = sizeof(*sprite) + 8 * 256; - sprite->mask = sizeof(*sprite) + (8 * 256) + (height * ((width + 3) & ~3u)); - LOG(("image = %d, mask = %d", sprite->image, sprite->mask)); - sprite->mode = (os_mode) 21; - sprite_palette = (os_sprite_palette *) (sprite + 1); - c->data.gif.sprite_image = ((char *) sprite) + sprite->image; - c->width = width; - c->height = height; - - do - { - if (DGifGetRecordType(c->data.gif.giffile, &recordtype) == GIF_ERROR) - { - LOG(("gif error %d", GifLastError())); - return(1); // more graceful exit - } - // TODO: ^^^ better error checking - switch (recordtype) - { - case IMAGE_DESC_RECORD_TYPE: - // The next line is used to handle animated GIFs - if (!got_image_data) - { - assert(DGifGetImageDesc(c->data.gif.giffile) != GIF_ERROR); - // TODO: ^^^ better error checking - - c->data.gif.sprite_area = sprite_area; - height = c->data.gif.giffile->Image.Height; - width = c->data.gif.giffile->Image.Width; - left = c->data.gif.giffile->Image.Left; - top = c->data.gif.giffile->Image.Top; - - if (c->data.gif.giffile->Image.Interlace) - { - // The image is interlaced, therefore we need to perform four - // passes over the image - for (count = i = 0; i < 4; i++) - { - LOG(("Interlaced GIF file")); - for (j=(top+InterlacedOffset[i]); j < (top+c->data.gif.giffile->Image.Height); j += InterlacedJumps[i]) - { - count++; - assert (DGifGetLine(c->data.gif.giffile, c->data.gif.sprite_image + (j * ((c->width + 3) & ~3u)) + left, (int)width) != GIF_ERROR); - // TODO: ^^^ better error checking - } - } - } - else - { - LOG(("running DGifGetLine")); - for (i=top; i<(height+top); i++) - { - if (DGifGetLine(c->data.gif.giffile, c->data.gif.sprite_image + (i * ((c->width + 3) & ~3u))+left, (int) width) == GIF_ERROR) - { - LOG(("error: gif line %lu - error %d", i, GifLastError())); - LOG(("exp height = %lu, width = %lu", height, width)); - return 1; - } - // TODO: ^^^ better error checking - } - } - got_image_data = -1; - } else recordtype = TERMINATE_RECORD_TYPE; - break; - case EXTENSION_RECORD_TYPE: - assert (DGifGetExtension(c->data.gif.giffile, &extcode, &extension) != GIF_ERROR); + if(!Anim_CommonPalette(a)) { - if (extension == NULL) - break; + LOG(("bad palette")); + Anim_Destroy(&a); + return 1; + } - do - { - // Is the extension block a Graphics Rendering Info block? - if (extcode == GRAPHICS_EXT_FUNC_CODE) - { - // Yep. Grab the transparency data - if ((extension[1] & 1) == 1) - trancol = extension[4]; - else - trancol = -1; - } - - DGifGetExtensionNext(c->data.gif.giffile, &extension); - } while (extension != NULL); - break; - case TERMINATE_RECORD_TYPE: - break; - default: // Should be trapped by DGifGetRecordType - break; - } - } while (recordtype != TERMINATE_RECORD_TYPE); + area = create_buffer_sprite(c, a, &bg); + if(!area) { - LOG(("creating image transparency mask, trancol %i", trancol)); + LOG(("Failed to create sprite")); + Anim_Destroy(&a); + xfree(area); + return 1; + } + c->data.gif.sprite_area = area; - // This is one evil piece of code. Still, it works... - for (j=0; jmask; - unsigned int pixofs = (j * ((c->width + 3) & ~3u)) + i; + header = (osspriteop_header*)(c->data.gif.sprite_area + 1); + f = a->pFrames + 0; + img = (pixel*)header + header->image; + mask = (pixel*)header + header->mask; - if (c->data.gif.sprite_image[pixofs] == trancol) - x[pixofs] = 0x00; - else - x[pixofs] = 0xFF; - } + Anim_DecompressAligned(f->pImageData, f->nImageSize, + a->nWidth, a->nHeight, img); -/* - And now for the obligatory quote from "The Matrix" - "Before you can bend the spoon, you must realise the truth." - "And what is the truth?" - "There is no spoon." - */ + if(f->pMaskData) { - // Load the colour map - colormap = (c->data.gif.giffile->Image.ColorMap ? - c->data.gif.giffile->Image.ColorMap->Colors : - c->data.gif.giffile->SColorMap->Colors); + int i,n = header->mask - header->image; - for (i=0; i < 256; i++) - sprite_palette->entries[i].on = - sprite_palette->entries[i].off = - (colormap[i].Blue << 24) | - (colormap[i].Green << 16) | - (colormap[i].Red << 8) | - 16; + Anim_DecompressAligned(f->pMaskData, f->nMaskSize, + a->nWidth, a->nHeight, mask); - DGifCloseFile(c->data.gif.giffile); + for(i=0; iwidth = width; - c->height = height; + img[i] = 255; + mask[i] = bg; + } + } + else + memset(mask, 255, header->mask - header->image); - c->title = xcalloc(100, 1); + c->title = xcalloc(100, sizeof(char)); sprintf(c->title, "GIF image (%lux%lu)", c->width, c->height); c->status = CONTENT_STATUS_DONE; -// Enable this if you want to debug the GIF loader -// xosspriteop_save_sprite_file(osspriteop_USER_AREA, c->data.gif.sprite_area, -// "gif"); +/* xosspriteop_save_sprite_file(osspriteop_USER_AREA, + c->data.gif.sprite_area, "gif"); */ + return 0; } - void nsgif_revive(struct content *c, unsigned int width, unsigned int height) { } @@ -297,7 +119,37 @@ void nsgif_reformat(struct content *c, unsigned int width, unsigned int height) { } -// Called when Netsurf is finished with us +void nsgif_redraw(struct content *c, long x, long y, + unsigned long width, unsigned long height) +{ + unsigned int size; + osspriteop_trans_tab *table; + + + xcolourtrans_generate_table_for_sprite(c->data.gif.sprite_area, + (osspriteop_id) (c->data.gif.sprite_area + 1), + colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, + 0, colourtrans_GIVEN_SPRITE, 0, 0, &size); + + table = xcalloc(size, 1); + + xcolourtrans_generate_table_for_sprite(c->data.gif.sprite_area, + (osspriteop_id) (c->data.gif.sprite_area + 1), + colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, + table, colourtrans_GIVEN_SPRITE, 0, 0, 0); + + xosspriteop_put_sprite_scaled(osspriteop_PTR, + c->data.gif.sprite_area, + (osspriteop_id) (c->data.gif.sprite_area + 1), + x, y - height, + /* osspriteop_USE_PALETTE is RO 3.5+ only. + * behaviour on RO < 3.5 is unknown... + */ + osspriteop_USE_MASK | osspriteop_USE_PALETTE, 0, table); + + xfree(table); +} + void nsgif_destroy(struct content *c) { xfree(c->title); @@ -305,35 +157,75 @@ void nsgif_destroy(struct content *c) xfree(c->data.gif.data); } -// Called when Netsurf wants us to draw the image -void nsgif_redraw(struct content *c, long x, long y, - unsigned long width, unsigned long height) -{ - /* TODO: scale to width, height */ - unsigned int size; - osspriteop_trans_tab *table; -/* JMB - lose this, it's filling my error log up too quickly ;) +static osspriteop_area *create_buffer_sprite( struct content *c, anim a, int *bgc ) +{ + unsigned int abw = ((a->nWidth + 3 ) & ~3) * a->nHeight; + unsigned int nBytes = abw*2 + 44 + 16 + 256*8; + struct osspriteop_area *result = xcalloc(1, nBytes); + struct osspriteop_header *spr = (osspriteop_header*)(result+1); + int i,n; + unsigned int *pPalDest = (unsigned int*)(spr+1); + unsigned int *pPalSrc; + + if ( !result ) + return NULL; + + result->size = nBytes; + result->sprite_count = 1; + result->first = sizeof(*result); + result->used = nBytes; + + spr->size = nBytes-sizeof(*result); + strncpy( spr->name, "gif", 12 ); + spr->width = ((a->nWidth+3)>>2)-1; + spr->height = a->nHeight-1; + spr->left_bit = 0; + spr->right_bit = ((a->nWidth & 3) * 8 - 1) & 31; + spr->image = sizeof(*spr) + 256*8; + spr->mask = sizeof(*spr) + 256*8 + abw; + spr->mode = os_MODE8BPP90X90; /* 28 */ + + c->data.gif.sprite_image = ((char*)spr) + spr->image; + c->width = a->nWidth; + c->height = a->nHeight; + + n = a->pFrames->pal->nColours; + pPalSrc = a->pFrames->pal->pColours; + for ( i=0; idata.gif.sprite_area, - (osspriteop_id) (c->data.gif.sprite_area + 1), - colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, - 0, colourtrans_GIVEN_SPRITE, 0, 0, &size); - table = xcalloc(size, 1); - xcolourtrans_generate_table_for_sprite(c->data.gif.sprite_area, - (osspriteop_id) (c->data.gif.sprite_area + 1), - colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, - table, colourtrans_GIVEN_SPRITE, 0, 0, 0); + pPalDest = (unsigned int*)(spr+1); - xosspriteop_put_sprite_scaled(osspriteop_PTR, - c->data.gif.sprite_area, - (osspriteop_id) (c->data.gif.sprite_area + 1), - x, y - c->height * 2, 8, 0, table); + if ( n < 256 ) + { + pPalDest[255*2] = 0xFFFFFF00; + pPalDest[255*2+1] = 0xFFFFFF00; + *bgc = 255; + } + else + { + unsigned int max = 0; + for ( i=0; i<256; i++ ) + { + unsigned int dark = pPalDest[i*2]; + dark = (dark>>24) + ((dark>>16)&0xFF) + ((dark>>8)&0xFF); + if ( dark > max ) + { + max = dark; + n = i; + } + } + *bgc = n; + } - xfree(table); + return result; } -- cgit v1.2.3