summaryrefslogtreecommitdiff
path: root/riscos/gif.c
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2003-07-18 21:02:29 +0000
committerJames Bursa <james@netsurf-browser.org>2003-07-18 21:02:29 +0000
commitc3c1fb916bb6135ddbd61225b18f7778274bd0be (patch)
tree7155448a2fb7504666d6be363911c4f50c1641dc /riscos/gif.c
parentd6053c3cb00772dc1c1f5422f0cdb7cdff03beb4 (diff)
downloadnetsurf-c3c1fb916bb6135ddbd61225b18f7778274bd0be.tar.gz
netsurf-c3c1fb916bb6135ddbd61225b18f7778274bd0be.tar.bz2
[project @ 2003-07-18 21:02:29 by bursa]
New GIF renderer using animlib (jmb). svn path=/import/netsurf/; revision=235
Diffstat (limited to 'riscos/gif.c')
-rw-r--r--riscos/gif.c408
1 files changed, 150 insertions, 258 deletions
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 <philpem@users.sourceforge.net>
- */
-/*******************
- * 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 <jmb202@ecs.soton.ac.uk>
+ * Parts modified from IGviewer source by Peter Hartley
+ * http://utter.chaos.org/~pdh/software/intergif.htm
*/
#include <assert.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
-#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; j<height; j++)
- for (i=0; i<width; i++)
- {
- unsigned char *x = ((char *)sprite) + sprite->mask;
- 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; i<n; i++)
+ if(!mask[i]) {
- c->width = 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; i<n; i++ )
+ {
+ *pPalDest++ = *pPalSrc;
+ *pPalDest++ = *pPalSrc++;
+ }
- LOG(("Redraw fired"));
+ if ( !bgc )
+ return result;
- philpem - Oops. Sorry about that!
-*/
+ /* A bit of faff here to return a useful (near-white) background colour */
- 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);
+ 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;
}