lv_sjpg.c 31 KB

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