feat(libs): add libjpeg-turbo decoder (#4567)
Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com> Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
2
.github/workflows/ccpp.yml
vendored
2
.github/workflows/ccpp.yml
vendored
@@ -86,7 +86,7 @@ jobs:
|
|||||||
|
|
||||||
install: |
|
install: |
|
||||||
apt-get update -y
|
apt-get update -y
|
||||||
apt-get install build-essential ccache python3 libpng-dev ruby-full gcovr cmake -q -y
|
apt-get install build-essential ccache python3 libpng-dev ruby-full gcovr cmake libjpeg62-turbo-dev -q -y
|
||||||
/usr/sbin/update-ccache-symlinks
|
/usr/sbin/update-ccache-symlinks
|
||||||
echo 'export PATH="/usr/lib/ccache:$PATH"' | tee -a ~/.bashrc
|
echo 'export PATH="/usr/lib/ccache:$PATH"' | tee -a ~/.bashrc
|
||||||
|
|
||||||
|
|||||||
3
Kconfig
3
Kconfig
@@ -1017,6 +1017,9 @@ menu "LVGL configuration"
|
|||||||
config LV_USE_TJPGD
|
config LV_USE_TJPGD
|
||||||
bool "TJPGD decoder library"
|
bool "TJPGD decoder library"
|
||||||
|
|
||||||
|
config LV_USE_LIBJPEG_TURBO
|
||||||
|
bool "libjpeg-turbo decoder library"
|
||||||
|
|
||||||
config LV_USE_GIF
|
config LV_USE_GIF
|
||||||
bool "GIF decoder library"
|
bool "GIF decoder library"
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
fs
|
fs
|
||||||
bmp
|
bmp
|
||||||
tjpgd
|
tjpgd
|
||||||
sjpg
|
libjpeg_turbo
|
||||||
lodepng
|
lodepng
|
||||||
gif
|
gif
|
||||||
freetype
|
freetype
|
||||||
|
|||||||
43
docs/libs/libjpeg_turbo.rst
Normal file
43
docs/libs/libjpeg_turbo.rst
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
=====================
|
||||||
|
libjpge-turbo decoder
|
||||||
|
=====================
|
||||||
|
|
||||||
|
libjpeg-turbo is a JPEG image codec that uses SIMD instructions to accelerate baseline JPEG compression and decompression on x86,
|
||||||
|
x86-64, Arm, PowerPC, and MIPS systems, as well as progressive JPEG compression on x86, x86-64, and Arm systems.
|
||||||
|
Detailed introduction: `libjpeg-turbo <https://github.com/libjpeg-turbo/libjpeg-turbo>`__.
|
||||||
|
|
||||||
|
Install
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo apt install libjpeg-turbo8-dev
|
||||||
|
|
||||||
|
Add libjpge-turbo to your project
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. code:: cmake
|
||||||
|
|
||||||
|
find_package(JPEG REQUIRED)
|
||||||
|
include_directories(${JPEG_INCLUDE_DIR})
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${JPEG_LIBRARIES})
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Enable :c:macro:`LV_USE_LIBJEPG_TURBO` in ``lv_conf.h``.
|
||||||
|
|
||||||
|
See the examples below.
|
||||||
|
It should be noted that each image of this decoder needs to consume ``image width x image height x 3`` bytes of RAM,
|
||||||
|
and it needs to be combined with the ref:`image-caching` feature to ensure that the memory usage is within a reasonable range.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. include:: ../examples/libs/libjpeg_turbo/index.rst
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
|
||||||
|
:ref:`libjpeg_turbo`
|
||||||
|
|
||||||
BIN
examples/libs/libjpeg_turbo/flower.jpg
Normal file
BIN
examples/libs/libjpeg_turbo/flower.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
6
examples/libs/libjpeg_turbo/index.rst
Normal file
6
examples/libs/libjpeg_turbo/index.rst
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Load an JPG image
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. lv_example:: libs/libjpeg_turbo/lv_example_libjpeg_turbo_1
|
||||||
|
:language: c
|
||||||
|
|
||||||
38
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo.h
Normal file
38
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_example_libjpeg_turbo.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LV_EXAMPLE_LIBJPEG_TURBO_H
|
||||||
|
#define LV_EXAMPLE_LIBJPEG_TURBO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void lv_example_libjpeg_turbo_1(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /*extern "C"*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*LV_EXAMPLE_LIBJPEG_TURBO_H*/
|
||||||
18
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo_1.c
Normal file
18
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo_1.c
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "../../lv_examples.h"
|
||||||
|
#if LV_USE_LIBJPEG_TURBO && LV_BUILD_EXAMPLES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a JPG image
|
||||||
|
*/
|
||||||
|
void lv_example_libjpeg_turbo_1(void)
|
||||||
|
{
|
||||||
|
lv_obj_t * wp;
|
||||||
|
|
||||||
|
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/libjpeg_turbo/flower.jpg");
|
||||||
|
lv_obj_center(wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
13
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo_1.py
Executable file
13
examples/libs/libjpeg_turbo/lv_example_libjpeg_turbo_1.py
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/opt/bin/lv_micropython -i
|
||||||
|
import lvgl as lv
|
||||||
|
import display_driver
|
||||||
|
import fs_driver
|
||||||
|
|
||||||
|
fs_drv = lv.fs_drv_t()
|
||||||
|
fs_driver.fs_register(fs_drv, 'S')
|
||||||
|
|
||||||
|
wp = lv.image(lv.scr_act())
|
||||||
|
# The File system is attached to letter 'S'
|
||||||
|
|
||||||
|
wp.set_src("S:flower.jpg")
|
||||||
|
wp.center()
|
||||||
@@ -22,6 +22,7 @@ extern "C" {
|
|||||||
#include "qrcode/lv_example_qrcode.h"
|
#include "qrcode/lv_example_qrcode.h"
|
||||||
#include "rlottie/lv_example_rlottie.h"
|
#include "rlottie/lv_example_rlottie.h"
|
||||||
#include "tjpgd/lv_example_tjpgd.h"
|
#include "tjpgd/lv_example_tjpgd.h"
|
||||||
|
#include "libjpeg_turbo/lv_example_libjpeg_turbo.h"
|
||||||
#include "tiny_ttf/lv_example_tiny_ttf.h"
|
#include "tiny_ttf/lv_example_tiny_ttf.h"
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
|
|||||||
@@ -591,6 +591,10 @@
|
|||||||
* Split JPG is a custom format optimized for embedded systems. */
|
* Split JPG is a custom format optimized for embedded systems. */
|
||||||
#define LV_USE_TJPGD 0
|
#define LV_USE_TJPGD 0
|
||||||
|
|
||||||
|
/* libjpeg-turbo decoder library.
|
||||||
|
* Supports complete JPEG specifications and high-performance JPEG decoding. */
|
||||||
|
#define LV_USE_LIBJPEG_TURBO 0
|
||||||
|
|
||||||
/*GIF decoder library*/
|
/*GIF decoder library*/
|
||||||
#define LV_USE_GIF 0
|
#define LV_USE_GIF 0
|
||||||
|
|
||||||
|
|||||||
1
lvgl.h
1
lvgl.h
@@ -96,6 +96,7 @@ extern "C" {
|
|||||||
#include "src/libs/gif/lv_gif.h"
|
#include "src/libs/gif/lv_gif.h"
|
||||||
#include "src/libs/qrcode/lv_qrcode.h"
|
#include "src/libs/qrcode/lv_qrcode.h"
|
||||||
#include "src/libs/tjpgd/lv_tjpgd.h"
|
#include "src/libs/tjpgd/lv_tjpgd.h"
|
||||||
|
#include "src/libs/libjpeg_turbo/lv_libjpeg_turbo.h"
|
||||||
#include "src/libs/freetype/lv_freetype.h"
|
#include "src/libs/freetype/lv_freetype.h"
|
||||||
#include "src/libs/rlottie/lv_rlottie.h"
|
#include "src/libs/rlottie/lv_rlottie.h"
|
||||||
#include "src/libs/ffmpeg/lv_ffmpeg.h"
|
#include "src/libs/ffmpeg/lv_ffmpeg.h"
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
#
|
#
|
||||||
# Note: This script is run by the CI workflows.
|
# Note: This script is run by the CI workflows.
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install gcc python3 libpng-dev ruby-full gcovr cmake
|
sudo apt install gcc python3 libpng-dev ruby-full gcovr cmake libjpeg-turbo8-dev
|
||||||
|
|||||||
477
src/libs/libjpeg_turbo/lv_libjpeg_turbo.c
Normal file
477
src/libs/libjpeg_turbo/lv_libjpeg_turbo.c
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_libjpeg_turbo.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "../../../lvgl.h"
|
||||||
|
#if LV_USE_LIBJPEG_TURBO
|
||||||
|
|
||||||
|
#include "lv_libjpeg_turbo.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define JPEG_PIXEL_SIZE 3 /* RGB888 */
|
||||||
|
#define JPEG_SIGNATURE 0xFFD8FF
|
||||||
|
#define IS_JPEG_SIGNATURE(x) (((x) & 0x00FFFFFF) == JPEG_SIGNATURE)
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
typedef struct error_mgr_s {
|
||||||
|
struct jpeg_error_mgr pub;
|
||||||
|
jmp_buf jb;
|
||||||
|
} error_mgr_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, 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 const void * decode_jpeg_file(const char * filename);
|
||||||
|
static bool get_jpeg_size(const char * filename, uint32_t * width, uint32_t * height);
|
||||||
|
static void error_exit(j_common_ptr cinfo);
|
||||||
|
static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the JPEG decoder functions in LVGL
|
||||||
|
*/
|
||||||
|
void lv_libjpeg_turbo_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_libjpeg_turbo_deinit(void)
|
||||||
|
{
|
||||||
|
lv_image_decoder_t * dec = NULL;
|
||||||
|
while((dec = lv_image_decoder_get_next(dec)) != NULL) {
|
||||||
|
if(dec->info_cb == decoder_info) {
|
||||||
|
lv_image_decoder_delete(dec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info about a JPEG image
|
||||||
|
* @param src can be file name or pointer to a C array
|
||||||
|
* @param header store the info here
|
||||||
|
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info
|
||||||
|
*/
|
||||||
|
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header)
|
||||||
|
{
|
||||||
|
LV_UNUSED(decoder); /*Unused*/
|
||||||
|
lv_image_src_t src_type = lv_image_src_get_type(src); /*Get the source type*/
|
||||||
|
|
||||||
|
/*If it's a JPEG file...*/
|
||||||
|
if(src_type == LV_IMAGE_SRC_FILE) {
|
||||||
|
const char * fn = src;
|
||||||
|
|
||||||
|
lv_fs_file_t f;
|
||||||
|
lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
|
||||||
|
if(res != LV_FS_RES_OK) {
|
||||||
|
LV_LOG_WARN("Can't open file: %s", fn);
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t jpg_signature = 0;
|
||||||
|
uint32_t rn;
|
||||||
|
lv_fs_read(&f, &jpg_signature, sizeof(jpg_signature), &rn);
|
||||||
|
lv_fs_close(&f);
|
||||||
|
|
||||||
|
if(rn != sizeof(jpg_signature)) {
|
||||||
|
LV_LOG_WARN("file: %s signature len = %" LV_PRIu32 " error", fn, rn);
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_jpeg_ext = (strcmp(lv_fs_get_ext(fn), "jpg") == 0)
|
||||||
|
|| (strcmp(lv_fs_get_ext(fn), "jpeg") == 0);
|
||||||
|
|
||||||
|
if(!IS_JPEG_SIGNATURE(jpg_signature)) {
|
||||||
|
if(is_jpeg_ext) {
|
||||||
|
LV_LOG_WARN("file: %s signature = 0X%" LV_PRIX32 " error", fn, jpg_signature);
|
||||||
|
}
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
if(!get_jpeg_size(fn, &width, &height)) {
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Save the data in the header*/
|
||||||
|
header->always_zero = 0;
|
||||||
|
header->cf = LV_COLOR_FORMAT_RGB888;
|
||||||
|
header->w = width;
|
||||||
|
header->h = height;
|
||||||
|
|
||||||
|
return LV_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LV_RESULT_INVALID; /*If didn't succeeded earlier then it's an error*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a JPEG image and return the decided image
|
||||||
|
* @param src can be file name or pointer to a C array
|
||||||
|
* @param style style of the image object (unused now but certain formats might use it)
|
||||||
|
* @return pointer to the decoded image or `LV_IMAGE_DECODER_OPEN_FAIL` if failed
|
||||||
|
*/
|
||||||
|
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
|
||||||
|
{
|
||||||
|
LV_UNUSED(decoder); /*Unused*/
|
||||||
|
|
||||||
|
/*Check the cache first*/
|
||||||
|
if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK;
|
||||||
|
|
||||||
|
/*If it's a JPEG file...*/
|
||||||
|
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
|
||||||
|
const char * fn = dsc->src;
|
||||||
|
|
||||||
|
lv_cache_lock();
|
||||||
|
lv_cache_entry_t * cache = lv_cache_add(dsc->header.w * dsc->header.h * JPEG_PIXEL_SIZE);
|
||||||
|
if(cache == NULL) {
|
||||||
|
lv_cache_unlock();
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t t = lv_tick_get();
|
||||||
|
const void * decoded_img = decode_jpeg_file(fn);
|
||||||
|
t = lv_tick_elaps(t);
|
||||||
|
cache->weight = t;
|
||||||
|
cache->data = decoded_img;
|
||||||
|
cache->free_data = 1;
|
||||||
|
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
|
||||||
|
cache->src = lv_strdup(dsc->src);
|
||||||
|
cache->src_type = LV_CACHE_SRC_TYPE_STR;
|
||||||
|
cache->free_src = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cache->src_type = LV_CACHE_SRC_TYPE_PTR;
|
||||||
|
cache->src = dsc->src;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsc->img_data = lv_cache_get_data(cache);
|
||||||
|
dsc->user_data = cache;
|
||||||
|
|
||||||
|
lv_cache_unlock();
|
||||||
|
return LV_RESULT_OK; /*If not returned earlier then it failed*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return LV_RESULT_INVALID; /*If not returned earlier then it failed*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the allocated resources
|
||||||
|
*/
|
||||||
|
static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
|
||||||
|
{
|
||||||
|
LV_UNUSED(decoder); /*Unused*/
|
||||||
|
lv_cache_lock();
|
||||||
|
lv_cache_release(dsc->user_data);
|
||||||
|
lv_cache_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc)
|
||||||
|
{
|
||||||
|
lv_cache_lock();
|
||||||
|
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
|
||||||
|
const char * fn = dsc->src;
|
||||||
|
|
||||||
|
lv_cache_entry_t * cache = lv_cache_find(fn, LV_CACHE_SRC_TYPE_STR, 0, 0);
|
||||||
|
if(cache) {
|
||||||
|
dsc->img_data = lv_cache_get_data(cache);
|
||||||
|
dsc->user_data = cache; /*Save the cache to release it in decoder_close*/
|
||||||
|
lv_cache_unlock();
|
||||||
|
return LV_RESULT_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_cache_unlock();
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t * alloc_file(const char * filename, uint32_t * size)
|
||||||
|
{
|
||||||
|
uint8_t * data = NULL;
|
||||||
|
lv_fs_file_t f;
|
||||||
|
uint32_t data_size;
|
||||||
|
uint32_t rn;
|
||||||
|
lv_fs_res_t res;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
res = lv_fs_open(&f, filename, LV_FS_MODE_RD);
|
||||||
|
if(res != LV_FS_RES_OK) {
|
||||||
|
LV_LOG_WARN("can't open %s", filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = lv_fs_seek(&f, 0, LV_FS_SEEK_END);
|
||||||
|
if(res != LV_FS_RES_OK) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = lv_fs_tell(&f, &data_size);
|
||||||
|
if(res != LV_FS_RES_OK) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = lv_fs_seek(&f, 0, LV_FS_SEEK_SET);
|
||||||
|
if(res != LV_FS_RES_OK) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Read file to buffer*/
|
||||||
|
data = lv_malloc(data_size);
|
||||||
|
if(data == NULL) {
|
||||||
|
LV_LOG_WARN("malloc failed for data");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = lv_fs_read(&f, data, data_size, &rn);
|
||||||
|
|
||||||
|
if(res == LV_FS_RES_OK && rn == data_size) {
|
||||||
|
*size = rn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LV_LOG_WARN("read file failed");
|
||||||
|
lv_free(data);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
failed:
|
||||||
|
lv_fs_close(&f);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void * decode_jpeg_file(const char * filename)
|
||||||
|
{
|
||||||
|
/* This struct contains the JPEG decompression parameters and pointers to
|
||||||
|
* working space (which is allocated as needed by the JPEG library).
|
||||||
|
*/
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
/* We use our private extension JPEG error handler.
|
||||||
|
* Note that this struct must live as long as the main JPEG parameter
|
||||||
|
* struct, to avoid dangling-pointer problems.
|
||||||
|
*/
|
||||||
|
error_mgr_t jerr;
|
||||||
|
|
||||||
|
/* More stuff */
|
||||||
|
JSAMPARRAY buffer; /* Output row buffer */
|
||||||
|
int row_stride; /* physical row width in output buffer */
|
||||||
|
|
||||||
|
uint8_t * output_buffer = NULL;
|
||||||
|
|
||||||
|
/* In this example we want to open the input file before doing anything else,
|
||||||
|
* so that the setjmp() error recovery below can assume the file is open.
|
||||||
|
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
|
||||||
|
* requires it in order to read binary files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t data_size;
|
||||||
|
uint8_t * data = alloc_file(filename, &data_size);
|
||||||
|
if(data == NULL) {
|
||||||
|
LV_LOG_WARN("can't load file %s", filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate and initialize JPEG decompression object */
|
||||||
|
|
||||||
|
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
|
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(output_buffer) {
|
||||||
|
lv_draw_buf_free(output_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, the JPEG code has signaled an error.
|
||||||
|
* We need to clean up the JPEG object, close the input file, and return.
|
||||||
|
*/
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
lv_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* 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
|
||||||
|
* (a) suspension is not possible with the stdio data source, and
|
||||||
|
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
|
||||||
|
* See libjpeg.doc for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* set parameters for decompression */
|
||||||
|
|
||||||
|
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
|
||||||
|
* with the stdio data source.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* We may need to do some setup of our own at this point before reading
|
||||||
|
* the data. After jpeg_start_decompress() we have the correct scaled
|
||||||
|
* output image dimensions available, as well as the output colormap
|
||||||
|
* if we asked for color quantization.
|
||||||
|
* In this example, we need to make an output work buffer of the right size.
|
||||||
|
*/
|
||||||
|
/* JSAMPLEs per row in output buffer */
|
||||||
|
row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
size_t output_buffer_size = cinfo.output_width * cinfo.output_height * JPEG_PIXEL_SIZE;
|
||||||
|
output_buffer = lv_draw_buf_malloc(output_buffer_size, LV_COLOR_FORMAT_RGB888);
|
||||||
|
if(output_buffer) {
|
||||||
|
uint8_t * cur_pos = output_buffer;
|
||||||
|
size_t stride = cinfo.output_width * JPEG_PIXEL_SIZE;
|
||||||
|
|
||||||
|
/* while (scan lines remain to be read) */
|
||||||
|
/* jpeg_read_scanlines(...); */
|
||||||
|
|
||||||
|
/* Here we use the library's state variable cinfo.output_scanline as the
|
||||||
|
* loop counter, so that we don't have to keep track ourselves.
|
||||||
|
*/
|
||||||
|
while(cinfo.output_scanline < cinfo.output_height) {
|
||||||
|
/* jpeg_read_scanlines expects an array of pointers to scanlines.
|
||||||
|
* Here the array is only one element long, but you could ask for
|
||||||
|
* more than one scanline at a time if that's more convenient.
|
||||||
|
*/
|
||||||
|
jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||||
|
|
||||||
|
/* Assume put_scanline_someplace wants a pointer and sample count. */
|
||||||
|
lv_memcpy(cur_pos, buffer[0], stride);
|
||||||
|
cur_pos += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish decompression */
|
||||||
|
|
||||||
|
jpeg_finish_decompress(&cinfo);
|
||||||
|
|
||||||
|
/* We can ignore the return value since suspension is not possible
|
||||||
|
* with the stdio data source.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Release JPEG decompression object */
|
||||||
|
|
||||||
|
/* This is an important step since it will release a good deal of memory. */
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
|
||||||
|
/* After finish_decompress, we can close the input file.
|
||||||
|
* Here we postpone it until after no more JPEG errors are possible,
|
||||||
|
* so as to simplify the setjmp error logic above. (Actually, I don't
|
||||||
|
* think that jpeg_destroy can do an error exit, but why assume anything...)
|
||||||
|
*/
|
||||||
|
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 output_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_jpeg_size(const char * filename, uint32_t * width, uint32_t * height)
|
||||||
|
{
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
error_mgr_t jerr;
|
||||||
|
|
||||||
|
uint8_t * data = NULL;
|
||||||
|
uint32_t data_size;
|
||||||
|
data = alloc_file(filename, &data_size);
|
||||||
|
if(data == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = error_exit;
|
||||||
|
|
||||||
|
if(setjmp(jerr.jb)) {
|
||||||
|
LV_LOG_WARN("read jpeg head failed");
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
lv_free(data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_create_decompress(&cinfo);
|
||||||
|
|
||||||
|
jpeg_mem_src(&cinfo, data, data_size);
|
||||||
|
|
||||||
|
int ret = jpeg_read_header(&cinfo, TRUE);
|
||||||
|
|
||||||
|
if(ret == JPEG_HEADER_OK) {
|
||||||
|
*width = cinfo.image_width;
|
||||||
|
*height = cinfo.image_height;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LV_LOG_WARN("read jpeg head failed: %d", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
|
||||||
|
lv_free(data);
|
||||||
|
|
||||||
|
return (ret == JPEG_HEADER_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_exit(j_common_ptr cinfo)
|
||||||
|
{
|
||||||
|
error_mgr_t * myerr = (error_mgr_t *)cinfo->err;
|
||||||
|
(*cinfo->err->output_message)(cinfo);
|
||||||
|
longjmp(myerr->jb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*LV_USE_LIBJPEG_TURBO*/
|
||||||
48
src/libs/libjpeg_turbo/lv_libjpeg_turbo.h
Normal file
48
src/libs/libjpeg_turbo/lv_libjpeg_turbo.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_libjpeg_turbo.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LV_LIBJPEG_TURBO_H
|
||||||
|
#define LV_LIBJPEG_TURBO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "../../lv_conf_internal.h"
|
||||||
|
#if LV_USE_LIBJPEG_TURBO
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the JPEG-Turbo decoder functions in LVGL
|
||||||
|
*/
|
||||||
|
void lv_libjpeg_turbo_init(void);
|
||||||
|
|
||||||
|
void lv_libjpeg_turbo_deinit(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*LV_USE_LIBJPEG_TURBO*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*LV_LIBJPEG_TURBO_H*/
|
||||||
@@ -1983,6 +1983,16 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* libjpeg-turbo decoder library.
|
||||||
|
* Supports complete JPEG specifications and high-performance JPEG decoding. */
|
||||||
|
#ifndef LV_USE_LIBJPEG_TURBO
|
||||||
|
#ifdef CONFIG_LV_USE_LIBJPEG_TURBO
|
||||||
|
#define LV_USE_LIBJPEG_TURBO CONFIG_LV_USE_LIBJPEG_TURBO
|
||||||
|
#else
|
||||||
|
#define LV_USE_LIBJPEG_TURBO 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/*GIF decoder library*/
|
/*GIF decoder library*/
|
||||||
#ifndef LV_USE_GIF
|
#ifndef LV_USE_GIF
|
||||||
#ifdef CONFIG_LV_USE_GIF
|
#ifdef CONFIG_LV_USE_GIF
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "libs/fsdrv/lv_fsdrv.h"
|
#include "libs/fsdrv/lv_fsdrv.h"
|
||||||
#include "libs/gif/lv_gif.h"
|
#include "libs/gif/lv_gif.h"
|
||||||
#include "libs/tjpgd/lv_tjpgd.h"
|
#include "libs/tjpgd/lv_tjpgd.h"
|
||||||
|
#include "libs/libjpeg_turbo/lv_libjpeg_turbo.h"
|
||||||
#include "libs/lodepng/lv_lodepng.h"
|
#include "libs/lodepng/lv_lodepng.h"
|
||||||
#include "draw/lv_draw.h"
|
#include "draw/lv_draw.h"
|
||||||
#include "misc/lv_cache.h"
|
#include "misc/lv_cache.h"
|
||||||
@@ -237,6 +238,10 @@ void lv_init(void)
|
|||||||
lv_tjpgd_init();
|
lv_tjpgd_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LV_USE_LIBJPEG_TURBO
|
||||||
|
lv_libjpeg_turbo_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LV_USE_BMP
|
#if LV_USE_BMP
|
||||||
lv_bmp_init();
|
lv_bmp_init();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -176,6 +176,10 @@ set(generate_test_runner_rb
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/unity/generate_test_runner.rb)
|
${CMAKE_CURRENT_SOURCE_DIR}/unity/generate_test_runner.rb)
|
||||||
set(generate_test_runner_config ${CMAKE_CURRENT_SOURCE_DIR}/config.yml)
|
set(generate_test_runner_config ${CMAKE_CURRENT_SOURCE_DIR}/config.yml)
|
||||||
|
|
||||||
|
# libjpeg is required for the jpeg test case
|
||||||
|
find_package(JPEG REQUIRED)
|
||||||
|
include_directories(${JPEG_INCLUDE_DIR})
|
||||||
|
|
||||||
# disable test targets for build only tests
|
# disable test targets for build only tests
|
||||||
if (ENABLE_TESTS)
|
if (ENABLE_TESTS)
|
||||||
file( GLOB_RECURSE TEST_CASE_FILES src/test_cases/*.c )
|
file( GLOB_RECURSE TEST_CASE_FILES src/test_cases/*.c )
|
||||||
@@ -204,7 +208,7 @@ foreach( test_case_fname ${TEST_CASE_FILES} )
|
|||||||
${test_case_fname}
|
${test_case_fname}
|
||||||
${test_runner_fname}
|
${test_runner_fname}
|
||||||
)
|
)
|
||||||
target_link_libraries(${test_name} test_common lvgl_demos lvgl png m ${TEST_LIBS})
|
target_link_libraries(${test_name} test_common lvgl_demos lvgl png ${JPEG_LIBRARIES} m ${TEST_LIBS})
|
||||||
target_include_directories(${test_name} PUBLIC ${TEST_INCLUDE_DIRS})
|
target_include_directories(${test_name} PUBLIC ${TEST_INCLUDE_DIRS})
|
||||||
target_compile_options(${test_name} PUBLIC ${LVGL_TESTFILE_COMPILE_OPTIONS})
|
target_compile_options(${test_name} PUBLIC ${LVGL_TESTFILE_COMPILE_OPTIONS})
|
||||||
|
|
||||||
|
|||||||
BIN
tests/ref_imgs/libs/jpg_2.png
Normal file
BIN
tests/ref_imgs/libs/jpg_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
@@ -64,6 +64,7 @@
|
|||||||
#define LV_USE_LODEPNG 1
|
#define LV_USE_LODEPNG 1
|
||||||
#define LV_USE_BMP 1
|
#define LV_USE_BMP 1
|
||||||
#define LV_USE_TJPGD 1
|
#define LV_USE_TJPGD 1
|
||||||
|
#define LV_USE_LIBJPEG_TURBO 1
|
||||||
#define LV_USE_GIF 1
|
#define LV_USE_GIF 1
|
||||||
#define LV_USE_QRCODE 1
|
#define LV_USE_QRCODE 1
|
||||||
#define LV_USE_BARCODE 1
|
#define LV_USE_BARCODE 1
|
||||||
|
|||||||
54
tests/src/test_cases/libs/test_libjpeg_turbo.c
Normal file
54
tests/src/test_cases/libs/test_libjpeg_turbo.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#if LV_BUILD_TEST
|
||||||
|
#include "../lvgl.h"
|
||||||
|
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "lv_test_helpers.h"
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
/* Function run before every test */
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
/* Function run after every test */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_images(void)
|
||||||
|
{
|
||||||
|
lv_obj_clean(lv_scr_act());
|
||||||
|
|
||||||
|
lv_obj_t * img;
|
||||||
|
|
||||||
|
img = lv_img_create(lv_scr_act());
|
||||||
|
lv_img_set_src(img, "A:src/test_assets/test_img_lvgl_logo.jpg");
|
||||||
|
lv_obj_center(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_jpg_2(void)
|
||||||
|
{
|
||||||
|
/* Temporarily remove tjpgd decoder */
|
||||||
|
lv_tjpgd_deinit();
|
||||||
|
|
||||||
|
create_images();
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_2.png");
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t mem_before = lv_test_get_free_mem();
|
||||||
|
for(uint32_t i = 0; i < 20; i++) {
|
||||||
|
create_images();
|
||||||
|
|
||||||
|
lv_obj_invalidate(lv_scr_act());
|
||||||
|
lv_refr_now(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_2.png");
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(mem_before, lv_test_get_free_mem());
|
||||||
|
|
||||||
|
/* Re-add tjpgd decoder */
|
||||||
|
lv_tjpgd_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -41,6 +41,9 @@ static void create_images(void)
|
|||||||
|
|
||||||
void test_tjpgd_1(void)
|
void test_tjpgd_1(void)
|
||||||
{
|
{
|
||||||
|
/* Temporarily remove libjpeg_turbo decoder */
|
||||||
|
lv_libjpeg_turbo_deinit();
|
||||||
|
|
||||||
create_images();
|
create_images();
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_1.png");
|
TEST_ASSERT_EQUAL_SCREENSHOT("libs/jpg_1.png");
|
||||||
@@ -58,6 +61,8 @@ void test_tjpgd_1(void)
|
|||||||
|
|
||||||
TEST_ASSERT_EQUAL(mem_before, lv_test_get_free_mem());
|
TEST_ASSERT_EQUAL(mem_before, lv_test_get_free_mem());
|
||||||
|
|
||||||
|
/* Re-add libjpeg_turbo decoder */
|
||||||
|
lv_libjpeg_turbo_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user