528 lines
15 KiB
C
528 lines
15 KiB
C
/*
|
|
* Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
|
|
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
|
|
* Copyright 2013-2022 Michael Drake <tlsa@netsurf-browser.org>
|
|
*
|
|
* 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
|
|
* Interface to progressive animated GIF file decoding.
|
|
*/
|
|
|
|
#ifndef NSNSGIF_H
|
|
#define NSNSGIF_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <inttypes.h>
|
|
|
|
/** Representation of infinity. */
|
|
#define NSGIF_INFINITE (UINT32_MAX)
|
|
|
|
/** Maximum colour table size */
|
|
#define NSGIF_MAX_COLOURS 256
|
|
|
|
/**
|
|
* Opaque type used by LibNSGIF to represent a GIF object in memory.
|
|
*/
|
|
typedef struct nsgif nsgif_t;
|
|
|
|
/**
|
|
* LibNSGIF rectangle structure.
|
|
*
|
|
* * Top left coordinate is `(x0, y0)`.
|
|
* * Width is `x1 - x0`.
|
|
* * Height is `y1 - y0`.
|
|
* * Units are pixels.
|
|
*/
|
|
typedef struct nsgif_rect {
|
|
/** x co-ordinate of redraw rectangle, left */
|
|
uint32_t x0;
|
|
/** y co-ordinate of redraw rectangle, top */
|
|
uint32_t y0;
|
|
/** x co-ordinate of redraw rectangle, right */
|
|
uint32_t x1;
|
|
/** y co-ordinate of redraw rectangle, bottom */
|
|
uint32_t y1;
|
|
} nsgif_rect_t;
|
|
|
|
/**
|
|
* LibNSGIF return codes.
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* Success.
|
|
*/
|
|
NSGIF_OK,
|
|
|
|
/**
|
|
* Out of memory error.
|
|
*/
|
|
NSGIF_ERR_OOM,
|
|
|
|
/**
|
|
* GIF source data is invalid, and no frames are recoverable.
|
|
*/
|
|
NSGIF_ERR_DATA,
|
|
|
|
/**
|
|
* Frame number is not valid.
|
|
*/
|
|
NSGIF_ERR_BAD_FRAME,
|
|
|
|
/**
|
|
* GIF source data contained an error in a frame.
|
|
*/
|
|
NSGIF_ERR_DATA_FRAME,
|
|
|
|
/**
|
|
* Unexpected end of GIF source data.
|
|
*/
|
|
NSGIF_ERR_END_OF_DATA,
|
|
|
|
/**
|
|
* Can't supply more data after calling \ref nsgif_data_complete.
|
|
*/
|
|
NSGIF_ERR_DATA_COMPLETE,
|
|
|
|
/**
|
|
* The current frame cannot be displayed.
|
|
*/
|
|
NSGIF_ERR_FRAME_DISPLAY,
|
|
|
|
/**
|
|
* Indicates an animation is complete, and \ref nsgif_reset must be
|
|
* called to restart the animation from the beginning.
|
|
*/
|
|
NSGIF_ERR_ANIMATION_END,
|
|
} nsgif_error;
|
|
|
|
/**
|
|
* NSGIF \ref nsgif_bitmap_t pixel format.
|
|
*
|
|
* All pixel formats are 32 bits per pixel (bpp). The different formats
|
|
* allow control over the ordering of the colour channels. All colour
|
|
* channels are 8 bits wide.
|
|
*
|
|
* Note that the GIF file format only supports an on/off mask, so the
|
|
* alpha (A) component (opacity) will always have a value of `0` (fully
|
|
* transparent) or `255` (fully opaque).
|
|
*/
|
|
typedef enum nsgif_bitmap_fmt {
|
|
/** Bite-wise RGBA: Byte order: 0xRR, 0xGG, 0xBB, 0xAA. */
|
|
NSGIF_BITMAP_FMT_R8G8B8A8,
|
|
|
|
/** Bite-wise BGRA: Byte order: 0xBB, 0xGG, 0xRR, 0xAA. */
|
|
NSGIF_BITMAP_FMT_B8G8R8A8,
|
|
|
|
/** Bite-wise ARGB: Byte order: 0xAA, 0xRR, 0xGG, 0xBB. */
|
|
NSGIF_BITMAP_FMT_A8R8G8B8,
|
|
|
|
/** Bite-wise ABGR: Byte order: 0xAA, 0xBB, 0xGG, 0xRR. */
|
|
NSGIF_BITMAP_FMT_A8B8G8R8,
|
|
|
|
/**
|
|
* 32-bit RGBA (0xRRGGBBAA).
|
|
*
|
|
* * On little endian host, same as \ref NSGIF_BITMAP_FMT_A8B8G8R8.
|
|
* * On big endian host, same as \ref NSGIF_BITMAP_FMT_R8G8B8A8.
|
|
*/
|
|
NSGIF_BITMAP_FMT_RGBA8888,
|
|
|
|
/**
|
|
* 32-bit BGRA (0xBBGGRRAA).
|
|
*
|
|
* * On little endian host, same as \ref NSGIF_BITMAP_FMT_A8R8G8B8.
|
|
* * On big endian host, same as \ref NSGIF_BITMAP_FMT_B8G8R8A8.
|
|
*/
|
|
NSGIF_BITMAP_FMT_BGRA8888,
|
|
|
|
/**
|
|
* 32-bit ARGB (0xAARRGGBB).
|
|
*
|
|
* * On little endian host, same as \ref NSGIF_BITMAP_FMT_B8G8R8A8.
|
|
* * On big endian host, same as \ref NSGIF_BITMAP_FMT_A8R8G8B8.
|
|
*/
|
|
NSGIF_BITMAP_FMT_ARGB8888,
|
|
|
|
/**
|
|
* 32-bit BGRA (0xAABBGGRR).
|
|
*
|
|
* * On little endian host, same as \ref NSGIF_BITMAP_FMT_R8G8B8A8.
|
|
* * On big endian host, same as \ref NSGIF_BITMAP_FMT_A8B8G8R8.
|
|
*/
|
|
NSGIF_BITMAP_FMT_ABGR8888,
|
|
} nsgif_bitmap_fmt_t;
|
|
|
|
/**
|
|
* Client bitmap type.
|
|
*
|
|
* These are client-created and destroyed, via the \ref nsgif_bitmap_cb_vt
|
|
* callbacks, but they are owned by a \ref nsgif_t.
|
|
*
|
|
* See \ref nsgif_bitmap_fmt for pixel format information.
|
|
*
|
|
* The bitmap may have a row_span greater than the bitmap width, but the
|
|
* difference between row span and width must be a whole number of pixels
|
|
* (a multiple of four bytes).
|
|
*/
|
|
typedef void nsgif_bitmap_t;
|
|
|
|
/** Bitmap callbacks function table */
|
|
typedef struct nsgif_bitmap_cb_vt {
|
|
/**
|
|
* Callback to create a bitmap with the given dimensions.
|
|
*
|
|
* \param[in] width Required bitmap width in pixels.
|
|
* \param[in] height Required bitmap height in pixels.
|
|
* \return pointer to client's bitmap structure or NULL on error.
|
|
*/
|
|
nsgif_bitmap_t* (*create)(int width, int height);
|
|
|
|
/**
|
|
* Callback to free a bitmap.
|
|
*
|
|
* \param[in] bitmap The bitmap to destroy.
|
|
*/
|
|
void (*destroy)(nsgif_bitmap_t *bitmap);
|
|
|
|
/**
|
|
* Get pointer to pixel buffer in a bitmap.
|
|
*
|
|
* The pixel buffer must be `(width + N) * height * sizeof(uint32_t)`.
|
|
* Where `N` is any number greater than or equal to 0.
|
|
* Note that the returned pointer to uint8_t must be 4-byte aligned.
|
|
*
|
|
* \param[in] bitmap The bitmap.
|
|
* \return pointer to bitmap's pixel buffer.
|
|
*/
|
|
uint8_t* (*get_buffer)(nsgif_bitmap_t *bitmap);
|
|
|
|
/* The following functions are optional. */
|
|
|
|
/**
|
|
* Set whether a bitmap can be plotted opaque.
|
|
*
|
|
* \param[in] bitmap The bitmap.
|
|
* \param[in] opaque Whether the current frame is opaque.
|
|
*/
|
|
void (*set_opaque)(nsgif_bitmap_t *bitmap, bool opaque);
|
|
|
|
/**
|
|
* Tests whether a bitmap has an opaque alpha channel.
|
|
*
|
|
* \param[in] bitmap The bitmap.
|
|
* \return true if the bitmap is opaque, false otherwise.
|
|
*/
|
|
bool (*test_opaque)(nsgif_bitmap_t *bitmap);
|
|
|
|
/**
|
|
* Bitmap modified notification.
|
|
*
|
|
* \param[in] bitmap The bitmap.
|
|
*/
|
|
void (*modified)(nsgif_bitmap_t *bitmap);
|
|
|
|
/**
|
|
* Get row span in pixels.
|
|
*
|
|
* If this callback is not provided, LibNSGIF will use the width.
|
|
*
|
|
* If row span is greater than width, this callback must be provided.
|
|
*
|
|
* \param[in] bitmap The bitmap.
|
|
*/
|
|
uint32_t (*get_rowspan)(nsgif_bitmap_t *bitmap);
|
|
} nsgif_bitmap_cb_vt;
|
|
|
|
/**
|
|
* Convert an error code to a string.
|
|
*
|
|
* \param[in] err The error code to convert.
|
|
* \return String representation of given error code.
|
|
*/
|
|
const char *nsgif_strerror(nsgif_error err);
|
|
|
|
/**
|
|
* Create the NSGIF object.
|
|
*
|
|
* \param[in] bitmap_vt Bitmap operation functions v-table.
|
|
* \param[in] bitmap_fmt Bitmap pixel format specification.
|
|
* \param[out] gif_out Return \ref nsgif_t object on success.
|
|
*
|
|
* \return NSGIF_OK on success, or appropriate error otherwise.
|
|
*/
|
|
nsgif_error nsgif_create(
|
|
const nsgif_bitmap_cb_vt *bitmap_vt,
|
|
nsgif_bitmap_fmt_t bitmap_fmt,
|
|
nsgif_t **gif_out);
|
|
|
|
/**
|
|
* Free a NSGIF object.
|
|
*
|
|
* \param[in] gif The NSGIF to free.
|
|
*/
|
|
void nsgif_destroy(nsgif_t *gif);
|
|
|
|
/**
|
|
* Scan the source image data.
|
|
*
|
|
* This is used to feed the source data into LibNSGIF. This must be called
|
|
* before calling \ref nsgif_frame_decode.
|
|
*
|
|
* It can be called multiple times with, with increasing sizes. If it is called
|
|
* several times, as more data is available (e.g. slow network fetch) the data
|
|
* already given to \ref nsgif_data_scan must be provided each time.
|
|
*
|
|
* Once all the data has been provided, call \ref nsgif_data_complete.
|
|
*
|
|
* For example, if you call \ref nsgif_data_scan with 25 bytes of data, and then
|
|
* fetch another 10 bytes, you would need to call \ref nsgif_data_scan with a
|
|
* size of 35 bytes, and the whole 35 bytes must be contiguous memory. It is
|
|
* safe to `realloc` the source buffer between calls to \ref nsgif_data_scan.
|
|
* (The actual data pointer is allowed to be different.)
|
|
*
|
|
* If an error occurs, all previously scanned frames are retained.
|
|
*
|
|
* Note that an error returned from this function is purely informational.
|
|
* So long as at least one frame is available, you can display frames.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
* \param[in] size Number of bytes in data.
|
|
* \param[in] data Raw source GIF data.
|
|
*
|
|
* \return NSGIF_OK on success, or appropriate error otherwise.
|
|
*/
|
|
nsgif_error nsgif_data_scan(
|
|
nsgif_t *gif,
|
|
size_t size,
|
|
const uint8_t *data);
|
|
|
|
/**
|
|
* Tell libnsgif that all the gif data has been provided.
|
|
*
|
|
* Call this after calling \ref nsgif_data_scan with the the entire GIF
|
|
* source data. You can call \ref nsgif_data_scan multiple times up until
|
|
* this is called, and after this is called, \ref nsgif_data_scan will
|
|
* return an error.
|
|
*
|
|
* You can decode a GIF before this is called, however, it will fail to
|
|
* decode any truncated final frame data and will not perform loops when
|
|
* driven via \ref nsgif_frame_prepare (because it doesn't know if there
|
|
* will be more frames supplied in future data).
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
*/
|
|
void nsgif_data_complete(
|
|
nsgif_t *gif);
|
|
|
|
/**
|
|
* Prepare to show a frame.
|
|
*
|
|
* If this is the last frame of an animation with a finite loop count, the
|
|
* returned `delay_cs` will be \ref NSGIF_INFINITE, indicating that the frame
|
|
* should be shown forever.
|
|
*
|
|
* Note that if \ref nsgif_data_complete has not been called on this gif,
|
|
* animated GIFs will not loop back to the start. Instead it will return
|
|
* \ref NSGIF_ERR_END_OF_DATA.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
* \param[out] area The area in pixels that must be redrawn.
|
|
* \param[out] delay_cs Time to wait after frame_new before next frame in cs.
|
|
* \param[out] frame_new The frame to decode.
|
|
*
|
|
* \return NSGIF_OK on success, or appropriate error otherwise.
|
|
*/
|
|
nsgif_error nsgif_frame_prepare(
|
|
nsgif_t *gif,
|
|
nsgif_rect_t *area,
|
|
uint32_t *delay_cs,
|
|
uint32_t *frame_new);
|
|
|
|
/**
|
|
* Decodes a GIF frame.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
* \param[in] frame The frame number to decode.
|
|
* \param[out] bitmap On success, returns pointer to the client-allocated,
|
|
* nsgif-owned client bitmap structure.
|
|
*
|
|
* \return NSGIF_OK on success, or appropriate error otherwise.
|
|
*/
|
|
nsgif_error nsgif_frame_decode(
|
|
nsgif_t *gif,
|
|
uint32_t frame,
|
|
nsgif_bitmap_t **bitmap);
|
|
|
|
/**
|
|
* Reset a GIF animation.
|
|
*
|
|
* Some animations are only meant to loop N times, and then show the
|
|
* final frame forever. This function resets the loop and frame counters,
|
|
* so that the animation can be replayed without the overhead of recreating
|
|
* the \ref nsgif_t object and rescanning the raw data.
|
|
*
|
|
* \param[in] gif A \ref nsgif_t object.
|
|
*
|
|
* \return NSGIF_OK on success, or appropriate error otherwise.
|
|
*/
|
|
nsgif_error nsgif_reset(
|
|
nsgif_t *gif);
|
|
|
|
/**
|
|
* Information about a GIF.
|
|
*/
|
|
typedef struct nsgif_info {
|
|
/** width of GIF (may increase during decoding) */
|
|
uint32_t width;
|
|
/** height of GIF (may increase during decoding) */
|
|
uint32_t height;
|
|
/** number of frames decoded */
|
|
uint32_t frame_count;
|
|
/** number of times to play animation (zero means loop forever) */
|
|
int loop_max;
|
|
/** background colour in same pixel format as \ref nsgif_bitmap_t. */
|
|
uint32_t background;
|
|
/** whether the GIF has a global colour table */
|
|
bool global_palette;
|
|
} nsgif_info_t;
|
|
|
|
/**
|
|
* Frame disposal method.
|
|
*
|
|
* Clients do not need to know about this, it is provided purely for dumping
|
|
* raw information about GIF frames.
|
|
*/
|
|
enum nsgif_disposal {
|
|
NSGIF_DISPOSAL_UNSPECIFIED, /**< No disposal method specified. */
|
|
NSGIF_DISPOSAL_NONE, /**< Frame remains. */
|
|
NSGIF_DISPOSAL_RESTORE_BG, /**< Clear frame to background colour. */
|
|
NSGIF_DISPOSAL_RESTORE_PREV, /**< Restore previous frame. */
|
|
NSGIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for NSGIF_DISPOSAL_RESTORE_PREV. */
|
|
};
|
|
|
|
/**
|
|
* Convert a disposal method to a string.
|
|
*
|
|
* \param[in] disposal The disposal method to convert.
|
|
* \return String representation of given disposal method.
|
|
*/
|
|
const char *nsgif_str_disposal(enum nsgif_disposal disposal);
|
|
|
|
/**
|
|
* Information about a GIF frame.
|
|
*/
|
|
typedef struct nsgif_frame_info {
|
|
/** whether the frame should be displayed/animated */
|
|
bool display;
|
|
/** whether the frame may have transparency */
|
|
bool transparency;
|
|
/** whether the frame has a local colour table */
|
|
bool local_palette;
|
|
/** whether the frame is interlaced */
|
|
bool interlaced;
|
|
/** Disposal method for previous frame; affects plotting */
|
|
uint8_t disposal;
|
|
/** delay (in cs) before animating the frame */
|
|
uint32_t delay;
|
|
|
|
/** Frame's redraw rectangle. */
|
|
nsgif_rect_t rect;
|
|
} nsgif_frame_info_t;
|
|
|
|
/**
|
|
* Get information about a GIF from an \ref nsgif_t object.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object to get info for.
|
|
*
|
|
* \return The gif info, or NULL on error.
|
|
*/
|
|
const nsgif_info_t *nsgif_get_info(const nsgif_t *gif);
|
|
|
|
/**
|
|
* Get information about a GIF from an \ref nsgif_t object.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object to get frame info for.
|
|
* \param[in] frame The frame number to get info for.
|
|
*
|
|
* \return The gif frame info, or NULL on error.
|
|
*/
|
|
const nsgif_frame_info_t *nsgif_get_frame_info(
|
|
const nsgif_t *gif,
|
|
uint32_t frame);
|
|
|
|
/**
|
|
* Get the global colour palette.
|
|
*
|
|
* If the GIF has no global colour table, this will return the default
|
|
* colour palette.
|
|
*
|
|
* Colours in same pixel format as \ref nsgif_bitmap_t.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
* \param[out] table Client buffer to hold the colour table.
|
|
* \param[out] entries The number of used entries in the colour table.
|
|
*/
|
|
void nsgif_global_palette(
|
|
const nsgif_t *gif,
|
|
uint32_t table[NSGIF_MAX_COLOURS],
|
|
size_t *entries);
|
|
|
|
/**
|
|
* Get the local colour palette for a frame.
|
|
*
|
|
* Frames may have no local palette. In this case they use the global palette.
|
|
* This function returns false if the frame has no local palette.
|
|
*
|
|
* Colours in same pixel format as \ref nsgif_bitmap_t.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object.
|
|
* \param[in] frame The frame to get the palette for.
|
|
* \param[out] table Client buffer to hold the colour table.
|
|
* \param[out] entries The number of used entries in the colour table.
|
|
* \return true if a palette is returned, false otherwise.
|
|
*/
|
|
bool nsgif_local_palette(
|
|
const nsgif_t *gif,
|
|
uint32_t frame,
|
|
uint32_t table[NSGIF_MAX_COLOURS],
|
|
size_t *entries);
|
|
|
|
/**
|
|
* Configure handling of small frame delays.
|
|
*
|
|
* Historically people created GIFs with a tiny frame delay, however the slow
|
|
* hardware of the time meant they actually played much slower. As computers
|
|
* sped up, to prevent animations playing faster than intended, decoders came
|
|
* to ignore overly small frame delays.
|
|
*
|
|
* By default a \ref nsgif_frame_prepare() managed animation will override
|
|
* frame delays of less than 2 centiseconds with a default frame delay of
|
|
* 10 centiseconds. This matches the behaviour of web browsers and other
|
|
* renderers.
|
|
*
|
|
* Both the minimum and the default values can be overridden for a given GIF
|
|
* by the client. To get frame delays exactly as specified by the GIF file, set
|
|
* `delay_min` to zero.
|
|
*
|
|
* Note that this does not affect the frame delay in the frame info
|
|
* (\ref nsgif_frame_info_t) structure, which will always contain values
|
|
* specified by the GIF.
|
|
*
|
|
* \param[in] gif The \ref nsgif_t object to configure.
|
|
* \param[in] delay_min The minimum frame delay in centiseconds.
|
|
* \param[in] delay_default The delay to use if a frame delay is less than
|
|
* `delay_min`.
|
|
*/
|
|
void nsgif_set_frame_delay_behaviour(
|
|
nsgif_t *gif,
|
|
uint16_t delay_min,
|
|
uint16_t delay_default);
|
|
|
|
#endif
|