1 /**
2  * @file lv_tjpgd.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../draw/lv_image_decoder_private.h"
11 #include "../../../lvgl.h"
12 #if LV_USE_TJPGD
13 
14 #include "tjpgd.h"
15 #include "lv_tjpgd.h"
16 #include "../../misc/lv_fs_private.h"
17 #include <string.h>
18 
19 /*********************
20  *      DEFINES
21  *********************/
22 
23 #define DECODER_NAME    "TJPGD"
24 
25 #define TJPGD_WORKBUFF_SIZE             4096    //Recommended by TJPGD library
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header);
35 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
36 
37 static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
38                                     const lv_area_t * full_area, lv_area_t * decoded_area);
39 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
40 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata);
41 static int is_jpg(const uint8_t * raw_data, size_t len);
42 
43 /**********************
44  *  STATIC VARIABLES
45  **********************/
46 
47 /**********************
48  *      MACROS
49  **********************/
50 
51 /**********************
52  *   GLOBAL FUNCTIONS
53  **********************/
54 
lv_tjpgd_init(void)55 void lv_tjpgd_init(void)
56 {
57     lv_image_decoder_t * dec = lv_image_decoder_create();
58     lv_image_decoder_set_info_cb(dec, decoder_info);
59     lv_image_decoder_set_open_cb(dec, decoder_open);
60     lv_image_decoder_set_get_area_cb(dec, decoder_get_area);
61     lv_image_decoder_set_close_cb(dec, decoder_close);
62 
63     dec->name = DECODER_NAME;
64 }
65 
lv_tjpgd_deinit(void)66 void lv_tjpgd_deinit(void)
67 {
68     lv_image_decoder_t * dec = NULL;
69     while((dec = lv_image_decoder_get_next(dec)) != NULL) {
70         if(dec->info_cb == decoder_info) {
71             lv_image_decoder_delete(dec);
72             break;
73         }
74     }
75 }
76 
77 /**********************
78  *   STATIC FUNCTIONS
79  **********************/
80 
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)81 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
82 {
83     LV_UNUSED(decoder);
84 
85     const void * src = dsc->src;
86     lv_image_src_t src_type = dsc->src_type;
87 
88     if(src_type == LV_IMAGE_SRC_VARIABLE) {
89         const lv_image_dsc_t * img_dsc = src;
90         uint8_t * raw_data = (uint8_t *)img_dsc->data;
91         const uint32_t raw_data_size = img_dsc->data_size;
92 
93         if(is_jpg(raw_data, raw_data_size) == true) {
94 #if LV_USE_FS_MEMFS
95             header->cf = LV_COLOR_FORMAT_RAW;
96             header->w = img_dsc->header.w;
97             header->h = img_dsc->header.h;
98             header->stride = img_dsc->header.w * 3;
99             return LV_RESULT_OK;
100 #else
101             LV_LOG_WARN("LV_USE_FS_MEMFS needs to enabled to decode from data");
102             return LV_RESULT_INVALID;
103 #endif
104         }
105     }
106     else if(src_type == LV_IMAGE_SRC_FILE) {
107         const char * fn = src;
108         const char * ext = lv_fs_get_ext(fn);
109         if((lv_strcmp(ext, "jpg") == 0) || (lv_strcmp(ext, "jpeg") == 0)) {
110             uint8_t workb[TJPGD_WORKBUFF_SIZE];
111             JDEC jd;
112             JRESULT rc = jd_prepare(&jd, input_func, workb, TJPGD_WORKBUFF_SIZE, &dsc->file);
113             if(rc) {
114                 LV_LOG_WARN("jd_prepare error: %d", rc);
115                 return LV_RESULT_INVALID;
116             }
117             header->cf = LV_COLOR_FORMAT_RAW;
118             header->w = jd.width;
119             header->h = jd.height;
120             header->stride = jd.width * 3;
121 
122             return LV_RESULT_OK;
123         }
124     }
125     return LV_RESULT_INVALID;
126 }
127 
input_func(JDEC * jd,uint8_t * buff,size_t ndata)128 static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata)
129 {
130     lv_fs_file_t * f = jd->device;
131     if(!f) return 0;
132 
133     if(buff) {
134         uint32_t rn = 0;
135         lv_fs_read(f, buff, (uint32_t)ndata, &rn);
136         return rn;
137     }
138     else {
139         uint32_t pos;
140         lv_fs_tell(f, &pos);
141         lv_fs_seek(f, (uint32_t)(ndata + pos),  LV_FS_SEEK_SET);
142         return ndata;
143     }
144     return 0;
145 }
146 
147 /**
148  * Decode a JPG image and return the decoded data.
149  * @param decoder pointer to the decoder
150  * @param dsc     pointer to the decoder descriptor
151  * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
152  */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)153 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
154 {
155     LV_UNUSED(decoder);
156     lv_fs_file_t * f = lv_malloc(sizeof(lv_fs_file_t));
157     if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
158 #if LV_USE_FS_MEMFS
159         const lv_image_dsc_t * img_dsc = dsc->src;
160         if(is_jpg(img_dsc->data, img_dsc->data_size) == true) {
161             lv_fs_path_ex_t path;
162             lv_fs_make_path_from_buffer(&path, LV_FS_MEMFS_LETTER, img_dsc->data, img_dsc->data_size);
163             lv_fs_res_t res;
164             res = lv_fs_open(f, (const char *)&path, LV_FS_MODE_RD);
165             if(res != LV_FS_RES_OK) {
166                 lv_free(f);
167                 return LV_RESULT_INVALID;
168             }
169         }
170 #else
171         LV_LOG_WARN("LV_USE_FS_MEMFS needs to enabled to decode from data");
172         return LV_RESULT_INVALID;
173 #endif
174     }
175     else if(dsc->src_type == LV_IMAGE_SRC_FILE) {
176         const char * fn = dsc->src;
177         if((lv_strcmp(lv_fs_get_ext(fn), "jpg") == 0) || (lv_strcmp(lv_fs_get_ext(fn), "jpeg") == 0)) {
178             lv_fs_res_t res;
179             res = lv_fs_open(f, fn, LV_FS_MODE_RD);
180             if(res != LV_FS_RES_OK) {
181                 lv_free(f);
182                 return LV_RESULT_INVALID;
183             }
184         }
185     }
186 
187     uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE);
188     JDEC * jd = lv_malloc(sizeof(JDEC));
189     dsc->user_data = jd;
190     JRESULT rc = jd_prepare(jd, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, f);
191     if(rc) return LV_RESULT_INVALID;
192 
193     dsc->header.cf = LV_COLOR_FORMAT_RGB888;
194     dsc->header.w = jd->width;
195     dsc->header.h = jd->height;
196     dsc->header.stride = jd->width * 3;
197 
198     if(rc != JDR_OK) {
199         lv_free(workb_temp);
200         lv_free(jd);
201         return LV_RESULT_INVALID;
202     }
203 
204     return LV_RESULT_OK;
205 }
206 
decoder_get_area(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,const lv_area_t * full_area,lv_area_t * decoded_area)207 static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
208                                     const lv_area_t * full_area, lv_area_t * decoded_area)
209 {
210     LV_UNUSED(decoder);
211     LV_UNUSED(full_area);
212 
213     JDEC * jd = dsc->user_data;
214     lv_draw_buf_t * decoded = (void *)dsc->decoded;
215 
216     uint32_t  mx, my;
217     mx = jd->msx * 8;
218     my = jd->msy * 8;         /* Size of the MCU (pixel) */
219     if(decoded_area->y1 == LV_COORD_MIN) {
220         decoded_area->y1 = 0;
221         decoded_area->y2 = my - 1;
222         decoded_area->x1 = -((int32_t)mx);
223         decoded_area->x2 = -1;
224         jd->scale = 0;
225         jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0;   /* Initialize DC values */
226         jd->rst = 0;
227         jd->rsc = 0;
228         if(decoded == NULL) {
229             decoded = lv_malloc_zeroed(sizeof(lv_draw_buf_t));
230             dsc->decoded = decoded;
231         }
232         else {
233             lv_fs_seek(jd->device, 0, LV_FS_SEEK_SET);
234             JRESULT rc = jd_prepare(jd, input_func, jd->pool_original, (size_t)TJPGD_WORKBUFF_SIZE, jd->device);
235             if(rc) return LV_RESULT_INVALID;
236         }
237         decoded->data = jd->workbuf;
238         decoded->header = dsc->header;
239     }
240 
241     decoded_area->x1 += mx;
242     decoded_area->x2 += mx;
243 
244     if(decoded_area->x1 >= jd->width) {
245         decoded_area->x1 = 0;
246         decoded_area->x2 = mx - 1;
247         decoded_area->y1 += my;
248         decoded_area->y2 += my;
249     }
250 
251     if(decoded_area->x2 >= jd->width) decoded_area->x2 = jd->width - 1;
252     if(decoded_area->y2 >= jd->height) decoded_area->y2 = jd->height - 1;
253 
254     decoded->header.w = lv_area_get_width(decoded_area);
255     decoded->header.h = lv_area_get_height(decoded_area);
256     decoded->header.stride = decoded->header.w * 3;
257     decoded->data_size = decoded->header.stride * decoded->header.h;
258 
259     /* Process restart interval if enabled */
260     JRESULT rc;
261     if(jd->nrst && jd->rst++ == jd->nrst) {
262         rc = jd_restart(jd, jd->rsc++);
263         if(rc != JDR_OK) return LV_RESULT_INVALID;
264         jd->rst = 1;
265     }
266 
267     /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */
268     rc = jd_mcu_load(jd);
269     if(rc != JDR_OK) return LV_RESULT_INVALID;
270 
271     /* Output the MCU (YCbCr to RGB, scaling and output) */
272     rc = jd_mcu_output(jd, NULL, decoded_area->x1, decoded_area->y1);
273     if(rc != JDR_OK) return LV_RESULT_INVALID;
274 
275     return LV_RESULT_OK;
276 }
277 
278 /**
279  * Free the allocated resources
280  * @param decoder pointer to the decoder where this function belongs
281  * @param dsc pointer to a descriptor which describes this decoding session
282  */
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)283 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
284 {
285     LV_UNUSED(decoder);
286     JDEC * jd = dsc->user_data;
287     lv_fs_close(jd->device);
288     lv_free(jd->device);
289     lv_free(jd->pool_original);
290     lv_free(jd);
291     lv_free((void *)dsc->decoded);
292 }
293 
is_jpg(const uint8_t * raw_data,size_t len)294 static int is_jpg(const uint8_t * raw_data, size_t len)
295 {
296     const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF,  0xE0,  0x00,  0x10, 0x4A,  0x46, 0x49, 0x46};
297     if(len < sizeof(jpg_signature)) return false;
298     return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0;
299 }
300 
301 #endif /*LV_USE_TJPGD*/
302