version 2.8
gdisp_image.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.org/license.html
6  */
7 
8 #include "../../gfx.h"
9 
10 #if GFX_USE_GDISP && GDISP_NEED_IMAGE
11 
12 #include "gdisp_image_support.h"
13 
14 #if GDISP_NEED_IMAGE_NATIVE
15  extern gdispImageError gdispImageOpen_NATIVE(gdispImage *img);
16  extern void gdispImageClose_NATIVE(gdispImage *img);
17  extern gdispImageError gdispImageCache_NATIVE(gdispImage *img);
18  extern 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);
19  extern delaytime_t gdispImageNext_NATIVE(gdispImage *img);
20 #endif
21 
22 #if GDISP_NEED_IMAGE_GIF
23  extern gdispImageError gdispImageOpen_GIF(gdispImage *img);
24  extern void gdispImageClose_GIF(gdispImage *img);
25  extern gdispImageError gdispImageCache_GIF(gdispImage *img);
26  extern 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);
27  extern delaytime_t gdispImageNext_GIF(gdispImage *img);
28 #endif
29 
30 #if GDISP_NEED_IMAGE_BMP
31  extern gdispImageError gdispImageOpen_BMP(gdispImage *img);
32  extern void gdispImageClose_BMP(gdispImage *img);
33  extern gdispImageError gdispImageCache_BMP(gdispImage *img);
34  extern 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);
35  extern delaytime_t gdispImageNext_BMP(gdispImage *img);
36  extern uint16_t gdispImageGetPaletteSize_BMP(gdispImage *img);
37  extern color_t gdispImageGetPalette_BMP(gdispImage *img, uint16_t index);
38  extern bool_t gdispImageAdjustPalette_BMP(gdispImage *img, uint16_t index, color_t newColor);
39 #endif
40 
41 #if GDISP_NEED_IMAGE_JPG
42  extern gdispImageError gdispImageOpen_JPG(gdispImage *img);
43  extern void gdispImageClose_JPG(gdispImage *img);
44  extern gdispImageError gdispImageCache_JPG(gdispImage *img);
45  extern 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);
46  extern delaytime_t gdispImageNext_JPG(gdispImage *img);
47 #endif
48 
49 #if GDISP_NEED_IMAGE_PNG
50  extern gdispImageError gdispImageOpen_PNG(gdispImage *img);
51  extern void gdispImageClose_PNG(gdispImage *img);
52  extern gdispImageError gdispImageCache_PNG(gdispImage *img);
53  extern 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);
54  extern delaytime_t gdispImageNext_PNG(gdispImage *img);
55 #endif
56 
57 /* The structure defining the routines for image drawing */
58 typedef struct gdispImageHandlers {
59  gdispImageError (*open)(gdispImage *img); /* The open function */
60  void (*close)(gdispImage *img); /* The close function */
61  gdispImageError (*cache)(gdispImage *img); /* The cache function */
62  gdispImageError (*draw)(GDisplay *g,
63  gdispImage *img,
64  coord_t x, coord_t y,
65  coord_t cx, coord_t cy,
66  coord_t sx, coord_t sy); /* The draw function */
67  delaytime_t (*next)(gdispImage *img); /* The next frame function */
68  uint16_t (*getPaletteSize)(gdispImage *img); /* Retrieve the size of the palette (number of entries) */
69  color_t (*getPalette)(gdispImage *img, uint16_t index); /* Retrieve a specific color value of the palette */
70  bool_t (*adjustPalette)(gdispImage *img, uint16_t index, color_t newColor); /* Replace a color value in the palette */
71 } gdispImageHandlers;
72 
73 static gdispImageHandlers ImageHandlers[] = {
74  #if GDISP_NEED_IMAGE_NATIVE
75  { gdispImageOpen_NATIVE, gdispImageClose_NATIVE,
76  gdispImageCache_NATIVE, gdispGImageDraw_NATIVE, gdispImageNext_NATIVE,
77  0, 0, 0
78  },
79  #endif
80  #if GDISP_NEED_IMAGE_GIF
81  { gdispImageOpen_GIF, gdispImageClose_GIF,
82  gdispImageCache_GIF, gdispGImageDraw_GIF, gdispImageNext_GIF,
83  0, 0, 0
84  },
85  #endif
86  #if GDISP_NEED_IMAGE_BMP
87  { gdispImageOpen_BMP, gdispImageClose_BMP,
88  gdispImageCache_BMP, gdispGImageDraw_BMP, gdispImageNext_BMP,
89  gdispImageGetPaletteSize_BMP, gdispImageGetPalette_BMP, gdispImageAdjustPalette_BMP
90  },
91  #endif
92  #if GDISP_NEED_IMAGE_JPG
93  { gdispImageOpen_JPG, gdispImageClose_JPG,
94  gdispImageCache_JPG, gdispGImageDraw_JPG, gdispImageNext_JPG,
95  0, 0, 0
96  },
97  #endif
98  #if GDISP_NEED_IMAGE_PNG
99  { gdispImageOpen_PNG, gdispImageClose_PNG,
100  gdispImageCache_PNG, gdispGImageDraw_PNG, gdispImageNext_PNG,
101  0, 0, 0
102  },
103  #endif
104 };
105 
106 void gdispImageInit(gdispImage *img) {
107  img->type = GDISP_IMAGE_TYPE_UNKNOWN;
108 }
109 
111  gdispImageError err;
112 
113  if (!img)
114  return GDISP_IMAGE_ERR_NULLPOINTER;
115  if (!f)
116  return GDISP_IMAGE_ERR_NOSUCHFILE;
117  img->f = f;
118  img->bgcolor = White;
119  for(img->fns = ImageHandlers; img->fns < ImageHandlers+sizeof(ImageHandlers)/sizeof(ImageHandlers[0]); img->fns++) {
120  err = img->fns->open(img);
121  if (err != GDISP_IMAGE_ERR_BADFORMAT) {
122  if ((err & GDISP_IMAGE_ERR_UNRECOVERABLE))
123  goto unrecoverable;
124 
125  // Everything is possible
126  return err;
127  }
128 
129  // Try the next decoder
130  gfileSetPos(img->f, 0);
131  }
132 
133  err = GDISP_IMAGE_ERR_BADFORMAT;
134  img->type = GDISP_IMAGE_TYPE_UNKNOWN;
135 
136 unrecoverable:
137  gfileClose(img->f);
138  img->f = 0;
139  img->flags = 0;
140  img->fns = 0;
141  img->priv = 0;
142  return err;
143 }
144 
145 void gdispImageClose(gdispImage *img) {
146  if (!img)
147  return;
148  if (img->fns)
149  img->fns->close(img);
150  gfileClose(img->f);
151  img->type = GDISP_IMAGE_TYPE_UNKNOWN;
152  img->flags = 0;
153  img->fns = 0;
154  img->priv = 0;
155 }
156 
157 bool_t gdispImageIsOpen(gdispImage *img) {
158  return img && img->type != GDISP_IMAGE_TYPE_UNKNOWN && img->fns != 0;
159 }
160 
161 void gdispImageSetBgColor(gdispImage *img, color_t bgcolor) {
162  if (!img)
163  return;
164  img->bgcolor = bgcolor;
165 }
166 
168  if (!img) return GDISP_IMAGE_ERR_NULLPOINTER;
169  if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT;
170  return img->fns->cache(img);
171 }
172 
173 gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
174  if (!img) return GDISP_IMAGE_ERR_NULLPOINTER;
175  if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT;
176 
177  // Check on window
178  if (cx <= 0 || cy <= 0) return GDISP_IMAGE_ERR_OK;
179  if (sx < 0) sx = 0;
180  if (sy < 0) sy = 0;
181  if (sx >= img->width || sy >= img->height) return GDISP_IMAGE_ERR_OK;
182  if (sx + cx > img->width) cx = img->width - sx;
183  if (sy + cy > img->height) cy = img->height - sy;
184 
185  // Draw
186  return img->fns->draw(g, img, x, y, cx, cy, sx, sy);
187 }
188 
189 delaytime_t gdispImageNext(gdispImage *img) {
190  if (!img) return GDISP_IMAGE_ERR_NULLPOINTER;
191  if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT;
192  return img->fns->next(img);
193 }
194 
195 uint16_t gdispImageGetPaletteSize(gdispImage *img) {
196  if (!img || !img->fns) return 0;
197  if (!img->fns->getPaletteSize) return 0;
198  return img->fns->getPaletteSize(img);
199 }
200 
201 color_t gdispImageGetPalette(gdispImage *img, uint16_t index) {
202  if (!img || !img->fns) return 0;
203  if (!img->fns->getPalette) return 0;
204  return img->fns->getPalette(img, index);
205 }
206 
207 bool_t gdispImageAdjustPalette(gdispImage *img, uint16_t index, color_t newColor) {
208  if (!img || !img->fns) return FALSE;
209  if (!img->fns->adjustPalette) return FALSE;
210  return img->fns->adjustPalette(img, index, newColor);
211 }
212 
213 
214 // Helper Routines
215 void *gdispImageAlloc(gdispImage *img, size_t sz) {
216  #if GDISP_NEED_IMAGE_ACCOUNTING
217  void *ptr;
218 
219  ptr = gfxAlloc(sz);
220  if (ptr) {
221  img->memused += sz;
222  if (img->memused > img->maxmemused)
223  img->maxmemused = img->memused;
224  }
225  return ptr;
226  #else
227  (void) img;
228  return gfxAlloc(sz);
229  #endif
230 }
231 
232 void gdispImageFree(gdispImage *img, void *ptr, size_t sz) {
233  #if GDISP_NEED_IMAGE_ACCOUNTING
234  gfxFree(ptr);
235  img->memused -= sz;
236  #else
237  (void) img;
238  (void) sz;
239  gfxFree(ptr);
240  #endif
241 }
242 
243 #if GFX_CPU_ENDIAN != GFX_CPU_ENDIAN_LITTLE && GFX_CPU_ENDIAN != GFX_CPU_ENDIAN_BIG \
244  && GFX_CPU_ENDIAN != GFX_CPU_ENDIAN_WBDWL && GFX_CPU_ENDIAN != GFX_CPU_ENDIAN_WLDWB
245 
246  union wbyteorder_u {
247  uint8_t b[2];
248  uint32_t w;
249  };
250  union dwbyteorder_u {
251  uint8_t b[4];
252  uint32_t l;
253  };
254 
255  uint16_t gdispImageH16toLE16(uint16_t w) {
256  union wbyteorder_u we;
257 
258  we.w = w;
259  return (((uint16_t)we.b[0]))|(((uint16_t)we.b[1]) << 8);
260  }
261  uint16_t gdispImageH16toBE16(uint16_t w) {
262  union wbyteorder_u we;
263 
264  we.w = w;
265  return (((uint16_t)we.b[0]) << 8)|(((uint16_t)we.b[1]));
266  }
267 
268  uint32_t gdispImageH32toLE32(uint32_t dw) {
269  union dwbyteorder_u we;
270 
271  we.l = dw;
272  return (((uint32_t)we.b[0]))
273  |(((uint32_t)we.b[1]) << 8)
274  |(((uint32_t)we.b[2]) << 16)
275  |(((uint32_t)we.b[3]) << 24);
276  }
277  uint32_t gdispImageH32toBE32(uint32_t dw) {
278  union dwbyteorder_u we;
279 
280  we.l = dw;
281  return (((uint32_t)we.b[0]) << 24)
282  |(((uint32_t)we.b[1]) << 16)
283  |(((uint32_t)we.b[2]) << 8)
284  |(((uint32_t)we.b[3]));
285  }
286 #endif
287 
288 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */
delaytime_t gdispImageNext(gdispImage *img)
Prepare for the next frame/page in the image file.
uint16_t gdispImageGetPaletteSize(gdispImage *img)
Get the number of entries in the color palette.
bool_t gdispImageIsOpen(gdispImage *img)
Is an image open.
int16_t coord_t
The type for a coordinate or length on the screen.
Definition: gdisp.h:39
void gdispImageClose(gdispImage *img)
Close an image and release any dynamically allocated working storage.
struct GFILE GFILE
A file pointer.
Definition: gfile.h:34
#define FALSE
Generic &#39;false&#39; boolean constant.
Definition: gfx.h:31
gdispImageError gdispImageCache(gdispImage *img)
Cache the image.
void * gfxAlloc(size_t sz)
Allocate memory.
void gdispImageSetBgColor(gdispImage *img, color_t bgcolor)
Set the background color of the image.
void gfxFree(void *ptr)
Free memory.
bool_t gfileSetPos(GFILE *f, long int pos)
Set the position of the read/write cursor.
gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy)
Draw the image.
The structure for an image.
Definition: gdisp_image.h:59
void gfileClose(GFILE *f)
Close file.
COLOR_TYPE color_t
The color type definition.
Definition: gdisp_colors.h:412
bool_t gdispImageAdjustPalette(gdispImage *img, uint16_t index, color_t newColor)
Modify an entry in the color palette.
color_t gdispImageGetPalette(gdispImage *img, uint16_t index)
Get an entry in the color palette.
void gdispImageInit(gdispImage *img)
Initialise a gdispImage object.
GDISP image support routines header file.
uint16_t gdispImageError
An image error code.
Definition: gdisp_image.h:37
gdispImageError gdispImageOpenGFile(gdispImage *img, GFILE *f)
Open an image using an open GFILE and get it ready for drawing.