diff --git a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c index df78807eca..f16fa04136 100644 --- a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c +++ b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c @@ -28,10 +28,40 @@ #define JPEG_PIXEL_SIZE 3 /* RGB888 */ #define JPEG_SIGNATURE 0xFFD8FF #define IS_JPEG_SIGNATURE(x) (((x) & 0x00FFFFFF) == JPEG_SIGNATURE) +#define ORIENTATION_TAG 0x112 /* Exif tag for orientation */ +#define APP1_MARKER JPEG_APP0 + 1 /* APP1 Marker code https://www.media.mit.edu/pia/Research/deepview/exif.html */ +#define MARKER_DATA_LIMIT 0xFFFF /* APP1 Marker limit */ /********************** * TYPEDEFS **********************/ +/** +* according to the Exif specification(http://www.cipa.jp/std/documents/e/DC-008-Translation-2019-E.pdf) +* Relationship between image data and orientation on a display screen according to an orientation tag +*/ +typedef enum { + /* Orientation = 0 is created when the image data in the Exif is not rotated */ + IMAGE_CLOCKWISE_NONE = 0, + /* Orientation = 1 is created when Oth row of the coded image data stored in the Exif image file + * and the visual top of the display screen, and Oth column and visual left, will each be matched for display + */ + IMAGE_CLOCKWISE_0 = 1, + /* Orientation = 2 is equivalent to an arrangement that is reversed Orientation = 1 horizontally */ + IMAGE_FLIP_HOR = 2, + /* Orientation = 3 is equivalent to an arrangement that is turned Orientation = 6 90 degrees clockwise */ + IMAGE_CLOCKWISE_180 = 3, + /* Orientation = 4 is equivalent to an arrangement that is reversed Orientation = 3 horizontally */ + IMAGE_FLIP_VER = 4, + /* Orientation = 5 is equivalent to an arrangement that is reversed Orientation = 6 horizontally */ + IMAGE_TRANSPOSE = 5, + /* Orientation = 6 is equivalent to an arrangement that is turned Orientation = 1 90 degrees clockwise */ + IMAGE_CLOCKWISE_90 = 6, + /* Orientation = 7 is equivalent to an arrangement that is reversed Orientation = 8 horizontally */ + IMAGE_TRANSVERSE = 7, + /* Orientation = 8 is equivalent to an arrangement that is turned Orientation = 3 90 degrees clockwise */ + IMAGE_CLOCKWISE_270 = 8, +} image_orientation_t; + typedef struct error_mgr_s { struct jpeg_error_mgr pub; jmp_buf jb; @@ -43,12 +73,15 @@ typedef struct error_mgr_s { static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header); static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); +static void convert_size_with_orientation(image_orientation_t image_orientation, uint32_t * width, uint32_t * height); static lv_draw_buf_t * decode_jpeg_file(const char * filename); -static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height, uint32_t * orientation); +static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height); static bool get_jpeg_size(uint8_t * data, uint32_t data_size, uint32_t * width, uint32_t * height); -static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * orientation); -static void rotate_buffer(lv_draw_buf_t * decoded, uint8_t * buffer, uint32_t line_index, uint32_t angle, - uint32_t row_stride); +static image_orientation_t get_jpeg_direction(uint8_t * data, uint32_t data_size); +static inline void process_buffer_orientation(image_orientation_t op, uint8_t * cur_pos, lv_image_header_t * header, + uint32_t line_index, uint8_t * buffer, uint32_t buf_stride); +static image_orientation_t jpeg_markers_reader(struct jpeg_decompress_struct * cinfo); +static void jpeg_cmyk_to_bgrx(uint8_t * cmyk_data, uint32_t pixel_count); static void error_exit(j_common_ptr cinfo); /********************** * STATIC VARIABLES @@ -93,7 +126,6 @@ void lv_libjpeg_turbo_deinit(void) } } } - /********************** * STATIC FUNCTIONS **********************/ @@ -134,16 +166,15 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_d uint32_t width; uint32_t height; - uint32_t orientation = 0; - if(!get_jpeg_head_info(src, &width, &height, &orientation)) { + if(!get_jpeg_head_info(src, &width, &height)) { return LV_RESULT_INVALID; } /*Save the data in the header*/ header->cf = LV_COLOR_FORMAT_RGB888; - header->w = (orientation % 180) ? height : width; - header->h = (orientation % 180) ? width : height; + header->w = width; + header->h = height; return LV_RESULT_OK; } @@ -207,6 +238,19 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * !lv_image_cache_is_enabled()) lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded); } +static void convert_size_with_orientation(image_orientation_t image_orientation, uint32_t * width, uint32_t * height) +{ + if(image_orientation == IMAGE_CLOCKWISE_NONE || image_orientation == IMAGE_CLOCKWISE_0 + || image_orientation == IMAGE_CLOCKWISE_180 || image_orientation == IMAGE_FLIP_VER || + image_orientation == IMAGE_FLIP_HOR) { + return; + } + + uint32_t tmp = *width; + *width = *height; + *height = tmp; +} + static lv_draw_buf_t * decode_jpeg_file(const char * filename) { /* This struct contains the JPEG decompression parameters and pointers to @@ -223,7 +267,6 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) JSAMPARRAY buffer; /* Output row buffer */ uint32_t row_stride; /* physical row width in output buffer */ - uint32_t image_angle = 0; /* image rotate angle */ lv_draw_buf_t * decoded = NULL; @@ -240,6 +283,9 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) return NULL; } + /* read jpeg exif orientation */ + image_orientation_t image_orientation = get_jpeg_direction(data, data_size); + /* allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ @@ -247,9 +293,7 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) jerr.pub.error_exit = error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if(setjmp(jerr.jb)) { - LV_LOG_WARN("decoding error"); - if(decoded) { lv_draw_buf_destroy(decoded); } @@ -262,20 +306,13 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) return NULL; } - /* Get rotate angle from Exif data */ - if(!get_jpeg_direction(data, data_size, &image_angle)) { - LV_LOG_WARN("read jpeg orientation failed."); - } - /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* specify data source (eg, a file or buffer) */ - jpeg_mem_src(&cinfo, data, data_size); /* read file parameters with jpeg_read_header() */ - jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since @@ -285,15 +322,18 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) */ /* set parameters for decompression */ - - cinfo.out_color_space = JCS_EXT_BGR; + if(cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK) { + cinfo.out_color_space = JCS_CMYK; + } + else { + cinfo.out_color_space = JCS_EXT_BGR; + } /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Start decompressor */ - jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible @@ -311,10 +351,23 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - uint32_t buf_width = (image_angle % 180) ? cinfo.output_height : cinfo.output_width; - uint32_t buf_height = (image_angle % 180) ? cinfo.output_width : cinfo.output_height; - decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, buf_width, buf_height, LV_COLOR_FORMAT_RGB888, - LV_STRIDE_AUTO); + + uint32_t width = cinfo.output_width; + uint32_t height = cinfo.output_height; + convert_size_with_orientation(image_orientation, &width, &height); + + lv_image_header_t image_header = { 0 }; + image_header.w = width; + image_header.h = height; + image_header.stride = row_stride; + + lv_color_format_t fm = LV_COLOR_FORMAT_RGB888; + if(cinfo.out_color_space == JCS_CMYK) { + fm = LV_COLOR_FORMAT_XRGB8888; + } + + /* Allocate the decoded draw buffer */ + decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, width, height, fm, LV_STRIDE_AUTO); if(decoded != NULL) { uint32_t line_index = 0; /* while (scan lines remain to be read) */ @@ -330,9 +383,13 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) */ jpeg_read_scanlines(&cinfo, buffer, 1); - /* Assume put_scanline_someplace wants a pointer and sample count. */ - rotate_buffer(decoded, buffer[0], line_index, image_angle, row_stride); + if(cinfo.out_color_space == JCS_CMYK) { + jpeg_cmyk_to_bgrx(buffer[0], decoded->header.w); + } + /* Assume put_scanline_someplace wants a pointer and sample count. */ + process_buffer_orientation(image_orientation, decoded->data, &image_header, line_index, buffer[0], + decoded->header.stride); line_index++; } } @@ -357,15 +414,10 @@ static lv_draw_buf_t * decode_jpeg_file(const char * filename) */ lv_free(data); - /* At this point you may want to check to see whether any corrupt-data - * warnings occurred (test whether jerr.pub.num_warnings is nonzero). - */ - - /* And we're done! */ return decoded; } -static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height, uint32_t * orientation) +static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t * height) { uint8_t * data = NULL; uint32_t data_size; @@ -378,15 +430,18 @@ static bool get_jpeg_head_info(const char * filename, uint32_t * width, uint32_t LV_LOG_WARN("read jpeg size failed."); } - if(!get_jpeg_direction(data, data_size, orientation)) { - LV_LOG_WARN("read jpeg orientation failed."); - } - lv_free(data); return JPEG_HEADER_OK; } +static void jpeg_decompress_prepare(struct jpeg_decompress_struct * cinfo, uint8_t * data, uint32_t data_size) +{ + jpeg_create_decompress(cinfo); + jpeg_mem_src(cinfo, data, data_size); + jpeg_save_markers(cinfo, APP1_MARKER, MARKER_DATA_LIMIT); +} + static bool get_jpeg_size(uint8_t * data, uint32_t data_size, uint32_t * width, uint32_t * height) { struct jpeg_decompress_struct cinfo; @@ -401,27 +456,31 @@ static bool get_jpeg_size(uint8_t * data, uint32_t data_size, uint32_t * width, return false; } - jpeg_create_decompress(&cinfo); - - jpeg_mem_src(&cinfo, data, data_size); + /* jpeg_create_decompress */ + jpeg_decompress_prepare(&cinfo, data, data_size); int ret = jpeg_read_header(&cinfo, TRUE); + if(ret != JPEG_HEADER_OK) { + LV_LOG_WARN("read jpeg header failed: %d", ret); + jpeg_destroy_decompress(&cinfo); + return false; + } - if(ret == JPEG_HEADER_OK) { - *width = cinfo.image_width; - *height = cinfo.image_height; - } - else { - LV_LOG_WARN("read jpeg head failed: %d", ret); - } + /* read file exif orientation */ + image_orientation_t op = jpeg_markers_reader(&cinfo); + + *width = cinfo.image_width; + *height = cinfo.image_height; + convert_size_with_orientation(op, width, height); jpeg_destroy_decompress(&cinfo); - return JPEG_HEADER_OK; + return true; } -static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * orientation) +static image_orientation_t get_jpeg_direction(uint8_t * data, uint32_t data_size) { + image_orientation_t res = IMAGE_CLOCKWISE_NONE; struct jpeg_decompress_struct cinfo; error_mgr_t jerr; @@ -431,26 +490,93 @@ static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * or if(setjmp(jerr.jb)) { LV_LOG_WARN("read jpeg orientation failed"); jpeg_destroy_decompress(&cinfo); - return false; + return res; + } + /* jpeg_create_decompress */ + jpeg_decompress_prepare(&cinfo, data, data_size); + /* read file exif orientation */ + res = jpeg_markers_reader(&cinfo); + + jpeg_destroy_decompress(&cinfo); + + LV_LOG_INFO("read jpeg orientation data : %d", res); + + return res; +} + +static inline void process_buffer_orientation(image_orientation_t op, uint8_t * cur_pos, lv_image_header_t * header, + uint32_t line_index, uint8_t * buffer, uint32_t buf_stride) +{ + uint32_t dst_index = 0; + switch(op) { + case IMAGE_CLOCKWISE_NONE: + case IMAGE_CLOCKWISE_0: + lv_memcpy(cur_pos + line_index * buf_stride, buffer, header->stride); + break; + case IMAGE_CLOCKWISE_90: + for(uint32_t x = 0; x < header->h; x++) { + dst_index = x * buf_stride + (header->w - line_index - 1) * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + case IMAGE_CLOCKWISE_180: + for(uint32_t x = 0; x < header->w; x++) { + dst_index = (header->h - line_index - 1) * buf_stride + x * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + (header->w - x - 1) * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + case IMAGE_CLOCKWISE_270: + for(uint32_t x = 0; x < header->h; x++) { + dst_index = (header->h - x - 1) * buf_stride + line_index * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + case IMAGE_FLIP_VER: + dst_index = (header->h - line_index - 1) * buf_stride; + lv_memcpy(cur_pos + dst_index, buffer, header->stride); + break; + case IMAGE_FLIP_HOR: + for(uint32_t x = 0; x < header->w; x++) { + dst_index = line_index * buf_stride + (header->w - x - 1) * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + case IMAGE_TRANSPOSE: + for(uint32_t x = 0; x < header->h; x++) { + dst_index = x * buf_stride + line_index * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + case IMAGE_TRANSVERSE: + for(uint32_t x = 0; x < header->h; x++) { + dst_index = (header->h - x - 1) * buf_stride + (header->w - line_index - 1) * JPEG_PIXEL_SIZE; + lv_memcpy(cur_pos + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); + } + break; + default: + lv_memcpy(cur_pos + line_index * buf_stride, buffer, header->stride); + break; + } +} + +static image_orientation_t jpeg_markers_reader(struct jpeg_decompress_struct * cinfo) +{ + image_orientation_t res = IMAGE_CLOCKWISE_NONE; + + if(cinfo == NULL || cinfo->marker == NULL) { + return res; } - jpeg_create_decompress(&cinfo); + cinfo->marker->read_markers(cinfo); - jpeg_mem_src(&cinfo, data, data_size); - - jpeg_save_markers(&cinfo, JPEG_APP0 + 1, 0xFFFF); - - cinfo.marker->read_markers(&cinfo); - - jpeg_saved_marker_ptr marker = cinfo.marker_list; + jpeg_saved_marker_ptr marker = cinfo->marker_list; while(marker != NULL) { - if(marker->marker == JPEG_APP0 + 1) { + if(marker->marker == APP1_MARKER) { JOCTET FAR * app1_data = marker->data; if(TRANS_32_VALUE(true, app1_data) == JPEG_EXIF) { uint16_t endian_tag = TRANS_16_VALUE(true, app1_data + 4 + 2); if(!(endian_tag == JPEG_LITTLE_ENDIAN_TAG || endian_tag == JPEG_BIG_ENDIAN_TAG)) { - jpeg_destroy_decompress(&cinfo); - return false; + return res; } bool is_big_endian = endian_tag == JPEG_BIG_ENDIAN_TAG; /* first ifd offset addr : 4bytes(Exif) + 2bytes(0x00) + 2bytes(align) + 2bytes(tag mark) */ @@ -461,37 +587,20 @@ static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * or /* ifd start: 4bytes(Exif) + 2bytes(0x00) + offset value(2bytes(align) + 2bytes(tag mark) + 4bytes(offset size)) */ unsigned int entry_offset = 4 + 2 + offset + 2; if(entry_offset >= marker->data_length) { - jpeg_destroy_decompress(&cinfo); - return false; + return res; } ifd = app1_data + entry_offset; unsigned short num_entries = TRANS_16_VALUE(is_big_endian, ifd - 2); if(entry_offset + num_entries * 12 >= marker->data_length) { - jpeg_destroy_decompress(&cinfo); - return false; + return res; } for(int i = 0; i < num_entries; i++) { unsigned short tag = TRANS_16_VALUE(is_big_endian, ifd); - if(tag == 0x0112) { + if(tag == ORIENTATION_TAG) { /* ifd entry: 12bytes = 2bytes(tag number) + 2bytes(kind of data) + 4bytes(number of components) + 4bytes(data) * orientation kind(0x03) of data is unsigned short */ - int dirc = TRANS_16_VALUE(is_big_endian, ifd + 2 + 2 + 4); - switch(dirc) { - case 1: - *orientation = 0; - break; - case 3: - *orientation = 180; - break; - case 6: - *orientation = 90; - break; - case 8: - *orientation = 270; - break; - default: - *orientation = 0; - } + uint32_t dirc = TRANS_16_VALUE(is_big_endian, ifd + 2 + 2 + 4); + res = (dirc >= IMAGE_CLOCKWISE_0 && dirc <= IMAGE_CLOCKWISE_270) ? (image_orientation_t)dirc : IMAGE_CLOCKWISE_NONE; } ifd += 12; } @@ -503,34 +612,25 @@ static bool get_jpeg_direction(uint8_t * data, uint32_t data_size, uint32_t * or marker = marker->next; } - jpeg_destroy_decompress(&cinfo); - - return JPEG_HEADER_OK; + return res; } -static void rotate_buffer(lv_draw_buf_t * decoded, uint8_t * buffer, uint32_t line_index, uint32_t angle, - uint32_t row_stride) +static void jpeg_cmyk_to_bgrx(uint8_t * cmyk_data, uint32_t pixel_count) { - if(angle == 90) { - for(uint32_t x = 0; x < decoded->header.h; x++) { - uint32_t dst_index = x * decoded->header.stride + (decoded->header.w - line_index - 1) * JPEG_PIXEL_SIZE; - lv_memcpy(decoded->data + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); - } - } - else if(angle == 180) { - for(uint32_t x = 0; x < decoded->header.w; x++) { - uint32_t dst_index = (decoded->header.h - line_index - 1) * decoded->header.stride + x * JPEG_PIXEL_SIZE; - lv_memcpy(decoded->data + dst_index, buffer + (decoded->header.w - x - 1) * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); - } - } - else if(angle == 270) { - for(uint32_t x = 0; x < decoded->header.h; x++) { - uint32_t dst_index = (decoded->header.h - x - 1) * decoded->header.stride + line_index * JPEG_PIXEL_SIZE; - lv_memcpy(decoded->data + dst_index, buffer + x * JPEG_PIXEL_SIZE, JPEG_PIXEL_SIZE); - } - } - else { - lv_memcpy(decoded->data + line_index * decoded->header.stride, buffer, row_stride); + uint8_t * ptr = cmyk_data; + for(uint32_t i = 0; i < pixel_count; i++) { + uint8_t c = 255 - ptr[0]; + uint8_t m = 255 - ptr[1]; + uint8_t y = 255 - ptr[2]; + uint8_t k = 255 - ptr[3]; + + uint16_t inv_k = 255 - k; + ptr[0] = (uint8_t)(((inv_k * (255 - y)) + 128) / 255); + ptr[1] = (uint8_t)(((inv_k * (255 - m)) + 128) / 255); + ptr[2] = (uint8_t)(((inv_k * (255 - c)) + 128) / 255); + ptr[3] = 255; + + ptr += 4; } } diff --git a/tests/ref_imgs/libs/jpg_2.png b/tests/ref_imgs/libs/jpg_2.png index 6a7ec4835b..4c852ecfad 100644 Binary files a/tests/ref_imgs/libs/jpg_2.png and b/tests/ref_imgs/libs/jpg_2.png differ diff --git a/tests/ref_imgs/libs/jpg_3.png b/tests/ref_imgs/libs/jpg_3.png index b80898ea05..21e419f661 100644 Binary files a/tests/ref_imgs/libs/jpg_3.png and b/tests/ref_imgs/libs/jpg_3.png differ diff --git a/tests/ref_imgs/libs/jpg_cmyk.png b/tests/ref_imgs/libs/jpg_cmyk.png new file mode 100644 index 0000000000..29502f9593 Binary files /dev/null and b/tests/ref_imgs/libs/jpg_cmyk.png differ diff --git a/tests/ref_imgs/libs/jpg_sign_error.png b/tests/ref_imgs/libs/jpg_sign_error.png new file mode 100644 index 0000000000..3607a3be77 Binary files /dev/null and b/tests/ref_imgs/libs/jpg_sign_error.png differ diff --git a/tests/ref_imgs_vg_lite/libs/jpg_2.png b/tests/ref_imgs_vg_lite/libs/jpg_2.png index 8c644b20de..f7372ebed6 100644 Binary files a/tests/ref_imgs_vg_lite/libs/jpg_2.png and b/tests/ref_imgs_vg_lite/libs/jpg_2.png differ diff --git a/tests/ref_imgs_vg_lite/libs/jpg_cmyk.png b/tests/ref_imgs_vg_lite/libs/jpg_cmyk.png new file mode 100644 index 0000000000..29502f9593 Binary files /dev/null and b/tests/ref_imgs_vg_lite/libs/jpg_cmyk.png differ diff --git a/tests/ref_imgs_vg_lite/libs/jpg_sign_error.png b/tests/ref_imgs_vg_lite/libs/jpg_sign_error.png new file mode 100644 index 0000000000..3607a3be77 Binary files /dev/null and b/tests/ref_imgs_vg_lite/libs/jpg_sign_error.png differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_cmyk.jpg b/tests/src/test_assets/test_img_lvgl_logo_cmyk.jpg new file mode 100644 index 0000000000..2b966472c0 Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_cmyk.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_decode_failed.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_decode_failed.jpg new file mode 100644 index 0000000000..c9aa980f29 Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_decode_failed.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_0.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_0.jpg index cf376169c6..ba8a8796b0 100644 Binary files a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_0.jpg and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_0.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg index 4012681446..a9d6940be6 100644 Binary files a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg index 2a51a73c72..3492729a76 100644 Binary files a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg index e4fc0fd70e..4a2bfe5d66 100644 Binary files a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_hflip.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_hflip.jpg new file mode 100644 index 0000000000..259dfbd2be Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_hflip.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transpose.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transpose.jpg new file mode 100644 index 0000000000..92e5f7343d Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transpose.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transverse.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transverse.jpg new file mode 100644 index 0000000000..5c03a3bfdb Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_transverse.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_vflip.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_vflip.jpg new file mode 100644 index 0000000000..d2ac4d06ef Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_exif_orientation_vflip.jpg differ diff --git a/tests/src/test_assets/test_img_lvgl_logo_with_sign_error.jpg b/tests/src/test_assets/test_img_lvgl_logo_with_sign_error.jpg new file mode 100644 index 0000000000..af33f10568 Binary files /dev/null and b/tests/src/test_assets/test_img_lvgl_logo_with_sign_error.jpg differ diff --git a/tests/src/test_cases/libs/test_libjpeg_turbo.c b/tests/src/test_cases/libs/test_libjpeg_turbo.c index 248b8de436..dad12c9372 100644 --- a/tests/src/test_cases/libs/test_libjpeg_turbo.c +++ b/tests/src/test_cases/libs/test_libjpeg_turbo.c @@ -15,44 +15,46 @@ void tearDown(void) /* Function run after every test */ } +static void create_image_unit(const char * img_src, uint32_t image_pos_x, uint32_t image_pos_y, const char * label_text, + uint32_t label_pos_x, uint32_t label_pos_y) +{ + lv_obj_t * img = lv_image_create(lv_screen_active()); + lv_image_set_src(img, img_src); + lv_obj_align(img, LV_ALIGN_CENTER, image_pos_x, image_pos_y); + + lv_obj_t * label = lv_label_create(lv_screen_active()); + lv_label_set_text(label, label_text); + lv_obj_align(label, LV_ALIGN_CENTER, label_pos_x, label_pos_y); +} + static void create_images(void) { lv_obj_clean(lv_screen_active()); - lv_obj_t * img; - lv_obj_t * label; - - img = lv_image_create(lv_screen_active()); - lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo.jpg"); - lv_obj_align(img, LV_ALIGN_CENTER, -150, -150); - - label = lv_label_create(lv_screen_active()); - lv_label_set_text(label, "jpeg with exif orientation 0"); - lv_obj_align(label, LV_ALIGN_CENTER, -150, -100); - - img = lv_image_create(lv_screen_active()); - lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg"); - lv_obj_align(img, LV_ALIGN_CENTER, 150, -150); - - label = lv_label_create(lv_screen_active()); - lv_label_set_text(label, "jpeg with exif orientation 180"); - lv_obj_align(label, LV_ALIGN_CENTER, 150, -100); - - img = lv_image_create(lv_screen_active()); - lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg"); - lv_obj_align(img, LV_ALIGN_CENTER, -150, 40); - - label = lv_label_create(lv_screen_active()); - lv_label_set_text(label, "jpeg with exif orientation 90"); - lv_obj_align(label, LV_ALIGN_CENTER, -150, 150); - - img = lv_image_create(lv_screen_active()); - lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg"); - lv_obj_align(img, LV_ALIGN_CENTER, 150, 40); - - label = lv_label_create(lv_screen_active()); - lv_label_set_text(label, "jpeg with exif orientation 270"); - lv_obj_align(label, LV_ALIGN_CENTER, 150, 150); + /* Test images with exif orientation 0 */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_0.jpg", -150, -150, + "jpeg with exif orientation 0", -150, -110); + /* Test images with exif orientation 180 */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_180.jpg", 150, -150, + "jpeg with exif orientation 180", 150, -110); + /* Test images with exif orientation hflip */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_hflip.jpg", -150, -60, + "jpeg with exif orientation hflip", -150, -20); + /* Test images with exif orientation vflip */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_vflip.jpg", 150, -60, + "jpeg with exif orientation vflip", 150, -20); + /* Test images with exif orientation 90 */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_90.jpg", -280, 70, "orientation 90", -280, + 150); + /* Test images with exif orientation 270 */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_270.jpg", -100, 70, "orientation 270", + -100, 150); + /* Test images with exif orientation transpose */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_transpose.jpg", 100, 70, + "orientation transpose", 100, 150); + /* Test images with exif orientation transverse */ + create_image_unit("A:src/test_assets/test_img_lvgl_logo_with_exif_orientation_transverse.jpg", 300, 70, + "orientation transverse", 300, 150); } void test_jpg_2(void) @@ -80,4 +82,54 @@ void test_jpg_2(void) lv_tjpgd_init(); } +void test_jpg_cmyk(void) +{ + /* Temporarily remove tjpgd decoder */ + lv_tjpgd_deinit(); + + lv_obj_clean(lv_screen_active()); + lv_obj_t * img = lv_image_create(lv_screen_active()); + lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_cmyk.jpg"); + lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); + + TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_cmyk.png"); + + /* Re-add tjpgd decoder */ + lv_tjpgd_init(); +} + +void test_jpg_sign_error(void) +{ + /* Temporarily remove tjpgd decoder */ + lv_tjpgd_deinit(); + + lv_obj_clean(lv_screen_active()); + lv_obj_t * img = lv_image_create(lv_screen_active()); + lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_with_sign_error.jpg"); + lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); + + TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_sign_error.png"); + + /* Re-add tjpgd decoder */ + lv_tjpgd_init(); +} + +void test_jpg_decode_failed(void) +{ + /* Temporarily remove tjpgd decoder */ + lv_tjpgd_deinit(); + + lv_image_decoder_dsc_t decoder_dsc; + const char * image_path = "A:src/test_assets/test_img_lvgl_logo_with_decode_failed.jpg"; + + /* Try to decode the image */ + lv_result_t res = lv_image_decoder_open(&decoder_dsc, image_path, NULL); + + /* Should fail when decoder is removed */ + TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res); + + /* Re-add tjpgd decoder */ + lv_tjpgd_init(); +} + #endif