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