1 /**
2 * @file lv_libpng.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../draw/lv_image_decoder_private.h"
10 #include "../../../lvgl.h"
11 #if LV_USE_LIBPNG
12
13 #include "lv_libpng.h"
14 #include <png.h>
15 #include <string.h>
16 #include "../../core/lv_global.h"
17
18 /*********************
19 * DEFINES
20 *********************/
21
22 #define DECODER_NAME "PNG"
23
24 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
25
26 /**********************
27 * TYPEDEFS
28 **********************/
29
30 /**********************
31 * STATIC PROTOTYPES
32 **********************/
33 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * src, lv_image_header_t * header);
34 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
35 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
36 static lv_draw_buf_t * decode_png(lv_image_decoder_dsc_t * dsc);
37
38 /**********************
39 * STATIC VARIABLES
40 **********************/
41
42 /**********************
43 * MACROS
44 **********************/
45
46 /**********************
47 * GLOBAL FUNCTIONS
48 **********************/
49
50 /**
51 * Register the PNG decoder functions in LVGL
52 */
lv_libpng_init(void)53 void lv_libpng_init(void)
54 {
55 lv_image_decoder_t * dec = lv_image_decoder_create();
56 lv_image_decoder_set_info_cb(dec, decoder_info);
57 lv_image_decoder_set_open_cb(dec, decoder_open);
58 lv_image_decoder_set_close_cb(dec, decoder_close);
59
60 dec->name = DECODER_NAME;
61 }
62
lv_libpng_deinit(void)63 void lv_libpng_deinit(void)
64 {
65 lv_image_decoder_t * dec = NULL;
66 while((dec = lv_image_decoder_get_next(dec)) != NULL) {
67 if(dec->info_cb == decoder_info) {
68 lv_image_decoder_delete(dec);
69 break;
70 }
71 }
72 }
73
74 /**********************
75 * STATIC FUNCTIONS
76 **********************/
77
78 /**
79 * Get info about a PNG image
80 * @param dsc can be file name or pointer to a C array
81 * @param header store the info here
82 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info
83 */
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)84 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
85 {
86 LV_UNUSED(decoder); /*Unused*/
87
88 lv_image_src_t src_type = dsc->src_type; /*Get the source type*/
89
90 if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_VARIABLE) {
91 uint32_t * size;
92 static const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
93 uint8_t buf[24];
94
95 /*If it's a PNG file...*/
96 if(src_type == LV_IMAGE_SRC_FILE) {
97 /* Read the width and height from the file. They have a constant location:
98 * [16..19]: width
99 * [20..23]: height
100 */
101 uint32_t rn;
102 lv_fs_read(&dsc->file, buf, sizeof(buf), &rn);
103
104 if(rn != sizeof(buf)) return LV_RESULT_INVALID;
105
106 if(lv_memcmp(buf, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
107
108 size = (uint32_t *)&buf[16];
109 }
110 /*If it's a PNG file in a C array...*/
111 else {
112 const lv_image_dsc_t * img_dsc = dsc->src;
113 const uint32_t data_size = img_dsc->data_size;
114 size = ((uint32_t *)img_dsc->data) + 4;
115
116 if(data_size < sizeof(magic)) return LV_RESULT_INVALID;
117 if(lv_memcmp(img_dsc->data, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
118 }
119
120 /*Save the data in the header*/
121 header->cf = LV_COLOR_FORMAT_ARGB8888;
122 /*The width and height are stored in Big endian format so convert them to little endian*/
123 header->w = (int32_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
124 header->h = (int32_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
125
126 return LV_RESULT_OK;
127 }
128
129 return LV_RESULT_INVALID; /*If didn't succeeded earlier then it's an error*/
130 }
131
132 /**
133 * Open a PNG image and return the decided image
134 * @param decoder pointer to the decoder
135 * @param dsc pointer to the decoder descriptor
136 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
137 */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)138 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
139 {
140 LV_UNUSED(decoder); /*Unused*/
141
142 LV_PROFILER_DECODER_BEGIN_TAG("lv_libpng_decoder_open");
143
144 lv_draw_buf_t * decoded;
145 decoded = decode_png(dsc);
146
147 if(decoded == NULL) {
148 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
149 return LV_RESULT_INVALID;
150 }
151
152 lv_draw_buf_t * adjusted = lv_image_decoder_post_process(dsc, decoded);
153 if(adjusted == NULL) {
154 lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
155 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
156 return LV_RESULT_INVALID;
157 }
158
159 /*The adjusted draw buffer is newly allocated.*/
160 if(adjusted != decoded) {
161 lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
162 decoded = adjusted;
163 }
164
165 dsc->decoded = decoded;
166
167 if(dsc->args.no_cache) {
168 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
169 return LV_RESULT_OK;
170 }
171
172 /*If the image cache is disabled, just return the decoded image*/
173 if(!lv_image_cache_is_enabled()) {
174 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
175 return LV_RESULT_OK;
176 }
177
178 /*Add the decoded image to the cache*/
179 lv_image_cache_data_t search_key;
180 search_key.src_type = dsc->src_type;
181 search_key.src = dsc->src;
182 search_key.slot.size = decoded->data_size;
183
184 lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL);
185
186 if(entry == NULL) {
187 lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
188 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
189 return LV_RESULT_INVALID;
190 }
191 dsc->cache_entry = entry;
192
193 LV_PROFILER_DECODER_END_TAG("lv_libpng_decoder_open");
194 return LV_RESULT_OK; /*The image is fully decoded. Return with its pointer*/
195 }
196
197 /**
198 * Free the allocated resources
199 */
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)200 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
201 {
202 LV_UNUSED(decoder); /*Unused*/
203
204 if(dsc->args.no_cache ||
205 !lv_image_cache_is_enabled()) lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, (lv_draw_buf_t *)dsc->decoded);
206 }
207
alloc_file(const char * filename,uint32_t * size)208 static uint8_t * alloc_file(const char * filename, uint32_t * size)
209 {
210 uint8_t * data = NULL;
211 lv_fs_file_t f;
212 uint32_t data_size;
213 uint32_t rn;
214 lv_fs_res_t res;
215
216 *size = 0;
217
218 res = lv_fs_open(&f, filename, LV_FS_MODE_RD);
219 if(res != LV_FS_RES_OK) {
220 LV_LOG_WARN("can't open %s", filename);
221 return NULL;
222 }
223
224 res = lv_fs_seek(&f, 0, LV_FS_SEEK_END);
225 if(res != LV_FS_RES_OK) {
226 goto failed;
227 }
228
229 res = lv_fs_tell(&f, &data_size);
230 if(res != LV_FS_RES_OK) {
231 goto failed;
232 }
233
234 res = lv_fs_seek(&f, 0, LV_FS_SEEK_SET);
235 if(res != LV_FS_RES_OK) {
236 goto failed;
237 }
238
239 /*Read file to buffer*/
240 data = lv_malloc(data_size);
241 if(data == NULL) {
242 LV_LOG_WARN("malloc failed for data");
243 goto failed;
244 }
245
246 res = lv_fs_read(&f, data, data_size, &rn);
247
248 if(res == LV_FS_RES_OK && rn == data_size) {
249 *size = rn;
250 }
251 else {
252 LV_LOG_WARN("read file failed");
253 lv_free(data);
254 data = NULL;
255 }
256
257 failed:
258 lv_fs_close(&f);
259
260 return data;
261 }
262
decode_png(lv_image_decoder_dsc_t * dsc)263 static lv_draw_buf_t * decode_png(lv_image_decoder_dsc_t * dsc)
264 {
265 int ret;
266 uint8_t * png_data;
267 uint32_t png_data_size;
268 /*Prepare png_image*/
269 png_image image;
270 lv_memzero(&image, sizeof(image));
271 image.version = PNG_IMAGE_VERSION;
272
273 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
274 png_data = alloc_file(dsc->src, &png_data_size);
275 if(png_data == NULL) {
276 LV_LOG_WARN("can't load file: %s", (const char *)dsc->src);
277 return NULL;
278 }
279 }
280 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
281 const lv_image_dsc_t * img_dsc = dsc->src;
282 png_data = (uint8_t *)img_dsc->data;
283 png_data_size = img_dsc->data_size;
284 }
285 else
286 return NULL;
287
288 /*Ready to read file*/
289 ret = png_image_begin_read_from_memory(&image, png_data, png_data_size);
290 if(!ret) {
291 LV_LOG_ERROR("png read failed: %d", ret);
292 if(dsc->src_type == LV_IMAGE_SRC_FILE)
293 lv_free(png_data);
294 return NULL;
295 }
296
297 lv_color_format_t cf;
298 if(dsc->args.use_indexed && (image.format & PNG_FORMAT_FLAG_COLORMAP)) {
299 cf = LV_COLOR_FORMAT_I8;
300 image.format = PNG_FORMAT_BGRA_COLORMAP;
301 }
302 else {
303 cf = LV_COLOR_FORMAT_ARGB8888;
304 image.format = PNG_FORMAT_BGRA;
305 }
306
307 /*Alloc image buffer*/
308 lv_draw_buf_t * decoded;
309 decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, image.width, image.height, cf, LV_STRIDE_AUTO);
310 if(decoded == NULL) {
311
312 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
313 LV_LOG_ERROR("alloc PNG_IMAGE_SIZE(%" LV_PRIu32 ") failed: %s", (uint32_t)PNG_IMAGE_SIZE(image),
314 (const char *)dsc->src);
315 lv_free(png_data);
316 }
317 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE)
318 LV_LOG_ERROR("alloc PNG_IMAGE_SIZE(%" LV_PRIu32 ")", (uint32_t)PNG_IMAGE_SIZE(image));
319
320 png_image_free(&image);
321 return NULL;
322 }
323
324 void * palette = decoded->data;
325 void * map = decoded->data + LV_COLOR_INDEXED_PALETTE_SIZE(cf) * sizeof(lv_color32_t);
326
327 /*Start decoding*/
328 ret = png_image_finish_read(&image, NULL, map, decoded->header.stride, palette);
329 png_image_free(&image);
330 if(dsc->src_type == LV_IMAGE_SRC_FILE)
331 lv_free(png_data);
332 if(!ret) {
333 LV_LOG_ERROR("png decode failed: %s", image.message);
334 lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
335 return NULL;
336 }
337
338 return decoded;
339 }
340
341 #endif /*LV_USE_LIBPNG*/
342