workshop: add gif-load using libnsgif

Also including a version of libnsgif that has been made self-contained by
inlining (might be old and not contain the latest fixes in libnsgif) the few
source files it depends on, having a direct copy of the libnsgif directory in
the gegl source tree might be better, unless distributions start packaging
libnsgif.
parent dfdec206
......@@ -421,8 +421,8 @@ int gegl_str_has_video_suffix (char *path)
g_str_has_suffix (path, ".webm") ||
g_str_has_suffix (path, ".MP4") ||
g_str_has_suffix (path, ".mkv") ||
g_str_has_suffix (path, ".gif") ||
g_str_has_suffix (path, ".GIF") ||
//g_str_has_suffix (path, ".gif") ||
//g_str_has_suffix (path, ".GIF") ||
g_str_has_suffix (path, ".MKV") ||
g_str_has_suffix (path, ".mov") ||
g_str_has_suffix (path, ".ogg");
......
......@@ -14,6 +14,7 @@ op_LTLIBRARIES = \
bilateral-filter-fast.la \
demosaic-bimedian.la \
demosaic-simple.la \
gif-load.la \
ditto.la \
domain-transform.la \
gradient-map.la \
......
/* This file is an image processing operation for GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2018 Øyvind Kolås <pippin@gimp.org>
*
* This code is based on the decode_gif example coming with netsurf.
*
* Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
* Licenced under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#ifdef GEGL_PROPERTIES
property_file_path (path, _("File"), "")
description (_("Path of file to load"))
property_int (frame, _("frame"), 0)
description (_("frame number to decode"))
property_int (frames, _("frames"), 0)
description (_("Number of frames in gif animation"))
#else
#define GEGL_OP_SOURCE
#define GEGL_OP_NAME gif_load
#define GEGL_OP_C_SOURCE gif-load.c
#include <gegl-op.h>
#include <gegl-gio-private.h>
#include "libnsgif.h"
#include "libnsgif.c"
#define IO_BUFFER_SIZE 4096
typedef struct
{
GFile *file;
GInputStream *stream;
gif_animation gif;
unsigned char *gif_data;
const Babl *format;
gint width;
gint height;
} Priv;
static void
cleanup(GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
Priv *p = (Priv*) o->user_data;
if (p != NULL)
{
gif_finalise (&p->gif);
if (p->gif_data) g_free (p->gif_data);
if (p->stream != NULL)
g_input_stream_close (G_INPUT_STREAM (p->stream), NULL, NULL);
g_clear_object (&p->stream);
g_clear_object (&p->file);
p->width = p->height = 0;
p->format = NULL;
}
}
static void *bitmap_create(int width, int height)
{
return calloc(width * height, 4);
}
static void bitmap_set_opaque(void *bitmap, bool opaque)
{
(void) opaque; /* unused */
assert(bitmap);
}
static bool bitmap_test_opaque(void *bitmap)
{
assert(bitmap);
return false;
}
static unsigned char *bitmap_get_buffer(void *bitmap)
{
assert(bitmap);
return bitmap;
}
static void bitmap_destroy(void *bitmap)
{
assert(bitmap);
free(bitmap);
}
static void bitmap_modified(void *bitmap)
{
assert(bitmap);
return;
}
static void
prepare (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
Priv *p = (o->user_data) ? o->user_data : g_new0 (Priv, 1);
g_assert (p != NULL);
p->format = babl_format ("R'G'B'A u8");
o->user_data = (void*) p;
if (p->gif_data == NULL)
{
gsize length;
gif_bitmap_callback_vt bitmap_callbacks = {
bitmap_create,
bitmap_destroy,
bitmap_get_buffer,
bitmap_set_opaque,
bitmap_test_opaque,
bitmap_modified
};
g_file_get_contents (o->path, (void*)&p->gif_data, &length, NULL);
gif_create(&p->gif, &bitmap_callbacks);
gif_initialise(&p->gif, length, p->gif_data);
o->frames = p->gif.frame_count;
g_assert (p->gif_data != NULL);
}
gegl_operation_set_format (operation, "output", p->format);
}
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
GeglRectangle result = { 0, 0, 0, 0 };
Priv *p = (Priv*) o->user_data;
result.width = p->gif.width;
result.height = p->gif.height;
return result;
}
static gboolean
process (GeglOperation *operation,
GeglBuffer *output,
const GeglRectangle *result,
gint level)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
Priv *p = (Priv*) o->user_data;
int code;
if (o->frame > o->frames-1) o->frame = o->frames-1;
if (o->frame < 0) o->frame = 0;
code = gif_decode_frame (&p->gif, o->frame);
if (code != GIF_OK)
g_warning ("gif_decode_frame:%i\n", code);
gegl_buffer_set (output, result, 0, p->format,
p->gif.frame_image,
p->gif.width * 4);
return FALSE;
}
static GeglRectangle
get_cached_region (GeglOperation *operation,
const GeglRectangle *roi)
{
return get_bounding_box (operation);
}
static void
finalize(GObject *object)
{
GeglProperties *o = GEGL_PROPERTIES (object);
if (o->user_data != NULL)
{
cleanup (GEGL_OPERATION (object));
g_clear_pointer (&o->user_data, g_free);
}
G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
}
static void
gegl_op_class_init (GeglOpClass *klass)
{
GeglOperationClass *operation_class;
GeglOperationSourceClass *source_class;
G_OBJECT_CLASS(klass)->finalize = finalize;
operation_class = GEGL_OPERATION_CLASS (klass);
source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
source_class->process = process;
operation_class->prepare = prepare;
operation_class->get_bounding_box = get_bounding_box;
operation_class->get_cached_region = get_cached_region;
gegl_operation_class_set_keys (operation_class,
"name", "gegl:gif-load",
"title", _("GIF File Loader"),
"categories" , "hidden",
"description" , _("GIF image loader."),
NULL);
gegl_operation_handlers_register_loader (
"image/gif", "gegl:gif-load");
gegl_operation_handlers_register_loader (
".gif", "gegl:gif-load");
}
#endif
This diff is collapsed.
/*
* Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
* Licenced under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*/
/** \file
* Progressive animated GIF file decoding (interface).
*/
#ifndef _LIBNSGIF_H_
#define _LIBNSGIF_H_
#include <stdbool.h>
#include <inttypes.h>
/* Error return values
*/
typedef enum {
GIF_WORKING = 1,
GIF_OK = 0,
GIF_INSUFFICIENT_FRAME_DATA = -1,
GIF_FRAME_DATA_ERROR = -2,
GIF_INSUFFICIENT_DATA = -3,
GIF_DATA_ERROR = -4,
GIF_INSUFFICIENT_MEMORY = -5,
GIF_FRAME_NO_DISPLAY = -6,
GIF_END_OF_FRAME = -7
} gif_result;
/* The GIF frame data
*/
typedef struct gif_frame {
bool display; /**< whether the frame should be displayed/animated */
unsigned int frame_delay; /**< delay (in cs) before animating the frame */
/** Internal members are listed below
*/
unsigned int frame_pointer; /**< offset (in bytes) to the GIF frame data */
bool virgin; /**< whether the frame has previously been used */
bool opaque; /**< whether the frame is totally opaque */
bool redraw_required; /**< whether a forcable screen redraw is required */
unsigned char disposal_method; /**< how the previous frame should be disposed; affects plotting */
bool transparency; /**< whether we acknoledge transparency */
unsigned char transparency_index; /**< the index designating a transparent pixel */
unsigned int redraw_x; /**< x co-ordinate of redraw rectangle */
unsigned int redraw_y; /**< y co-ordinate of redraw rectangle */
unsigned int redraw_width; /**< width of redraw rectangle */
unsigned int redraw_height; /**< height of redraw rectangle */
} gif_frame;
/* API for Bitmap callbacks
*/
typedef void* (*gif_bitmap_cb_create)(int width, int height);
typedef void (*gif_bitmap_cb_destroy)(void *bitmap);
typedef unsigned char* (*gif_bitmap_cb_get_buffer)(void *bitmap);
typedef void (*gif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
typedef bool (*gif_bitmap_cb_test_opaque)(void *bitmap);
typedef void (*gif_bitmap_cb_modified)(void *bitmap);
/* The Bitmap callbacks function table
*/
typedef struct gif_bitmap_callback_vt {
gif_bitmap_cb_create bitmap_create; /**< Create a bitmap. */
gif_bitmap_cb_destroy bitmap_destroy; /**< Free a bitmap. */
gif_bitmap_cb_get_buffer bitmap_get_buffer; /**< Return a pointer to the pixel data in a bitmap. */
/** Members below are optional
*/
gif_bitmap_cb_set_opaque bitmap_set_opaque; /**< Sets whether a bitmap should be plotted opaque. */
gif_bitmap_cb_test_opaque bitmap_test_opaque; /**< Tests whether a bitmap has an opaque alpha channel. */
gif_bitmap_cb_modified bitmap_modified; /**< The bitmap image has changed, so flush any persistant cache. */
} gif_bitmap_callback_vt;
/* The GIF animation data
*/
typedef struct gif_animation {
gif_bitmap_callback_vt bitmap_callbacks; /**< callbacks for bitmap functions */
unsigned char *gif_data; /**< pointer to GIF data */
unsigned int width; /**< width of GIF (may increase during decoding) */
unsigned int height; /**< heigth of GIF (may increase during decoding) */
unsigned int frame_count; /**< number of frames decoded */
unsigned int frame_count_partial; /**< number of frames partially decoded */
gif_frame *frames; /**< decoded frames */
int decoded_frame; /**< current frame decoded to bitmap */
void *frame_image; /**< currently decoded image; stored as bitmap from bitmap_create callback */
int loop_count; /**< number of times to loop animation */
gif_result current_error; /**< current error type, or 0 for none*/
/** Internal members are listed below
*/
unsigned int buffer_position; /**< current index into GIF data */
unsigned int buffer_size; /**< total number of bytes of GIF data available */
unsigned int frame_holders; /**< current number of frame holders */
unsigned int background_index; /**< index in the colour table for the background colour */
unsigned int aspect_ratio; /**< image aspect ratio (ignored) */
unsigned int colour_table_size; /**< size of colour table (in entries) */
bool global_colours; /**< whether the GIF has a global colour table */
unsigned int *global_colour_table; /**< global colour table */
unsigned int *local_colour_table; /**< local colour table */
} gif_animation;
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);
gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data);
gif_result gif_decode_frame(gif_animation *gif, unsigned int frame);
void gif_finalise(gif_animation *gif);
#endif
......@@ -244,6 +244,7 @@ operations/transform/shear.c
operations/transform/transform.c
operations/transform/transform-core.c
operations/transform/translate.c
operations/workshop/gif-load.c
operations/workshop/bayer-matrix.c
operations/workshop/bilateral-filter-fast.c
operations/workshop/demosaic-bimedian.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment