lv_sjpg.c 33 KB

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