1 /**
2  * @file lv_sjpg.c
3  *
4  */
5 
6 /*----------------------------------------------------------------------------------------------------------------------------------
7 /    Added normal JPG support [7/10/2020]
8 /    ----------
9 /    SJPEG is a custom created modified JPEG file format for small embedded platforms.
10 /    It will contain multiple JPEG fragments all embedded into a single file with a custom header.
11 /    This makes JPEG decoding easier using any JPEG library. Overall file size will be almost
12 /    similar to the parent jpeg file. We can generate sjpeg from any jpeg using a python script
13 /    provided along with this project.
14 /                                                                                     (by vinodstanur | 2020 )
15 /    SJPEG FILE STRUCTURE
16 /    --------------------------------------------------------------------------------------------------------------------------------
17 /    Bytes                       |   Value                                                                                           |
18 /    --------------------------------------------------------------------------------------------------------------------------------
19 /
20 /    0 - 7                       |   "_SJPG__" followed by '\0'
21 /
22 /    8 - 13                      |   "V1.00" followed by '\0'       [VERSION OF SJPG FILE for future compatibiliby]
23 /
24 /    14 - 15                     |   X_RESOLUTION (width)            [little endian]
25 /
26 /    16 - 17                     |   Y_RESOLUTION (height)           [little endian]
27 /
28 /    18 - 19                     |   TOTAL_FRAMES inside sjpeg       [little endian]
29 /
30 /    20 - 21                     |   JPEG BLOCK WIDTH (16 normally)  [little endian]
31 /
32 /    22 - [(TOTAL_FRAMES*2 )]    |   SIZE OF EACH JPEG SPLIT FRAGMENTS   (FRAME_INFO_ARRAY)
33 /
34 /   SJPEG data                   |   Each JPEG frame can be extracted from SJPEG data by parsing the FRAME_INFO_ARRAY one time.
35 /
36 /----------------------------------------------------------------------------------------------------------------------------------
37 /                   JPEG DECODER
38 /                   ------------
39 /   We are using TJpgDec - Tiny JPEG Decompressor library from ELM-CHAN for decoding each split-jpeg fragments.
40 /   The tjpgd.c and tjpgd.h is not modified and those are used as it is. So if any update comes for the tiny-jpeg,
41 /   just replace those files with updated files.
42 /---------------------------------------------------------------------------------------------------------------------------------*/
43 
44 /*********************
45  *      INCLUDES
46  *********************/
47 
48 #include "../../../lvgl.h"
49 #if LV_USE_SJPG
50 
51 #include "tjpgd.h"
52 #include "lv_sjpg.h"
53 #include "../../../misc/lv_fs.h"
54 
55 /*********************
56  *      DEFINES
57  *********************/
58 #define TJPGD_WORKBUFF_SIZE             4096    //Recommended by TJPGD libray
59 
60 //NEVER EDIT THESE OFFSET VALUES
61 #define SJPEG_VERSION_OFFSET            8
62 #define SJPEG_X_RES_OFFSET              14
63 #define SJPEG_y_RES_OFFSET              16
64 #define SJPEG_TOTAL_FRAMES_OFFSET       18
65 #define SJPEG_BLOCK_WIDTH_OFFSET        20
66 #define SJPEG_FRAME_INFO_ARRAY_OFFSET   22
67 
68 /**********************
69  *      TYPEDEFS
70  **********************/
71 
72 enum io_source_type {
73     SJPEG_IO_SOURCE_C_ARRAY,
74     SJPEG_IO_SOURCE_DISK,
75 };
76 
77 typedef struct {
78     enum io_source_type type;
79     lv_fs_file_t lv_file;
80     uint8_t * img_cache_buff;
81     int img_cache_x_res;
82     int img_cache_y_res;
83     uint8_t * raw_sjpg_data;              //Used when type==SJPEG_IO_SOURCE_C_ARRAY.
84     uint32_t raw_sjpg_data_size;          //Num bytes pointed to by raw_sjpg_data.
85     uint32_t raw_sjpg_data_next_read_pos; //Used for all types.
86 } io_source_t;
87 
88 typedef struct {
89     uint8_t * sjpeg_data;
90     uint32_t sjpeg_data_size;
91     int sjpeg_x_res;
92     int sjpeg_y_res;
93     int sjpeg_total_frames;
94     int sjpeg_single_frame_height;
95     int sjpeg_cache_frame_index;
96     uint8_t ** frame_base_array;        //to save base address of each split frames upto sjpeg_total_frames.
97     int * frame_base_offset;            //to save base offset for fseek
98     uint8_t * frame_cache;
99     uint8_t * workb;                    //JPG work buffer for jpeg library
100     JDEC * tjpeg_jd;
101     io_source_t io;
102 } SJPEG;
103 
104 /**********************
105  *  STATIC PROTOTYPES
106  **********************/
107 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
108 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
109 static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
110                                   lv_coord_t len, uint8_t * buf);
111 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
112 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata);
113 static int is_jpg(const uint8_t * raw_data, size_t len);
114 static void lv_sjpg_cleanup(SJPEG * sjpeg);
115 static void lv_sjpg_free(SJPEG * sjpeg);
116 
117 /**********************
118  *  STATIC VARIABLES
119  **********************/
120 
121 /**********************
122  *      MACROS
123  **********************/
124 
125 /**********************
126  *   GLOBAL FUNCTIONS
127  **********************/
lv_split_jpeg_init(void)128 void lv_split_jpeg_init(void)
129 {
130     lv_img_decoder_t * dec = lv_img_decoder_create();
131     lv_img_decoder_set_info_cb(dec, decoder_info);
132     lv_img_decoder_set_open_cb(dec, decoder_open);
133     lv_img_decoder_set_close_cb(dec, decoder_close);
134     lv_img_decoder_set_read_line_cb(dec, decoder_read_line);
135 }
136 
137 /**********************
138  *   STATIC FUNCTIONS
139  **********************/
140 /**
141  * Get info about an SJPG / JPG image
142  * @param decoder pointer to the decoder where this function belongs
143  * @param src can be file name or pointer to a C array
144  * @param header store the info here
145  * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
146  */
decoder_info(lv_img_decoder_t * decoder,const void * src,lv_img_header_t * header)147 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
148 {
149     LV_UNUSED(decoder);
150 
151     /*Check whether the type `src` is known by the decoder*/
152     /* Read the SJPG/JPG header and find `width` and `height` */
153 
154     lv_img_src_t src_type = lv_img_src_get_type(src);          /*Get the source type*/
155 
156     lv_res_t ret = LV_RES_OK;
157 
158     if(src_type == LV_IMG_SRC_VARIABLE) {
159         const lv_img_dsc_t * img_dsc = src;
160         uint8_t * raw_sjpeg_data = (uint8_t *)img_dsc->data;
161         const uint32_t raw_sjpeg_data_size = img_dsc->data_size;
162 
163         if(!strncmp((char *)raw_sjpeg_data, "_SJPG__", strlen("_SJPG__"))) {
164 
165             raw_sjpeg_data += 14; //seek to res info ... refer sjpeg format
166             header->always_zero = 0;
167             header->cf = LV_IMG_CF_RAW;
168 
169             header->w = *raw_sjpeg_data++;
170             header->w |= *raw_sjpeg_data++ << 8;
171 
172             header->h = *raw_sjpeg_data++;
173             header->h |= *raw_sjpeg_data++ << 8;
174 
175             return ret;
176 
177         }
178         else if(is_jpg(raw_sjpeg_data, raw_sjpeg_data_size) == true) {
179             header->always_zero = 0;
180             header->cf = LV_IMG_CF_RAW;
181 
182             uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
183             if(!workb_temp) return LV_RES_INV;
184 
185             io_source_t io_source_temp;
186             io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY;
187             io_source_temp.raw_sjpg_data = raw_sjpeg_data;
188             io_source_temp.raw_sjpg_data_size = raw_sjpeg_data_size;
189             io_source_temp.raw_sjpg_data_next_read_pos = 0;
190 
191             JDEC jd_tmp;
192 
193             JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
194             if(rc == JDR_OK) {
195                 header->w = jd_tmp.width;
196                 header->h = jd_tmp.height;
197 
198             }
199             else {
200                 ret = LV_RES_INV;
201                 goto end;
202             }
203 
204 end:
205             lv_mem_free(workb_temp);
206 
207             return ret;
208 
209         }
210     }
211     else if(src_type == LV_IMG_SRC_FILE) {
212         const char * fn = src;
213         if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) {
214 
215             uint8_t buff[22];
216             memset(buff, 0, sizeof(buff));
217 
218             lv_fs_file_t file;
219             lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD);
220             if(res != LV_FS_RES_OK) return 78;
221 
222             uint32_t rn;
223             res = lv_fs_read(&file, buff, 8, &rn);
224             if(res != LV_FS_RES_OK || rn != 8) {
225                 lv_fs_close(&file);
226                 return LV_RES_INV;
227             }
228 
229             if(strcmp((char *)buff, "_SJPG__") == 0) {
230                 lv_fs_seek(&file, 14, LV_FS_SEEK_SET);
231                 res = lv_fs_read(&file, buff, 4, &rn);
232                 if(res != LV_FS_RES_OK || rn != 4) {
233                     lv_fs_close(&file);
234                     return LV_RES_INV;
235                 }
236                 header->always_zero = 0;
237                 header->cf = LV_IMG_CF_RAW;
238                 uint8_t * raw_sjpeg_data = buff;
239                 header->w = *raw_sjpeg_data++;
240                 header->w |= *raw_sjpeg_data++ << 8;
241                 header->h = *raw_sjpeg_data++;
242                 header->h |= *raw_sjpeg_data++ << 8;
243                 lv_fs_close(&file);
244                 return LV_RES_OK;
245 
246             }
247         }
248         else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) {
249             lv_fs_file_t file;
250             lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD);
251             if(res != LV_FS_RES_OK) return 78;
252 
253             uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
254             if(!workb_temp) {
255                 lv_fs_close(&file);
256                 return LV_RES_INV;
257             }
258 
259             io_source_t io_source_temp;
260             io_source_temp.type = SJPEG_IO_SOURCE_DISK;
261             io_source_temp.raw_sjpg_data_next_read_pos = 0;
262             io_source_temp.img_cache_buff = NULL;
263             io_source_temp.lv_file = file;
264             JDEC jd_tmp;
265 
266             JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
267             lv_mem_free(workb_temp);
268             lv_fs_close(&file);
269 
270             if(rc == JDR_OK) {
271                 header->always_zero = 0;
272                 header->cf = LV_IMG_CF_RAW;
273                 header->w = jd_tmp.width;
274                 header->h = jd_tmp.height;
275                 return LV_RES_OK;
276             }
277         }
278     }
279     return LV_RES_INV;
280 }
281 
img_data_cb(JDEC * jd,void * data,JRECT * rect)282 static int img_data_cb(JDEC * jd, void * data, JRECT * rect)
283 {
284     io_source_t * io = jd->device;
285     uint8_t * cache = io->img_cache_buff;
286     const int xres = io->img_cache_x_res;
287     uint8_t * buf = data;
288     const int INPUT_PIXEL_SIZE = 3;
289     const int row_width = rect->right - rect->left + 1; // Row width in pixels.
290     const int row_size = row_width * INPUT_PIXEL_SIZE;  // Row size (bytes).
291 
292     for(int y = rect->top; y <= rect->bottom; y++) {
293         int row_offset = y * xres * INPUT_PIXEL_SIZE + rect->left * INPUT_PIXEL_SIZE;
294         memcpy(cache + row_offset, buf, row_size);
295         buf += row_size;
296     }
297 
298     return 1;
299 }
300 
input_func(JDEC * jd,uint8_t * buff,size_t ndata)301 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata)
302 {
303     io_source_t * io = jd->device;
304 
305     if(!io) return 0;
306 
307     if(io->type == SJPEG_IO_SOURCE_C_ARRAY) {
308         const uint32_t bytes_left = io->raw_sjpg_data_size - io->raw_sjpg_data_next_read_pos;
309         const uint32_t to_read = ndata <= bytes_left ? (uint32_t)ndata : bytes_left;
310         if(to_read == 0)
311             return 0;
312         if(buff) {
313             memcpy(buff, io->raw_sjpg_data + io->raw_sjpg_data_next_read_pos, to_read);
314         }
315         io->raw_sjpg_data_next_read_pos += to_read;
316         return to_read;
317     }
318     else if(io->type == SJPEG_IO_SOURCE_DISK) {
319 
320         lv_fs_file_t * lv_file_p = &(io->lv_file);
321 
322         if(buff) {
323             uint32_t rn = 0;
324             lv_fs_read(lv_file_p, buff, (uint32_t)ndata, &rn);
325             return rn;
326         }
327         else {
328             uint32_t pos;
329             lv_fs_tell(lv_file_p, &pos);
330             lv_fs_seek(lv_file_p, (uint32_t)(ndata + pos),  LV_FS_SEEK_SET);
331             return ndata;
332         }
333     }
334     return 0;
335 }
336 
337 /**
338  * Open SJPG image and return the decided image
339  * @param decoder pointer to the decoder where this function belongs
340  * @param dsc pointer to a descriptor which describes this decoding session
341  * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
342  */
decoder_open(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)343 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
344 {
345     LV_UNUSED(decoder);
346     lv_res_t lv_ret = LV_RES_OK;
347 
348     if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
349         uint8_t * data;
350         SJPEG * sjpeg = (SJPEG *) dsc->user_data;
351         const uint32_t raw_sjpeg_data_size = ((lv_img_dsc_t *)dsc->src)->data_size;
352         if(sjpeg == NULL) {
353             sjpeg =  lv_mem_alloc(sizeof(SJPEG));
354             if(!sjpeg) return LV_RES_INV;
355 
356             memset(sjpeg, 0, sizeof(SJPEG));
357 
358             dsc->user_data = sjpeg;
359             sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
360             sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
361         }
362 
363         if(!strncmp((char *) sjpeg->sjpeg_data, "_SJPG__", strlen("_SJPG__"))) {
364 
365             data = sjpeg->sjpeg_data;
366             data += 14;
367 
368             sjpeg->sjpeg_x_res = *data++;
369             sjpeg->sjpeg_x_res |= *data++ << 8;
370 
371             sjpeg->sjpeg_y_res = *data++;
372             sjpeg->sjpeg_y_res |= *data++ << 8;
373 
374             sjpeg->sjpeg_total_frames = *data++;
375             sjpeg->sjpeg_total_frames |= *data++ << 8;
376 
377             sjpeg->sjpeg_single_frame_height = *data++;
378             sjpeg->sjpeg_single_frame_height |= *data++ << 8;
379 
380             sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
381             if(! sjpeg->frame_base_array) {
382                 lv_sjpg_cleanup(sjpeg);
383                 sjpeg = NULL;
384                 return LV_RES_INV;
385             }
386 
387             sjpeg->frame_base_offset = NULL;
388 
389             uint8_t * img_frame_base = data +  sjpeg->sjpeg_total_frames * 2;
390             sjpeg->frame_base_array[0] = img_frame_base;
391 
392             for(int i = 1; i <  sjpeg->sjpeg_total_frames; i++) {
393                 int offset = *data++;
394                 offset |= *data++ << 8;
395                 sjpeg->frame_base_array[i] = sjpeg->frame_base_array[i - 1] + offset;
396             }
397             sjpeg->sjpeg_cache_frame_index = -1;
398             sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3/*2*/);
399             if(! sjpeg->frame_cache) {
400                 lv_sjpg_cleanup(sjpeg);
401                 sjpeg = NULL;
402                 return LV_RES_INV;
403             }
404             sjpeg->io.img_cache_buff = sjpeg->frame_cache;
405             sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
406             sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
407             if(! sjpeg->workb) {
408                 lv_sjpg_cleanup(sjpeg);
409                 sjpeg = NULL;
410                 return LV_RES_INV;
411             }
412 
413             sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
414             if(! sjpeg->tjpeg_jd) {
415                 lv_sjpg_cleanup(sjpeg);
416                 sjpeg = NULL;
417                 return LV_RES_INV;
418             }
419             sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
420             sjpeg->io.lv_file.file_d = NULL;
421             dsc->img_data = NULL;
422             return lv_ret;
423         }
424         else if(is_jpg(sjpeg->sjpeg_data, raw_sjpeg_data_size) == true) {
425 
426             uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
427             if(! workb_temp) {
428                 lv_sjpg_cleanup(sjpeg);
429                 sjpeg = NULL;
430                 return LV_RES_INV;
431             }
432             io_source_t io_source_temp;
433             io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY;
434             io_source_temp.raw_sjpg_data =  sjpeg->sjpeg_data;
435             io_source_temp.raw_sjpg_data_size = sjpeg->sjpeg_data_size;
436             io_source_temp.raw_sjpg_data_next_read_pos = 0;
437 
438             JDEC jd_tmp;
439             JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
440             lv_mem_free(workb_temp);
441 
442             if(rc == JDR_OK) {
443                 sjpeg->sjpeg_x_res = jd_tmp.width;
444                 sjpeg->sjpeg_y_res = jd_tmp.height;
445                 sjpeg->sjpeg_total_frames = 1;
446                 sjpeg->sjpeg_single_frame_height = jd_tmp.height;
447 
448                 sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
449                 if(! sjpeg->frame_base_array) {
450                     lv_sjpg_cleanup(sjpeg);
451                     sjpeg = NULL;
452                     return LV_RES_INV;
453                 }
454                 sjpeg->frame_base_offset = NULL;
455 
456                 uint8_t * img_frame_base = sjpeg->sjpeg_data;
457                 sjpeg->frame_base_array[0] = img_frame_base;
458 
459                 sjpeg->sjpeg_cache_frame_index = -1;
460                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
461                 if(! sjpeg->frame_cache) {
462                     lv_sjpg_cleanup(sjpeg);
463                     sjpeg = NULL;
464                     return LV_RES_INV;
465                 }
466 
467                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
468                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
469                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
470                 if(! sjpeg->workb) {
471                     lv_sjpg_cleanup(sjpeg);
472                     sjpeg = NULL;
473                     return LV_RES_INV;
474                 }
475 
476                 sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
477                 if(! sjpeg->tjpeg_jd) {
478                     lv_sjpg_cleanup(sjpeg);
479                     sjpeg = NULL;
480                     return LV_RES_INV;
481                 }
482 
483                 sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
484                 sjpeg->io.lv_file.file_d = NULL;
485                 dsc->img_data = NULL;
486                 return lv_ret;
487             }
488             else {
489                 lv_ret = LV_RES_INV;
490                 goto end;
491             }
492 
493 end:
494             lv_mem_free(workb_temp);
495 
496             return lv_ret;
497         }
498     }
499     else if(dsc->src_type == LV_IMG_SRC_FILE) {
500         /* If all fine, then the file will be kept open */
501         const char * fn = dsc->src;
502         uint8_t * data;
503 
504         if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) {
505 
506             uint8_t buff[22];
507             memset(buff, 0, sizeof(buff));
508 
509             lv_fs_file_t lv_file;
510             lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD);
511             if(res != LV_FS_RES_OK) {
512                 return 78;
513             }
514 
515             uint32_t rn;
516             res = lv_fs_read(&lv_file, buff, 22, &rn);
517             if(res != LV_FS_RES_OK || rn != 22) {
518                 lv_fs_close(&lv_file);
519                 return LV_RES_INV;
520             }
521 
522             if(strcmp((char *)buff, "_SJPG__") == 0) {
523 
524                 SJPEG * sjpeg = (SJPEG *) dsc->user_data;
525                 if(sjpeg == NULL) {
526                     sjpeg = lv_mem_alloc(sizeof(SJPEG));
527 
528                     if(! sjpeg) {
529                         lv_fs_close(&lv_file);
530                         return LV_RES_INV;
531                     }
532                     memset(sjpeg, 0, sizeof(SJPEG));
533 
534                     dsc->user_data = sjpeg;
535                     sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
536                     sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
537                 }
538                 data = buff;
539                 data += 14;
540 
541                 sjpeg->sjpeg_x_res = *data++;
542                 sjpeg->sjpeg_x_res |= *data++ << 8;
543 
544                 sjpeg->sjpeg_y_res = *data++;
545                 sjpeg->sjpeg_y_res |= *data++ << 8;
546 
547                 sjpeg->sjpeg_total_frames = *data++;
548                 sjpeg->sjpeg_total_frames |= *data++ << 8;
549 
550                 sjpeg->sjpeg_single_frame_height = *data++;
551                 sjpeg->sjpeg_single_frame_height |= *data++ << 8;
552 
553                 sjpeg->frame_base_array = NULL;//lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
554                 sjpeg->frame_base_offset = lv_mem_alloc(sizeof(int) * sjpeg->sjpeg_total_frames);
555                 if(! sjpeg->frame_base_offset) {
556                     lv_fs_close(&lv_file);
557                     lv_sjpg_cleanup(sjpeg);
558                     return LV_RES_INV;
559                 }
560                 int img_frame_start_offset = (SJPEG_FRAME_INFO_ARRAY_OFFSET + sjpeg->sjpeg_total_frames * 2);
561                 sjpeg->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now...
562 
563                 for(int i = 1; i <  sjpeg->sjpeg_total_frames; i++) {
564                     res = lv_fs_read(&lv_file, buff, 2, &rn);
565                     if(res != LV_FS_RES_OK || rn != 2) {
566                         lv_fs_close(&lv_file);
567                         return LV_RES_INV;
568                     }
569 
570                     data = buff;
571                     int offset = *data++;
572                     offset |= *data++ << 8;
573                     sjpeg->frame_base_offset[i] = sjpeg->frame_base_offset[i - 1] + offset;
574                 }
575 
576                 sjpeg->sjpeg_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time.
577                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
578                 if(! sjpeg->frame_cache) {
579                     lv_fs_close(&lv_file);
580                     lv_sjpg_cleanup(sjpeg);
581                     return LV_RES_INV;
582                 }
583                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
584                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
585                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
586                 if(! sjpeg->workb) {
587                     lv_fs_close(&lv_file);
588                     lv_sjpg_cleanup(sjpeg);
589                     return LV_RES_INV;
590                 }
591 
592                 sjpeg->tjpeg_jd =    lv_mem_alloc(sizeof(JDEC));
593                 if(! sjpeg->tjpeg_jd) {
594                     lv_fs_close(&lv_file);
595                     lv_sjpg_cleanup(sjpeg);
596                     return LV_RES_INV;
597                 }
598 
599                 sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
600                 sjpeg->io.lv_file = lv_file;
601                 dsc->img_data = NULL;
602                 return LV_RES_OK;
603             }
604         }
605         else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) {
606 
607             lv_fs_file_t lv_file;
608             lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD);
609             if(res != LV_FS_RES_OK) {
610                 return LV_RES_INV;
611             }
612 
613             SJPEG * sjpeg = (SJPEG *) dsc->user_data;
614             if(sjpeg == NULL) {
615                 sjpeg = lv_mem_alloc(sizeof(SJPEG));
616                 if(! sjpeg) {
617                     lv_fs_close(&lv_file);
618                     return LV_RES_INV;
619                 }
620 
621                 memset(sjpeg, 0, sizeof(SJPEG));
622                 dsc->user_data = sjpeg;
623                 sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
624                 sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
625             }
626 
627             uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
628             if(! workb_temp) {
629                 lv_fs_close(&lv_file);
630                 lv_sjpg_cleanup(sjpeg);
631                 return LV_RES_INV;
632             }
633 
634             io_source_t io_source_temp;
635             io_source_temp.type = SJPEG_IO_SOURCE_DISK;
636             io_source_temp.raw_sjpg_data_next_read_pos = 0;
637             io_source_temp.img_cache_buff = NULL;
638             io_source_temp.lv_file = lv_file;
639 
640             JDEC jd_tmp;
641 
642             JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
643 
644             lv_mem_free(workb_temp);
645 
646             if(rc == JDR_OK) {
647                 sjpeg->sjpeg_x_res = jd_tmp.width;
648                 sjpeg->sjpeg_y_res = jd_tmp.height;
649                 sjpeg->sjpeg_total_frames = 1;
650                 sjpeg->sjpeg_single_frame_height = jd_tmp.height;
651 
652                 sjpeg->frame_base_array = NULL;
653                 sjpeg->frame_base_offset =  lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
654                 if(! sjpeg->frame_base_offset) {
655                     lv_fs_close(&lv_file);
656                     lv_sjpg_cleanup(sjpeg);
657                     return LV_RES_INV;
658                 }
659 
660                 int img_frame_start_offset = 0;
661                 sjpeg->frame_base_offset[0] = img_frame_start_offset;
662 
663                 sjpeg->sjpeg_cache_frame_index = -1;
664                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
665                 if(! sjpeg->frame_cache) {
666                     lv_fs_close(&lv_file);
667                     lv_sjpg_cleanup(sjpeg);
668                     return LV_RES_INV;
669                 }
670 
671                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
672                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
673                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
674                 if(! sjpeg->workb) {
675                     lv_fs_close(&lv_file);
676                     lv_sjpg_cleanup(sjpeg);
677                     return LV_RES_INV;
678                 }
679 
680                 sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
681                 if(! sjpeg->tjpeg_jd) {
682                     lv_fs_close(&lv_file);
683                     lv_sjpg_cleanup(sjpeg);
684                     return LV_RES_INV;
685                 }
686 
687                 sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
688                 sjpeg->io.lv_file = lv_file;
689                 dsc->img_data = NULL;
690                 return LV_RES_OK;
691 
692             }
693             else {
694                 if(dsc->user_data) lv_mem_free(dsc->user_data);
695                 lv_fs_close(&lv_file);
696                 return  LV_RES_INV;
697             }
698         }
699     }
700 
701     return LV_RES_INV;
702 }
703 
704 /**
705  * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
706  * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL)
707  * @param decoder pointer to the decoder the function associated with
708  * @param dsc pointer to decoder descriptor
709  * @param x start x coordinate
710  * @param y start y coordinate
711  * @param len number of pixels to decode
712  * @param buf a buffer to store the decoded pixels
713  * @return LV_RES_OK: ok; LV_RES_INV: failed
714  */
715 
decoder_read_line(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)716 static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
717                                   lv_coord_t len, uint8_t * buf)
718 {
719     LV_UNUSED(decoder);
720     if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
721         SJPEG * sjpeg = (SJPEG *) dsc->user_data;
722         JRESULT rc;
723 
724         int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
725 
726         /*If line not from cache, refresh cache */
727         if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
728             sjpeg->io.raw_sjpg_data = sjpeg->frame_base_array[ sjpeg_req_frame_index ];
729             if(sjpeg_req_frame_index == (sjpeg->sjpeg_total_frames - 1)) {
730                 /*This is the last frame. */
731                 const uint32_t frame_offset = (uint32_t)(sjpeg->io.raw_sjpg_data - sjpeg->sjpeg_data);
732                 sjpeg->io.raw_sjpg_data_size = sjpeg->sjpeg_data_size - frame_offset;
733             }
734             else {
735                 sjpeg->io.raw_sjpg_data_size =
736                     (uint32_t)(sjpeg->frame_base_array[sjpeg_req_frame_index + 1] - sjpeg->io.raw_sjpg_data);
737             }
738             sjpeg->io.raw_sjpg_data_next_read_pos = 0;
739             rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
740             if(rc != JDR_OK) return LV_RES_INV;
741             rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0);
742             if(rc != JDR_OK) return LV_RES_INV;
743             sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
744         }
745 
746         int offset = 0;
747         uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res *
748                           3;
749 
750 #if  LV_COLOR_DEPTH == 32
751         for(int i = 0; i < len; i++) {
752             buf[offset + 3] = 0xff;
753             buf[offset + 2] = *cache++;
754             buf[offset + 1] = *cache++;
755             buf[offset + 0] = *cache++;
756             offset += 4;
757         }
758 
759 #elif  LV_COLOR_DEPTH == 16
760 
761         for(int i = 0; i < len; i++) {
762             uint16_t col_16bit = (*cache++ & 0xf8) << 8;
763             col_16bit |= (*cache++ & 0xFC) << 3;
764             col_16bit |= (*cache++ >> 3);
765 #if  LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1
766             buf[offset++] = col_16bit >> 8;
767             buf[offset++] = col_16bit & 0xff;
768 #else
769             buf[offset++] = col_16bit & 0xff;
770             buf[offset++] = col_16bit >> 8;
771 #endif // LV_BIG_ENDIAN_SYSTEM
772         }
773 
774 #elif  LV_COLOR_DEPTH == 8
775 
776         for(int i = 0; i < len; i++) {
777             uint8_t col_8bit = (*cache++ & 0xC0);
778             col_8bit |= (*cache++ & 0xe0) >> 2;
779             col_8bit |= (*cache++ & 0xe0) >> 5;
780             buf[offset++] = col_8bit;
781         }
782 #else
783 #error Unsupported LV_COLOR_DEPTH
784 
785 #endif // LV_COLOR_DEPTH
786         return LV_RES_OK;
787     }
788     else if(dsc->src_type == LV_IMG_SRC_FILE) {
789         SJPEG * sjpeg = (SJPEG *) dsc->user_data;
790         JRESULT rc;
791         int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
792 
793         lv_fs_file_t * lv_file_p = &(sjpeg->io.lv_file);
794         if(!lv_file_p) goto end;
795 
796         /*If line not from cache, refresh cache */
797         if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
798             sjpeg->io.raw_sjpg_data_next_read_pos = (int)(sjpeg->frame_base_offset [ sjpeg_req_frame_index ]);
799             lv_fs_seek(&(sjpeg->io.lv_file), sjpeg->io.raw_sjpg_data_next_read_pos, LV_FS_SEEK_SET);
800 
801             rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
802             if(rc != JDR_OK) return LV_RES_INV;
803 
804             rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0);
805             if(rc != JDR_OK) return LV_RES_INV;
806 
807             sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
808         }
809 
810         int offset = 0;
811         uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res *
812                           3;
813 
814 #if LV_COLOR_DEPTH == 32
815         for(int i = 0; i < len; i++) {
816             buf[offset + 3] = 0xff;
817             buf[offset + 2] = *cache++;
818             buf[offset + 1] = *cache++;
819             buf[offset + 0] = *cache++;
820             offset += 4;
821         }
822 #elif  LV_COLOR_DEPTH == 16
823 
824         for(int i = 0; i < len; i++) {
825             uint16_t col_8bit = (*cache++ & 0xf8) << 8;
826             col_8bit |= (*cache++ & 0xFC) << 3;
827             col_8bit |= (*cache++ >> 3);
828 #if  LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1
829             buf[offset++] = col_8bit >> 8;
830             buf[offset++] = col_8bit & 0xff;
831 #else
832             buf[offset++] = col_8bit & 0xff;
833             buf[offset++] = col_8bit >> 8;
834 #endif // LV_BIG_ENDIAN_SYSTEM
835         }
836 
837 #elif  LV_COLOR_DEPTH == 8
838 
839         for(int i = 0; i < len; i++) {
840             uint8_t col_8bit = (*cache++ & 0xC0);
841             col_8bit |= (*cache++ & 0xe0) >> 2;
842             col_8bit |= (*cache++ & 0xe0) >> 5;
843             buf[offset++] = col_8bit;
844         }
845 
846 #else
847 #error Unsupported LV_COLOR_DEPTH
848 
849 #endif // LV_COLOR_DEPTH
850 
851         return LV_RES_OK;
852     }
853 end:
854     return LV_RES_INV;
855 }
856 
857 /**
858  * Free the allocated resources
859  * @param decoder pointer to the decoder where this function belongs
860  * @param dsc pointer to a descriptor which describes this decoding session
861  */
decoder_close(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)862 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
863 {
864     LV_UNUSED(decoder);
865     /*Free all allocated data*/
866     SJPEG * sjpeg = (SJPEG *) dsc->user_data;
867     if(!sjpeg) return;
868 
869     switch(dsc->src_type) {
870         case LV_IMG_SRC_FILE:
871             if(sjpeg->io.lv_file.file_d) {
872                 lv_fs_close(&(sjpeg->io.lv_file));
873             }
874             lv_sjpg_cleanup(sjpeg);
875             break;
876 
877         case LV_IMG_SRC_VARIABLE:
878             lv_sjpg_cleanup(sjpeg);
879             break;
880 
881         default:
882             ;
883     }
884 }
885 
is_jpg(const uint8_t * raw_data,size_t len)886 static int is_jpg(const uint8_t * raw_data, size_t len)
887 {
888     const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF,  0xE0,  0x00,  0x10, 0x4A,  0x46, 0x49, 0x46};
889     if(len < sizeof(jpg_signature)) return false;
890     return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0;
891 }
892 
lv_sjpg_free(SJPEG * sjpeg)893 static void lv_sjpg_free(SJPEG * sjpeg)
894 {
895     if(sjpeg->frame_cache) lv_mem_free(sjpeg->frame_cache);
896     if(sjpeg->frame_base_array) lv_mem_free(sjpeg->frame_base_array);
897     if(sjpeg->frame_base_offset) lv_mem_free(sjpeg->frame_base_offset);
898     if(sjpeg->tjpeg_jd) lv_mem_free(sjpeg->tjpeg_jd);
899     if(sjpeg->workb) lv_mem_free(sjpeg->workb);
900 }
901 
lv_sjpg_cleanup(SJPEG * sjpeg)902 static void lv_sjpg_cleanup(SJPEG * sjpeg)
903 {
904     if(! sjpeg) return;
905 
906     lv_sjpg_free(sjpeg);
907     lv_mem_free(sjpeg);
908 }
909 
910 #endif /*LV_USE_SJPG*/
911