1 /**
2 * @file lv_png.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../../lvgl.h"
10 #if LV_USE_PNG
11
12 #include "lv_png.h"
13 #include "lodepng.h"
14 #include <stdlib.h>
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23
24 /**********************
25 * STATIC PROTOTYPES
26 **********************/
27 static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
28 static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
29 static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
30 static void convert_color_depth(uint8_t * img, uint32_t px_cnt);
31
32 /**********************
33 * STATIC VARIABLES
34 **********************/
35
36 /**********************
37 * MACROS
38 **********************/
39
40 /**********************
41 * GLOBAL FUNCTIONS
42 **********************/
43
44 /**
45 * Register the PNG decoder functions in LVGL
46 */
lv_png_init(void)47 void lv_png_init(void)
48 {
49 lv_img_decoder_t * dec = lv_img_decoder_create();
50 lv_img_decoder_set_info_cb(dec, decoder_info);
51 lv_img_decoder_set_open_cb(dec, decoder_open);
52 lv_img_decoder_set_close_cb(dec, decoder_close);
53 }
54
55 /**********************
56 * STATIC FUNCTIONS
57 **********************/
58
59 /**
60 * Get info about a PNG image
61 * @param src can be file name or pointer to a C array
62 * @param header store the info here
63 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
64 */
decoder_info(struct _lv_img_decoder_t * decoder,const void * src,lv_img_header_t * header)65 static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
66 {
67 (void) decoder; /*Unused*/
68 lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
69
70 /*If it's a PNG file...*/
71 if(src_type == LV_IMG_SRC_FILE) {
72 const char * fn = src;
73 if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
74
75 /* Read the width and height from the file. They have a constant location:
76 * [16..23]: width
77 * [24..27]: height
78 */
79 uint32_t size[2];
80 lv_fs_file_t f;
81 lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
82 if(res != LV_FS_RES_OK) return LV_RES_INV;
83 lv_fs_seek(&f, 16, LV_FS_SEEK_SET);
84 uint32_t rn;
85 lv_fs_read(&f, &size, 8, &rn);
86 if(rn != 8) return LV_RES_INV;
87 lv_fs_close(&f);
88 /*Save the data in the header*/
89 header->always_zero = 0;
90 header->cf = LV_IMG_CF_RAW_ALPHA;
91 /*The width and height are stored in Big endian format so convert them to little endian*/
92 header->w = (lv_coord_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
93 header->h = (lv_coord_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
94
95 return LV_RES_OK;
96 }
97 }
98 /*If it's a PNG file in a C array...*/
99 else if(src_type == LV_IMG_SRC_VARIABLE) {
100 const lv_img_dsc_t * img_dsc = src;
101 const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
102 if(memcmp(magic, img_dsc->data, sizeof(magic))) return LV_RES_INV;
103 header->always_zero = 0;
104 header->cf = img_dsc->header.cf; /*Save the color format*/
105 header->w = img_dsc->header.w; /*Save the color width*/
106 header->h = img_dsc->header.h; /*Save the color height*/
107 return LV_RES_OK;
108 }
109
110 return LV_RES_INV; /*If didn't succeeded earlier then it's an error*/
111 }
112
113
114 /**
115 * Open a PNG image and return the decided image
116 * @param src can be file name or pointer to a C array
117 * @param style style of the image object (unused now but certain formats might use it)
118 * @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
119 */
decoder_open(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)120 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
121 {
122
123 (void) decoder; /*Unused*/
124 uint32_t error; /*For the return values of PNG decoder functions*/
125
126 uint8_t * img_data = NULL;
127
128 /*If it's a PNG file...*/
129 if(dsc->src_type == LV_IMG_SRC_FILE) {
130 const char * fn = dsc->src;
131
132 if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
133
134 /*Load the PNG file into buffer. It's still compressed (not decoded)*/
135 unsigned char * png_data; /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/
136 size_t png_data_size; /*Size of `png_data` in bytes*/
137
138 error = lodepng_load_file(&png_data, &png_data_size, fn); /*Load the file*/
139 if(error) {
140 LV_LOG_WARN("error %u: %s\n", error, lodepng_error_text(error));
141 return LV_RES_INV;
142 }
143
144 /*Decode the PNG image*/
145 uint32_t png_width; /*Will be the width of the decoded image*/
146 uint32_t png_height; /*Will be the width of the decoded image*/
147
148 /*Decode the loaded image in ARGB8888 */
149 error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size);
150 lv_mem_free(png_data); /*Free the loaded file*/
151 if(error) {
152 LV_LOG_WARN("error %u: %s\n", error, lodepng_error_text(error));
153 return LV_RES_INV;
154 }
155
156 /*Convert the image to the system's color depth*/
157 convert_color_depth(img_data, png_width * png_height);
158 dsc->img_data = img_data;
159 return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/
160 }
161 }
162 /*If it's a PNG file in a C array...*/
163 else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
164 const lv_img_dsc_t * img_dsc = dsc->src;
165 uint32_t png_width; /*No used, just required by he decoder*/
166 uint32_t png_height; /*No used, just required by he decoder*/
167
168 /*Decode the image in ARGB8888 */
169 error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size);
170
171 if(error) {
172 return LV_RES_INV;
173 }
174
175 /*Convert the image to the system's color depth*/
176 convert_color_depth(img_data, png_width * png_height);
177
178 dsc->img_data = img_data;
179 return LV_RES_OK; /*Return with its pointer*/
180 }
181
182 return LV_RES_INV; /*If not returned earlier then it failed*/
183 }
184
185 /**
186 * Free the allocated resources
187 */
decoder_close(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)188 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
189 {
190 LV_UNUSED(decoder); /*Unused*/
191 if(dsc->img_data) {
192 lv_mem_free((uint8_t *)dsc->img_data);
193 dsc->img_data = NULL;
194 }
195 }
196
197 /**
198 * If the display is not in 32 bit format (ARGB888) then covert the image to the current color depth
199 * @param img the ARGB888 image
200 * @param px_cnt number of pixels in `img`
201 */
convert_color_depth(uint8_t * img,uint32_t px_cnt)202 static void convert_color_depth(uint8_t * img, uint32_t px_cnt)
203 {
204 #if LV_COLOR_DEPTH == 32
205 lv_color32_t * img_argb = (lv_color32_t *)img;
206 lv_color_t c;
207 lv_color_t * img_c = (lv_color_t *) img;
208 uint32_t i;
209 for(i = 0; i < px_cnt; i++) {
210 c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
211 img_c[i].ch.red = c.ch.blue;
212 img_c[i].ch.blue = c.ch.red;
213 }
214 #elif LV_COLOR_DEPTH == 16
215 lv_color32_t * img_argb = (lv_color32_t *)img;
216 lv_color_t c;
217 uint32_t i;
218 for(i = 0; i < px_cnt; i++) {
219 c = lv_color_make(img_argb[i].ch.blue, img_argb[i].ch.green, img_argb[i].ch.red);
220 img[i * 3 + 2] = img_argb[i].ch.alpha;
221 img[i * 3 + 1] = c.full >> 8;
222 img[i * 3 + 0] = c.full & 0xFF;
223 }
224 #elif LV_COLOR_DEPTH == 8
225 lv_color32_t * img_argb = (lv_color32_t *)img;
226 lv_color_t c;
227 uint32_t i;
228 for(i = 0; i < px_cnt; i++) {
229 c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
230 img[i * 2 + 1] = img_argb[i].ch.alpha;
231 img[i * 2 + 0] = c.full;
232 }
233 #elif LV_COLOR_DEPTH == 1
234 lv_color32_t * img_argb = (lv_color32_t *)img;
235 uint8_t b;
236 uint32_t i;
237 for(i = 0; i < px_cnt; i++) {
238 b = img_argb[i].ch.red | img_argb[i].ch.green | img_argb[i].ch.blue;
239 img[i * 2 + 1] = img_argb[i].ch.alpha;
240 img[i * 2 + 0] = b > 128 ? 1 : 0;
241 }
242 #endif
243 }
244
245 #endif /*LV_USE_PNG*/
246
247
248