From ca55b2ed8dd81bbab451157e76f978d0ae5a4136 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 18 Sep 2023 21:19:00 +0200 Subject: [PATCH] arch(img_decoder): replace read_liine_c with get_area_cb also remove sjpeg support as get_area_cb can de quite same (some optimization is still needed to not decode the out of bounds chunks) --- examples/libs/sjpg/lv_example_sjpg_1.c | 6 +- lvgl.h | 2 +- src/draw/lv_image_decoder.h | 4 +- src/draw/sw/lv_draw_sw_img.c | 1 + src/libs/jpg/lv_jpg.c | 290 ++++++ src/libs/{sjpg/lv_sjpg.h => jpg/lv_jpg.h} | 2 +- src/libs/{sjpg => jpg}/tjpgd.c | 829 +++++++--------- src/libs/{sjpg => jpg}/tjpgd.h | 67 +- src/libs/{sjpg => jpg}/tjpgdcnf.h | 4 +- src/libs/sjpg/lv_sjpg.c | 931 ------------------ src/lv_init.c | 4 +- src/misc/lv_color.h | 4 +- src/misc/lv_fs.c | 6 +- src/misc/lv_fs.h | 4 +- tests/CMakeLists.txt | 4 +- tests/ref_imgs/libs/jpg_1.png | Bin 0 -> 9519 bytes tests/ref_imgs/libs/png_1.png | Bin 0 -> 5607 bytes tests/src/test_assets/test_img_lvgl_logo.jpg | Bin 0 -> 1947 bytes tests/src/test_assets/test_img_lvgl_logo.png | Bin 0 -> 1873 bytes .../src/test_assets/test_img_lvgl_logo_jpg.c | 174 ++++ .../src/test_assets/test_img_lvgl_logo_png.c | 169 ++++ .../test_cases/{ => draw}/test_clip_corner.c | 0 .../src/test_cases/{ => draw}/test_draw_arc.c | 0 .../test_cases/{ => draw}/test_draw_blend.c | 2 +- .../test_cases/{ => draw}/test_draw_label.c | 0 .../test_cases/{ => draw}/test_draw_layer.c | 0 .../test_cases/{ => draw}/test_draw_line.c | 0 .../{ => draw}/test_draw_rectangle.c | 0 .../{ => draw}/test_draw_transform.c | 0 .../{ => draw}/test_draw_triangle.c | 0 .../{ => draw}/test_image_formats.c | 1 + .../src/test_cases/{ => libs}/test_barcode.c | 0 tests/src/test_cases/libs/test_jpg.c | 63 ++ tests/src/test_cases/libs/test_png.c | 63 ++ .../src/test_cases/{ => libs}/test_tiny_ttf.c | 0 .../test_cases/{ => widgets}/test_animimg.c | 0 tests/src/test_cases/{ => widgets}/test_arc.c | 0 tests/src/test_cases/{ => widgets}/test_bar.c | 0 tests/src/test_cases/{ => widgets}/test_btn.c | 0 .../test_cases/{ => widgets}/test_btnmatrix.c | 0 .../test_cases/{ => widgets}/test_calendar.c | 0 .../src/test_cases/{ => widgets}/test_chart.c | 0 .../test_cases/{ => widgets}/test_checkbox.c | 0 .../test_cases/{ => widgets}/test_dropdown.c | 0 .../src/test_cases/{ => widgets}/test_label.c | 0 tests/src/test_cases/{ => widgets}/test_led.c | 0 .../src/test_cases/{ => widgets}/test_line.c | 0 .../src/test_cases/{ => widgets}/test_list.c | 0 .../test_cases/{ => widgets}/test_msgbox.c | 0 .../test_cases/{ => widgets}/test_roller.c | 0 .../test_cases/{ => widgets}/test_slider.c | 0 .../test_cases/{ => widgets}/test_spinbox.c | 0 .../test_cases/{ => widgets}/test_spinner.c | 0 .../test_cases/{ => widgets}/test_switch.c | 0 .../src/test_cases/{ => widgets}/test_table.c | 0 .../test_cases/{ => widgets}/test_tabview.c | 0 .../test_cases/{ => widgets}/test_textarea.c | 0 tests/src/test_cases/{ => widgets}/test_win.c | 0 58 files changed, 1182 insertions(+), 1448 deletions(-) create mode 100644 src/libs/jpg/lv_jpg.c rename src/libs/{sjpg/lv_sjpg.h => jpg/lv_jpg.h} (94%) rename src/libs/{sjpg => jpg}/tjpgd.c (51%) rename src/libs/{sjpg => jpg}/tjpgd.h (53%) rename src/libs/{sjpg => jpg}/tjpgdcnf.h (93%) delete mode 100644 src/libs/sjpg/lv_sjpg.c create mode 100644 tests/ref_imgs/libs/jpg_1.png create mode 100644 tests/ref_imgs/libs/png_1.png create mode 100644 tests/src/test_assets/test_img_lvgl_logo.jpg create mode 100644 tests/src/test_assets/test_img_lvgl_logo.png create mode 100644 tests/src/test_assets/test_img_lvgl_logo_jpg.c create mode 100644 tests/src/test_assets/test_img_lvgl_logo_png.c rename tests/src/test_cases/{ => draw}/test_clip_corner.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_arc.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_blend.c (99%) rename tests/src/test_cases/{ => draw}/test_draw_label.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_layer.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_line.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_rectangle.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_transform.c (100%) rename tests/src/test_cases/{ => draw}/test_draw_triangle.c (100%) rename tests/src/test_cases/{ => draw}/test_image_formats.c (99%) rename tests/src/test_cases/{ => libs}/test_barcode.c (100%) create mode 100644 tests/src/test_cases/libs/test_jpg.c create mode 100644 tests/src/test_cases/libs/test_png.c rename tests/src/test_cases/{ => libs}/test_tiny_ttf.c (100%) rename tests/src/test_cases/{ => widgets}/test_animimg.c (100%) rename tests/src/test_cases/{ => widgets}/test_arc.c (100%) rename tests/src/test_cases/{ => widgets}/test_bar.c (100%) rename tests/src/test_cases/{ => widgets}/test_btn.c (100%) rename tests/src/test_cases/{ => widgets}/test_btnmatrix.c (100%) rename tests/src/test_cases/{ => widgets}/test_calendar.c (100%) rename tests/src/test_cases/{ => widgets}/test_chart.c (100%) rename tests/src/test_cases/{ => widgets}/test_checkbox.c (100%) rename tests/src/test_cases/{ => widgets}/test_dropdown.c (100%) rename tests/src/test_cases/{ => widgets}/test_label.c (100%) rename tests/src/test_cases/{ => widgets}/test_led.c (100%) rename tests/src/test_cases/{ => widgets}/test_line.c (100%) rename tests/src/test_cases/{ => widgets}/test_list.c (100%) rename tests/src/test_cases/{ => widgets}/test_msgbox.c (100%) rename tests/src/test_cases/{ => widgets}/test_roller.c (100%) rename tests/src/test_cases/{ => widgets}/test_slider.c (100%) rename tests/src/test_cases/{ => widgets}/test_spinbox.c (100%) rename tests/src/test_cases/{ => widgets}/test_spinner.c (100%) rename tests/src/test_cases/{ => widgets}/test_switch.c (100%) rename tests/src/test_cases/{ => widgets}/test_table.c (100%) rename tests/src/test_cases/{ => widgets}/test_tabview.c (100%) rename tests/src/test_cases/{ => widgets}/test_textarea.c (100%) rename tests/src/test_cases/{ => widgets}/test_win.c (100%) diff --git a/examples/libs/sjpg/lv_example_sjpg_1.c b/examples/libs/sjpg/lv_example_sjpg_1.c index d6dc3e5c2..8c9cd3f69 100644 --- a/examples/libs/sjpg/lv_example_sjpg_1.c +++ b/examples/libs/sjpg/lv_example_sjpg_1.c @@ -8,10 +8,14 @@ void lv_example_sjpg_1(void) { lv_obj_t * wp; + LV_IMAGE_DECLARE(codeblocks) + wp = lv_image_create(lv_scr_act()); /* Assuming a File system is attached to letter 'A' * E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */ - lv_image_set_src(wp, "A:lvgl/examples/libs/sjpg/small_image.sjpg"); + lv_image_set_src(wp, "A:codeblocks.jpg"); + // lv_image_set_src(wp, &codeblocks); + lv_obj_center(wp); } #endif diff --git a/lvgl.h b/lvgl.h index cb499623a..93dff4942 100644 --- a/lvgl.h +++ b/lvgl.h @@ -95,7 +95,7 @@ extern "C" { #include "src/libs/png/lv_png.h" #include "src/libs/gif/lv_gif.h" #include "src/libs/qrcode/lv_qrcode.h" -#include "src/libs/sjpg/lv_sjpg.h" +#include "src/libs/jpg/lv_jpg.h" #include "src/libs/freetype/lv_freetype.h" #include "src/libs/rlottie/lv_rlottie.h" #include "src/libs/ffmpeg/lv_ffmpeg.h" diff --git a/src/draw/lv_image_decoder.h b/src/draw/lv_image_decoder.h index e80b9e0b4..b1ab2c396 100644 --- a/src/draw/lv_image_decoder.h +++ b/src/draw/lv_image_decoder.h @@ -88,7 +88,6 @@ typedef lv_res_t (*lv_image_decoder_get_area_cb_t)(struct _lv_image_decoder_t * */ typedef void (*lv_image_decoder_close_f_t)(struct _lv_image_decoder_t * decoder, struct _lv_image_decoder_dsc_t * dsc); - typedef struct _lv_image_decoder_t { lv_image_decoder_info_f_t info_cb; lv_image_decoder_open_f_t open_cb; @@ -242,6 +241,9 @@ lv_res_t lv_image_decoder_built_in_info(lv_image_decoder_t * decoder, const void lv_res_t lv_image_decoder_built_in_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, const lv_area_t * full_area, lv_area_t * decoded_area); +lv_res_t lv_img_decoder_built_in_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, + const lv_area_t * full_area, lv_area_t * decoded_area); + /** * Open a built in image * @param decoder the decoder where this function belongs diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index 40b5605c0..f2ad9f77d 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -215,6 +215,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_image(lv_draw_unit_t * draw_unit, const lv lv_image_decoder_close(&decoder_dsc); } + static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * draw_area, const lv_image_decoder_dsc_t * src, lv_draw_image_sup_t * sup, const lv_area_t * img_coords) { diff --git a/src/libs/jpg/lv_jpg.c b/src/libs/jpg/lv_jpg.c new file mode 100644 index 000000000..d9ac645b2 --- /dev/null +++ b/src/libs/jpg/lv_jpg.c @@ -0,0 +1,290 @@ +/** + * @file lv_sjpg.c + * + */ + +/*---------------------------------------------------------------------------------------------------------------------------------- +/ Added normal JPG support [7/10/2020] +/ ---------- +/ SJPEG is a custom created modified JPEG file format for small embedded platforms. +/ It will contain multiple JPEG fragments all embedded into a single file with a custom header. +/ This makes JPEG decoding easier using any JPEG library. Overall file size will be almost +/ similar to the parent jpeg file. We can generate sjpeg from any jpeg using a python script +/ provided along with this project. +/ (by vinodstanur | 2020 ) +/ SJPEG FILE STRUCTURE +/ -------------------------------------------------------------------------------------------------------------------------------- +/ Bytes | Value | +/ -------------------------------------------------------------------------------------------------------------------------------- +/ +/ 0 - 7 | "_SJPG__" followed by '\0' +/ +/ 8 - 13 | "V1.00" followed by '\0' [VERSION OF SJPG FILE for future compatibiliby] +/ +/ 14 - 15 | X_RESOLUTION (width) [little endian] +/ +/ 16 - 17 | Y_RESOLUTION (height) [little endian] +/ +/ 18 - 19 | TOTAL_FRAMES inside sjpeg [little endian] +/ +/ 20 - 21 | JPEG BLOCK WIDTH (16 normally) [little endian] +/ +/ 22 - [(TOTAL_FRAMES*2 )] | SIZE OF EACH JPEG SPLIT FRAGMENTS (FRAME_INFO_ARRAY) +/ +/ SJPEG data | Each JPEG frame can be extracted from SJPEG data by parsing the FRAME_INFO_ARRAY one time. +/ +/---------------------------------------------------------------------------------------------------------------------------------- +/ JPEG DECODER +/ ------------ +/ We are using TJpgDec - Tiny JPEG Decompressor library from ELM-CHAN for decoding each split-jpeg fragments. +/ 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, +/ just replace those files with updated files. +/---------------------------------------------------------------------------------------------------------------------------------*/ + +/********************* + * INCLUDES + *********************/ + +#include "../../../lvgl.h" +#if LV_USE_SJPG + +#include "tjpgd.h" +#include "lv_jpg.h" +#include "../../misc/lv_fs.h" + +/********************* + * DEFINES + *********************/ +#define TJPGD_WORKBUFF_SIZE 4096 //Recommended by TJPGD library + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header); +static lv_res_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); + +static lv_res_t 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); +static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); +static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata); +static int is_jpg(const uint8_t * raw_data, size_t len); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_jpeg_init(void) +{ + lv_image_decoder_t * dec = lv_image_decoder_create(); + lv_image_decoder_set_info_cb(dec, decoder_info); + lv_image_decoder_set_open_cb(dec, decoder_open); + lv_image_decoder_set_get_area_cb(dec, decoder_get_area); + lv_image_decoder_set_close_cb(dec, decoder_close); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_res_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header) +{ + LV_UNUSED(decoder); + + lv_image_src_t src_type = lv_image_src_get_type(src); + + if(src_type == LV_IMAGE_SRC_VARIABLE) { + const lv_image_dsc_t * img_dsc = src; + uint8_t * raw_data = (uint8_t *)img_dsc->data; + const uint32_t raw_sjpeg_data_size = img_dsc->data_size; + + if(is_jpg(raw_data, raw_sjpeg_data_size) == true) { + header->always_zero = 0; + header->cf = LV_COLOR_FORMAT_RAW; + header->w = img_dsc->header.w; + header->h = img_dsc->header.h; + header->stride = img_dsc->header.w * 3; + return LV_RES_OK; + + } + } + else if(src_type == LV_IMAGE_SRC_FILE) { + const char * fn = src; + if((strcmp(lv_fs_get_ext(fn), "jpg") == 0) || (strcmp(lv_fs_get_ext(fn), "jpeg") == 0)) { + lv_fs_file_t f; + lv_fs_res_t res; + res = lv_fs_open(&f, fn, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) return LV_RES_INV; + + uint8_t workb[TJPGD_WORKBUFF_SIZE]; + JDEC jd; + JRESULT rc = jd_prepare(&jd, input_func, workb, TJPGD_WORKBUFF_SIZE, &f); + if(rc) { + LV_LOG_WARN("jd_prepare error: %d", rc); + lv_fs_close(&f); + return LV_RES_INV; + } + header->always_zero = 0; + header->cf = LV_COLOR_FORMAT_RAW; + header->w = jd.width; + header->h = jd.height; + header->stride = jd.width * 3; + + lv_fs_close(&f); + return LV_RES_OK; + } + } + return LV_RES_INV; +} + +static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata) +{ + lv_fs_file_t * f = jd->device; + if(!f) return 0; + + if(buff) { + uint32_t rn = 0; + lv_fs_read(f, buff, (uint32_t)ndata, &rn); + return rn; + } + else { + uint32_t pos; + lv_fs_tell(f, &pos); + lv_fs_seek(f, (uint32_t)(ndata + pos), LV_FS_SEEK_SET); + return ndata; + } + return 0; +} + +static lv_res_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) +{ + LV_UNUSED(decoder); + lv_fs_file_t * f = lv_malloc(sizeof(lv_fs_file_t)); + if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { + const lv_image_dsc_t * img_dsc = dsc->src; + if(is_jpg(img_dsc->data, img_dsc->data_size) == true) { + lv_fs_path_ex_t path; + lv_fs_make_path_from_buffer(&path, LV_FS_MEMFS_LETTER, img_dsc->data, img_dsc->data_size); + lv_fs_res_t res; + res = lv_fs_open(f, (const char *)&path, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + lv_free(f); + return LV_RES_INV; + } + } + } + else if(dsc->src_type == LV_IMAGE_SRC_FILE) { + const char * fn = dsc->src; + if((strcmp(lv_fs_get_ext(fn), "jpg") == 0) || (strcmp(lv_fs_get_ext(fn), "jpeg") == 0)) { + lv_fs_res_t res; + res = lv_fs_open(f, fn, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + lv_free(f); + return LV_RES_INV; + } + } + } + + uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE); + JDEC * jd = lv_malloc(sizeof(JDEC)); + dsc->user_data = jd; + JRESULT rc = jd_prepare(jd, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, f); + if(rc) return rc; + + dsc->header.always_zero = 0; + dsc->header.cf = LV_COLOR_FORMAT_RGB888; + dsc->header.w = jd->width; + dsc->header.h = jd->height; + dsc->header.stride = jd->width * 3; + + if(rc != JDR_OK) { + lv_free(workb_temp); + lv_free(jd); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t 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) +{ + LV_UNUSED(decoder); + LV_UNUSED(full_area); + + JDEC * jd = dsc->user_data; + + uint32_t mx, my; + mx = jd->msx * 8; + my = jd->msy * 8; /* Size of the MCU (pixel) */ + if(decoded_area->y1 == LV_COORD_MIN) { + decoded_area->y1 = 0; + decoded_area->y2 = 7; + decoded_area->x1 = 0 - mx; + decoded_area->x2 = 7 - mx; + jd->scale = 0; + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ + dsc->img_data = jd->workbuf; + jd->rst = 0; + jd->rsc = 0; + dsc->header.stride = mx * 3; + } + + decoded_area->x1 += mx; + decoded_area->x2 += mx; + + if(decoded_area->x1 >= jd->width) { + decoded_area->x1 = 0; + decoded_area->x2 = 7; + decoded_area->y1 += my; + decoded_area->y2 += my; + } + + JRESULT rc; + if (jd->nrst && jd->rst++ == jd->nrst) { /* Process restart interval if enabled */ + rc = jd_restart(jd, jd->rsc++); + if (rc != JDR_OK) return rc; + jd->rst = 1; + } + rc = jd_mcu_load(jd); /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */ + if (rc != JDR_OK) return rc; + rc = jd_mcu_output(jd, NULL, decoded_area->x1, decoded_area->y1); /* Output the MCU (YCbCr to RGB, scaling and output) */ + if (rc != JDR_OK) return rc; + + return LV_RES_OK; +} + +/** + * Free the allocated resources + * @param decoder pointer to the decoder where this function belongs + * @param dsc pointer to a descriptor which describes this decoding session + */ +static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) +{ + LV_UNUSED(decoder); + JDEC * jd = dsc->user_data; + lv_fs_close(jd->device); + lv_free(jd->device); + lv_free(jd->pool_original); + lv_free(jd); +} + +static int is_jpg(const uint8_t * raw_data, size_t len) +{ + const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46}; + if(len < sizeof(jpg_signature)) return false; + return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0; +} + +#endif /*LV_USE_SJPG*/ diff --git a/src/libs/sjpg/lv_sjpg.h b/src/libs/jpg/lv_jpg.h similarity index 94% rename from src/libs/sjpg/lv_sjpg.h rename to src/libs/jpg/lv_jpg.h index d06e80de5..c301dca20 100644 --- a/src/libs/sjpg/lv_sjpg.h +++ b/src/libs/jpg/lv_jpg.h @@ -28,7 +28,7 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -void lv_split_jpeg_init(void); +void lv_jpeg_init(void); /********************** * MACROS diff --git a/src/libs/sjpg/tjpgd.c b/src/libs/jpg/tjpgd.c similarity index 51% rename from src/libs/sjpg/tjpgd.c rename to src/libs/jpg/tjpgd.c index 13c6f5e18..92a910744 100644 --- a/src/libs/sjpg/tjpgd.c +++ b/src/libs/jpg/tjpgd.c @@ -16,21 +16,21 @@ / Oct 04, 2011 R0.01 First release. / Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. / Sep 03, 2012 R0.01b Added JD_TBLCLIP option. -/ Mar 16, 2019 R0.01c Supported stdint.h. +/ Mar 16, 2019 R0.01c Supprted stdint.h. / Jul 01, 2020 R0.01d Fixed wrong integer type usage. -/ May 08, 2021 R0.02 Supported grayscale image. Separated configuration options. +/ May 08, 2021 R0.02 Supprted grayscale image. Separated configuration options. / Jun 11, 2021 R0.02a Some performance improvement. / Jul 01, 2021 R0.03 Added JD_FASTDECODE option. / Some performance improvement. /----------------------------------------------------------------------------*/ #include "tjpgd.h" -#if LV_USE_SJPG + #if JD_FASTDECODE == 2 - #define HUFF_BIT 10 /* Bit length to apply fast huffman decode */ - #define HUFF_LEN (1 << HUFF_BIT) - #define HUFF_MASK (HUFF_LEN - 1) +#define HUFF_BIT 10 /* Bit length to apply fast huffman decode */ +#define HUFF_LEN (1 << HUFF_BIT) +#define HUFF_MASK (HUFF_LEN - 1) #endif @@ -39,7 +39,7 @@ /*-----------------------------------------------*/ static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 @@ -53,14 +53,14 @@ static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion t /*-------------------------------------------------*/ static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ - (uint16_t)(1.00000 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(1.00000 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.27590 * 8192), - (uint16_t)(1.38704 * 8192), (uint16_t)(1.92388 * 8192), (uint16_t)(1.81226 * 8192), (uint16_t)(1.63099 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.08979 * 8192), (uint16_t)(0.75066 * 8192), (uint16_t)(0.38268 * 8192), - (uint16_t)(1.30656 * 8192), (uint16_t)(1.81226 * 8192), (uint16_t)(1.70711 * 8192), (uint16_t)(1.53636 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.02656 * 8192), (uint16_t)(0.70711 * 8192), (uint16_t)(0.36048 * 8192), - (uint16_t)(1.17588 * 8192), (uint16_t)(1.63099 * 8192), (uint16_t)(1.53636 * 8192), (uint16_t)(1.38268 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(0.92388 * 8192), (uint16_t)(0.63638 * 8192), (uint16_t)(0.32442 * 8192), - (uint16_t)(1.00000 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(1.00000 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.27590 * 8192), - (uint16_t)(0.78570 * 8192), (uint16_t)(1.08979 * 8192), (uint16_t)(1.02656 * 8192), (uint16_t)(0.92388 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.61732 * 8192), (uint16_t)(0.42522 * 8192), (uint16_t)(0.21677 * 8192), - (uint16_t)(0.54120 * 8192), (uint16_t)(0.75066 * 8192), (uint16_t)(0.70711 * 8192), (uint16_t)(0.63638 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.42522 * 8192), (uint16_t)(0.29290 * 8192), (uint16_t)(0.14932 * 8192), - (uint16_t)(0.27590 * 8192), (uint16_t)(0.38268 * 8192), (uint16_t)(0.36048 * 8192), (uint16_t)(0.32442 * 8192), (uint16_t)(0.27590 * 8192), (uint16_t)(0.21678 * 8192), (uint16_t)(0.14932 * 8192), (uint16_t)(0.07612 * 8192) + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), + (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), + (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), + (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), + (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) }; @@ -114,10 +114,10 @@ static const uint8_t Clip8[1024] = { #else /* JD_TBLCLIP */ -static uint8_t BYTECLIP(int val) +static uint8_t BYTECLIP (int val) { - if(val < 0) return 0; - if(val > 255) return 255; + if (val < 0) return 0; + if (val > 255) return 255; return (uint8_t)val; } @@ -129,23 +129,23 @@ static uint8_t BYTECLIP(int val) /* Allocate a memory block from memory pool */ /*-----------------------------------------------------------------------*/ -static void * alloc_pool( /* Pointer to allocated memory block (NULL:no memory available) */ - JDEC * jd, /* Pointer to the decompressor object */ +static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ + JDEC* jd, /* Pointer to the decompressor object */ size_t ndata /* Number of bytes to allocate */ ) { - char * rp = 0; + char *rp = 0; ndata = (ndata + 3) & ~3; /* Align block size to the word boundary */ - if(jd->sz_pool >= ndata) { + if (jd->sz_pool >= ndata) { jd->sz_pool -= ndata; - rp = (char *)jd->pool; /* Get start of available memory pool */ - jd->pool = (void *)(rp + ndata); /* Allocate required bytes */ + rp = (char*)jd->pool; /* Get start of available memory pool */ + jd->pool = (void*)(rp + ndata); /* Allocate requierd bytes */ } - return (void *)rp; /* Return allocated memory block (NULL:no memory to allocate) */ + return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ } @@ -155,29 +155,29 @@ static void * alloc_pool( /* Pointer to allocated memory block (NULL:no memory a /* Create de-quantization and prescaling tables with a DQT segment */ /*-----------------------------------------------------------------------*/ -static JRESULT create_qt_tbl( /* 0:OK, !0:Failed */ - JDEC * jd, /* Pointer to the decompressor object */ - const uint8_t * data, /* Pointer to the quantizer tables */ +static JRESULT create_qt_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the quantizer tables */ size_t ndata /* Size of input data */ ) { unsigned int i, zi; uint8_t d; - int32_t * pb; + int32_t *pb; - while(ndata) { /* Process all tables in the segment */ - if(ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ + while (ndata) { /* Process all tables in the segment */ + if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ ndata -= 65; d = *data++; /* Get table property */ - if(d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ + if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ i = d & 3; /* Get table ID */ - pb = alloc_pool(jd, 64 * sizeof(int32_t)); /* Allocate a memory block for the table */ - if(!pb) return JDR_MEM1; /* Err: not enough memory */ + pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ jd->qttbl[i] = pb; /* Register the table */ - for(i = 0; i < 64; i++) { /* Load the table */ + for (i = 0; i < 64; i++) { /* Load the table */ zi = Zig[i]; /* Zigzag-order to raster-order conversion */ - pb[zi] = (int32_t)((uint32_t) * data++ * Ipsf[zi]); /* Apply scale factor of Arai algorithm to the de-quantizers */ + pb[zi] = (int32_t)((uint32_t)*data++ * Ipsf[zi]); /* Apply scale factor of Arai algorithm to the de-quantizers */ } } @@ -191,9 +191,9 @@ static JRESULT create_qt_tbl( /* 0:OK, !0:Failed */ /* Create huffman code tables with a DHT segment */ /*-----------------------------------------------------------------------*/ -static JRESULT create_huffman_tbl( /* 0:OK, !0:Failed */ - JDEC * jd, /* Pointer to the decompressor object */ - const uint8_t * data, /* Pointer to the packed huffman tables */ +static JRESULT create_huffman_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the packed huffman tables */ size_t ndata /* Size of input data */ ) { @@ -203,67 +203,64 @@ static JRESULT create_huffman_tbl( /* 0:OK, !0:Failed */ uint16_t hc, *ph; - while(ndata) { /* Process all tables in the segment */ - if(ndata < 17) return JDR_FMT1; /* Err: wrong data size */ + while (ndata) { /* Process all tables in the segment */ + if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ ndata -= 17; d = *data++; /* Get table number and class */ - if(d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ - cls = d >> 4; - num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ + if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ + cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ - if(!pb) return JDR_MEM1; /* Err: not enough memory */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ jd->huffbits[num][cls] = pb; - for(np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ + for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ np += (pb[i] = *data++); /* Get sum of code words for each code */ } - ph = alloc_pool(jd, np * sizeof(uint16_t)); /* Allocate a memory block for the code word table */ - if(!ph) return JDR_MEM1; /* Err: not enough memory */ + ph = alloc_pool(jd, np * sizeof (uint16_t));/* Allocate a memory block for the code word table */ + if (!ph) return JDR_MEM1; /* Err: not enough memory */ jd->huffcode[num][cls] = ph; hc = 0; - for(j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ + for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ b = pb[i]; - while(b--) ph[j++] = hc++; + while (b--) ph[j++] = hc++; hc <<= 1; } - if(ndata < np) return JDR_FMT1; /* Err: wrong data size */ + if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ ndata -= np; pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ - if(!pd) return JDR_MEM1; /* Err: not enough memory */ + if (!pd) return JDR_MEM1; /* Err: not enough memory */ jd->huffdata[num][cls] = pd; - for(i = 0; i < np; i++) { /* Load decoded data corresponds to each code word */ + for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code word */ d = *data++; - if(!cls && d > 11) return JDR_FMT1; + if (!cls && d > 11) return JDR_FMT1; pd[i] = d; } #if JD_FASTDECODE == 2 - { /* Create fast huffman decode table */ + { /* Create fast huffman decode table */ unsigned int span, td, ti; - uint16_t * tbl_ac = 0; - uint8_t * tbl_dc = 0; + uint16_t *tbl_ac = 0; + uint8_t *tbl_dc = 0; - if(cls) { - tbl_ac = alloc_pool(jd, HUFF_LEN * sizeof(uint16_t)); /* LUT for AC elements */ - if(!tbl_ac) return JDR_MEM1; /* Err: not enough memory */ + if (cls) { + tbl_ac = alloc_pool(jd, HUFF_LEN * sizeof (uint16_t)); /* LUT for AC elements */ + if (!tbl_ac) return JDR_MEM1; /* Err: not enough memory */ jd->hufflut_ac[num] = tbl_ac; - memset(tbl_ac, 0xFF, HUFF_LEN * sizeof(uint16_t)); /* Default value (0xFFFF: may be long code) */ - } - else { - tbl_dc = alloc_pool(jd, HUFF_LEN * sizeof(uint8_t)); /* LUT for AC elements */ - if(!tbl_dc) return JDR_MEM1; /* Err: not enough memory */ + memset(tbl_ac, 0xFF, HUFF_LEN * sizeof (uint16_t)); /* Default value (0xFFFF: may be long code) */ + } else { + tbl_dc = alloc_pool(jd, HUFF_LEN * sizeof (uint8_t)); /* LUT for AC elements */ + if (!tbl_dc) return JDR_MEM1; /* Err: not enough memory */ jd->hufflut_dc[num] = tbl_dc; - memset(tbl_dc, 0xFF, HUFF_LEN * sizeof(uint8_t)); /* Default value (0xFF: may be long code) */ + memset(tbl_dc, 0xFF, HUFF_LEN * sizeof (uint8_t)); /* Default value (0xFF: may be long code) */ } - for(i = b = 0; b < HUFF_BIT; b++) { /* Create LUT */ - for(j = pb[b]; j; j--) { + for (i = b = 0; b < HUFF_BIT; b++) { /* Create LUT */ + for (j = pb[b]; j; j--) { ti = ph[i] << (HUFF_BIT - 1 - b) & HUFF_MASK; /* Index of input pattern for the code */ - if(cls) { + if (cls) { td = pd[i++] | ((b + 1) << 8); /* b15..b8: code length, b7..b0: zero run and data length */ - for(span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_ac[ti++] = (uint16_t)td) ; - } - else { + for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_ac[ti++] = (uint16_t)td) ; + } else { td = pd[i++] | ((b + 1) << 4); /* b7..b4: code length, b3..b0: data length */ - for(span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_dc[ti++] = (uint8_t)td) ; + for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_dc[ti++] = (uint8_t)td) ; } } } @@ -282,145 +279,133 @@ static JRESULT create_huffman_tbl( /* 0:OK, !0:Failed */ /* Extract a huffman decoded data from input stream */ /*-----------------------------------------------------------------------*/ -static int huffext( /* >=0: decoded data, <0: error code */ - JDEC * jd, /* Pointer to the decompressor object */ +static int huffext ( /* >=0: decoded data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ unsigned int id, /* Table ID (0:Y, 1:C) */ unsigned int cls /* Table class (0:DC, 1:AC) */ ) { size_t dc = jd->dctr; - uint8_t * dp = jd->dptr; + uint8_t *dp = jd->dptr; unsigned int d, flg = 0; #if JD_FASTDECODE == 0 uint8_t bm, nd, bl; - const uint8_t * hb = jd->huffbits[id][cls]; /* Bit distribution table */ - const uint16_t * hc = jd->huffcode[id][cls]; /* Code word table */ - const uint8_t * hd = jd->huffdata[id][cls]; /* Data table */ + const uint8_t *hb = jd->huffbits[id][cls]; /* Bit distribution table */ + const uint16_t *hc = jd->huffcode[id][cls]; /* Code word table */ + const uint8_t *hd = jd->huffdata[id][cls]; /* Data table */ bm = jd->dbit; /* Bit mask to extract */ - d = 0; - bl = 16; /* Max code length */ + d = 0; bl = 16; /* Max code length */ do { - if(!bm) { /* Next byte? */ - if(!dc) { /* No input data is available, re-fill input buffer */ + if (!bm) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ dp = jd->inbuf; /* Top of input buffer */ dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ - } - else { + if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ + } else { dp++; /* Next data ptr */ } dc--; /* Decrement number of available bytes */ - if(flg) { /* In flag sequence? */ + if (flg) { /* In flag sequence? */ flg = 0; /* Exit flag sequence */ - if(*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + if (*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ *dp = 0xFF; /* The flag is a data 0xFF */ - } - else { - if(*dp == 0xFF) { /* Is start of flag sequence? */ - flg = 1; - continue; /* Enter flag sequence, get trailing byte */ + } else { + if (*dp == 0xFF) { /* Is start of flag sequence? */ + flg = 1; continue; /* Enter flag sequence, get trailing byte */ } } bm = 0x80; /* Read from MSB */ } d <<= 1; /* Get a bit */ - if(*dp & bm) d++; + if (*dp & bm) d++; bm >>= 1; - for(nd = *hb++; nd; nd--) { /* Search the code word in this bit length */ - if(d == *hc++) { /* Matched? */ - jd->dbit = bm; - jd->dctr = dc; - jd->dptr = dp; + for (nd = *hb++; nd; nd--) { /* Search the code word in this bit length */ + if (d == *hc++) { /* Matched? */ + jd->dbit = bm; jd->dctr = dc; jd->dptr = dp; return *hd; /* Return the decoded data */ } hd++; } bl--; - } while(bl); + } while (bl); #else - const uint8_t * hb, *hd; - const uint16_t * hc; + const uint8_t *hb, *hd; + const uint16_t *hc; unsigned int nc, bl, wbit = jd->dbit % 32; uint32_t w = jd->wreg & ((1UL << wbit) - 1); - while(wbit < 16) { /* Prepare 16 bits into the working register */ - if(jd->marker) { + while (wbit < 16) { /* Prepare 16 bits into the working register */ + if (jd->marker) { d = 0xFF; /* Input stream has stalled for a marker. Generate stuff bits */ - } - else { - if(!dc) { /* Buffer empty, re-fill input buffer */ + } else { + if (!dc) { /* Buffer empty, re-fill input buffer */ dp = jd->inbuf; /* Top of input buffer */ dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ + if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ } - d = *dp++; - dc--; - if(flg) { /* In flag sequence? */ + d = *dp++; dc--; + if (flg) { /* In flag sequence? */ flg = 0; /* Exit flag sequence */ - if(d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ + if (d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ d = 0xFF; - } - else { - if(d == 0xFF) { /* Is start of flag sequence? */ - flg = 1; - continue; /* Enter flag sequence, get trailing byte */ + } else { + if (d == 0xFF) { /* Is start of flag sequence? */ + flg = 1; continue; /* Enter flag sequence, get trailing byte */ } } } w = w << 8 | d; /* Shift 8 bits in the working register */ wbit += 8; } - jd->dctr = dc; - jd->dptr = dp; + jd->dctr = dc; jd->dptr = dp; jd->wreg = w; #if JD_FASTDECODE == 2 - /* Table search for the short codes */ + /* Table serch for the short codes */ d = (unsigned int)(w >> (wbit - HUFF_BIT)); /* Short code as table index */ - if(cls) { /* AC element */ + if (cls) { /* AC element */ d = jd->hufflut_ac[id][d]; /* Table decode */ - if(d != 0xFFFF) { /* It is done if hit in short code */ + if (d != 0xFFFF) { /* It is done if hit in short code */ jd->dbit = wbit - (d >> 8); /* Snip the code length */ return d & 0xFF; /* b7..0: zero run and following data bits */ } - } - else { /* DC element */ + } else { /* DC element */ d = jd->hufflut_dc[id][d]; /* Table decode */ - if(d != 0xFF) { /* It is done if hit in short code */ + if (d != 0xFF) { /* It is done if hit in short code */ jd->dbit = wbit - (d >> 4); /* Snip the code length */ return d & 0xF; /* b3..0: following data bits */ } } - /* Incremental search for the codes longer than HUFF_BIT */ + /* Incremental serch for the codes longer than HUFF_BIT */ hb = jd->huffbits[id][cls] + HUFF_BIT; /* Bit distribution table */ hc = jd->huffcode[id][cls] + jd->longofs[id][cls]; /* Code word table */ hd = jd->huffdata[id][cls] + jd->longofs[id][cls]; /* Data table */ bl = HUFF_BIT + 1; #else - /* Incremental search for all codes */ + /* Incremental serch for all codes */ hb = jd->huffbits[id][cls]; /* Bit distribution table */ hc = jd->huffcode[id][cls]; /* Code word table */ hd = jd->huffdata[id][cls]; /* Data table */ bl = 1; #endif - for(; bl <= 16; bl++) { /* Incremental search */ + for ( ; bl <= 16; bl++) { /* Incremental search */ nc = *hb++; - if(nc) { + if (nc) { d = w >> (wbit - bl); do { /* Search the code word in this bit length */ - if(d == *hc++) { /* Matched? */ + if (d == *hc++) { /* Matched? */ jd->dbit = wbit - bl; /* Snip the huffman code */ return *hd; /* Return the decoded data */ } hd++; - } while(--nc); + } while (--nc); } } #endif @@ -435,13 +420,13 @@ static int huffext( /* >=0: decoded data, <0: error code */ /* Extract N bits from input stream */ /*-----------------------------------------------------------------------*/ -static int bitext( /* >=0: extracted data, <0: error code */ - JDEC * jd, /* Pointer to the decompressor object */ +static int bitext ( /* >=0: extracted data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ unsigned int nbit /* Number of bits to extract (1 to 16) */ ) { size_t dc = jd->dctr; - uint8_t * dp = jd->dptr; + uint8_t *dp = jd->dptr; unsigned int d, flg = 0; #if JD_FASTDECODE == 0 @@ -449,38 +434,33 @@ static int bitext( /* >=0: extracted data, <0: error code */ d = 0; do { - if(!mbit) { /* Next byte? */ - if(!dc) { /* No input data is available, re-fill input buffer */ + if (!mbit) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ dp = jd->inbuf; /* Top of input buffer */ dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ - } - else { + if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ + } else { dp++; /* Next data ptr */ } dc--; /* Decrement number of available bytes */ - if(flg) { /* In flag sequence? */ + if (flg) { /* In flag sequence? */ flg = 0; /* Exit flag sequence */ - if(*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + if (*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ *dp = 0xFF; /* The flag is a data 0xFF */ - } - else { - if(*dp == 0xFF) { /* Is start of flag sequence? */ - flg = 1; - continue; /* Enter flag sequence */ + } else { + if (*dp == 0xFF) { /* Is start of flag sequence? */ + flg = 1; continue; /* Enter flag sequence */ } } mbit = 0x80; /* Read from MSB */ } d <<= 1; /* Get a bit */ - if(*dp & mbit) d |= 1; + if (*dp & mbit) d |= 1; mbit >>= 1; nbit--; - } while(nbit); + } while (nbit); - jd->dbit = mbit; - jd->dctr = dc; - jd->dptr = dp; + jd->dbit = mbit; jd->dctr = dc; jd->dptr = dp; return (int)d; #else @@ -488,37 +468,31 @@ static int bitext( /* >=0: extracted data, <0: error code */ uint32_t w = jd->wreg & ((1UL << wbit) - 1); - while(wbit < nbit) { /* Prepare nbit bits into the working register */ - if(jd->marker) { + while (wbit < nbit) { /* Prepare nbit bits into the working register */ + if (jd->marker) { d = 0xFF; /* Input stream stalled, generate stuff bits */ - } - else { - if(!dc) { /* Buffer empty, re-fill input buffer */ + } else { + if (!dc) { /* Buffer empty, re-fill input buffer */ dp = jd->inbuf; /* Top of input buffer */ dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ + if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ } - d = *dp++; - dc--; - if(flg) { /* In flag sequence? */ + d = *dp++; dc--; + if (flg) { /* In flag sequence? */ flg = 0; /* Exit flag sequence */ - if(d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ + if (d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ d = 0xFF; - } - else { - if(d == 0xFF) { /* Is start of flag sequence? */ - flg = 1; - continue; /* Enter flag sequence, get trailing byte */ + } else { + if (d == 0xFF) { /* Is start of flag sequence? */ + flg = 1; continue; /* Enter flag sequence, get trailing byte */ } } } w = w << 8 | d; /* Get 8 bits into the working register */ wbit += 8; } - jd->wreg = w; - jd->dbit = wbit - nbit; - jd->dctr = dc; - jd->dptr = dp; + jd->wreg = w; jd->dbit = wbit - nbit; + jd->dctr = dc; jd->dptr = dp; return (int)(w >> ((wbit - nbit) % 32)); #endif @@ -531,37 +505,34 @@ static int bitext( /* >=0: extracted data, <0: error code */ /* Process restart interval */ /*-----------------------------------------------------------------------*/ -static JRESULT restart( - JDEC * jd, /* Pointer to the decompressor object */ - uint16_t rstn /* Expected restert sequence number */ +JRESULT jd_restart ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t rstn /* Expected restert sequense number */ ) { unsigned int i; - uint8_t * dp = jd->dptr; + uint8_t *dp = jd->dptr; size_t dc = jd->dctr; #if JD_FASTDECODE == 0 uint16_t d = 0; /* Get two bytes from the input stream */ - for(i = 0; i < 2; i++) { - if(!dc) { /* No input data is available, re-fill input buffer */ + for (i = 0; i < 2; i++) { + if (!dc) { /* No input data is available, re-fill input buffer */ dp = jd->inbuf; dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return JDR_INP; - } - else { + if (!dc) return JDR_INP; + } else { dp++; } dc--; d = d << 8 | *dp; /* Get a byte */ } - jd->dptr = dp; - jd->dctr = dc; - jd->dbit = 0; + jd->dptr = dp; jd->dctr = dc; jd->dbit = 0; /* Check the marker */ - if((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { + if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ } @@ -569,27 +540,25 @@ static JRESULT restart( uint16_t marker; - if(jd->marker) { /* Generate a maker if it has been detected */ + if (jd->marker) { /* Generate a maker if it has been detected */ marker = 0xFF00 | jd->marker; jd->marker = 0; - } - else { + } else { marker = 0; - for(i = 0; i < 2; i++) { /* Get a restart marker */ - if(!dc) { /* No input data is available, re-fill input buffer */ + for (i = 0; i < 2; i++) { /* Get a restart marker */ + if (!dc) { /* No input data is available, re-fill input buffer */ dp = jd->inbuf; dc = jd->infunc(jd, dp, JD_SZBUF); - if(!dc) return JDR_INP; + if (!dc) return JDR_INP; } marker = (marker << 8) | *dp++; /* Get a byte */ dc--; } - jd->dptr = dp; - jd->dctr = dc; + jd->dptr = dp; jd->dctr = dc; } /* Check the marker */ - if((marker & 0xFFD8) != 0xFFD0 || (marker & 7) != (rstn & 7)) { + if ((marker & 0xFFD8) != 0xFFD0 || (marker & 7) != (rstn & 7)) { return JDR_FMT1; /* Err: expected RSTn marker was not detected (may be collapted data) */ } @@ -607,19 +576,18 @@ static JRESULT restart( /* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ /*-----------------------------------------------------------------------*/ -static void block_idct( - int32_t * src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ - jd_yuv_t * dst /* Pointer to the destination to store the block as byte array */ +static void block_idct ( + int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ + jd_yuv_t* dst /* Pointer to the destination to store the block as byte array */ ) { - const int32_t M13 = (int32_t)(1.41421 * 4096), M2 = (int32_t)(1.08239 * 4096), M4 = (int32_t)(2.61313 * 4096), - M5 = (int32_t)(1.84776 * 4096); + const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); int32_t v0, v1, v2, v3, v4, v5, v6, v7; int32_t t10, t11, t12, t13; int i; /* Process columns */ - for(i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { v0 = src[8 * 0]; /* Get even elements */ v1 = src[8 * 2]; v2 = src[8 * 4]; @@ -666,7 +634,7 @@ static void block_idct( /* Process rows */ src -= 8; - for(i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ v1 = src[2]; v2 = src[4]; @@ -720,8 +688,7 @@ static void block_idct( dst[4] = BYTECLIP((v3 - v4) >> 8); #endif - dst += 8; - src += 8; /* Next row */ + dst += 8; src += 8; /* Next row */ } } @@ -732,40 +699,39 @@ static void block_idct( /* Load all blocks in an MCU into working buffer */ /*-----------------------------------------------------------------------*/ -static JRESULT mcu_load( - JDEC * jd /* Pointer to the decompressor object */ +JRESULT jd_mcu_load ( + JDEC* jd /* Pointer to the decompressor object */ ) { - int32_t * tmp = (int32_t *)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ + int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ int d, e; unsigned int blk, nby, i, bc, z, id, cmp; - jd_yuv_t * bp; - const int32_t * dqf; + jd_yuv_t *bp; + const int32_t *dqf; nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ bp = jd->mcubuf; /* Pointer to the first block of MCU */ - for(blk = 0; blk < nby + 2; blk++) { /* Get nby Y blocks and two C blocks */ + for (blk = 0; blk < nby + 2; blk++) { /* Get nby Y blocks and two C blocks */ cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ - if(cmp && jd->ncomp != 3) { /* Clear C blocks if not exist (monochrome image) */ - for(i = 0; i < 64; bp[i++] = 128) ; + if (cmp && jd->ncomp != 3) { /* Clear C blocks if not exist (monochrome image) */ + for (i = 0; i < 64; bp[i++] = 128) ; - } - else { /* Load Y/C blocks from input stream */ + } else { /* Load Y/C blocks from input stream */ id = cmp ? 1 : 0; /* Huffman table ID of this component */ /* Extract a DC element from input stream */ d = huffext(jd, id, 0); /* Extract a huffman coded data (bit length) */ - if(d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input */ + if (d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input */ bc = (unsigned int)d; d = jd->dcv[cmp]; /* DC value of previous block */ - if(bc) { /* If there is any difference from previous block */ + if (bc) { /* If there is any difference from previous block */ e = bitext(jd, bc); /* Extract data bits */ - if(e < 0) return (JRESULT)(0 - e); /* Err: input */ + if (e < 0) return (JRESULT)(0 - e); /* Err: input */ bc = 1 << (bc - 1); /* MSB position */ - if(!(e & bc)) e -= (bc << 1) - 1; /* Restore negative value if needed */ + if (!(e & bc)) e -= (bc << 1) - 1; /* Restore negative value if needed */ d += e; /* Get current value */ jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ } @@ -773,38 +739,34 @@ static JRESULT mcu_load( tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ /* Extract following 63 AC elements from input stream */ - memset(&tmp[1], 0, 63 * sizeof(int32_t)); /* Initialize all AC elements */ + memset(&tmp[1], 0, 63 * sizeof (int32_t)); /* Initialize all AC elements */ z = 1; /* Top of the AC elements (in zigzag-order) */ do { d = huffext(jd, id, 1); /* Extract a huffman coded value (zero runs and bit length) */ - if(d == 0) break; /* EOB? */ - if(d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input error */ + if (d == 0) break; /* EOB? */ + if (d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input error */ bc = (unsigned int)d; z += bc >> 4; /* Skip leading zero run */ - if(z >= 64) return JDR_FMT1; /* Too long zero run */ - if(bc &= 0x0F) { /* Bit length? */ + if (z >= 64) return JDR_FMT1; /* Too long zero run */ + if (bc &= 0x0F) { /* Bit length? */ d = bitext(jd, bc); /* Extract data bits */ - if(d < 0) return (JRESULT)(0 - d); /* Err: input device */ + if (d < 0) return (JRESULT)(0 - d); /* Err: input device */ bc = 1 << (bc - 1); /* MSB position */ - if(!(d & bc)) d -= (bc << 1) - 1; /* Restore negative value if needed */ + if (!(d & bc)) d -= (bc << 1) - 1; /* Restore negative value if needed */ i = Zig[z]; /* Get raster-order index */ tmp[i] = d * dqf[i] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ } - } while(++z < 64); /* Next AC element */ + } while (++z < 64); /* Next AC element */ - if(JD_FORMAT != 2 || !cmp) { /* C components may not be processed if in grayscale output */ - if(z == 1 || (JD_USE_SCALE && - jd->scale == - 3)) { /* If no AC element or scale ratio is 1/8, IDCT can be omitted and the block is filled with DC value */ + if (JD_FORMAT != 2 || !cmp) { /* C components may not be processed if in grayscale output */ + if (z == 1 || (JD_USE_SCALE && jd->scale == 3)) { /* If no AC element or scale ratio is 1/8, IDCT can be ommited and the block is filled with DC value */ d = (jd_yuv_t)((*tmp / 256) + 128); - if(JD_FASTDECODE >= 1) { - for(i = 0; i < 64; bp[i++] = d) ; - } - else { + if (JD_FASTDECODE >= 1) { + for (i = 0; i < 64; bp[i++] = d) ; + } else { memset(bp, d, 64); } - } - else { + } else { block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ } } @@ -823,139 +785,59 @@ static JRESULT mcu_load( /* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ /*-----------------------------------------------------------------------*/ -static JRESULT mcu_output( - JDEC * jd, /* Pointer to the decompressor object */ - int (*outfunc)(JDEC *, void *, JRECT *), /* RGB output function */ - unsigned int img_x, /* MCU location in the image */ - unsigned int img_y /* MCU location in the image */ +JRESULT jd_mcu_output ( + JDEC* jd, /* Pointer to the decompressor object */ + int (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + unsigned int x, /* MCU location in the image */ + unsigned int y /* MCU location in the image */ ) { - const int CVACC = (sizeof(int) > 2) ? 1024 : 128; /* Adaptive accuracy for both 16-/32-bit systems */ + const int CVACC = (sizeof (int) > 2) ? 1024 : 128; /* Adaptive accuracy for both 16-/32-bit systems */ unsigned int ix, iy, mx, my, rx, ry; int yy, cb, cr; - jd_yuv_t * py, *pc; - uint8_t * pix; + jd_yuv_t *py, *pc; + uint8_t *pix; JRECT rect; - mx = jd->msx * 8; - my = jd->msy * 8; /* MCU size (pixel) */ - rx = (img_x + mx <= jd->width) ? mx : jd->width - - img_x; /* Output rectangular size (it may be clipped at right/bottom end of image) */ - ry = (img_y + my <= jd->height) ? my : jd->height - img_y; - if(JD_USE_SCALE) { - rx >>= jd->scale; - ry >>= jd->scale; - if(!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ - img_x >>= jd->scale; - img_y >>= jd->scale; + mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ + rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end of image) */ + ry = (y + my <= jd->height) ? my : jd->height - y; + if (JD_USE_SCALE) { + rx >>= jd->scale; ry >>= jd->scale; + if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ + x >>= jd->scale; y >>= jd->scale; } - rect.left = img_x; - rect.right = img_x + rx - 1; /* Rectangular area in the frame buffer */ - rect.top = img_y; - rect.bottom = img_y + ry - 1; + rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ + rect.top = y; rect.bottom = y + ry - 1; - if(!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ - pix = (uint8_t *)jd->workbuf; + if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ + pix = (uint8_t*)jd->workbuf; - if(JD_FORMAT != 2) { /* RGB output (build an RGB MCU from Y/C component) */ - for(iy = 0; iy < my; iy++) { + if (JD_FORMAT != 2) { /* RGB output (build an RGB MCU from Y/C component) */ + for (iy = 0; iy < my; iy++) { pc = py = jd->mcubuf; - if(my == 16) { /* Double block height? */ + if (my == 16) { /* Double block height? */ pc += 64 * 4 + (iy >> 1) * 8; - if(iy >= 8) py += 64; - } - else { /* Single block height */ + if (iy >= 8) py += 64; + } else { /* Single block height */ pc += mx * 8 + iy * 8; } py += iy * 8; - for(ix = 0; ix < mx; ix++) { + for (ix = 0; ix < mx; ix++) { cb = pc[0] - 128; /* Get Cb/Cr component and remove offset */ cr = pc[64] - 128; - if(mx == 16) { /* Double block width? */ - if(ix == 8) py += 64 - 8; /* Jump to next block if double block height */ + if (mx == 16) { /* Double block width? */ + if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ pc += ix & 1; /* Step forward chroma pointer every two pixels */ - } - else { /* Single block width */ + } else { /* Single block width */ pc++; /* Step forward chroma pointer every pixel */ } yy = *py++; /* Get Y component */ - *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr) / CVACC); - *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC); *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb) / CVACC); - } - } - } - else { /* Monochrome output (build a grayscale MCU from Y comopnent) */ - for(iy = 0; iy < my; iy++) { - py = jd->mcubuf + iy * 8; - if(my == 16) { /* Double block height? */ - if(iy >= 8) py += 64; - } - for(ix = 0; ix < mx; ix++) { - if(mx == 16) { /* Double block width? */ - if(ix == 8) py += 64 - 8; /* Jump to next block if double block height */ - } - *pix++ = (uint8_t) * py++; /* Get and store a Y value as grayscale */ - } - } - } - - /* Descale the MCU rectangular if needed */ - if(JD_USE_SCALE && jd->scale) { - unsigned int x, y, r, g, b, s, w, a; - uint8_t * op; - - /* Get averaged RGB value of each square corresponds to a pixel */ - s = jd->scale * 2; /* Number of shifts for averaging */ - w = 1 << jd->scale; /* Width of square */ - a = (mx - w) * (JD_FORMAT != 2 ? 3 : 1); /* Bytes to skip for next line in the square */ - op = (uint8_t *)jd->workbuf; - for(iy = 0; iy < my; iy += w) { - for(ix = 0; ix < mx; ix += w) { - pix = (uint8_t *)jd->workbuf + (iy * mx + ix) * (JD_FORMAT != 2 ? 3 : 1); - r = g = b = 0; - for(y = 0; y < w; y++) { /* Accumulate RGB value in the square */ - for(x = 0; x < w; x++) { - r += *pix++; /* Accumulate R or Y (monochrome output) */ - if(JD_FORMAT != 2) { /* RGB output? */ - g += *pix++; /* Accumulate G */ - b += *pix++; /* Accumulate B */ - } - } - pix += a; - } /* Put the averaged pixel value */ - *op++ = (uint8_t)(r >> s); /* Put R or Y (monochrome output) */ - if(JD_FORMAT != 2) { /* RGB output? */ - *op++ = (uint8_t)(g >> s); /* Put G */ - *op++ = (uint8_t)(b >> s); /* Put B */ - } - } - } - } - - } - else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ - - /* Build a 1/8 descaled RGB MCU from discrete comopnents */ - pix = (uint8_t *)jd->workbuf; - pc = jd->mcubuf + mx * my; - cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ - cr = pc[64] - 128; - for(iy = 0; iy < my; iy += 8) { - py = jd->mcubuf; - if(iy == 8) py += 64 * 2; - for(ix = 0; ix < mx; ix += 8) { - yy = *py; /* Get Y component */ - py += 64; - if(JD_FORMAT != 2) { - *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr / CVACC)); *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC); - *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb / CVACC)); - } - else { - *pix++ = yy; + *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr) / CVACC); } } } @@ -963,15 +845,15 @@ static JRESULT mcu_output( /* Squeeze up pixel table if a part of MCU is to be truncated */ mx >>= jd->scale; - if(rx < mx) { /* Is the MCU spans rigit edge? */ - uint8_t * s, *d; - unsigned int x, y; + if (rx < mx) { /* Is the MCU spans rigit edge? */ + uint8_t *s, *d; + unsigned int xi, yi; - s = d = (uint8_t *)jd->workbuf; - for(y = 0; y < ry; y++) { - for(x = 0; x < rx; x++) { /* Copy effective pixels */ + s = d = (uint8_t*)jd->workbuf; + for (yi = 0; yi < ry; yi++) { + for (xi = 0; xi < rx; xi++) { /* Copy effective pixels */ *d++ = *s++; - if(JD_FORMAT != 2) { + if (JD_FORMAT != 2) { *d++ = *s++; *d++ = *s++; } @@ -981,9 +863,9 @@ static JRESULT mcu_output( } /* Convert RGB888 to RGB565 if needed */ - if(JD_FORMAT == 1) { - uint8_t * s = (uint8_t *)jd->workbuf; - uint16_t w, *d = (uint16_t *)s; + if (JD_FORMAT == 1) { + uint8_t *s = (uint8_t*)jd->workbuf; + uint16_t w, *d = (uint16_t*)s; unsigned int n = rx * ry; do { @@ -991,11 +873,12 @@ static JRESULT mcu_output( w |= (*s++ & 0xFC) << 3; /* -----GGGGGG----- */ w |= *s++ >> 3; /* -----------BBBBB */ *d++ = w; - } while(--n); + } while (--n); } /* Output the rectangular */ - return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; + if(outfunc) return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; + return 0; } @@ -1008,155 +891,152 @@ static JRESULT mcu_output( #define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) -JRESULT jd_prepare( - JDEC * jd, /* Blank decompressor object */ - size_t (*infunc)(JDEC *, uint8_t *, size_t), /* JPEG stream input function */ - void * pool, /* Working buffer for the decompression session */ +JRESULT jd_prepare ( + JDEC* jd, /* Blank decompressor object */ + size_t (*infunc)(JDEC*, uint8_t*, size_t), /* JPEG strem input function */ + void* pool, /* Working buffer for the decompression session */ size_t sz_pool, /* Size of working buffer */ - void * dev /* I/O device identifier for the session */ + void* dev /* I/O device identifier for the session */ ) { - uint8_t * seg, b; + uint8_t *seg, b; uint16_t marker; unsigned int n, i, ofs; size_t len; JRESULT rc; - memset(jd, 0, sizeof( - JDEC)); /* Clear decompression object (this might be a problem if machine's null pointer is not all bits zero) */ - jd->pool = pool; /* Work memory */ + memset(jd, 0, sizeof (JDEC)); /* Clear decompression object (this might be a problem if machine's null pointer is not all bits zero) */ + jd->pool = pool; /* Work memroy */ + jd->pool_original = pool; jd->sz_pool = sz_pool; /* Size of given work memory */ jd->infunc = infunc; /* Stream input function */ jd->device = dev; /* I/O device identifier */ jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ - if(!seg) return JDR_MEM1; + if (!seg) return JDR_MEM1; ofs = marker = 0; /* Find SOI marker */ do { - if(jd->infunc(jd, seg, 1) != 1) return JDR_INP; /* Err: SOI was not detected */ + if (jd->infunc(jd, seg, 1) != 1) return JDR_INP; /* Err: SOI was not detected */ ofs++; marker = marker << 8 | seg[0]; - } while(marker != 0xFFD8); + } while (marker != 0xFFD8); - for(;;) { /* Parse JPEG segments */ + for (;;) { /* Parse JPEG segments */ /* Get a JPEG marker */ - if(jd->infunc(jd, seg, 4) != 4) return JDR_INP; + if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; marker = LDB_WORD(seg); /* Marker */ len = LDB_WORD(seg + 2); /* Length field */ - if(len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; + if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; len -= 2; /* Segent content size */ ofs += 4 + len; /* Number of bytes loaded */ - switch(marker & 0xFF) { - case 0xC0: /* SOF0 (baseline JPEG) */ - if(len > JD_SZBUF) return JDR_MEM2; - if(jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ + switch (marker & 0xFF) { + case 0xC0: /* SOF0 (baseline JPEG) */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ - jd->width = LDB_WORD(&seg[3]); /* Image width in unit of pixel */ - jd->height = LDB_WORD(&seg[1]); /* Image height in unit of pixel */ - jd->ncomp = seg[5]; /* Number of color components */ - if(jd->ncomp != 3 && jd->ncomp != 1) return JDR_FMT3; /* Err: Supports only Grayscale and Y/Cb/Cr */ + jd->width = LDB_WORD(&seg[3]); /* Image width in unit of pixel */ + jd->height = LDB_WORD(&seg[1]); /* Image height in unit of pixel */ + jd->ncomp = seg[5]; /* Number of color components */ + if (jd->ncomp != 3 && jd->ncomp != 1) return JDR_FMT3; /* Err: Supports only Grayscale and Y/Cb/Cr */ - /* Check each image component */ - for(i = 0; i < jd->ncomp; i++) { - b = seg[7 + 3 * i]; /* Get sampling factor */ - if(i == 0) { /* Y component */ - if(b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ - return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ - } - jd->msx = b >> 4; - jd->msy = b & 15; /* Size of MCU [blocks] */ + /* Check each image component */ + for (i = 0; i < jd->ncomp; i++) { + b = seg[7 + 3 * i]; /* Get sampling factor */ + if (i == 0) { /* Y component */ + if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ + return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ } - else { /* Cb/Cr component */ - if(b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cb/Cr must be 1 */ - } - jd->qtid[i] = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ - if(jd->qtid[i] > 3) return JDR_FMT3; /* Err: Invalid ID */ + jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ + } else { /* Cb/Cr component */ + if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cb/Cr must be 1 */ } - break; + jd->qtid[i] = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ + if (jd->qtid[i] > 3) return JDR_FMT3; /* Err: Invalid ID */ + } + break; - case 0xDD: /* DRI - Define Restart Interval */ - if(len > JD_SZBUF) return JDR_MEM2; - if(jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ + case 0xDD: /* DRI - Define Restart Interval */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ - jd->nrst = LDB_WORD(seg); /* Get restart interval (MCUs) */ - break; + jd->nrst = LDB_WORD(seg); /* Get restart interval (MCUs) */ + break; - case 0xC4: /* DHT - Define Huffman Tables */ - if(len > JD_SZBUF) return JDR_MEM2; - if(jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ + case 0xC4: /* DHT - Define Huffman Tables */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ - rc = create_huffman_tbl(jd, seg, len); /* Create huffman tables */ - if(rc) return rc; - break; + rc = create_huffman_tbl(jd, seg, len); /* Create huffman tables */ + if (rc) return rc; + break; - case 0xDB: /* DQT - Define Quaitizer Tables */ - if(len > JD_SZBUF) return JDR_MEM2; - if(jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ + case 0xDB: /* DQT - Define Quaitizer Tables */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ - rc = create_qt_tbl(jd, seg, len); /* Create de-quantizer tables */ - if(rc) return rc; - break; + rc = create_qt_tbl(jd, seg, len); /* Create de-quantizer tables */ + if (rc) return rc; + break; - case 0xDA: /* SOS - Start of Scan */ - if(len > JD_SZBUF) return JDR_MEM2; - if(jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ + case 0xDA: /* SOS - Start of Scan */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ - if(!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ - if(seg[0] != jd->ncomp) return JDR_FMT3; /* Err: Wrong color components */ + if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ + if (seg[0] != jd->ncomp) return JDR_FMT3; /* Err: Wrong color components */ - /* Check if all tables corresponding to each components have been loaded */ - for(i = 0; i < jd->ncomp; i++) { - b = seg[2 + 2 * i]; /* Get huffman table ID */ - if(b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ - n = i ? 1 : 0; /* Component class */ - if(!jd->huffbits[n][0] || !jd->huffbits[n][1]) { /* Check huffman table for this component */ - return JDR_FMT1; /* Err: Nnot loaded */ - } - if(!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ - return JDR_FMT1; /* Err: Not loaded */ - } + /* Check if all tables corresponding to each components have been loaded */ + for (i = 0; i < jd->ncomp; i++) { + b = seg[2 + 2 * i]; /* Get huffman table ID */ + if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ + n = i ? 1 : 0; /* Component class */ + if (!jd->huffbits[n][0] || !jd->huffbits[n][1]) { /* Check huffman table for this component */ + return JDR_FMT1; /* Err: Nnot loaded */ } - - /* Allocate working buffer for MCU and pixel output */ - n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ - if(!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ - len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ - if(len < 256) len = 256; /* but at least 256 byte is required for IDCT */ - jd->workbuf = alloc_pool(jd, - len); /* and it may occupy a part of following MCU working buffer for RGB output */ - if(!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ - jd->mcubuf = alloc_pool(jd, (n + 2) * 64 * sizeof(jd_yuv_t)); /* Allocate MCU working buffer */ - if(!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ - - /* Align stream read offset to JD_SZBUF */ - if(ofs %= JD_SZBUF) { - jd->dctr = jd->infunc(jd, seg + ofs, (size_t)(JD_SZBUF - ofs)); + if (!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ + return JDR_FMT1; /* Err: Not loaded */ } - jd->dptr = seg + ofs - (JD_FASTDECODE ? 0 : 1); + } - return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ + /* Allocate working buffer for MCU and pixel output */ + n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ + if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ + len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ + if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ + jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ + if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ + jd->mcubuf = alloc_pool(jd, (n + 2) * 64 * sizeof (jd_yuv_t)); /* Allocate MCU working buffer */ + if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ - case 0xC1: /* SOF1 */ - case 0xC2: /* SOF2 */ - case 0xC3: /* SOF3 */ - case 0xC5: /* SOF5 */ - case 0xC6: /* SOF6 */ - case 0xC7: /* SOF7 */ - case 0xC9: /* SOF9 */ - case 0xCA: /* SOF10 */ - case 0xCB: /* SOF11 */ - case 0xCD: /* SOF13 */ - case 0xCE: /* SOF14 */ - case 0xCF: /* SOF15 */ - case 0xD9: /* EOI */ - return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ + /* Align stream read offset to JD_SZBUF */ + if (ofs %= JD_SZBUF) { + jd->dctr = jd->infunc(jd, seg + ofs, (size_t)(JD_SZBUF - ofs)); + } + jd->dptr = seg + ofs - (JD_FASTDECODE ? 0 : 1); - default: /* Unknown segment (comment, exif or etc..) */ - /* Skip segment data (null pointer specifies to remove data from the stream) */ - if(jd->infunc(jd, 0, len) != len) return JDR_INP; + return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ + + case 0xC1: /* SOF1 */ + case 0xC2: /* SOF2 */ + case 0xC3: /* SOF3 */ + case 0xC5: /* SOF5 */ + case 0xC6: /* SOF6 */ + case 0xC7: /* SOF7 */ + case 0xC9: /* SOF9 */ + case 0xCA: /* SOF10 */ + case 0xCB: /* SOF11 */ + case 0xCD: /* SOF13 */ + case 0xCE: /* SOF14 */ + case 0xCF: /* SOF15 */ + case 0xD9: /* EOI */ + return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ + + default: /* Unknown segment (comment, exif or etc..) */ + /* Skip segment data (null pointer specifies to remove data from the stream) */ + if (jd->infunc(jd, 0, len) != len) return JDR_INP; } } } @@ -1168,9 +1048,9 @@ JRESULT jd_prepare( /* Start to decompress the JPEG picture */ /*-----------------------------------------------------------------------*/ -JRESULT jd_decomp( - JDEC * jd, /* Initialized decompression object */ - int (*outfunc)(JDEC *, void *, JRECT *), /* RGB output function */ +JRESULT jd_decomp ( + JDEC* jd, /* Initialized decompression object */ + int (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ uint8_t scale /* Output de-scaling factor (0 to 3) */ ) { @@ -1179,31 +1059,28 @@ JRESULT jd_decomp( JRESULT rc; - if(scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; + if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; jd->scale = scale; - mx = jd->msx * 8; - my = jd->msy * 8; /* Size of the MCU (pixel) */ + mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ rst = rsc = 0; rc = JDR_OK; - for(y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ - for(x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ - if(jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ - rc = restart(jd, rsc++); - if(rc != JDR_OK) return rc; + for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ + for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ + if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ + rc = jd_restart(jd, rsc++); + if (rc != JDR_OK) return rc; rst = 1; } - rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */ - if(rc != JDR_OK) return rc; - rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (YCbCr to RGB, scaling and output) */ - if(rc != JDR_OK) return rc; + rc = jd_mcu_load(jd); /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */ + if (rc != JDR_OK) return rc; + rc = jd_mcu_output(jd, outfunc, x, y); /* Output the MCU (YCbCr to RGB, scaling and output) */ + if (rc != JDR_OK) return rc; } } return rc; } - -#endif /*LV_USE_SJPG*/ diff --git a/src/libs/sjpg/tjpgd.h b/src/libs/jpg/tjpgd.h similarity index 53% rename from src/libs/sjpg/tjpgd.h rename to src/libs/jpg/tjpgd.h index 4f0d1e220..317cd362c 100644 --- a/src/libs/sjpg/tjpgd.h +++ b/src/libs/jpg/tjpgd.h @@ -8,12 +8,18 @@ extern "C" { #endif -#include "../../lv_conf_internal.h" -#if LV_USE_SJPG - #include "tjpgdcnf.h" #include + +#if defined(_WIN32) /* VC++ or some compiler without stdint.h */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned long uint32_t; +typedef long int32_t; +#else /* Embedded platform */ #include +#endif #if JD_FASTDECODE >= 1 typedef int16_t jd_yuv_t; @@ -35,6 +41,8 @@ typedef enum { JDR_FMT3 /* 8: Not supported JPEG standard */ } JRESULT; + + /* Rectangular region in the output image */ typedef struct { uint16_t left; /* Left end */ @@ -43,48 +51,59 @@ typedef struct { uint16_t bottom; /* Bottom end */ } JRECT; + + /* Decompressor object structure */ -typedef struct _JDEC JDEC; -struct _JDEC { +typedef struct JDEC JDEC; +struct JDEC { size_t dctr; /* Number of bytes available in the input buffer */ - uint8_t * dptr; /* Current data read ptr */ - uint8_t * inbuf; /* Bit stream input buffer */ - uint8_t dbit; /* Number of bits available in wreg or reading bit mask */ + uint8_t* dptr; /* Current data read ptr */ + uint8_t* inbuf; /* Bit stream input buffer */ + uint8_t dbit; /* Number of bits availavble in wreg or reading bit mask */ uint8_t scale; /* Output scaling ratio */ uint8_t msx, msy; /* MCU size in unit of block (width, height) */ uint8_t qtid[3]; /* Quantization table ID of each component, Y, Cb, Cr */ uint8_t ncomp; /* Number of color components 1:grayscale, 3:color */ int16_t dcv[3]; /* Previous DC element of each component */ - uint16_t nrst; /* Restart interval */ + uint16_t nrst; /* Restart inverval */ + uint16_t rst; /* Restart count*/ + uint16_t rsc; /* Expected restart sequence ID*/ uint16_t width, height; /* Size of the input image (pixel) */ - uint8_t * huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ - uint16_t * huffcode[2][2]; /* Huffman code word tables [id][dcac] */ - uint8_t * huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ - int32_t * qttbl[4]; /* Dequantizer tables [id] */ + uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ + uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ + uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ + int32_t* qttbl[4]; /* Dequantizer tables [id] */ #if JD_FASTDECODE >= 1 uint32_t wreg; /* Working shift register */ uint8_t marker; /* Detected marker (0:None) */ #if JD_FASTDECODE == 2 uint8_t longofs[2][2]; /* Table offset of long code [id][dcac] */ - uint16_t * hufflut_ac[2]; /* Fast huffman decode tables for AC short code [id] */ - uint8_t * hufflut_dc[2]; /* Fast huffman decode tables for DC short code [id] */ + uint16_t* hufflut_ac[2]; /* Fast huffman decode tables for AC short code [id] */ + uint8_t* hufflut_dc[2]; /* Fast huffman decode tables for DC short code [id] */ #endif #endif - void * workbuf; /* Working buffer for IDCT and RGB output */ - jd_yuv_t * mcubuf; /* Working buffer for the MCU */ - void * pool; /* Pointer to available memory pool */ - size_t sz_pool; /* Size of memory pool (bytes available) */ - size_t (*infunc)(JDEC *, uint8_t *, size_t); /* Pointer to jpeg stream input function */ - void * device; /* Pointer to I/O device identifier for the session */ + void* workbuf; /* Working buffer for IDCT and RGB output */ + jd_yuv_t* mcubuf; /* Working buffer for the MCU */ + void* pool; /* Pointer to available memory pool */ + void* pool_original; /* Pointer to original pool */ + size_t sz_pool; /* Size of momory pool (bytes available) */ + size_t (*infunc)(JDEC*, uint8_t*, size_t); /* Pointer to jpeg stream input function */ + void* device; /* Pointer to I/O device identifiler for the session */ }; /* TJpgDec API functions */ -JRESULT jd_prepare(JDEC * jd, size_t (*infunc)(JDEC *, uint8_t *, size_t), void * pool, size_t sz_pool, void * dev); -JRESULT jd_decomp(JDEC * jd, int (*outfunc)(JDEC *, void *, JRECT *), uint8_t scale); +JRESULT jd_prepare (JDEC* jd, size_t (*infunc)(JDEC*,uint8_t*,size_t), void* pool, size_t sz_pool, void* dev); + +JRESULT jd_decomp (JDEC* jd, int (*outfunc)(JDEC*,void*,JRECT*), uint8_t scale); + +JRESULT jd_mcu_load (JDEC* jd); + +JRESULT jd_mcu_output(JDEC* jd, int (*outfunc)(JDEC*, void*, JRECT*), unsigned int x, unsigned int y); + +JRESULT jd_restart(JDEC* jd, uint16_t rstn); -#endif /*LV_USE_SJPG*/ #ifdef __cplusplus } diff --git a/src/libs/sjpg/tjpgdcnf.h b/src/libs/jpg/tjpgdcnf.h similarity index 93% rename from src/libs/sjpg/tjpgdcnf.h rename to src/libs/jpg/tjpgdcnf.h index 24fc4eaa7..dc27d6a95 100644 --- a/src/libs/sjpg/tjpgdcnf.h +++ b/src/libs/jpg/tjpgdcnf.h @@ -12,7 +12,7 @@ / 2: Grayscale (8-bit/pix) */ -#define JD_USE_SCALE 1 +#define JD_USE_SCALE 0 /* Switches output descaling feature. / 0: Disable / 1: Enable @@ -24,7 +24,7 @@ / 1: Enable */ -#define JD_FASTDECODE 0 +#define JD_FASTDECODE 1 /* Optimization level / 0: Basic optimization. Suitable for 8/16-bit MCUs. / 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. diff --git a/src/libs/sjpg/lv_sjpg.c b/src/libs/sjpg/lv_sjpg.c deleted file mode 100644 index 71dbcfcad..000000000 --- a/src/libs/sjpg/lv_sjpg.c +++ /dev/null @@ -1,931 +0,0 @@ -/** - * @file lv_sjpg.c - * - */ - -/*---------------------------------------------------------------------------------------------------------------------------------- -/ Added normal JPG support [7/10/2020] -/ ---------- -/ SJPEG is a custom created modified JPEG file format for small embedded platforms. -/ It will contain multiple JPEG fragments all embedded into a single file with a custom header. -/ This makes JPEG decoding easier using any JPEG library. Overall file size will be almost -/ similar to the parent jpeg file. We can generate sjpeg from any jpeg using a python script -/ provided along with this project. -/ (by vinodstanur | 2020 ) -/ SJPEG FILE STRUCTURE -/ -------------------------------------------------------------------------------------------------------------------------------- -/ Bytes | Value | -/ -------------------------------------------------------------------------------------------------------------------------------- -/ -/ 0 - 7 | "_SJPG__" followed by '\0' -/ -/ 8 - 13 | "V1.00" followed by '\0' [VERSION OF SJPG FILE for future compatibiliby] -/ -/ 14 - 15 | X_RESOLUTION (width) [little endian] -/ -/ 16 - 17 | Y_RESOLUTION (height) [little endian] -/ -/ 18 - 19 | TOTAL_FRAMES inside sjpeg [little endian] -/ -/ 20 - 21 | JPEG BLOCK WIDTH (16 normally) [little endian] -/ -/ 22 - [(TOTAL_FRAMES*2 )] | SIZE OF EACH JPEG SPLIT FRAGMENTS (FRAME_INFO_ARRAY) -/ -/ SJPEG data | Each JPEG frame can be extracted from SJPEG data by parsing the FRAME_INFO_ARRAY one time. -/ -/---------------------------------------------------------------------------------------------------------------------------------- -/ JPEG DECODER -/ ------------ -/ We are using TJpgDec - Tiny JPEG Decompressor library from ELM-CHAN for decoding each split-jpeg fragments. -/ 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, -/ just replace those files with updated files. -/---------------------------------------------------------------------------------------------------------------------------------*/ - -/********************* - * INCLUDES - *********************/ - -#include "../../../lvgl.h" -#if LV_USE_SJPG - -#include "tjpgd.h" -#include "lv_sjpg.h" -#include "../../misc/lv_fs.h" - -/********************* - * DEFINES - *********************/ -#define TJPGD_WORKBUFF_SIZE 4096 //Recommended by TJPGD library - -//NEVER EDIT THESE OFFSET VALUES -#define SJPEG_VERSION_OFFSET 8 -#define SJPEG_X_RES_OFFSET 14 -#define SJPEG_y_RES_OFFSET 16 -#define SJPEG_TOTAL_FRAMES_OFFSET 18 -#define SJPEG_BLOCK_WIDTH_OFFSET 20 -#define SJPEG_FRAME_INFO_ARRAY_OFFSET 22 - -/********************** - * TYPEDEFS - **********************/ - -enum io_source_type { - SJPEG_IO_SOURCE_C_ARRAY, - SJPEG_IO_SOURCE_DISK, -}; - -typedef struct { - enum io_source_type type; - lv_fs_file_t lv_file; - uint8_t * img_cache_buff; - int img_cache_x_res; - int img_cache_y_res; - uint8_t * raw_sjpg_data; //Used when type==SJPEG_IO_SOURCE_C_ARRAY. - uint32_t raw_sjpg_data_size; //Num bytes pointed to by raw_sjpg_data. - uint32_t raw_sjpg_data_next_read_pos; //Used for all types. -} io_source_t; - - -typedef struct { - uint8_t * sjpeg_data; - uint32_t sjpeg_data_size; - int sjpeg_x_res; - int sjpeg_y_res; - int sjpeg_total_frames; - int sjpeg_single_frame_height; - int sjpeg_cache_frame_index; - uint8_t ** frame_base_array; //to save base address of each split frames upto sjpeg_total_frames. - int * frame_base_offset; //to save base offset for fseek - uint8_t * frame_cache; - uint8_t * workb; //JPG work buffer for jpeg library - JDEC * tjpeg_jd; - io_source_t io; -} SJPEG; - -/********************** - * STATIC PROTOTYPES - **********************/ -static lv_res_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header); -static lv_res_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); -static lv_res_t decoder_read_line(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_coord_t x, - lv_coord_t y, - lv_coord_t len, uint8_t * buf); -static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); -static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata); -static int is_jpg(const uint8_t * raw_data, size_t len); -static void lv_sjpg_cleanup(SJPEG * sjpeg); -static void lv_sjpg_free(SJPEG * sjpeg); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ -void lv_split_jpeg_init(void) -{ - lv_image_decoder_t * dec = lv_image_decoder_create(); - lv_image_decoder_set_info_cb(dec, decoder_info); - lv_image_decoder_set_open_cb(dec, decoder_open); - lv_image_decoder_set_close_cb(dec, decoder_close); - /* - Disabled for now - lv_image_decoder_set_read_line_cb(dec, decoder_read_line); - */ - LV_UNUSED(decoder_read_line); -} - -/********************** - * STATIC FUNCTIONS - **********************/ -/** - * Get info about an SJPG / JPG image - * @param decoder pointer to the decoder where this function belongs - * @param src can be file name or pointer to a C array - * @param header store the info here - * @return LV_RES_OK: no error; LV_RES_INV: can't get the info - */ -static lv_res_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header) -{ - LV_UNUSED(decoder); - - /*Check whether the type `src` is known by the decoder*/ - /* Read the SJPG/JPG header and find `width` and `height` */ - - lv_image_src_t src_type = lv_image_src_get_type(src); /*Get the source type*/ - - lv_res_t ret = LV_RES_OK; - - if(src_type == LV_IMAGE_SRC_VARIABLE) { - const lv_image_dsc_t * img_dsc = src; - uint8_t * raw_sjpeg_data = (uint8_t *)img_dsc->data; - const uint32_t raw_sjpeg_data_size = img_dsc->data_size; - - if(!strncmp((char *)raw_sjpeg_data, "_SJPG__", strlen("_SJPG__"))) { - - raw_sjpeg_data += 14; //seek to res info ... refer sjpeg format - header->always_zero = 0; - header->cf = LV_COLOR_FORMAT_RAW; - - header->w = *raw_sjpeg_data++; - header->w |= *raw_sjpeg_data++ << 8; - - header->h = *raw_sjpeg_data++; - header->h |= *raw_sjpeg_data++ << 8; - - return ret; - - } - else if(is_jpg(raw_sjpeg_data, raw_sjpeg_data_size) == true) { - header->always_zero = 0; - header->cf = LV_COLOR_FORMAT_RAW; - - uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(!workb_temp) return LV_RES_INV; - - io_source_t io_source_temp; - io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY; - io_source_temp.raw_sjpg_data = raw_sjpeg_data; - io_source_temp.raw_sjpg_data_size = raw_sjpeg_data_size; - io_source_temp.raw_sjpg_data_next_read_pos = 0; - - JDEC jd_tmp; - - JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); - if(rc == JDR_OK) { - header->w = jd_tmp.width; - header->h = jd_tmp.height; - - } - else { - ret = LV_RES_INV; - goto end; - } - -end: - lv_free(workb_temp); - - return ret; - - } - } - else if(src_type == LV_IMAGE_SRC_FILE) { - const char * fn = src; - if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) { - - uint8_t buff[22]; - memset(buff, 0, sizeof(buff)); - - lv_fs_file_t file; - lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) return 78; - - uint32_t rn; - res = lv_fs_read(&file, buff, 8, &rn); - if(res != LV_FS_RES_OK || rn != 8) { - lv_fs_close(&file); - return LV_RES_INV; - } - - if(strcmp((char *)buff, "_SJPG__") == 0) { - lv_fs_seek(&file, 14, LV_FS_SEEK_SET); - res = lv_fs_read(&file, buff, 4, &rn); - if(res != LV_FS_RES_OK || rn != 4) { - lv_fs_close(&file); - return LV_RES_INV; - } - header->always_zero = 0; - header->cf = LV_COLOR_FORMAT_RAW; - uint8_t * raw_sjpeg_data = buff; - header->w = *raw_sjpeg_data++; - header->w |= *raw_sjpeg_data++ << 8; - header->h = *raw_sjpeg_data++; - header->h |= *raw_sjpeg_data++ << 8; - lv_fs_close(&file); - return LV_RES_OK; - - } - } - else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) { - lv_fs_file_t file; - lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) return 78; - - uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(!workb_temp) { - lv_fs_close(&file); - return LV_RES_INV; - } - - io_source_t io_source_temp; - io_source_temp.type = SJPEG_IO_SOURCE_DISK; - io_source_temp.raw_sjpg_data_next_read_pos = 0; - io_source_temp.img_cache_buff = NULL; - io_source_temp.lv_file = file; - JDEC jd_tmp; - - JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); - lv_free(workb_temp); - lv_fs_close(&file); - - if(rc == JDR_OK) { - header->always_zero = 0; - header->cf = LV_COLOR_FORMAT_RAW; - header->w = jd_tmp.width; - header->h = jd_tmp.height; - return LV_RES_OK; - } - } - } - return LV_RES_INV; -} - -static int img_data_cb(JDEC * jd, void * data, JRECT * rect) -{ - io_source_t * io = jd->device; - uint8_t * cache = io->img_cache_buff; - const int xres = io->img_cache_x_res; - uint8_t * buf = data; - const int INPUT_PIXEL_SIZE = 3; - const int row_width = rect->right - rect->left + 1; // Row width in pixels. - const int row_size = row_width * INPUT_PIXEL_SIZE; // Row size (bytes). - - for(int y = rect->top; y <= rect->bottom; y++) { - int row_offset = y * xres * INPUT_PIXEL_SIZE + rect->left * INPUT_PIXEL_SIZE; - memcpy(cache + row_offset, buf, row_size); - buf += row_size; - } - - return 1; -} - -static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata) -{ - io_source_t * io = jd->device; - - if(!io) return 0; - - if(io->type == SJPEG_IO_SOURCE_C_ARRAY) { - const uint32_t bytes_left = io->raw_sjpg_data_size - io->raw_sjpg_data_next_read_pos; - const uint32_t to_read = ndata <= bytes_left ? (uint32_t)ndata : bytes_left; - if(to_read == 0) - return 0; - if(buff) { - memcpy(buff, io->raw_sjpg_data + io->raw_sjpg_data_next_read_pos, to_read); - } - io->raw_sjpg_data_next_read_pos += to_read; - return to_read; - } - else if(io->type == SJPEG_IO_SOURCE_DISK) { - - lv_fs_file_t * lv_file_p = &(io->lv_file); - - if(buff) { - uint32_t rn = 0; - lv_fs_read(lv_file_p, buff, (uint32_t)ndata, &rn); - return rn; - } - else { - uint32_t pos; - lv_fs_tell(lv_file_p, &pos); - lv_fs_seek(lv_file_p, (uint32_t)(ndata + pos), LV_FS_SEEK_SET); - return ndata; - } - } - return 0; -} - -/** - * Open SJPG image and return the decided image - * @param decoder pointer to the decoder where this function belongs - * @param dsc pointer to a descriptor which describes this decoding session - * @return LV_RES_OK: no error; LV_RES_INV: can't get the info - */ -static lv_res_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) -{ - LV_UNUSED(decoder); - lv_res_t lv_ret = LV_RES_OK; - - if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - uint8_t * data; - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - const uint32_t raw_sjpeg_data_size = ((lv_image_dsc_t *)dsc->src)->data_size; - if(sjpeg == NULL) { - sjpeg = lv_malloc(sizeof(SJPEG)); - if(!sjpeg) return LV_RES_INV; - - memset(sjpeg, 0, sizeof(SJPEG)); - - dsc->user_data = sjpeg; - sjpeg->sjpeg_data = (uint8_t *)((lv_image_dsc_t *)(dsc->src))->data; - sjpeg->sjpeg_data_size = ((lv_image_dsc_t *)(dsc->src))->data_size; - } - - if(!strncmp((char *) sjpeg->sjpeg_data, "_SJPG__", strlen("_SJPG__"))) { - - data = sjpeg->sjpeg_data; - data += 14; - - sjpeg->sjpeg_x_res = *data++; - sjpeg->sjpeg_x_res |= *data++ << 8; - - sjpeg->sjpeg_y_res = *data++; - sjpeg->sjpeg_y_res |= *data++ << 8; - - sjpeg->sjpeg_total_frames = *data++; - sjpeg->sjpeg_total_frames |= *data++ << 8; - - sjpeg->sjpeg_single_frame_height = *data++; - sjpeg->sjpeg_single_frame_height |= *data++ << 8; - - sjpeg->frame_base_array = lv_malloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); - if(! sjpeg->frame_base_array) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - - sjpeg->frame_base_offset = NULL; - - uint8_t * img_frame_base = data + sjpeg->sjpeg_total_frames * 2; - sjpeg->frame_base_array[0] = img_frame_base; - - for(int i = 1; i < sjpeg->sjpeg_total_frames; i++) { - int offset = *data++; - offset |= *data++ << 8; - sjpeg->frame_base_array[i] = sjpeg->frame_base_array[i - 1] + offset; - } - sjpeg->sjpeg_cache_frame_index = -1; - sjpeg->frame_cache = (void *)lv_malloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3/*2*/); - if(! sjpeg->frame_cache) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - sjpeg->io.img_cache_buff = sjpeg->frame_cache; - sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; - sjpeg->workb = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! sjpeg->workb) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - - sjpeg->tjpeg_jd = lv_malloc(sizeof(JDEC)); - if(! sjpeg->tjpeg_jd) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY; - sjpeg->io.lv_file.file_d = NULL; - dsc->img_data = NULL; - return lv_ret; - } - else if(is_jpg(sjpeg->sjpeg_data, raw_sjpeg_data_size) == true) { - - uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! workb_temp) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - io_source_t io_source_temp; - io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY; - io_source_temp.raw_sjpg_data = sjpeg->sjpeg_data; - io_source_temp.raw_sjpg_data_size = sjpeg->sjpeg_data_size; - io_source_temp.raw_sjpg_data_next_read_pos = 0; - - JDEC jd_tmp; - JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); - lv_free(workb_temp); - - - if(rc == JDR_OK) { - sjpeg->sjpeg_x_res = jd_tmp.width; - sjpeg->sjpeg_y_res = jd_tmp.height; - sjpeg->sjpeg_total_frames = 1; - sjpeg->sjpeg_single_frame_height = jd_tmp.height; - - sjpeg->frame_base_array = lv_malloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); - if(! sjpeg->frame_base_array) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - sjpeg->frame_base_offset = NULL; - - uint8_t * img_frame_base = sjpeg->sjpeg_data; - sjpeg->frame_base_array[0] = img_frame_base; - - sjpeg->sjpeg_cache_frame_index = -1; - sjpeg->frame_cache = (void *)lv_malloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); - if(! sjpeg->frame_cache) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - - sjpeg->io.img_cache_buff = sjpeg->frame_cache; - sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; - sjpeg->workb = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! sjpeg->workb) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - - sjpeg->tjpeg_jd = lv_malloc(sizeof(JDEC)); - if(! sjpeg->tjpeg_jd) { - lv_sjpg_cleanup(sjpeg); - sjpeg = NULL; - return LV_RES_INV; - } - - sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY; - sjpeg->io.lv_file.file_d = NULL; - dsc->img_data = NULL; - return lv_ret; - } - else { - lv_ret = LV_RES_INV; - goto end; - } - -end: - lv_free(workb_temp); - - return lv_ret; - } - } - else if(dsc->src_type == LV_IMAGE_SRC_FILE) { - /* If all fine, then the file will be kept open */ - const char * fn = dsc->src; - uint8_t * data; - - if(strcmp(lv_fs_get_ext(fn), "sjpg") == 0) { - - uint8_t buff[22]; - memset(buff, 0, sizeof(buff)); - - - lv_fs_file_t lv_file; - lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - return 78; - } - - - uint32_t rn; - res = lv_fs_read(&lv_file, buff, 22, &rn); - if(res != LV_FS_RES_OK || rn != 22) { - lv_fs_close(&lv_file); - return LV_RES_INV; - } - - if(strcmp((char *)buff, "_SJPG__") == 0) { - - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - if(sjpeg == NULL) { - sjpeg = lv_malloc(sizeof(SJPEG)); - - if(! sjpeg) { - lv_fs_close(&lv_file); - return LV_RES_INV; - } - memset(sjpeg, 0, sizeof(SJPEG)); - - dsc->user_data = sjpeg; - sjpeg->sjpeg_data = (uint8_t *)((lv_image_dsc_t *)(dsc->src))->data; - sjpeg->sjpeg_data_size = ((lv_image_dsc_t *)(dsc->src))->data_size; - } - data = buff; - data += 14; - - sjpeg->sjpeg_x_res = *data++; - sjpeg->sjpeg_x_res |= *data++ << 8; - - sjpeg->sjpeg_y_res = *data++; - sjpeg->sjpeg_y_res |= *data++ << 8; - - sjpeg->sjpeg_total_frames = *data++; - sjpeg->sjpeg_total_frames |= *data++ << 8; - - sjpeg->sjpeg_single_frame_height = *data++; - sjpeg->sjpeg_single_frame_height |= *data++ << 8; - - sjpeg->frame_base_array = NULL;//lv_malloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames ); - sjpeg->frame_base_offset = lv_malloc(sizeof(int) * sjpeg->sjpeg_total_frames); - if(! sjpeg->frame_base_offset) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - int img_frame_start_offset = (SJPEG_FRAME_INFO_ARRAY_OFFSET + sjpeg->sjpeg_total_frames * 2); - sjpeg->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now... - - for(int i = 1; i < sjpeg->sjpeg_total_frames; i++) { - res = lv_fs_read(&lv_file, buff, 2, &rn); - if(res != LV_FS_RES_OK || rn != 2) { - lv_fs_close(&lv_file); - return LV_RES_INV; - } - - data = buff; - int offset = *data++; - offset |= *data++ << 8; - sjpeg->frame_base_offset[i] = sjpeg->frame_base_offset[i - 1] + offset; - } - - sjpeg->sjpeg_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time. - sjpeg->frame_cache = (void *)lv_malloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); - if(! sjpeg->frame_cache) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - sjpeg->io.img_cache_buff = sjpeg->frame_cache; - sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; - sjpeg->workb = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! sjpeg->workb) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - sjpeg->tjpeg_jd = lv_malloc(sizeof(JDEC)); - if(! sjpeg->tjpeg_jd) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - sjpeg->io.type = SJPEG_IO_SOURCE_DISK; - sjpeg->io.lv_file = lv_file; - dsc->img_data = NULL; - return LV_RES_OK; - } - } - else if(strcmp(lv_fs_get_ext(fn), "jpg") == 0) { - - lv_fs_file_t lv_file; - lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - return LV_RES_INV; - } - - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - if(sjpeg == NULL) { - sjpeg = lv_malloc(sizeof(SJPEG)); - if(! sjpeg) { - lv_fs_close(&lv_file); - return LV_RES_INV; - } - - memset(sjpeg, 0, sizeof(SJPEG)); - dsc->user_data = sjpeg; - sjpeg->sjpeg_data = (uint8_t *)((lv_image_dsc_t *)(dsc->src))->data; - sjpeg->sjpeg_data_size = ((lv_image_dsc_t *)(dsc->src))->data_size; - } - - uint8_t * workb_temp = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! workb_temp) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - io_source_t io_source_temp; - io_source_temp.type = SJPEG_IO_SOURCE_DISK; - io_source_temp.raw_sjpg_data_next_read_pos = 0; - io_source_temp.img_cache_buff = NULL; - io_source_temp.lv_file = lv_file; - - JDEC jd_tmp; - - JRESULT rc = jd_prepare(&jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp); - - lv_free(workb_temp); - - - if(rc == JDR_OK) { - sjpeg->sjpeg_x_res = jd_tmp.width; - sjpeg->sjpeg_y_res = jd_tmp.height; - sjpeg->sjpeg_total_frames = 1; - sjpeg->sjpeg_single_frame_height = jd_tmp.height; - - sjpeg->frame_base_array = NULL; - sjpeg->frame_base_offset = lv_malloc(sizeof(uint8_t *) * sjpeg->sjpeg_total_frames); - if(! sjpeg->frame_base_offset) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - int img_frame_start_offset = 0; - sjpeg->frame_base_offset[0] = img_frame_start_offset; - - sjpeg->sjpeg_cache_frame_index = -1; - sjpeg->frame_cache = (void *)lv_malloc(sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3); - if(! sjpeg->frame_cache) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - sjpeg->io.img_cache_buff = sjpeg->frame_cache; - sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res; - sjpeg->workb = lv_malloc(TJPGD_WORKBUFF_SIZE); - if(! sjpeg->workb) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - sjpeg->tjpeg_jd = lv_malloc(sizeof(JDEC)); - if(! sjpeg->tjpeg_jd) { - lv_fs_close(&lv_file); - lv_sjpg_cleanup(sjpeg); - return LV_RES_INV; - } - - sjpeg->io.type = SJPEG_IO_SOURCE_DISK; - sjpeg->io.lv_file = lv_file; - dsc->img_data = NULL; - return LV_RES_OK; - - } - else { - if(dsc->user_data) lv_free(dsc->user_data); - lv_fs_close(&lv_file); - return LV_RES_INV; - } - } - } - - return LV_RES_INV; -} - -/** - * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. - * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL) - * @param decoder pointer to the decoder the function associated with - * @param dsc pointer to decoder descriptor - * @param x start x coordinate - * @param y start y coordinate - * @param len number of pixels to decode - * @param buf a buffer to store the decoded pixels - * @return LV_RES_OK: ok; LV_RES_INV: failed - */ - -static lv_res_t decoder_read_line(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_coord_t x, - lv_coord_t y, - lv_coord_t len, uint8_t * buf) -{ - LV_UNUSED(decoder); - if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - JRESULT rc; - - int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height; - - /*If line not from cache, refresh cache */ - if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) { - sjpeg->io.raw_sjpg_data = sjpeg->frame_base_array[ sjpeg_req_frame_index ]; - if(sjpeg_req_frame_index == (sjpeg->sjpeg_total_frames - 1)) { - /*This is the last frame. */ - const uint32_t frame_offset = (uint32_t)(sjpeg->io.raw_sjpg_data - sjpeg->sjpeg_data); - sjpeg->io.raw_sjpg_data_size = sjpeg->sjpeg_data_size - frame_offset; - } - else { - sjpeg->io.raw_sjpg_data_size = - (uint32_t)(sjpeg->frame_base_array[sjpeg_req_frame_index + 1] - sjpeg->io.raw_sjpg_data); - } - sjpeg->io.raw_sjpg_data_next_read_pos = 0; - rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io)); - if(rc != JDR_OK) return LV_RES_INV; - rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0); - if(rc != JDR_OK) return LV_RES_INV; - sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index; - } - - int offset = 0; - uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res * - 3; - -#if LV_COLOR_DEPTH == 32 - for(int i = 0; i < len; i++) { - buf[offset + 3] = 0xff; - buf[offset + 2] = *cache++; - buf[offset + 1] = *cache++; - buf[offset + 0] = *cache++; - offset += 4; - } -#elif LV_COLOR_DEPTH == 24 - for(int i = 0; i < len; i++) { - buf[offset + 2] = *cache++; - buf[offset + 1] = *cache++; - buf[offset + 0] = *cache++; - offset += 3; - } -#elif LV_COLOR_DEPTH == 16 - for(int i = 0; i < len; i++) { - uint16_t col_16bit = (*cache++ & 0xf8) << 8; - col_16bit |= (*cache++ & 0xFC) << 3; - col_16bit |= (*cache++ >> 3); -#if LV_BIG_ENDIAN_SYSTEM == 1 - buf[offset++] = col_16bit >> 8; - buf[offset++] = col_16bit & 0xff; -#else - buf[offset++] = col_16bit & 0xff; - buf[offset++] = col_16bit >> 8; -#endif // LV_BIG_ENDIAN_SYSTEM - } -#elif LV_COLOR_DEPTH == 8 - for(int i = 0; i < len; i++) { - uint8_t col_8bit = (*cache++ & 0xC0); - col_8bit |= (*cache++ & 0xe0) >> 2; - col_8bit |= (*cache++ & 0xe0) >> 5; - buf[offset++] = col_8bit; - } -#else -#error Unsupported LV_COLOR_DEPTH -#endif // LV_COLOR_DEPTH - return LV_RES_OK; - } - else if(dsc->src_type == LV_IMAGE_SRC_FILE) { - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - JRESULT rc; - int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height; - - lv_fs_file_t * lv_file_p = &(sjpeg->io.lv_file); - if(!lv_file_p) goto end; - - /*If line not from cache, refresh cache */ - if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) { - sjpeg->io.raw_sjpg_data_next_read_pos = (int)(sjpeg->frame_base_offset [ sjpeg_req_frame_index ]); - lv_fs_seek(&(sjpeg->io.lv_file), sjpeg->io.raw_sjpg_data_next_read_pos, LV_FS_SEEK_SET); - - rc = jd_prepare(sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io)); - if(rc != JDR_OK) return LV_RES_INV; - - rc = jd_decomp(sjpeg->tjpeg_jd, img_data_cb, 0); - if(rc != JDR_OK) return LV_RES_INV; - - sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index; - } - - int offset = 0; - uint8_t * cache = (uint8_t *)sjpeg->frame_cache + x * 3 + (y % sjpeg->sjpeg_single_frame_height) * sjpeg->sjpeg_x_res * - 3; - -#if LV_COLOR_DEPTH == 32 - for(int i = 0; i < len; i++) { - buf[offset + 3] = 0xff; - buf[offset + 2] = *cache++; - buf[offset + 1] = *cache++; - buf[offset + 0] = *cache++; - offset += 4; - } -#elif LV_COLOR_DEPTH == 24 - for(int i = 0; i < len; i++) { - buf[offset + 2] = *cache++; - buf[offset + 1] = *cache++; - buf[offset + 0] = *cache++; - offset += 3; - } -#elif LV_COLOR_DEPTH == 16 - - for(int i = 0; i < len; i++) { - uint16_t col_8bit = (*cache++ & 0xf8) << 8; - col_8bit |= (*cache++ & 0xFC) << 3; - col_8bit |= (*cache++ >> 3); -#if LV_BIG_ENDIAN_SYSTEM == 1 - buf[offset++] = col_8bit >> 8; - buf[offset++] = col_8bit & 0xff; -#else - buf[offset++] = col_8bit & 0xff; - buf[offset++] = col_8bit >> 8; -#endif // LV_BIG_ENDIAN_SYSTEM - } - -#elif LV_COLOR_DEPTH == 8 - - for(int i = 0; i < len; i++) { - uint8_t col_8bit = (*cache++ & 0xC0); - col_8bit |= (*cache++ & 0xe0) >> 2; - col_8bit |= (*cache++ & 0xe0) >> 5; - buf[offset++] = col_8bit; - } - -#else -#error Unsupported LV_COLOR_DEPTH - - -#endif // LV_COLOR_DEPTH - - return LV_RES_OK; - } -end: - return LV_RES_INV; -} - -/** - * Free the allocated resources - * @param decoder pointer to the decoder where this function belongs - * @param dsc pointer to a descriptor which describes this decoding session - */ -static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) -{ - LV_UNUSED(decoder); - /*Free all allocated data*/ - SJPEG * sjpeg = (SJPEG *) dsc->user_data; - if(!sjpeg) return; - - switch(dsc->src_type) { - case LV_IMAGE_SRC_FILE: - if(sjpeg->io.lv_file.file_d) { - lv_fs_close(&(sjpeg->io.lv_file)); - } - lv_sjpg_cleanup(sjpeg); - break; - - case LV_IMAGE_SRC_VARIABLE: - lv_sjpg_cleanup(sjpeg); - break; - - default: - ; - } -} - -static int is_jpg(const uint8_t * raw_data, size_t len) -{ - const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46}; - if(len < sizeof(jpg_signature)) return false; - return memcmp(jpg_signature, raw_data, sizeof(jpg_signature)) == 0; -} - -static void lv_sjpg_free(SJPEG * sjpeg) -{ - if(sjpeg->frame_cache) lv_free(sjpeg->frame_cache); - if(sjpeg->frame_base_array) lv_free(sjpeg->frame_base_array); - if(sjpeg->frame_base_offset) lv_free(sjpeg->frame_base_offset); - if(sjpeg->tjpeg_jd) lv_free(sjpeg->tjpeg_jd); - if(sjpeg->workb) lv_free(sjpeg->workb); -} - -static void lv_sjpg_cleanup(SJPEG * sjpeg) -{ - if(! sjpeg) return; - - lv_sjpg_free(sjpeg); - lv_free(sjpeg); -} - -#endif /*LV_USE_SJPG*/ diff --git a/src/lv_init.c b/src/lv_init.c index 0f00a5438..4adc35116 100644 --- a/src/lv_init.c +++ b/src/lv_init.c @@ -17,7 +17,7 @@ #include "libs/fsdrv/lv_fsdrv.h" #include "libs/gif/lv_gif.h" #include "libs/png/lv_png.h" -#include "libs/sjpg/lv_sjpg.h" +#include "libs/jpg/lv_jpg.h" #include "draw/lv_draw.h" #include "misc/lv_cache.h" #include "misc/lv_cache_builtin.h" @@ -220,7 +220,7 @@ void lv_init(void) #endif #if LV_USE_SJPG - lv_split_jpeg_init(); + lv_jpeg_init(); #endif #if LV_USE_BMP diff --git a/src/misc/lv_color.h b/src/misc/lv_color.h index 7a4915287..f136e4ecf 100644 --- a/src/misc/lv_color.h +++ b/src/misc/lv_color.h @@ -167,14 +167,14 @@ typedef uint8_t lv_color_format_t; /** * Get the pixel size of a color format in bytes - * @param src_cf a color format (`LV_IMAGE_CF_...`) + * @param src_cf a color format (`LV_COLOR_FORMAT_...`) * @return the pixel size in bytes */ uint8_t lv_color_format_get_size(lv_color_format_t src_cf); /** * Get the pixel size of a color format in bits, bpp - * @param src_cf a color format (`LV_IMAGE_CF_...`) + * @param src_cf a color format (`LV_COLOR_FORMAT_...`) * @return the pixel size in bits */ uint8_t lv_color_format_get_bpp(lv_color_format_t cf); diff --git a/src/misc/lv_fs.c b/src/misc/lv_fs.c index c927e0513..3090ce04e 100644 --- a/src/misc/lv_fs.c +++ b/src/misc/lv_fs.c @@ -106,7 +106,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo /* If this is a memory-mapped file, then set "cache" to the memory buffer */ if(drv->cache_size == LV_FS_CACHE_FROM_BUFFER) { lv_fs_path_ex_t * path_ex = (lv_fs_path_ex_t *)path; - file_p->cache->buffer = path_ex->buffer; + file_p->cache->buffer = (void *)path_ex->buffer; file_p->cache->start = 0; file_p->cache->file_position = 0; file_p->cache->end = path_ex->size; @@ -121,7 +121,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo return LV_FS_RES_OK; } -void lv_fs_make_path_from_buffer(lv_fs_path_ex_t * path, char letter, void * buf, uint32_t size) +void lv_fs_make_path_from_buffer(lv_fs_path_ex_t * path, char letter, const void * buf, uint32_t size) { path->path[0] = letter; path->path[1] = ':'; @@ -175,7 +175,7 @@ static lv_fs_res_t lv_fs_read_cached(lv_fs_file_t * file_p, char * buf, uint32_t /* Do not allow reading beyond the actual memory block for memory-mapped files */ if(file_p->drv->cache_size == LV_FS_CACHE_FROM_BUFFER) { if(btr > buffer_remaining_length) - btr = buffer_remaining_length; + btr = buffer_remaining_length - 1; } if(btr <= buffer_remaining_length) { diff --git a/src/misc/lv_fs.h b/src/misc/lv_fs.h index 651267e77..b2eef0e39 100644 --- a/src/misc/lv_fs.h +++ b/src/misc/lv_fs.h @@ -115,7 +115,7 @@ typedef struct { /* Extended path object to specify the buffer for memory-mapped files */ typedef struct { char path[4]; /* This is needed to make it compatible with a normal path */ - void * buffer; + const void * buffer; uint32_t size; } lv_fs_path_ex_t; @@ -180,7 +180,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo * @param buf address of the memory buffer * @param size size of the memory buffer in bytes */ -void lv_fs_make_path_from_buffer(lv_fs_path_ex_t * path, char letter, void * buf, uint32_t size); +void lv_fs_make_path_from_buffer(lv_fs_path_ex_t * path, char letter, const void * buf, uint32_t size); /** * Close an already opened file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 51da5a614..9eb1ad50d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -159,6 +159,8 @@ add_library(test_common src/test_assets/font_3_bin.c src/test_assets/test_img_caret_down.c src/test_assets/test_arc_bg.c + src/test_assets/test_img_lvgl_logo_png.c + src/test_assets/test_img_lvgl_logo_jpg.c src/test_assets/ubuntu_font.c unity/unity_support.c unity/unity.c @@ -176,7 +178,7 @@ set(generate_test_runner_config ${CMAKE_CURRENT_SOURCE_DIR}/config.yml) # disable test targets for build only tests if (ENABLE_TESTS) - file( GLOB TEST_CASE_FILES src/test_cases/*.c ) + file( GLOB_RECURSE TEST_CASE_FILES src/test_cases/*.c ) else() set(TEST_CASE_FILES) endif() diff --git a/tests/ref_imgs/libs/jpg_1.png b/tests/ref_imgs/libs/jpg_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b29c8a56207128d7e9510d0f2907349d7d746f77 GIT binary patch literal 9519 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 Y(c%3>9?OUeQ4r#PHq)$ literal 0 HcmV?d00001 diff --git a/tests/src/test_assets/test_img_lvgl_logo.png b/tests/src/test_assets/test_img_lvgl_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2484cf84ade58f3533a94166ec9a4d0c0f31ab64 GIT binary patch literal 1873 zcmV-X2d?;uP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00y~9L_t(&-tC%yj9o<)$3N%3 z_jaiu7z3JWcjn!Wwc=_k4MuT^ioZxq)zn4^SV$1X=s%`tYvd1wB4|@> znm{o?z>>DmVpB@2M53*vcK6=7uRjb5(w1%6-M9Dn$D7J__x)UV-Ph!Olb4sdGk0dr z`OZ0W=FEjQ+Gyi{hX9y-z7v(@Ko44eHjN_;p=?c(XrQg`DXP#~6DXO@!1ZTHn*p2v zmL@KGzOC}+k%i1cpnnDkDglB2T?pI)e13d`uC9Vepq+pOqQh|XBm4Rflz1<{;W)rg{}i!L5*WISsN8CC5-G)-JQ+{|19g^Rr+ zrxOFf<-n(a)Bf2zCz-MER^WNyK&sN)Sl8N%upi;C#)k8!>_Sq$2)qP5V)BJ-MIuc; zYi#&2W5Zu7yofLeQUr>?pdf!XHhjR?aEZx>nVPdkuS0kV*xab9; z^dxYs&iL;Jj3T*)C`$E3;5DEdSTU8!8B@pzd(1pL?+SJ-@bNwa;Z zXdkc;I40+$zfj?hVjLZxv{>SJ z6xa{!H>PkOqHBOZSWGf5(C6jiAZ5Z@4L|h}-r~`b(v`sOI_Lv50#8Dpa(JAvnb^F;KPN^QCdVa^8(0BaA&?yOW! z3K_2p1%{_G4`ag>#)cb>4g1?9O~8?(N5)&z4aOGUJ}Ct>#xkEBI4UYzCe~*}hk;SA zkBg=_mCJ!I`QW2X(j*cHwg9f|vh>CZO>XkCu6N1ciHVhQ9G&*>3$UOS-Ceyb?kK`Z zV5C(^a&F*_alybUYwetIZfFtkQQ(9M>uYrLjQ{^ktI3yDct+rwD(9pW_=BLYfn1>w zR$j>jl<%W%n8iqM6QbV-3QBMd@W`2r1m!(vOEHd))ksDB2H{p*=2VyW!GE7v(#w z67Z9nE+ybVsyqRF8n~y+6c!gNxW-u_N#JT=b9H~u-6{MEc-XJVO4xLyBeT+srn8#^ zRMsPW6IeJ>8o5f~TJIsAl=9tCRm5?WS{vT1a3ye=h(2U&{K^B!x(mp;C;>hPoCKDFJZEg!XG~9~dgxsUj1Aupd}t=! zT}uRLf?j28zR|m(jcKozO}gs_*g z+XA?E;LyRbrYzD$drdz4Aj)c=O1h%_Q=h?