From 403f12872d55a71b04287ed828be0c63be19e856 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Mon, 4 Oct 2004 23:54:42 +0000 Subject: [project @ 2004-10-04 23:54:42 by rjw] Moved GIF file reading to image/, optimisation of plotting for GIFs, JNGs, PNGs and JPEGs, initial work for toolbar customisation. Possibly some other things too. svn path=/import/netsurf/; revision=1301 --- image/gif.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 image/gif.c (limited to 'image/gif.c') diff --git a/image/gif.c b/image/gif.c new file mode 100644 index 000000000..091c7c2ed --- /dev/null +++ b/image/gif.c @@ -0,0 +1,242 @@ +/* + * 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 John M Bell + * Copyright 2004 Richard Wilson + */ + +#include +#include +#include +#include +#include "oslib/osfile.h" +#include "oslib/osspriteop.h" +#include "netsurf/utils/config.h" +#include "netsurf/content/content.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/options.h" +#include "netsurf/image/bitmap.h" +#include "netsurf/image/gif.h" +#include "netsurf/image/gifread.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/messages.h" +#include "netsurf/utils/utils.h" + + +/* GIF FUNCTIONALITY + ================= + + All GIFs are dynamically decompressed using the routines that gifread.c + provides. Whilst this allows support for progressive decoding, it is + not implemented here as NetSurf currently does not provide such support. + + [rjw] - Sun 4th April 2004 +*/ + +#ifdef WITH_GIF + +static void nsgif_animate(void *p); + + +bool nsgif_create(struct content *c, const char *params[]) { + union content_msg_data msg_data; + /* Initialise our data structure + */ + c->data.gif.gif = calloc(sizeof(gif_animation), 1); + if (!c->data.gif.gif) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + c->data.gif.current_frame = 0; + return true; +} + + +bool nsgif_convert(struct content *c, int iwidth, int iheight) { + int res; + struct gif_animation *gif; + union content_msg_data msg_data; + + /* Create our animation + */ + gif = c->data.gif.gif; + gif->gif_data = c->source_data; + gif->buffer_size = c->source_size; + gif->buffer_position = 0; // Paranoid + + /* Initialise the GIF + */ + res = gif_initialise(gif); + switch (res) { + case GIF_INSUFFICIENT_MEMORY: + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + case GIF_INSUFFICIENT_DATA: + case GIF_DATA_ERROR: + msg_data.error = messages_get("BadGIF"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + /* Abort on bad GIFs + */ + if ((gif->frame_count_partial == 0) || (gif->width == 0) || + (gif->height == 0)) { + msg_data.error = messages_get("BadGIF"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + /* Store our content width and description + */ + c->width = gif->width; + c->height = gif->height; + c->title = malloc(100); + if (c->title) { + snprintf(c->title, 100, messages_get("GIFTitle"), c->width, c->height, c->source_size); + } + c->size += (gif->width * gif->height * 4) + 16 + 44 + 100; + + /* Initialise the first frame so if we try to use the image data directly prior to + a plot we get some sensible data + */ + gif_decode_frame(c->data.gif.gif, 0); + + /* Schedule the animation if we have one + */ + if (gif->frame_count > 1) { + schedule(gif->frames[0].frame_delay, nsgif_animate, c); + } + + /* Exit as a success + */ + c->bitmap = gif->frame_image; + c->status = CONTENT_STATUS_DONE; + return true; +} + + +bool nsgif_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour) { + + int previous_frame; + unsigned int frame, current_frame; + + /* If we have a gui_window then we work from there, if not we use the global + settings. We default to the first image if we don't have a GUI as we are + drawing a thumbnail unless something has gone very wrong somewhere else. + */ +/* if (ro_gui_current_redraw_gui) { + if (ro_gui_current_redraw_gui->option.animate_images) { +*/ current_frame = c->data.gif.current_frame; +/* } else { + current_frame = 0; + } + } else { + if (c->data.gif.gif->loop_count == 0) { + current_frame = 0; + } else { + if (c->data.gif.gif->frame_count > 1) { + current_frame = c->data.gif.gif->frame_count - 1; + } else { + current_frame = 0; + } + } + } +*/ + /* Decode from the last frame to the current frame + */ + if (current_frame < c->data.gif.gif->decoded_frame) { + previous_frame = 0; + } else { + previous_frame = c->data.gif.gif->decoded_frame + 1; + } + for (frame = previous_frame; frame <= current_frame; frame++) { + gif_decode_frame(c->data.gif.gif, frame); + } + c->bitmap = c->data.gif.gif->frame_image; + + return bitmap_redraw(c, x, y, width, height, + clip_x0, clip_y0, clip_x1, clip_y1, + scale, background_colour); +} + + +void nsgif_destroy(struct content *c) +{ + /* Free all the associated memory buffers + */ + schedule_remove(nsgif_animate, c); + gif_finalise(c->data.gif.gif); + free(c->data.gif.gif); +} + + +/** Performs any necessary animation. + + @param c The content to animate +*/ +void nsgif_animate(void *p) +{ + struct content *c = p; + union content_msg_data data; + int delay; + + /* Advance by a frame, updating the loop count accordingly + */ + c->data.gif.current_frame++; + if (c->data.gif.current_frame == c->data.gif.gif->frame_count) { + c->data.gif.current_frame = 0; + + /* A loop count of 0 has a special meaning of infinite + */ + if (c->data.gif.gif->loop_count != 0) { + c->data.gif.gif->loop_count--; + if (c->data.gif.gif->loop_count == 0) { + c->data.gif.current_frame = c->data.gif.gif->frame_count - 1; + c->data.gif.gif->loop_count = -1; + } + } + } + + + /* Continue animating if we should + */ + if (c->data.gif.gif->loop_count >= 0) { + delay = c->data.gif.gif->frames[c->data.gif.current_frame].frame_delay; + if (delay < option_minimum_gif_delay) delay = option_minimum_gif_delay; + schedule(delay, nsgif_animate, c); + } + + /* area within gif to redraw */ + data.redraw.x = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_x; + data.redraw.y = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_y; + data.redraw.width = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_width; + data.redraw.height = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_height; + + /* redraw background (true) or plot on top (false) */ + if (c->data.gif.current_frame > 0) { + data.redraw.full_redraw = + c->data.gif.gif->frames[c->data.gif.current_frame - 1].redraw_required; + } else { + data.redraw.full_redraw = true; + } + + /* other data */ + data.redraw.object = c; + data.redraw.object_x = 0; + data.redraw.object_y = 0; + data.redraw.object_width = c->width; + data.redraw.object_height = c->height; + + content_broadcast(c, CONTENT_MSG_REDRAW, data); +} + +#endif -- cgit v1.2.3