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