summaryrefslogtreecommitdiff
path: root/include/nsgif.h
blob: c20c976139ab1d7a6758f518b3621619e5af5337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
 * 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)

typedef struct nsgif nsgif_t;

/**
 * GIF 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;

/**
 * NSGIF 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,

	/**
	 * Too many frames.
	 */
	NSGIF_ERR_FRAME_COUNT,

	/**
	 * GIF source data ended without one complete frame available.
	 */
	NSGIF_ERR_END_OF_DATA,

	/**
	 * GIF source data ended with incomplete frame.
	 */
	NSGIF_ERR_END_OF_FRAME,

	/**
	 * 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;

/**
 * Client bitmap type.
 *
 * These are client-created and destroyed, via the \ref bitmap callbacks,
 * but they are owned by a \ref nsgif.
 *
 * The pixel buffer is is 32bpp, treated as individual bytes in the component
 * order RR GG BB AA. For example, a 1x1 image with a single orange pixel would
 * be encoded as the following sequence of bytes: 0xff, 0x88, 0x00, 0x00.
 */
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 * height * sizeof(uint32_t)`.
	 * 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);
} 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[out] gif_out    Return NSGIF object on success.
 *
 * \return NSGIF_OK on success, or appropriate error otherwise.
 */
nsgif_error nsgif_create(
		const nsgif_bitmap_cb_vt *bitmap_vt,
		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.
 *
 * 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 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.
 *
 * \param[in]  gif     The NSGIF 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);

/**
 * 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.
 *
 * \param[in]  gif        The NSGIF 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 nsgif 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 NSGIF object and rescanning the raw data.
 *
 * \param[in]  gif  A NSGIF 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 loop animation */
	int loop_max;
	/** number of animation loops so far */
	int loop_count;
} 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;

	/** 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 NSGIF object.
 *
 * \param[in]  gif  The NSGIF 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 NSGIF object.
 *
 * \param[in]  gif    The NSGIF 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);

#endif