aboutsummaryrefslogtreecommitdiffstats
path: root/include/gdisp/image.h
blob: ff2e9d85d3edbc6aa0c08f9c8c91bbf78e7be751 (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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
 * This file is subject to the terms of the GFX License. If a copy of
 * the license was not distributed with this file, you can obtain one at:
 *
 *              http://ugfx.org/license.html
 */

/**
 * @file    include/gdisp/image.h
 * @brief   GDISP image header file.
 *
 * @defgroup Image Image
 * @ingroup GDISP
 * @{
 */

#ifndef _GDISP_IMAGE_H
#define _GDISP_IMAGE_H
#if (GFX_USE_GDISP && GDISP_NEED_IMAGE) || defined(__DOXYGEN__)

/**
 * @brief	The type of image
 */
typedef uint16_t	gdispImageType;
	#define GDISP_IMAGE_TYPE_UNKNOWN	0
	#define GDISP_IMAGE_TYPE_NATIVE		1
	#define GDISP_IMAGE_TYPE_GIF		2
	#define GDISP_IMAGE_TYPE_BMP		3
	#define GDISP_IMAGE_TYPE_JPG		4
	#define GDISP_IMAGE_TYPE_PNG		5

/**
 * @brief	An image error code
 */
typedef uint16_t	gdispImageError;
	#define GDISP_IMAGE_ERR_OK					0
	#define GDISP_IMAGE_ERR_UNRECOVERABLE		0x8000
	#define GDISP_IMAGE_ERR_BADFORMAT			(GDISP_IMAGE_ERR_UNRECOVERABLE+1)
	#define GDISP_IMAGE_ERR_BADDATA				(GDISP_IMAGE_ERR_UNRECOVERABLE+2)
	#define GDISP_IMAGE_ERR_UNSUPPORTED			(GDISP_IMAGE_ERR_UNRECOVERABLE+3)
	#define GDISP_IMAGE_ERR_UNSUPPORTED_OK		3
	#define GDISP_IMAGE_ERR_NOMEMORY			(GDISP_IMAGE_ERR_UNRECOVERABLE+4)

/**
 * @brief	Image flags
 */
typedef uint16_t	gdispImageFlags;
	#define GDISP_IMAGE_FLG_TRANSPARENT			0x0001	/* The image has transparency */
	#define GDISP_IMAGE_FLG_ANIMATED			0x0002	/* The image has animation */
	#define GDISP_IMAGE_FLG_MULTIPAGE			0x0004	/* The image has multiple pages */

struct gdispImageIO;

/**
 * @brief	An image IO close function
 *
 * @param[in] pio	Pointer to the io structure
 * @param[in] desc	The descriptor. A filename or an image structure pointer.
 *
 */
typedef void (*gdispImageIOCloseFn)(struct gdispImageIO *pio);

/**
 * @brief	An image IO read function
 * @returns	The number of bytes actually read or 0 on error
 *
 * @param[in] pio	Pointer to the io structure
 * @param[in] buf	Where the results should be placed
 * @param[in] len	The number of bytes to read
 *
 */
typedef size_t (*gdispImageIOReadFn)(struct gdispImageIO *pio, void *buf, size_t len);

/**
 * @brief	An image IO seek function
 *
 * @param[in] pio	Pointer to the io structure
 * @param[in] pos	Which byte to seek to relative to the start of the "file".
 *
 */
typedef void (*gdispImageIOSeekFn)(struct gdispImageIO *pio, size_t pos);

typedef struct gdispImageIOFunctions {
	gdispImageIOReadFn			read;				/* @< The function to read input */
	gdispImageIOSeekFn			seek;				/* @< The function to seek input */
	gdispImageIOCloseFn			close;				/* @< The function to close input */
	} gdispImageIOFunctions;

/**
 * @brief	The structure defining the IO routines for image handling
 */
typedef struct gdispImageIO {
	const void *				fd;					/* @< The "file" descriptor */
	size_t						pos;				/* @< The current "file" position */
	const gdispImageIOFunctions	*fns;				/* @< The current "file" functions */
} gdispImageIO;

/**
 * @brief	The structure for an image
 */
typedef struct gdispImage {
	gdispImageType						type;				/* @< The image type */
	gdispImageFlags						flags;				/* @< The image flags */
	color_t								bgcolor;			/* @< The default background color */
	coord_t								width, height;		/* @< The image dimensions */
	gdispImageIO						io;					/* @< The image IO functions */
	#if GDISP_NEED_IMAGE_ACCOUNTING
		uint32_t							memused;			/* @< How much RAM is currently allocated */
		uint32_t							maxmemused;			/* @< How much RAM has been allocated (maximum) */
	#endif
	const struct gdispImageHandlers *	fns;				/* @< Don't mess with this! */
	struct gdispImagePrivate *			priv;				/* @< Don't mess with this! */
} gdispImage;
	
#ifdef __cplusplus
extern "C" {
#endif

	/**
	 * @brief	Sets the io fields in the image structure to routines
	 * 			that support reading from an image stored in RAM or Flash.
	 * 			
	 * @return	TRUE if the IO open function succeeds
	 *
	 * @param[in] img   	The image structure
	 * @param[in] memimage	A pointer to the image in RAM or Flash 
	 *
	 * @note	Always returns TRUE for a Memory Reader
	 */
	bool_t gdispImageSetMemoryReader(gdispImage *img, const void *memimage);

	#if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__)
		/**
		 * @brief	Sets the io fields in the image structure to routines
		 * 			that support reading from an image stored on a BaseFileStream (eg SDCard).
		 *
		 * @return	TRUE if the IO open function succeeds
		 *
		 * @param[in] img   			The image structure
		 * @param[in] BaseFileStreamPtr	A pointer to the (open) BaseFileStream object.
		 *
		 */
		bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr);
	#endif

	#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX || defined(__DOXYGEN__)
		/**
		 * @brief	Sets the io fields in the image structure to routines
		 * 			that support reading from an image stored in Win32 simulators native
		 * 			file system.
		 * @pre		Only available on the Win32 simulator
		 *
		 * @return	TRUE if the IO open function succeeds
		 *
		 * @param[in] img   	The image structure
		 * @param[in] filename	The filename to open
		 *
		 */
		bool_t gdispImageSetFileReader(gdispImage *img, const char *filename);
		/* Old definition */
		#define gdispImageSetSimulFileReader(img, fname)	gdispImageSetFileReader(img, fname)
	#endif
	
	/**
	 * @brief	Open an image ready for drawing
	 * @details	Determine the image format and get ready to decode the first image frame
	 * @return	GDISP_IMAGE_ERR_OK (0) on success or an error code.
	 * 
	 * @param[in] img   The image structure
	 * 
	 * @pre		The io fields should be filled in before calling gdispImageOpen()
	 * 
	 * @note	This determines which decoder to use and then initialises all other fields
	 * 			in the gdispImage structure.
	 * @note	The image background color is set to White.
	 * @note	There are three types of return - everything OK, partial success and unrecoverable
	 * 			failures. For everything OK it returns GDISP_IMAGE_ERR_OK. A partial success can
	 * 			be distinguished from a unrecoverable failure by testing the GDISP_IMAGE_ERR_UNRECOVERABLE
	 * 			bit in the error code.
	 * 			A partial success return code means an image can still be drawn but perhaps with
	 * 			reduced functionality eg only the first page of a multi-page image.
	 * @note	@p gdispImageClose() can be called even after a failure to open the image to ensure
	 * 			that the IO close routine gets called.
	 */
	gdispImageError gdispImageOpen(gdispImage *img);
	
	/**
	 * @brief	Close an image and release any dynamically allocated working storage.
	 * 
	 * @param[in] img   The image structure
	 * 
	 * @pre		gdispImageOpen() must have returned successfully.
	 *
	 * @note	Also calls the IO close function (if it hasn't already been called).
	 */
	void gdispImageClose(gdispImage *img);

	/**
	 * @brief	Is an image open.
	 * @return	TRUE if the image is currently open.
	 *
	 * @param[in] img   The image structure
	 *
	 * @note	Be careful with calling this on an uninitialized image structure as the image
	 * 			will contain random data which may be interpreted as meaning the image
	 * 			is open. Clearing the Image structure to 0's will guarantee the image
	 * 			is seen as being closed.
	 */
	bool_t gdispImageIsOpen(gdispImage *img);

	/**
	 * @brief	Set the background color of the image.
	 *
	 * @param[in] img   	The image structure
	 * @param[in] bgcolor	The background color to use
	 *
	 * @pre		gdispImageOpen() must have returned successfully.
	 *
	 * @note	This color is only used when an image has to restore part of the background before
	 * 			continuing with drawing that includes transparency eg some GIF animations.
	 */
	void gdispImageSetBgColor(gdispImage *img, color_t bgcolor);
	
	/**
	 * @brief	Cache the image
	 * @details	Decodes and caches the current frame into RAM.
	 * @return	GDISP_IMAGE_ERR_OK (0) on success or an error code.
	 *
	 * @param[in] img   The image structure
	 *
	 * @pre		gdispImageOpen() must have returned successfully.
	 *
	 * @note	This can use a LOT of RAM!
	 * @note	The decoder may choose to ignore the request for caching. If it does so it will
	 * 			return GDISP_IMAGE_ERR_UNSUPPORTED_OK.
	 * @note	A fatal error here does not necessarily mean that drawing the image will fail. For
	 * 			example, a GDISP_IMAGE_ERR_NOMEMORY error simply means there isn't enough RAM to
	 * 			cache the image.
	 */
	gdispImageError gdispImageCache(gdispImage *img);

	/**
	 * @brief	Draw the image
	 * @return	GDISP_IMAGE_ERR_OK (0) on success or an error code.
	 * 
	 * @param[in] g   	The display to draw on
	 * @param[in] img   The image structure
	 * @param[in] x,y	The screen location to draw the image
	 * @param[in] cx,cy	The area on the screen to draw
	 * @param[in] sx,sy	The image position to start drawing at
	 * 
	 * @pre		gdispImageOpen() must have returned successfully.
	 *
	 * @note	If sx,sy + cx,cy is outside the image boundaries the area outside the image
	 * 			is simply not drawn.
	 * @note	If @p gdispImageCache() has been called first for this frame, this routine will draw using a
	 * 			fast blit from the cached frame. If not, it reads the input and decodes it as it
	 * 			is drawing. This may be significantly slower than if the image has been cached (but
	 * 			uses a lot less RAM)
	 */
	gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
	#define gdispImageDraw(img,x,y,cx,cy,sx,sy)		gdispGImageDraw(GDISP,img,x,y,cx,cy,sx,sy)

	/**
	 * @brief	Prepare for the next frame/page in the image file.
	 * @return	A time in milliseconds to keep displaying the current frame before trying to draw
	 * 			the next frame. Watch out for the special values TIME_IMMEDIATE and TIME_INFINITE.
	 * 
	 * @param[in] img   The image structure
	 * 
	 * @pre		gdispImageOpen() must have returned successfully.
	 *
	 * @note	It will return TIME_IMMEDIATE if the first frame/page hasn't been drawn or if the next frame
	 * 			should be drawn immediately.
	 * @note	It will return TIME_INFINITE if another image frame doesn't exist or an error has occurred.
	 * @note	Images that support multiple pages (eg TIFF files) will return TIME_IMMEDIATE between pages
	 * 			and then TIME_INFINITE when there are no more pages.
	 * @note	An image that displays a looped animation will never return TIME_INFINITE unless it
	 * 			gets an error.
	 * @note	Calling gdispImageDraw() after getting a TIME_INFINITE will go back to drawing the first
	 * 			frame/page.
	 */
	delaytime_t gdispImageNext(gdispImage *img);
	
	#if GDISP_NEED_IMAGE_NATIVE
		/**
		 * @brief	The image drawing routines for a NATIVE format image.
		 * 
		 * @note	Only use these functions if you absolutely know the format
		 * 			of the image you are decoding. Generally you should use the
		 * 			generic functions and it will auto-detect the format.
		 * @note	A NATIVE format image is defined as an 8 byte header described below, immediately
		 * 			followed by the bitmap data. The bitmap data is stored in the native format for
		 * 			the display controller. If the pixel format specified in the header does not
		 * 			match the controller native format then the image is rejected.
		 * @note	The 8 byte header:
		 *  			{ 'N', 'I', width.hi, width.lo, height.hi, height.lo, format.hi, format.lo }
		 *  			The format word = GDISP_PIXELFORMAT
		 * @{
		 */
		gdispImageError gdispImageOpen_NATIVE(gdispImage *img);
		void gdispImageClose_NATIVE(gdispImage *img);
		gdispImageError gdispImageCache_NATIVE(gdispImage *img);
		gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
		delaytime_t gdispImageNext_NATIVE(gdispImage *img);
		/* @} */
	#endif

	#if GDISP_NEED_IMAGE_GIF
		/**
		 * @brief	The image drawing routines for a GIF image.
		 * @note	Only use these functions if you absolutely know the format
		 * 			of the image you are decoding. Generally you should use the
		 * 			generic functions and it will auto-detect the format.
		 * @{
		 */
		gdispImageError gdispImageOpen_GIF(gdispImage *img);
		void gdispImageClose_GIF(gdispImage *img);
		gdispImageError gdispImageCache_GIF(gdispImage *img);
		gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
		delaytime_t gdispImageNext_GIF(gdispImage *img);
		/* @} */
	#endif

	#if GDISP_NEED_IMAGE_BMP
		/**
		 * @brief	The image drawing routines for a BMP image.
		 * @note	Only use these functions if you absolutely know the format
		 * 			of the image you are decoding. Generally you should use the
		 * 			generic functions and it will auto-detect the format.
		 * @{
		 */
		gdispImageError gdispImageOpen_BMP(gdispImage *img);
		void gdispImageClose_BMP(gdispImage *img);
		gdispImageError gdispImageCache_BMP(gdispImage *img);
		gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
		delaytime_t gdispImageNext_BMP(gdispImage *img);
		/* @} */
	#endif
	
	#if GDISP_NEED_IMAGE_JPG
		/**
		 * @brief	The image drawing routines for a JPG image.
		 * @note	Only use these functions if you absolutely know the format
		 * 			of the image you are decoding. Generally you should use the
		 * 			generic functions and it will auto-detect the format.
		 * @{
		 */
		gdispImageError gdispImageOpen_JPG(gdispImage *img);
		void gdispImageClose_JPG(gdispImage *img);
		gdispImageError gdispImageCache_JPG(gdispImage *img);
		gdispImageError gdispGImageDraw_JPG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
		delaytime_t gdispImageNext_JPG(gdispImage *img);
		/* @} */
	#endif

	#if GDISP_NEED_IMAGE_PNG
		/**
		 * @brief	The image drawing routines for a PNG image.
		 * @note	Only use these functions if you absolutely know the format
		 * 			of the image you are decoding. Generally you should use the
		 * 			generic functions and it will auto-detect the format.
		 * @{
		 */
		gdispImageError gdispImageOpen_PNG(gdispImage *img);
		void gdispImageClose_PNG(gdispImage *img);
		gdispImageError gdispImageCache_PNG(gdispImage *img);
		gdispImageError gdispGImageDraw_PNG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
		delaytime_t gdispImageNext_PNG(gdispImage *img);
		/* @} */
	#endif

#ifdef __cplusplus
}
#endif

#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */
#endif /* _GDISP_IMAGE_H */
/** @} */