µGFX  2.9
version 2.9
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.io/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(gImage *img);
16  extern void gdispImageClose_NATIVE(gImage *img);
17  extern gdispImageError gdispImageCache_NATIVE(gImage *img);
18  extern gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy);
19  extern gDelay gdispImageNext_NATIVE(gImage *img);
20 #endif
21 
22 #if GDISP_NEED_IMAGE_GIF
23  extern gdispImageError gdispImageOpen_GIF(gImage *img);
24  extern void gdispImageClose_GIF(gImage *img);
25  extern gdispImageError gdispImageCache_GIF(gImage *img);
26  extern gdispImageError gdispGImageDraw_GIF(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy);
27  extern gDelay gdispImageNext_GIF(gImage *img);
28 #endif
29 
30 #if GDISP_NEED_IMAGE_BMP
31  extern gdispImageError gdispImageOpen_BMP(gImage *img);
32  extern void gdispImageClose_BMP(gImage *img);
33  extern gdispImageError gdispImageCache_BMP(gImage *img);
34  extern gdispImageError gdispGImageDraw_BMP(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy);
35  extern gDelay gdispImageNext_BMP(gImage *img);
36  extern gU16 gdispImageGetPaletteSize_BMP(gImage *img);
37  extern gColor gdispImageGetPalette_BMP(gImage *img, gU16 index);
38  extern gBool gdispImageAdjustPalette_BMP(gImage *img, gU16 index, gColor newColor);
39 #endif
40 
41 #if GDISP_NEED_IMAGE_JPG
42  extern gdispImageError gdispImageOpen_JPG(gImage *img);
43  extern void gdispImageClose_JPG(gImage *img);
44  extern gdispImageError gdispImageCache_JPG(gImage *img);
45  extern gdispImageError gdispGImageDraw_JPG(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy);
46  extern gDelay gdispImageNext_JPG(gImage *img);
47 #endif
48 
49 #if GDISP_NEED_IMAGE_PNG
50  extern gdispImageError gdispImageOpen_PNG(gImage *img);
51  extern void gdispImageClose_PNG(gImage *img);
52  extern gdispImageError gdispImageCache_PNG(gImage *img);
53  extern gdispImageError gdispGImageDraw_PNG(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy);
54  extern gDelay gdispImageNext_PNG(gImage *img);
55 #endif
56 
57 /* The structure defining the routines for image drawing */
58 typedef struct gdispImageHandlers {
59  gdispImageError (*open)(gImage *img); /* The open function */
60  void (*close)(gImage *img); /* The close function */
61  gdispImageError (*cache)(gImage *img); /* The cache function */
62  gdispImageError (*draw)(GDisplay *g,
63  gImage *img,
64  gCoord x, gCoord y,
65  gCoord cx, gCoord cy,
66  gCoord sx, gCoord sy); /* The draw function */
67  gDelay (*next)(gImage *img); /* The next frame function */
68  gU16 (*getPaletteSize)(gImage *img); /* Retrieve the size of the palette (number of entries) */
69  gColor (*getPalette)(gImage *img, gU16 index); /* Retrieve a specific color value of the palette */
70  gBool (*adjustPalette)(gImage *img, gU16 index, gColor 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(gImage *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 = GFX_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(gImage *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 gBool gdispImageIsOpen(gImage *img) {
158  return img && img->type != GDISP_IMAGE_TYPE_UNKNOWN && img->fns != 0;
159 }
160 
161 void gdispImageSetBgColor(gImage *img, gColor 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, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord 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 gDelay gdispImageNext(gImage *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 gU16 gdispImageGetPaletteSize(gImage *img) {
196  if (!img || !img->fns) return 0;
197  if (!img->fns->getPaletteSize) return 0;
198  return img->fns->getPaletteSize(img);
199 }
200 
201 gColor gdispImageGetPalette(gImage *img, gU16 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 gBool gdispImageAdjustPalette(gImage *img, gU16 index, gColor newColor) {
208  if (!img || !img->fns) return gFalse;
209  if (!img->fns->adjustPalette) return gFalse;
210  return img->fns->adjustPalette(img, index, newColor);
211 }
212 
213 
214 // Helper Routines
215 void *gdispImageAlloc(gImage *img, gMemSize 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(gImage *img, void *ptr, gMemSize 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  gU8 b[2];
248  gU32 w;
249  };
250  union dwbyteorder_u {
251  gU8 b[4];
252  gU32 l;
253  };
254 
255  gU16 gdispImageH16toLE16(gU16 w) {
256  union wbyteorder_u we;
257 
258  we.w = w;
259  return (((gU16)we.b[0]))|(((gU16)we.b[1]) << 8);
260  }
261  gU16 gdispImageH16toBE16(gU16 w) {
262  union wbyteorder_u we;
263 
264  we.w = w;
265  return (((gU16)we.b[0]) << 8)|(((gU16)we.b[1]));
266  }
267 
268  gU32 gdispImageH32toLE32(gU32 dw) {
269  union dwbyteorder_u we;
270 
271  we.l = dw;
272  return (((gU32)we.b[0]))
273  |(((gU32)we.b[1]) << 8)
274  |(((gU32)we.b[2]) << 16)
275  |(((gU32)we.b[3]) << 24);
276  }
277  gU32 gdispImageH32toBE32(gU32 dw) {
278  union dwbyteorder_u we;
279 
280  we.l = dw;
281  return (((gU32)we.b[0]) << 24)
282  |(((gU32)we.b[1]) << 16)
283  |(((gU32)we.b[2]) << 8)
284  |(((gU32)we.b[3]));
285  }
286 #endif
287 
288 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */
GDISP image support routines header file.
COLOR_TYPE gColor
The color type definition.
Definition: gdisp_colors.h:437
gI16 gCoord
The type for a coordinate or length on the screen.
Definition: gdisp.h:39
gBool gfileSetPos(GFILE *f, gFileSize pos)
Set the position of the read/write cursor.
void gfileClose(GFILE *f)
Close file.
struct GFILE GFILE
A file pointer.
Definition: gfile.h:34
void * gfxAlloc(gMemSize sz)
Allocate memory.
void gfxFree(void *ptr)
Free memory.
gdispImageError gdispImageCache(gImage *img)
Cache the image.
gdispImageError gdispImageOpenGFile(gImage *img, GFILE *f)
Open an image using an open GFILE and get it ready for drawing.
gBool gdispImageAdjustPalette(gImage *img, gU16 index, gColor newColor)
Modify an entry in the color palette.
gdispImageError gdispGImageDraw(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy)
Draw the image.
gU16 gdispImageGetPaletteSize(gImage *img)
Get the number of entries in the color palette.
void gdispImageInit(gImage *img)
Initialise a gImage object.
gU16 gdispImageError
An image error code.
Definition: gdisp_image.h:37
gDelay gdispImageNext(gImage *img)
Prepare for the next frame/page in the image file.
gBool gdispImageIsOpen(gImage *img)
Is an image open.
void gdispImageClose(gImage *img)
Close an image and release any dynamically allocated working storage.
void gdispImageSetBgColor(gImage *img, gColor bgcolor)
Set the background color of the image.
gColor gdispImageGetPalette(gImage *img, gU16 index)
Get an entry in the color palette.
The structure for an image.
Definition: gdisp_image.h:59