1 /**
2  * @file lv_libjpeg_turbo.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../draw/lv_image_decoder_private.h"
10 #include "../../../lvgl.h"
11 #if LV_USE_LIBJPEG_TURBO
12 
13 #include "lv_libjpeg_turbo.h"
14 #include <stdio.h>
15 #include <jpeglib.h>
16 #include <jpegint.h>
17 #include <setjmp.h>
18 #include "../../core/lv_global.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 
24 #define DECODER_NAME    "JPEG_TURBO"
25 
26 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
27 
28 #define JPEG_PIXEL_SIZE 3 /* RGB888 */
29 #define JPEG_SIGNATURE 0xFFD8FF
30 #define IS_JPEG_SIGNATURE(x) (((x) & 0x00FFFFFF) == JPEG_SIGNATURE)
31 
32 /**********************
33  *      TYPEDEFS
34  **********************/
35 typedef struct error_mgr_s {
36     struct jpeg_error_mgr pub;
37     jmp_buf jb;
38 } error_mgr_t;
39 
40 /**********************
41  *  STATIC PROTOTYPES
42  **********************/
43 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header);
44 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
45 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
46 static lv_draw_buf_t * decode_jpeg_file(const char * filename);
47 static uint8_t * read_file(const char * filename, uint32_t * size);
48 static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height, uint32_t * orientation);
49 static bool get_jpeg_size(uint8_t * data, uint32_t data_size, uint32_t * width, uint32_t * height);
50 static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * orientation);
51 static void rotate_buffer(lv_draw_buf_t * decoded, uint8_t * buffer, uint32_t line_index, uint32_t angle);
52 static void error_exit(j_common_ptr cinfo);
53 /**********************
54  *  STATIC VARIABLES
55  **********************/
56 const int JPEG_EXIF = 0x45786966; /* Exif data structure tag */
57 const int JPEG_BIG_ENDIAN_TAG = 0x4d4d;
58 const int JPEG_LITTLE_ENDIAN_TAG = 0x4949;
59 
60 /**********************
61  *      MACROS
62  **********************/
63 #define TRANS_32_VALUE(big_endian, data) big_endian ? \
64     ((*(data) << 24) | (*((data) + 1) << 16) | (*((data) + 2) << 8) | *((data) + 3)) : \
65     (*(data) | (*((data) + 1) << 8) | (*((data) + 2) << 16) | (*((data) + 3) << 24))
66 #define TRANS_16_VALUE(big_endian, data) big_endian ? \
67     ((*(data) << 8) | *((data) + 1)) : (*(data) | (*((data) + 1) << 8))
68 
69 /**********************
70  *   GLOBAL FUNCTIONS
71  **********************/
72 
73 /**
74  * Register the JPEG decoder functions in LVGL
75  */
lv_libjpeg_turbo_init(void)76 void lv_libjpeg_turbo_init(void)
77 {
78     lv_image_decoder_t * dec = lv_image_decoder_create();
79     lv_image_decoder_set_info_cb(dec, decoder_info);
80     lv_image_decoder_set_open_cb(dec, decoder_open);
81     lv_image_decoder_set_close_cb(dec, decoder_close);
82 
83     dec->name = DECODER_NAME;
84 }
85 
lv_libjpeg_turbo_deinit(void)86 void lv_libjpeg_turbo_deinit(void)
87 {
88     lv_image_decoder_t * dec = NULL;
89     while((dec = lv_image_decoder_get_next(dec)) != NULL) {
90         if(dec->info_cb == decoder_info) {
91             lv_image_decoder_delete(dec);
92             break;
93         }
94     }
95 }
96 
97 /**********************
98  *   STATIC FUNCTIONS
99  **********************/
100 
101 /**
102  * Get info about a JPEG image
103  * @param dsc image descriptor containing the source and type of the image and other info.
104  * @param header store the info here
105  * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info
106  */
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)107 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
108 {
109     LV_UNUSED(decoder); /*Unused*/
110     lv_image_src_t src_type = dsc->src_type;          /*Get the source type*/
111 
112     /*If it's a JPEG file...*/
113     if(src_type == LV_IMAGE_SRC_FILE) {
114         const char * src = dsc->src;
115         uint32_t jpg_signature = 0;
116         uint32_t rn;
117         lv_fs_read(&dsc->file, &jpg_signature, sizeof(jpg_signature), &rn);
118 
119         if(rn != sizeof(jpg_signature)) {
120             LV_LOG_WARN("file: %s signature len = %" LV_PRIu32 " error", src, rn);
121             return LV_RESULT_INVALID;
122         }
123 
124         const char * ext = lv_fs_get_ext(src);
125         bool is_jpeg_ext = (lv_strcmp(ext, "jpg") == 0)
126                            || (lv_strcmp(ext, "jpeg") == 0);
127 
128         if(!IS_JPEG_SIGNATURE(jpg_signature)) {
129             if(is_jpeg_ext) {
130                 LV_LOG_WARN("file: %s signature = 0X%" LV_PRIX32 " error", src, jpg_signature);
131             }
132             return LV_RESULT_INVALID;
133         }
134 
135         uint32_t width;
136         uint32_t height;
137         uint32_t orientation = 0;
138 
139         if(!get_jpeg_head_info(src, &width, &height, &orientation)) {
140             return LV_RESULT_INVALID;
141         }
142 
143         /*Save the data in the header*/
144         header->cf = LV_COLOR_FORMAT_RGB888;
145         header->w = (orientation % 180) ? height : width;
146         header->h = (orientation % 180) ? width : height;
147 
148         return LV_RESULT_OK;
149     }
150 
151     return LV_RESULT_INVALID;         /*If didn't succeeded earlier then it's an error*/
152 }
153 
154 /**
155  * Open a JPEG image and return the decided image
156  * @param decoder pointer to the decoder
157  * @param dsc     pointer to the decoder descriptor
158  * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
159  */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)160 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
161 {
162     LV_UNUSED(decoder); /*Unused*/
163 
164     /*If it's a JPEG file...*/
165     if(dsc->src_type == LV_IMAGE_SRC_FILE) {
166         const char * fn = dsc->src;
167         lv_draw_buf_t * decoded = decode_jpeg_file(fn);
168         if(decoded == NULL) {
169             LV_LOG_WARN("decode jpeg file failed");
170             return LV_RESULT_INVALID;
171         }
172 
173         dsc->decoded = decoded;
174 
175         if(dsc->args.no_cache) return LV_RESULT_OK;
176 
177         /*If the image cache is disabled, just return the decoded image*/
178         if(!lv_image_cache_is_enabled()) return LV_RESULT_OK;
179 
180         /*Add the decoded image to the cache*/
181         lv_image_cache_data_t search_key;
182         search_key.src_type = dsc->src_type;
183         search_key.src = dsc->src;
184         search_key.slot.size = decoded->data_size;
185 
186         lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL);
187 
188         if(entry == NULL) {
189             lv_draw_buf_destroy(decoded);
190             return LV_RESULT_INVALID;
191         }
192         dsc->cache_entry = entry;
193         return LV_RESULT_OK;    /*If not returned earlier then it failed*/
194     }
195 
196     return LV_RESULT_INVALID;    /*If not returned earlier then it failed*/
197 }
198 
199 /**
200  * Free the allocated resources
201  */
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)202 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
203 {
204     LV_UNUSED(decoder); /*Unused*/
205 
206     if(dsc->args.no_cache ||
207        !lv_image_cache_is_enabled()) lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded);
208 }
209 
read_file(const char * filename,uint32_t * size)210 static uint8_t * read_file(const char * filename, uint32_t * size)
211 {
212     uint8_t * data = NULL;
213     lv_fs_file_t f;
214     uint32_t data_size;
215     uint32_t rn;
216     lv_fs_res_t res;
217 
218     *size = 0;
219 
220     res = lv_fs_open(&f, filename, LV_FS_MODE_RD);
221     if(res != LV_FS_RES_OK) {
222         LV_LOG_WARN("can't open %s", filename);
223         return NULL;
224     }
225 
226     res = lv_fs_seek(&f, 0, LV_FS_SEEK_END);
227     if(res != LV_FS_RES_OK) {
228         goto failed;
229     }
230 
231     res = lv_fs_tell(&f, &data_size);
232     if(res != LV_FS_RES_OK) {
233         goto failed;
234     }
235 
236     res = lv_fs_seek(&f, 0, LV_FS_SEEK_SET);
237     if(res != LV_FS_RES_OK) {
238         goto failed;
239     }
240 
241     /*Read file to buffer*/
242     data = lv_malloc(data_size);
243     if(data == NULL) {
244         LV_LOG_WARN("malloc failed for data");
245         goto failed;
246     }
247 
248     res = lv_fs_read(&f, data, data_size, &rn);
249 
250     if(res == LV_FS_RES_OK && rn == data_size) {
251         *size = rn;
252     }
253     else {
254         LV_LOG_WARN("read file failed");
255         lv_free(data);
256         data = NULL;
257     }
258 
259 failed:
260     lv_fs_close(&f);
261 
262     return data;
263 }
264 
decode_jpeg_file(const char * filename)265 static lv_draw_buf_t * decode_jpeg_file(const char * filename)
266 {
267     /* This struct contains the JPEG decompression parameters and pointers to
268      * working space (which is allocated as needed by the JPEG library).
269      */
270     struct jpeg_decompress_struct cinfo;
271     /* We use our private extension JPEG error handler.
272      * Note that this struct must live as long as the main JPEG parameter
273      * struct, to avoid dangling-pointer problems.
274      */
275     error_mgr_t jerr;
276 
277     /* More stuff */
278     JSAMPARRAY buffer;  /* Output row buffer */
279 
280     int row_stride;     /* physical row width in output buffer */
281     uint32_t image_angle = 0;   /* image rotate angle */
282 
283     lv_draw_buf_t * decoded = NULL;
284 
285     /* In this example we want to open the input file before doing anything else,
286      * so that the setjmp() error recovery below can assume the file is open.
287      * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
288      * requires it in order to read binary files.
289      */
290 
291     uint32_t data_size;
292     uint8_t * data = read_file(filename, &data_size);
293     if(data == NULL) {
294         LV_LOG_WARN("can't load file %s", filename);
295         return NULL;
296     }
297 
298     /* allocate and initialize JPEG decompression object */
299 
300     /* We set up the normal JPEG error routines, then override error_exit. */
301     cinfo.err = jpeg_std_error(&jerr.pub);
302     jerr.pub.error_exit = error_exit;
303     /* Establish the setjmp return context for my_error_exit to use. */
304     if(setjmp(jerr.jb)) {
305 
306         LV_LOG_WARN("decoding error");
307 
308         if(decoded) {
309             lv_draw_buf_destroy(decoded);
310         }
311 
312         /* If we get here, the JPEG code has signaled an error.
313         * We need to clean up the JPEG object, close the input file, and return.
314         */
315         jpeg_destroy_decompress(&cinfo);
316         lv_free(data);
317         return NULL;
318     }
319 
320     /* Get rotate angle from Exif data */
321     if(!get_jpeg_direction(data, data_size, &image_angle)) {
322         LV_LOG_WARN("read jpeg orientation failed.");
323     }
324 
325     /* Now we can initialize the JPEG decompression object. */
326     jpeg_create_decompress(&cinfo);
327 
328     /* specify data source (eg, a file or buffer) */
329 
330     jpeg_mem_src(&cinfo, data, data_size);
331 
332     /* read file parameters with jpeg_read_header() */
333 
334     jpeg_read_header(&cinfo, TRUE);
335 
336     /* We can ignore the return value from jpeg_read_header since
337      *   (a) suspension is not possible with the stdio data source, and
338      *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
339      * See libjpeg.doc for more info.
340      */
341 
342     /* set parameters for decompression */
343 
344     cinfo.out_color_space = JCS_EXT_BGR;
345 
346     /* In this example, we don't need to change any of the defaults set by
347      * jpeg_read_header(), so we do nothing here.
348      */
349 
350     /* Start decompressor */
351 
352     jpeg_start_decompress(&cinfo);
353 
354     /* We can ignore the return value since suspension is not possible
355      * with the stdio data source.
356      */
357 
358     /* We may need to do some setup of our own at this point before reading
359      * the data.  After jpeg_start_decompress() we have the correct scaled
360      * output image dimensions available, as well as the output colormap
361      * if we asked for color quantization.
362      * In this example, we need to make an output work buffer of the right size.
363      */
364     /* JSAMPLEs per row in output buffer */
365     row_stride = cinfo.output_width * cinfo.output_components;
366     /* Make a one-row-high sample array that will go away when done with image */
367     buffer = (*cinfo.mem->alloc_sarray)
368              ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
369     uint32_t buf_width = (image_angle % 180) ? cinfo.output_height : cinfo.output_width;
370     uint32_t buf_height = (image_angle % 180) ? cinfo.output_width : cinfo.output_height;
371     decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, buf_width, buf_height, LV_COLOR_FORMAT_RGB888,
372                                     LV_STRIDE_AUTO);
373     if(decoded != NULL) {
374         uint32_t line_index = 0;
375         /* while (scan lines remain to be read) */
376         /* jpeg_read_scanlines(...); */
377 
378         /* Here we use the library's state variable cinfo.output_scanline as the
379          * loop counter, so that we don't have to keep track ourselves.
380          */
381         while(cinfo.output_scanline < cinfo.output_height) {
382             /* jpeg_read_scanlines expects an array of pointers to scanlines.
383              * Here the array is only one element long, but you could ask for
384              * more than one scanline at a time if that's more convenient.
385              */
386             jpeg_read_scanlines(&cinfo, buffer, 1);
387 
388             /* Assume put_scanline_someplace wants a pointer and sample count. */
389             rotate_buffer(decoded, buffer[0], line_index, image_angle);
390 
391             line_index++;
392         }
393     }
394 
395     /* Finish decompression */
396 
397     jpeg_finish_decompress(&cinfo);
398 
399     /* We can ignore the return value since suspension is not possible
400      * with the stdio data source.
401      */
402 
403     /* Release JPEG decompression object */
404 
405     /* This is an important step since it will release a good deal of memory. */
406     jpeg_destroy_decompress(&cinfo);
407 
408     /* After finish_decompress, we can close the input file.
409     * Here we postpone it until after no more JPEG errors are possible,
410     * so as to simplify the setjmp error logic above.  (Actually, I don't
411     * think that jpeg_destroy can do an error exit, but why assume anything...)
412     */
413     lv_free(data);
414 
415     /* At this point you may want to check to see whether any corrupt-data
416     * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
417     */
418 
419     /* And we're done! */
420     return decoded;
421 }
422 
get_jpeg_head_info(const char * filename,uint32_t * width,uint32_t * height,uint32_t * orientation)423 static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height, uint32_t * orientation)
424 {
425     uint8_t * data = NULL;
426     uint32_t data_size;
427     data = read_file(filename, &data_size);
428     if(data == NULL) {
429         return false;
430     }
431 
432     if(!get_jpeg_size(data, data_size, width, height)) {
433         LV_LOG_WARN("read jpeg size failed.");
434     }
435 
436     if(!get_jpeg_direction(data, data_size, orientation)) {
437         LV_LOG_WARN("read jpeg orientation failed.");
438     }
439 
440     lv_free(data);
441 
442     return JPEG_HEADER_OK;
443 }
444 
get_jpeg_size(uint8_t * data,uint32_t data_size,uint32_t * width,uint32_t * height)445 static bool get_jpeg_size(uint8_t * data, uint32_t data_size, uint32_t * width, uint32_t * height)
446 {
447     struct jpeg_decompress_struct cinfo;
448     error_mgr_t jerr;
449 
450     cinfo.err = jpeg_std_error(&jerr.pub);
451     jerr.pub.error_exit = error_exit;
452 
453     if(setjmp(jerr.jb)) {
454         LV_LOG_WARN("read jpeg head failed");
455         jpeg_destroy_decompress(&cinfo);
456         return false;
457     }
458 
459     jpeg_create_decompress(&cinfo);
460 
461     jpeg_mem_src(&cinfo, data, data_size);
462 
463     int ret = jpeg_read_header(&cinfo, TRUE);
464 
465     if(ret == JPEG_HEADER_OK) {
466         *width = cinfo.image_width;
467         *height = cinfo.image_height;
468     }
469     else {
470         LV_LOG_WARN("read jpeg head failed: %d", ret);
471     }
472 
473     jpeg_destroy_decompress(&cinfo);
474 
475     return JPEG_HEADER_OK;
476 }
477 
get_jpeg_direction(uint8_t * data,uint32_t data_size,uint32_t * orientation)478 static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * orientation)
479 {
480     struct jpeg_decompress_struct cinfo;
481     error_mgr_t jerr;
482 
483     cinfo.err = jpeg_std_error(&jerr.pub);
484     jerr.pub.error_exit = error_exit;
485 
486     if(setjmp(jerr.jb)) {
487         LV_LOG_WARN("read jpeg orientation failed");
488         jpeg_destroy_decompress(&cinfo);
489         return false;
490     }
491 
492     jpeg_create_decompress(&cinfo);
493 
494     jpeg_mem_src(&cinfo, data, data_size);
495 
496     jpeg_save_markers(&cinfo, JPEG_APP0 + 1, 0xFFFF);
497 
498     cinfo.marker->read_markers(&cinfo);
499 
500     jpeg_saved_marker_ptr marker = cinfo.marker_list;
501     while(marker != NULL) {
502         if(marker->marker == JPEG_APP0 + 1) {
503             JOCTET FAR * app1_data = marker->data;
504             if(TRANS_32_VALUE(true, app1_data) == JPEG_EXIF) {
505                 uint16_t endian_tag = TRANS_16_VALUE(true, app1_data + 4 + 2);
506                 if(!(endian_tag == JPEG_LITTLE_ENDIAN_TAG || endian_tag == JPEG_BIG_ENDIAN_TAG)) {
507                     jpeg_destroy_decompress(&cinfo);
508                     return false;
509                 }
510                 bool is_big_endian = endian_tag == JPEG_BIG_ENDIAN_TAG;
511                 /* first ifd offset addr : 4bytes(Exif) + 2bytes(0x00) + 2bytes(align) + 2bytes(tag mark) */
512                 unsigned int offset = TRANS_32_VALUE(is_big_endian, app1_data + 8 + 2);
513                 /* ifd base : 4bytes(Exif) + 2bytes(0x00) */
514                 unsigned char * ifd = 0;
515                 do {
516                     /* ifd start: 4bytes(Exif) + 2bytes(0x00) + offset value(2bytes(align) + 2bytes(tag mark) + 4bytes(offset size)) */
517                     unsigned int entry_offset = 4 + 2 + offset + 2;
518                     if(entry_offset >= marker->data_length) {
519                         jpeg_destroy_decompress(&cinfo);
520                         return false;
521                     }
522                     ifd = app1_data + entry_offset;
523                     unsigned short num_entries = TRANS_16_VALUE(is_big_endian, ifd - 2);
524                     if(entry_offset + num_entries * 12 >= marker->data_length) {
525                         jpeg_destroy_decompress(&cinfo);
526                         return false;
527                     }
528                     for(int i = 0; i < num_entries; i++) {
529                         unsigned short tag = TRANS_16_VALUE(is_big_endian, ifd);
530                         if(tag == 0x0112) {
531                             /* ifd entry: 12bytes = 2bytes(tag number) + 2bytes(kind of data) + 4bytes(number of components) + 4bytes(data)
532                             * orientation kind(0x03) of data is unsigned short */
533                             int dirc = TRANS_16_VALUE(is_big_endian, ifd + 2 + 2 + 4);
534                             switch(dirc) {
535                                 case 1:
536                                     *orientation = 0;
537                                     break;
538                                 case 3:
539                                     *orientation = 180;
540                                     break;
541                                 case 6:
542                                     *orientation = 90;
543                                     break;
544                                 case 8:
545                                     *orientation = 270;
546                                     break;
547                                 default:
548                                     *orientation = 0;
549                             }
550                         }
551                         ifd += 12;
552                     }
553                     offset = TRANS_32_VALUE(is_big_endian, ifd);
554                 } while(offset != 0);
555             }
556             break;
557         }
558         marker = marker->next;
559     }
560 
561     jpeg_destroy_decompress(&cinfo);
562 
563     return JPEG_HEADER_OK;
564 }
565 
rotate_buffer(lv_draw_buf_t * decoded,uint8_t * buffer,uint32_t line_index,uint32_t angle)566 static void rotate_buffer(lv_draw_buf_t * decoded, uint8_t * buffer, uint32_t line_index, uint32_t angle)
567 {
568     if(angle == 90) {
569         for(uint32_t x = 0; x < decoded->header.h; x++) {
570             uint32_t dst_index = x * decoded->header.stride + (decoded->header.w - line_index - 1)  * JPEG_PIXEL_SIZE;
571             lv_memcpy(decoded->data + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE);
572         }
573     }
574     else if(angle == 180) {
575         for(uint32_t x = 0; x < decoded->header.w; x++) {
576             uint32_t dst_index = (decoded->header.h - line_index - 1) * decoded->header.stride + x * JPEG_PIXEL_SIZE;
577             lv_memcpy(decoded->data + dst_index, buffer + (decoded->header.w - x - 1) * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE);
578         }
579     }
580     else if(angle == 270) {
581         for(uint32_t x = 0; x < decoded->header.h; x++) {
582             uint32_t dst_index = (decoded->header.h - x - 1) * decoded->header.stride + line_index * JPEG_PIXEL_SIZE;
583             lv_memcpy(decoded->data + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE);
584         }
585     }
586     else {
587         lv_memcpy(decoded->data + line_index * decoded->header.stride, buffer, decoded->header.stride);
588     }
589 }
590 
error_exit(j_common_ptr cinfo)591 static void error_exit(j_common_ptr cinfo)
592 {
593     error_mgr_t * myerr = (error_mgr_t *)cinfo->err;
594     (*cinfo->err->output_message)(cinfo);
595     longjmp(myerr->jb, 1);
596 }
597 
598 #endif /*LV_USE_LIBJPEG_TURBO*/
599