µGFX  2.9
version 2.9
gdisp_image_native.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 && GDISP_NEED_IMAGE_NATIVE
11 
12 #include "gdisp_image_support.h"
13 
14 /**
15  * How big a pixel array to allocate for blitting
16  * Bigger is faster but uses more RAM.
17  */
18 #define BLIT_BUFFER_SIZE_NATIVE 32
19 
20 #define HEADER_SIZE_NATIVE 8
21 #define FRAME0POS_NATIVE (HEADER_SIZE_NATIVE)
22 
23 /**
24  * Helper Routines Needed
25  */
26 void *gdispImageAlloc(gImage *img, gMemSize sz);
27 void gdispImageFree(gImage *img, void *ptr, gMemSize sz);
28 
29 typedef struct gdispImagePrivate_NATIVE {
30  gPixel *frame0cache;
31  gPixel buf[BLIT_BUFFER_SIZE_NATIVE];
32  } gdispImagePrivate_NATIVE;
33 
34 void gdispImageClose_NATIVE(gImage *img) {
35  gdispImagePrivate_NATIVE * priv;
36 
37  priv = (gdispImagePrivate_NATIVE *)img->priv;
38  if (priv) {
39  if (priv->frame0cache)
40  gdispImageFree(img, (void *)priv->frame0cache, img->width * img->height * sizeof(gPixel));
41  gdispImageFree(img, (void *)priv, sizeof(gdispImagePrivate_NATIVE));
42  img->priv = 0;
43  }
44 }
45 
46 gdispImageError gdispImageOpen_NATIVE(gImage *img) {
47  gU8 hdr[HEADER_SIZE_NATIVE];
48 
49  /* Read the 8 byte header */
50  if (gfileRead(img->f, hdr, 8) != 8)
51  return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
52 
53  if (hdr[0] != 'N' || hdr[1] != 'I')
54  return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
55 
56  if (hdr[6] != GDISP_PIXELFORMAT/256 || hdr[7] != (GDISP_PIXELFORMAT & 0xFF))
57  return GDISP_IMAGE_ERR_UNSUPPORTED; // Unsupported pixel format
58 
59  /* We know we are a native format image */
60  img->flags = 0;
61  img->width = (((gU16)hdr[2])<<8) | (hdr[3]);
62  img->height = (((gU16)hdr[4])<<8) | (hdr[5]);
63  if (img->width < 1 || img->height < 1)
64  return GDISP_IMAGE_ERR_BADDATA;
65  if (!(img->priv = gdispImageAlloc(img, sizeof(gdispImagePrivate_NATIVE))))
66  return GDISP_IMAGE_ERR_NOMEMORY;
67  ((gdispImagePrivate_NATIVE *)(img->priv))->frame0cache = 0;
68 
69  img->type = GDISP_IMAGE_TYPE_NATIVE;
70  return GDISP_IMAGE_ERR_OK;
71 }
72 
73 gdispImageError gdispImageCache_NATIVE(gImage *img) {
74  gMemSize len;
75  gdispImagePrivate_NATIVE * priv;
76 
77  /* If we are already cached - just return OK */
78  priv = (gdispImagePrivate_NATIVE *)img->priv;
79  if (priv->frame0cache)
80  return GDISP_IMAGE_ERR_OK;
81 
82  /* We need to allocate the cache */
83  len = img->width * img->height * sizeof(gPixel);
84  priv->frame0cache = (gPixel *)gdispImageAlloc(img, len);
85  if (!priv->frame0cache)
86  return GDISP_IMAGE_ERR_NOMEMORY;
87 
88  /* Read the entire bitmap into cache */
89  gfileSetPos(img->f, FRAME0POS_NATIVE);
90  if (gfileRead(img->f, priv->frame0cache, len) != len)
91  return GDISP_IMAGE_ERR_BADDATA;
92 
93  return GDISP_IMAGE_ERR_OK;
94 }
95 
96 gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gImage *img, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord sx, gCoord sy) {
97  gCoord mx, mcx;
98  gFileSize pos;
99  gMemSize len;
100  gdispImagePrivate_NATIVE * priv;
101 
102  priv = (gdispImagePrivate_NATIVE *)img->priv;
103 
104  /* Check some reasonableness */
105  if (sx >= img->width || sy >= img->height) return GDISP_IMAGE_ERR_OK;
106  if (sx + cx > img->width) cx = img->width - sx;
107  if (sy + cy > img->height) cy = img->height - sy;
108 
109  /* Draw from the image cache - if it exists */
110  if (priv->frame0cache) {
111  gdispGBlitArea(g, x, y, cx, cy, sx, sy, img->width, priv->frame0cache);
112  return GDISP_IMAGE_ERR_OK;
113  }
114 
115  /* For this image decoder we cheat and just seek straight to the region we want to display */
116  pos = FRAME0POS_NATIVE + (img->width * sy + sx) * sizeof(gPixel);
117 
118  /* Cycle through the lines */
119  for(;cy;cy--, y++) {
120  /* Move to the start of the line */
121  gfileSetPos(img->f, pos);
122 
123  /* Draw the line in chunks using BitBlt */
124  for(mx = x, mcx = cx; mcx > 0; mcx -= len, mx += len) {
125  // Read the data
126  len = gfileRead(img->f,
127  priv->buf,
128  mcx > BLIT_BUFFER_SIZE_NATIVE ? (BLIT_BUFFER_SIZE_NATIVE*sizeof(gPixel)) : (mcx * sizeof(gPixel)))
129  / sizeof(gPixel);
130  if (!len)
131  return GDISP_IMAGE_ERR_BADDATA;
132 
133  /* Blit the chunk of data */
134  gdispGBlitArea(g, mx, y, len, 1, 0, 0, len, priv->buf);
135  }
136 
137  /* Get the position for the start of the next line */
138  pos += img->width*sizeof(gPixel);
139  }
140 
141  return GDISP_IMAGE_ERR_OK;
142 }
143 
144 gDelay gdispImageNext_NATIVE(gImage *img) {
145  (void) img;
146 
147  /* No more frames/pages */
148  return gDelayForever;
149 }
150 
151 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_NATIVE */
GDISP image support routines header file.
void gdispGBlitArea(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gCoord srcx, gCoord srcy, gCoord srccx, const gPixel *buffer)
Fill an area using the supplied bitmap.
gColor gPixel
The pixel format.
Definition: gdisp.h:226
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.
gMemSize gfileRead(GFILE *f, void *buf, gMemSize len)
Read from file.
gU16 gdispImageError
An image error code.
Definition: gdisp_image.h:37
The structure for an image.
Definition: gdisp_image.h:59