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 
89 typedef struct {
90     uint8_t * sjpeg_data;
91     uint32_t sjpeg_data_size;
92     int sjpeg_x_res;
93     int sjpeg_y_res;
94     int sjpeg_total_frames;
95     int sjpeg_single_frame_height;
96     int sjpeg_cache_frame_index;
97     uint8_t ** frame_base_array;        //to save base address of each split frames upto sjpeg_total_frames.
98     int * frame_base_offset;            //to save base offset for fseek
99     uint8_t * frame_cache;
100     uint8_t * workb;                    //JPG work buffer for jpeg library
101     JDEC * tjpeg_jd;
102     io_source_t io;
103 } SJPEG;
104 
105 /**********************
106  *  STATIC PROTOTYPES
107  **********************/
108 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
109 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
110 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,
111                                   lv_coord_t len, uint8_t * buf);
112 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
113 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata);
114 static int is_jpg(const uint8_t * raw_data);
115 static void lv_sjpg_cleanup(SJPEG * sjpeg);
116 static void lv_sjpg_free(SJPEG * sjpeg);
117 
118 /**********************
119  *  STATIC VARIABLES
120  **********************/
121 
122 /**********************
123  *      MACROS
124  **********************/
125 
126 /**********************
127  *   GLOBAL FUNCTIONS
128  **********************/
lv_split_jpeg_init(void)129 void lv_split_jpeg_init(void)
130 {
131     lv_img_decoder_t * dec = lv_img_decoder_create();
132     lv_img_decoder_set_info_cb(dec, decoder_info);
133     lv_img_decoder_set_open_cb(dec, decoder_open);
134     lv_img_decoder_set_close_cb(dec, decoder_close);
135     lv_img_decoder_set_read_line_cb(dec, decoder_read_line);
136 }
137 
138 /**********************
139  *   STATIC FUNCTIONS
140  **********************/
141 /**
142  * Get info about an SJPG / JPG image
143  * @param decoder pointer to the decoder where this function belongs
144  * @param src can be file name or pointer to a C array
145  * @param header store the info here
146  * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
147  */
decoder_info(lv_img_decoder_t * decoder,const void * src,lv_img_header_t * header)148 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
149 {
150     LV_UNUSED(decoder);
151 
152     /*Check whether the type `src` is known by the decoder*/
153     /* Read the SJPG/JPG header and find `width` and `height` */
154 
155     lv_img_src_t src_type = lv_img_src_get_type(src);          /*Get the source type*/
156 
157     lv_res_t ret = LV_RES_OK;
158 
159     if(src_type == LV_IMG_SRC_VARIABLE) {
160         uint8_t * raw_sjpeg_data = (uint8_t *)((lv_img_dsc_t *)src)->data;
161         const uint32_t raw_sjpeg_data_size = ((lv_img_dsc_t *)src)->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) == 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(&fn[strlen(fn) - 5], ".sjpg")) {
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(&fn[strlen(fn) - 4], ".jpg")) {
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         if(sjpeg == NULL) {
352             sjpeg =  lv_mem_alloc(sizeof(SJPEG));
353             if(!sjpeg) return LV_RES_INV;
354 
355             memset(sjpeg, 0, sizeof(SJPEG));
356 
357             dsc->user_data = sjpeg;
358             sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
359             sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
360         }
361 
362         if(!strncmp((char *) sjpeg->sjpeg_data, "_SJPG__", strlen("_SJPG__"))) {
363 
364             data = sjpeg->sjpeg_data;
365             data += 14;
366 
367             sjpeg->sjpeg_x_res = *data++;
368             sjpeg->sjpeg_x_res |= *data++ << 8;
369 
370             sjpeg->sjpeg_y_res = *data++;
371             sjpeg->sjpeg_y_res |= *data++ << 8;
372 
373             sjpeg->sjpeg_total_frames = *data++;
374             sjpeg->sjpeg_total_frames |= *data++ << 8;
375 
376             sjpeg->sjpeg_single_frame_height = *data++;
377             sjpeg->sjpeg_single_frame_height |= *data++ << 8;
378 
379             sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
380             if(! sjpeg->frame_base_array) {
381                 lv_sjpg_cleanup(sjpeg);
382                 sjpeg = NULL;
383                 return LV_RES_INV;
384             }
385 
386             sjpeg->frame_base_offset = NULL;
387 
388             uint8_t * img_frame_base = data +  sjpeg->sjpeg_total_frames * 2;
389             sjpeg->frame_base_array[0] = img_frame_base;
390 
391             for(int i = 1; i <  sjpeg->sjpeg_total_frames; i++) {
392                 int offset = *data++;
393                 offset |= *data++ << 8;
394                 sjpeg->frame_base_array[i] = sjpeg->frame_base_array[i - 1] + offset;
395             }
396             sjpeg->sjpeg_cache_frame_index = -1;
397             sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3/*2*/);
398             if(! sjpeg->frame_cache) {
399                 lv_sjpg_cleanup(sjpeg);
400                 sjpeg = NULL;
401                 return LV_RES_INV;
402             }
403             sjpeg->io.img_cache_buff = sjpeg->frame_cache;
404             sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
405             sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
406             if(! sjpeg->workb) {
407                 lv_sjpg_cleanup(sjpeg);
408                 sjpeg = NULL;
409                 return LV_RES_INV;
410             }
411 
412             sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
413             if(! sjpeg->tjpeg_jd) {
414                 lv_sjpg_cleanup(sjpeg);
415                 sjpeg = NULL;
416                 return LV_RES_INV;
417             }
418             sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
419             sjpeg->io.lv_file.file_d = NULL;
420             dsc->img_data = NULL;
421             return lv_ret;
422         }
423 
424         else if(is_jpg(sjpeg->sjpeg_data) == 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 
443             if(rc == JDR_OK) {
444                 sjpeg->sjpeg_x_res = jd_tmp.width;
445                 sjpeg->sjpeg_y_res = jd_tmp.height;
446                 sjpeg->sjpeg_total_frames = 1;
447                 sjpeg->sjpeg_single_frame_height = jd_tmp.height;
448 
449                 sjpeg->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
450                 if(! sjpeg->frame_base_array) {
451                     lv_sjpg_cleanup(sjpeg);
452                     sjpeg = NULL;
453                     return LV_RES_INV;
454                 }
455                 sjpeg->frame_base_offset = NULL;
456 
457                 uint8_t * img_frame_base = sjpeg->sjpeg_data;
458                 sjpeg->frame_base_array[0] = img_frame_base;
459 
460                 sjpeg->sjpeg_cache_frame_index = -1;
461                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
462                 if(! sjpeg->frame_cache) {
463                     lv_sjpg_cleanup(sjpeg);
464                     sjpeg = NULL;
465                     return LV_RES_INV;
466                 }
467 
468                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
469                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
470                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
471                 if(! sjpeg->workb) {
472                     lv_sjpg_cleanup(sjpeg);
473                     sjpeg = NULL;
474                     return LV_RES_INV;
475                 }
476 
477                 sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
478                 if(! sjpeg->tjpeg_jd) {
479                     lv_sjpg_cleanup(sjpeg);
480                     sjpeg = NULL;
481                     return LV_RES_INV;
482                 }
483 
484                 sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
485                 sjpeg->io.lv_file.file_d = NULL;
486                 dsc->img_data = NULL;
487                 return lv_ret;
488             }
489             else {
490                 lv_ret = LV_RES_INV;
491                 goto end;
492             }
493 
494 end:
495             lv_mem_free(workb_temp);
496 
497             return lv_ret;
498         }
499     }
500     else if(dsc->src_type == LV_IMG_SRC_FILE) {
501         /* If all fine, then the file will be kept open */
502         const char * fn = dsc->src;
503         uint8_t * data;
504 
505         if(!strcmp(&fn[strlen(fn) - 5], ".sjpg")) {
506 
507             uint8_t buff[22];
508             memset(buff, 0, sizeof(buff));
509 
510 
511             lv_fs_file_t lv_file;
512             lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD);
513             if(res != LV_FS_RES_OK) {
514                 return 78;
515             }
516 
517 
518             uint32_t rn;
519             res = lv_fs_read(&lv_file, buff, 22, &rn);
520             if(res != LV_FS_RES_OK || rn != 22) {
521                 lv_fs_close(&lv_file);
522                 return LV_RES_INV;
523             }
524 
525             if(strcmp((char *)buff, "_SJPG__") == 0) {
526 
527                 SJPEG * sjpeg = (SJPEG *) dsc->user_data;
528                 if(sjpeg == NULL) {
529                     sjpeg = lv_mem_alloc(sizeof(SJPEG));
530 
531                     if(! sjpeg) {
532                         lv_fs_close(&lv_file);
533                         return LV_RES_INV;
534                     }
535                     memset(sjpeg, 0, sizeof(SJPEG));
536 
537                     dsc->user_data = sjpeg;
538                     sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
539                     sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
540                 }
541                 data = buff;
542                 data += 14;
543 
544                 sjpeg->sjpeg_x_res = *data++;
545                 sjpeg->sjpeg_x_res |= *data++ << 8;
546 
547                 sjpeg->sjpeg_y_res = *data++;
548                 sjpeg->sjpeg_y_res |= *data++ << 8;
549 
550                 sjpeg->sjpeg_total_frames = *data++;
551                 sjpeg->sjpeg_total_frames |= *data++ << 8;
552 
553                 sjpeg->sjpeg_single_frame_height = *data++;
554                 sjpeg->sjpeg_single_frame_height |= *data++ << 8;
555 
556                 sjpeg->frame_base_array = NULL;//lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
557                 sjpeg->frame_base_offset = lv_mem_alloc(sizeof(int) * sjpeg->sjpeg_total_frames);
558                 if(! sjpeg->frame_base_offset) {
559                     lv_fs_close(&lv_file);
560                     lv_sjpg_cleanup(sjpeg);
561                     return LV_RES_INV;
562                 }
563                 int img_frame_start_offset = (SJPEG_FRAME_INFO_ARRAY_OFFSET + sjpeg->sjpeg_total_frames * 2);
564                 sjpeg->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now...
565 
566                 for(int i = 1; i <  sjpeg->sjpeg_total_frames; i++) {
567                     res = lv_fs_read(&lv_file, buff, 2, &rn);
568                     if(res != LV_FS_RES_OK || rn != 2) {
569                         lv_fs_close(&lv_file);
570                         return LV_RES_INV;
571                     }
572 
573                     data = buff;
574                     int offset = *data++;
575                     offset |= *data++ << 8;
576                     sjpeg->frame_base_offset[i] = sjpeg->frame_base_offset[i - 1] + offset;
577                 }
578 
579                 sjpeg->sjpeg_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time.
580                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
581                 if(! sjpeg->frame_cache) {
582                     lv_fs_close(&lv_file);
583                     lv_sjpg_cleanup(sjpeg);
584                     return LV_RES_INV;
585                 }
586                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
587                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
588                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
589                 if(! sjpeg->workb) {
590                     lv_fs_close(&lv_file);
591                     lv_sjpg_cleanup(sjpeg);
592                     return LV_RES_INV;
593                 }
594 
595                 sjpeg->tjpeg_jd =    lv_mem_alloc(sizeof(JDEC));
596                 if(! sjpeg->tjpeg_jd) {
597                     lv_fs_close(&lv_file);
598                     lv_sjpg_cleanup(sjpeg);
599                     return LV_RES_INV;
600                 }
601 
602                 sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
603                 sjpeg->io.lv_file = lv_file;
604                 dsc->img_data = NULL;
605                 return LV_RES_OK;
606             }
607         }
608         else if(!strcmp(&fn[strlen(fn) - 4], ".jpg")) {
609 
610             lv_fs_file_t lv_file;
611             lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD);
612             if(res != LV_FS_RES_OK) {
613                 return LV_RES_INV;
614             }
615 
616             SJPEG * sjpeg = (SJPEG *) dsc->user_data;
617             if(sjpeg == NULL) {
618                 sjpeg = lv_mem_alloc(sizeof(SJPEG));
619                 if(! sjpeg) {
620                     lv_fs_close(&lv_file);
621                     return LV_RES_INV;
622                 }
623 
624                 memset(sjpeg, 0, sizeof(SJPEG));
625                 dsc->user_data = sjpeg;
626                 sjpeg->sjpeg_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
627                 sjpeg->sjpeg_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
628             }
629 
630             uint8_t * workb_temp = lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
631             if(! workb_temp) {
632                 lv_fs_close(&lv_file);
633                 lv_sjpg_cleanup(sjpeg);
634                 return LV_RES_INV;
635             }
636 
637             io_source_t io_source_temp;
638             io_source_temp.type = SJPEG_IO_SOURCE_DISK;
639             io_source_temp.raw_sjpg_data_next_read_pos = 0;
640             io_source_temp.img_cache_buff = NULL;
641             io_source_temp.lv_file = lv_file;
642 
643             JDEC jd_tmp;
644 
645             JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
646 
647             lv_mem_free(workb_temp);
648 
649 
650             if(rc == JDR_OK) {
651                 sjpeg->sjpeg_x_res = jd_tmp.width;
652                 sjpeg->sjpeg_y_res = jd_tmp.height;
653                 sjpeg->sjpeg_total_frames = 1;
654                 sjpeg->sjpeg_single_frame_height = jd_tmp.height;
655 
656                 sjpeg->frame_base_array = NULL;
657                 sjpeg->frame_base_offset =  lv_mem_alloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames);
658                 if(! sjpeg->frame_base_offset) {
659                     lv_fs_close(&lv_file);
660                     lv_sjpg_cleanup(sjpeg);
661                     return LV_RES_INV;
662                 }
663 
664                 int img_frame_start_offset = 0;
665                 sjpeg->frame_base_offset[0] = img_frame_start_offset;
666 
667                 sjpeg->sjpeg_cache_frame_index = -1;
668                 sjpeg->frame_cache = (void *)lv_mem_alloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3);
669                 if(! sjpeg->frame_cache) {
670                     lv_fs_close(&lv_file);
671                     lv_sjpg_cleanup(sjpeg);
672                     return LV_RES_INV;
673                 }
674 
675                 sjpeg->io.img_cache_buff = sjpeg->frame_cache;
676                 sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
677                 sjpeg->workb =   lv_mem_alloc(TJPGD_WORKBUFF_SIZE);
678                 if(! sjpeg->workb) {
679                     lv_fs_close(&lv_file);
680                     lv_sjpg_cleanup(sjpeg);
681                     return LV_RES_INV;
682                 }
683 
684                 sjpeg->tjpeg_jd =   lv_mem_alloc(sizeof(JDEC));
685                 if(! sjpeg->tjpeg_jd) {
686                     lv_fs_close(&lv_file);
687                     lv_sjpg_cleanup(sjpeg);
688                     return LV_RES_INV;
689                 }
690 
691                 sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
692                 sjpeg->io.lv_file = lv_file;
693                 dsc->img_data = NULL;
694                 return LV_RES_OK;
695 
696             }
697             else {
698                 if(dsc->user_data) lv_mem_free(dsc->user_data);
699                 lv_fs_close(&lv_file);
700                 return  LV_RES_INV;
701             }
702         }
703     }
704 
705     return LV_RES_INV;
706 }
707 
708 /**
709  * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
710  * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL)
711  * @param decoder pointer to the decoder the function associated with
712  * @param dsc pointer to decoder descriptor
713  * @param x start x coordinate
714  * @param y start y coordinate
715  * @param len number of pixels to decode
716  * @param buf a buffer to store the decoded pixels
717  * @return LV_RES_OK: ok; LV_RES_INV: failed
718  */
719 
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)720 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,
721                                   lv_coord_t len, uint8_t * buf)
722 {
723     LV_UNUSED(decoder);
724     if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
725         SJPEG * sjpeg = (SJPEG *) dsc->user_data;
726         JRESULT rc;
727 
728         int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
729 
730         /*If line not from cache, refresh cache */
731         if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
732             sjpeg->io.raw_sjpg_data = sjpeg->frame_base_array[ sjpeg_req_frame_index ];
733             if(sjpeg_req_frame_index == (sjpeg->sjpeg_total_frames - 1)) {
734                 /*This is the last frame. */
735                 const uint32_t frame_offset = (uint32_t)(sjpeg->io.raw_sjpg_data - sjpeg->sjpeg_data);
736                 sjpeg->io.raw_sjpg_data_size = sjpeg->sjpeg_data_size - frame_offset;
737             }
738             else {
739                 sjpeg->io.raw_sjpg_data_size =
740                     (uint32_t)(sjpeg->frame_base_array[sjpeg_req_frame_index + 1] - sjpeg->io.raw_sjpg_data);
741             }
742             sjpeg->io.raw_sjpg_data_next_read_pos = 0;
743             rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
744             if(rc != JDR_OK) return LV_RES_INV;
745             rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0);
746             if(rc != JDR_OK) return LV_RES_INV;
747             sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
748         }
749 
750         int offset = 0;
751         uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res *
752                           3;
753 
754 #if  LV_COLOR_DEPTH == 32
755         for(int i = 0; i < len; i++) {
756             buf[offset + 3] = 0xff;
757             buf[offset + 2] = *cache++;
758             buf[offset + 1] = *cache++;
759             buf[offset + 0] = *cache++;
760             offset += 4;
761         }
762 
763 #elif  LV_COLOR_DEPTH == 16
764 
765         for(int i = 0; i < len; i++) {
766             uint16_t col_16bit = (*cache++ & 0xf8) << 8;
767             col_16bit |= (*cache++ & 0xFC) << 3;
768             col_16bit |= (*cache++ >> 3);
769 #if  LV_BIG_ENDIAN_SYSTEM == 1
770             buf[offset++] = col_16bit >> 8;
771             buf[offset++] = col_16bit & 0xff;
772 #else
773             buf[offset++] = col_16bit & 0xff;
774             buf[offset++] = col_16bit >> 8;
775 #endif // LV_BIG_ENDIAN_SYSTEM
776         }
777 
778 #elif  LV_COLOR_DEPTH == 8
779 
780         for(int i = 0; i < len; i++) {
781             uint8_t col_8bit = (*cache++ & 0xC0);
782             col_8bit |= (*cache++ & 0xe0) >> 2;
783             col_8bit |= (*cache++ & 0xe0) >> 5;
784             buf[offset++] = col_8bit;
785         }
786 #else
787 #error Unsupported LV_COLOR_DEPTH
788 
789 
790 #endif // LV_COLOR_DEPTH
791         return LV_RES_OK;
792     }
793     else if(dsc->src_type == LV_IMG_SRC_FILE) {
794         SJPEG * sjpeg = (SJPEG *) dsc->user_data;
795         JRESULT rc;
796         int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
797 
798         lv_fs_file_t * lv_file_p = &(sjpeg->io.lv_file);
799         if(!lv_file_p) goto end;
800 
801         /*If line not from cache, refresh cache */
802         if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
803             sjpeg->io.raw_sjpg_data_next_read_pos = (int)(sjpeg->frame_base_offset [ sjpeg_req_frame_index ]);
804             lv_fs_seek(&(sjpeg->io.lv_file), sjpeg->io.raw_sjpg_data_next_read_pos, LV_FS_SEEK_SET);
805 
806             rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
807             if(rc != JDR_OK) return LV_RES_INV;
808 
809             rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0);
810             if(rc != JDR_OK) return LV_RES_INV;
811 
812             sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
813         }
814 
815         int offset = 0;
816         uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res *
817                           3;
818 
819 #if LV_COLOR_DEPTH == 32
820         for(int i = 0; i < len; i++) {
821             buf[offset + 3] = 0xff;
822             buf[offset + 2] = *cache++;
823             buf[offset + 1] = *cache++;
824             buf[offset + 0] = *cache++;
825             offset += 4;
826         }
827 #elif  LV_COLOR_DEPTH == 16
828 
829         for(int i = 0; i < len; i++) {
830             uint16_t col_8bit = (*cache++ & 0xf8) << 8;
831             col_8bit |= (*cache++ & 0xFC) << 3;
832             col_8bit |= (*cache++ >> 3);
833 #if  LV_BIG_ENDIAN_SYSTEM == 1
834             buf[offset++] = col_8bit >> 8;
835             buf[offset++] = col_8bit & 0xff;
836 #else
837             buf[offset++] = col_8bit & 0xff;
838             buf[offset++] = col_8bit >> 8;
839 #endif // LV_BIG_ENDIAN_SYSTEM
840         }
841 
842 #elif  LV_COLOR_DEPTH == 8
843 
844         for(int i = 0; i < len; i++) {
845             uint8_t col_8bit = (*cache++ & 0xC0);
846             col_8bit |= (*cache++ & 0xe0) >> 2;
847             col_8bit |= (*cache++ & 0xe0) >> 5;
848             buf[offset++] = col_8bit;
849         }
850 
851 #else
852 #error Unsupported LV_COLOR_DEPTH
853 
854 
855 #endif // LV_COLOR_DEPTH
856 
857         return LV_RES_OK;
858     }
859 end:
860     return LV_RES_INV;
861 }
862 
863 /**
864  * Free the allocated resources
865  * @param decoder pointer to the decoder where this function belongs
866  * @param dsc pointer to a descriptor which describes this decoding session
867  */
decoder_close(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)868 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
869 {
870     LV_UNUSED(decoder);
871     /*Free all allocated data*/
872     SJPEG * sjpeg = (SJPEG *) dsc->user_data;
873     if(!sjpeg) return;
874 
875     switch(dsc->src_type) {
876         case LV_IMG_SRC_FILE:
877             if(sjpeg->io.lv_file.file_d) {
878                 lv_fs_close(&(sjpeg->io.lv_file));
879             }
880             lv_sjpg_cleanup(sjpeg);
881             break;
882 
883         case LV_IMG_SRC_VARIABLE:
884             lv_sjpg_cleanup(sjpeg);
885             break;
886 
887         default:
888             ;
889     }
890 }
891 
is_jpg(const uint8_t * raw_data)892 static int is_jpg(const uint8_t * raw_data)
893 {
894     const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF,  0xE0,  0x00,  0x10, 0x4A,  0x46, 0x49, 0x46};
895     return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0;
896 }
897 
lv_sjpg_free(SJPEG * sjpeg)898 static void lv_sjpg_free(SJPEG * sjpeg)
899 {
900     if(sjpeg->frame_cache) lv_mem_free(sjpeg->frame_cache);
901     if(sjpeg->frame_base_array) lv_mem_free(sjpeg->frame_base_array);
902     if(sjpeg->frame_base_offset) lv_mem_free(sjpeg->frame_base_offset);
903     if(sjpeg->tjpeg_jd) lv_mem_free(sjpeg->tjpeg_jd);
904     if(sjpeg->workb) lv_mem_free(sjpeg->workb);
905 }
906 
lv_sjpg_cleanup(SJPEG * sjpeg)907 static void lv_sjpg_cleanup(SJPEG * sjpeg)
908 {
909     if(! sjpeg) return;
910 
911     lv_sjpg_free(sjpeg);
912     lv_mem_free(sjpeg);
913 }
914 
915 #endif /*LV_USE_SJPG*/
916