1 /**
2 * @file lv_lodepng.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../draw/lv_image_decoder_private.h"
10 #include "../../../lvgl.h"
11 #include "../../core/lv_global.h"
12 #if LV_USE_LODEPNG
13
14 #include "lv_lodepng.h"
15 #include "lodepng.h"
16 #include <stdlib.h>
17
18 /*********************
19 * DEFINES
20 *********************/
21
22 #define DECODER_NAME "LODEPNG"
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 * dec, lv_image_decoder_dsc_t * dsc);
36 static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt);
37 static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size);
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_lodepng_init(void)53 void lv_lodepng_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_lodepng_deinit(void)63 void lv_lodepng_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 decoder pointer to the decoder where this function belongs
81 * @param dsc image descriptor containing the source and type of the image and other info.
82 * @param header image information is set in header parameter
83 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info
84 */
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)85 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
86 {
87 LV_UNUSED(decoder); /*Unused*/
88
89 lv_image_src_t src_type = dsc->src_type; /*Get the source type*/
90
91 if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_VARIABLE) {
92 uint32_t * size;
93 static const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
94 uint8_t buf[24];
95
96 /*If it's a PNG file...*/
97 if(src_type == LV_IMAGE_SRC_FILE) {
98 /* Read the width and height from the file. They have a constant location:
99 * [16..19]: width
100 * [20..23]: height
101 */
102 uint32_t rn;
103 lv_fs_read(&dsc->file, buf, sizeof(buf), &rn);
104
105 if(rn != sizeof(buf)) return LV_RESULT_INVALID;
106
107 if(lv_memcmp(buf, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
108
109 size = (uint32_t *)&buf[16];
110 }
111 /*If it's a PNG file in a C array...*/
112 else {
113 const lv_image_dsc_t * img_dsc = dsc->src;
114 const uint32_t data_size = img_dsc->data_size;
115 size = ((uint32_t *)img_dsc->data) + 4;
116
117 if(data_size < sizeof(magic)) return LV_RESULT_INVALID;
118 if(lv_memcmp(img_dsc->data, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
119 }
120
121 /*Save the data in the header*/
122 header->cf = LV_COLOR_FORMAT_ARGB8888;
123 /*The width and height are stored in Big endian format so convert them to little endian*/
124 header->w = (int32_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
125 header->h = (int32_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
126
127 return LV_RESULT_OK;
128 }
129
130 return LV_RESULT_INVALID; /*If didn't succeeded earlier then it's an error*/
131 }
132
133 /**
134 * Open a PNG image and decode it into dsc.decoded
135 * @param decoder pointer to the decoder where this function belongs
136 * @param dsc decoded image descriptor
137 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
138 */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)139 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
140 {
141 LV_UNUSED(decoder);
142 LV_PROFILER_DECODER_BEGIN_TAG("lv_lodepng_decoder_open");
143
144 const uint8_t * png_data = NULL;
145 size_t png_data_size = 0;
146 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
147 const char * fn = dsc->src;
148
149 /*Load the file*/
150 unsigned error = lodepng_load_file((void *)&png_data, &png_data_size, fn);
151 if(error) {
152 if(png_data != NULL) {
153 lv_free((void *)png_data);
154 }
155 LV_LOG_WARN("error %u: %s\n", error, lodepng_error_text(error));
156 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
157 return LV_RESULT_INVALID;
158 }
159 }
160 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
161 const lv_image_dsc_t * img_dsc = dsc->src;
162 png_data = img_dsc->data;
163 png_data_size = img_dsc->data_size;
164 }
165 else {
166 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
167 return LV_RESULT_INVALID;
168 }
169
170 lv_draw_buf_t * decoded = decode_png_data(png_data, png_data_size);
171
172 if(dsc->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)png_data);
173
174 if(!decoded) {
175 LV_LOG_WARN("Error decoding PNG");
176 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
177 return LV_RESULT_INVALID;
178 }
179
180 lv_draw_buf_t * adjusted = lv_image_decoder_post_process(dsc, decoded);
181 if(adjusted == NULL) {
182 lv_draw_buf_destroy(decoded);
183 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
184 return LV_RESULT_INVALID;
185 }
186
187 /*The adjusted draw buffer is newly allocated.*/
188 if(adjusted != decoded) {
189 lv_draw_buf_destroy(decoded);
190 decoded = adjusted;
191 }
192
193 dsc->decoded = decoded;
194
195 if(dsc->args.no_cache) {
196 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
197 return LV_RESULT_OK;
198 }
199
200 /*If the image cache is disabled, just return the decoded image*/
201 if(!lv_image_cache_is_enabled()) {
202 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
203 return LV_RESULT_OK;
204 }
205
206 /*Add the decoded image to the cache*/
207 lv_image_cache_data_t search_key;
208 search_key.src_type = dsc->src_type;
209 search_key.src = dsc->src;
210 search_key.slot.size = decoded->data_size;
211
212 lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL);
213
214 if(entry == NULL) {
215 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
216 return LV_RESULT_INVALID;
217 }
218 dsc->cache_entry = entry;
219
220 LV_PROFILER_DECODER_END_TAG("lv_lodepng_decoder_open");
221 return LV_RESULT_OK; /*If not returned earlier then it failed*/
222 }
223
224 /**
225 * Close PNG image and free data
226 * @param decoder pointer to the decoder where this function belongs
227 * @param dsc decoded image descriptor
228 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
229 */
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)230 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
231 {
232 LV_UNUSED(decoder);
233
234 if(dsc->args.no_cache ||
235 !lv_image_cache_is_enabled()) lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded);
236 }
237
decode_png_data(const void * png_data,size_t png_data_size)238 static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size)
239 {
240 unsigned png_width; /*Not used, just required by the decoder*/
241 unsigned png_height; /*Not used, just required by the decoder*/
242 lv_draw_buf_t * decoded = NULL;
243
244 /*Decode the image in ARGB8888 */
245 unsigned error = lodepng_decode32((unsigned char **)&decoded, &png_width, &png_height, png_data, png_data_size);
246 if(error) {
247 if(decoded != NULL) lv_draw_buf_destroy(decoded);
248 return NULL;
249 }
250
251 /*Convert the image to the system's color depth*/
252 convert_color_depth(decoded->data, png_width * png_height);
253
254 return decoded;
255 }
256
257 /**
258 * If the display is not in 32 bit format (ARGB888) then convert the image to the current color depth
259 * @param img the ARGB888 image
260 * @param px_cnt number of pixels in `img`
261 */
convert_color_depth(uint8_t * img_p,uint32_t px_cnt)262 static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt)
263 {
264 lv_color32_t * img_argb = (lv_color32_t *)img_p;
265 uint32_t i;
266 for(i = 0; i < px_cnt; i++) {
267 uint8_t blue = img_argb[i].blue;
268 img_argb[i].blue = img_argb[i].red;
269 img_argb[i].red = blue;
270 }
271 }
272
273 #endif /*LV_USE_LODEPNG*/
274