./configure \
--prefix=$PWD/output \
CC= 你的GCC路径
成功生成Makefile,继续执行make,make install,将在当前目录生成ouput文件夹。里面包含了库文件和头文件
#include
#include
#include
#include
/*创建私有的报错错误参数*/
struct my_error_mgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
/*私有的错误处理入口*/
void my_error_exit(j_common_ptr cinfo)
{
struct my_error_mgr *myerr = (struct my_error_mgr *)cinfo->err;
/*错误消息打印*/
(*cinfo->err->output_message)(cinfo);
/* 跳转到指定的函数*/
longjmp(myerr->setjmp_buffer, 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("input param error \n");
exit(0);
}
printf("jpeg input path:%s\n", argv[1]);
printf("jpeg output path:%s \n", argv[2]);
/*解码器需要的参数*/
struct jpeg_decompress_struct cinfo;
/*私有的错误处理参数*/
struct my_error_mgr jerr;
/*打开一个jpg文件句柄*/
FILE *infile = fopen(argv[1], "rb");
if (infile == NULL)
{
printf("open %s failed\n", argv[1]);
exit(0);
}
/*打开一个解码后的文件句柄*/
FILE *outfile = fopen(argv[2], "wb");
if (outfile == NULL)
{
printf("open %s failed\n", argv[2]);
fclose(infile);
exit(0);
}
/*设置解码错误断点*/
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/*设置跳转入口*/
if (setjmp(jerr.setjmp_buffer) != 0)
{
/*销毁解码器*/
jpeg_destroy_decompress(&cinfo);
fclose(infile);
fclose(outfile);
exit(0);
}
/*创建解码器*/
{
/*创建一个解码器*/
jpeg_create_decompress(&cinfo);
/*传入输入文件的句柄*/
jpeg_stdio_src(&cinfo, infile);
/*获取jpeg的信息*/
jpeg_read_header(&cinfo, TRUE);
/*这是解码后的分辨率等比例缩放*/
cinfo.scale_num = 1;
cinfo.scale_denom = 1;
/*写入参数准备解码*/
jpeg_start_decompress(&cinfo);
}
/*开始解码*/
{
/*获取一行的字节数*/
int row_stride = cinfo.output_width * cinfo.output_components;
/*通过jpeglib为创建的解码器分配一行所需要的内存*/
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
/*开始一行一行的解码与数据的copy*/
while (cinfo.output_scanline < cinfo.output_height)
{
jpeg_read_scanlines(&cinfo, buffer, 1);
fwrite(buffer[0], 1, row_stride, outfile);
}
}
printf("read %s(%dx%d) decode and write %s(%dx%d) success\n", argv[1], cinfo.image_width, cinfo.image_height, argv[0], cinfo.output_width, cinfo.output_height);
/*结束解码*/
jpeg_finish_decompress(&cinfo);
/*销毁解码器,以及回收内存*/
jpeg_destroy_decompress(&cinfo);
/*关闭句柄*/
fclose(infile);
fclose(outfile);
return 0;
}
#include
#include
#include
#include
/*创建私有的报错错误参数*/
struct my_error_mgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
/*私有的错误处理入口*/
void my_error_exit(j_common_ptr cinfo)
{
struct my_error_mgr *myerr = (struct my_error_mgr *)cinfo->err;
/*错误消息打印*/
(*cinfo->err->output_message)(cinfo);
/* 跳转到指定的函数*/
longjmp(myerr->setjmp_buffer, 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("input param error \n");
exit(0);
}
printf("jpeg input path:%s\n", argv[1]);
printf("jpeg output path:%s \n", argv[2]);
/*解码器需要的参数*/
struct jpeg_compress_struct cinfo;
/*私有的错误处理参数*/
struct my_error_mgr jerr;
/*打开一个jpg文件句柄*/
FILE *infile = fopen(argv[1], "rb");
if (infile == NULL)
{
printf("open %s failed\n", argv[1]);
exit(0);
}
/*打开一个解码后的文件句柄*/
FILE *outfile = fopen(argv[2], "wb");
if (outfile == NULL)
{
printf("open %s failed\n", argv[2]);
fclose(infile);
exit(0);
}
/*设置解码错误断点*/
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/*设置跳转入口*/
if (setjmp(jerr.setjmp_buffer) != 0)
{
/*销毁解码器*/
jpeg_destroy_compress(&cinfo);
fclose(infile);
fclose(outfile);
exit(0);
}
/*创建解码器*/
{
/*创建一个解码器*/
jpeg_create_compress(&cinfo);
/*传入输入文件的句柄*/
jpeg_stdio_dest(&cinfo, outfile);
/*设置输入参数*/
cinfo.image_width = 227;
cinfo.image_height = 149;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
/*这是解码后的分辨率等比例缩放*/
// cinfo.scale_num = 8;
// cinfo.scale_denom = 1;
/*设置其他的默认参数*/
jpeg_set_defaults(&cinfo);
/*设置编码质量*/
jpeg_set_quality(&cinfo, 128, TRUE);
/*写入参数准备解码*/
jpeg_start_compress(&cinfo, TRUE);
}
/*开始解码*/
{
/*获取一行的字节数*/
int row_stride = cinfo.image_width * cinfo.input_components;
/*通过jpeglib为创建的解码器分配一行所需要的内存*/
JSAMPROW row_pointer[1]; //= (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
char *raw_row_buffer = malloc(row_stride);
/*开始一行一行的解码与数据的copy*/
while (cinfo.next_scanline < cinfo.image_height)
{
fread(raw_row_buffer, 1, row_stride, infile);
row_pointer[0] = raw_row_buffer;
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
free(raw_row_buffer);
}
printf("read %s(%dx%d) enecode and write %s success\n", argv[1], cinfo.image_width, cinfo.image_height, argv[0]);
/*结束解码*/
jpeg_finish_compress(&cinfo);
/*销毁解码器,以及回收内存*/
jpeg_destroy_compress(&cinfo);
/*关闭句柄*/
fclose(infile);
fclose(outfile);
return 0;
}
#include "../../../lvgl.h"
#if LV_USE_JPG
#include "lv_jpg.h"
#include
#include
#include
#include
#include
#include
#include "jpeglib.h"
#include
#include "ssd20x/mi_sys_datatype.h"
#include "ssd20x/mi_sys.h"
#include "common/ssd20x_common.h"
#include "common/sat_user_time.h"
struct my_error_mgr
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr *my_error_ptr;
static void my_error_exit(j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr)cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message)(cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t decoder_info(struct _lv_img_decoder_t *decoder, const void *src, lv_img_header_t *header);
static lv_res_t decoder_open(lv_img_decoder_t *dec, lv_img_decoder_dsc_t *dsc);
static void decoder_close(lv_img_decoder_t *dec, lv_img_decoder_dsc_t *dsc);
// static void convert_color_depth(uint8_t *img, uint32_t px_cnt);
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @功能: 注册jpg解码库
* @return:
*/
void lv_jpg_init(void)
{
lv_img_decoder_t *dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_close_cb(dec, decoder_close);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Get info about a PNG image
* @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(struct _lv_img_decoder_t *decoder, const void *src, lv_img_header_t *header)
{
(void)decoder; /*Unused*/
lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
/*If it's a PNG file...*/
if (src_type == LV_IMG_SRC_FILE)
{
const char *fn = src;
if ((strcmp(lv_fs_get_ext(fn), "jpg") == 0) || (strcmp(lv_fs_get_ext(fn), "JPG") == 0) ||
(strcmp(lv_fs_get_ext(fn), "jpeg") == 0) || (strcmp(lv_fs_get_ext(fn), "JPEG") == 0))
{
#if 1
uint32_t *param = (uint32_t *)&fn[strlen(fn) + 2];
header->w = *param;
param++;
header->h = *param;
#endif
header->always_zero = 0;
header->cf = LV_IMG_CF_TRUE_COLOR;
/*The width and height are stored in Big endian format so convert them to little endian*/
#if 0
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 获取图片参数
*/
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_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_fs_close(&f);
LV_LOG_ERROR("setjmp(jerr.setjmp_buffer) failed \n");
return LV_RES_INV;
}
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 创建解码器
*/
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, f.file_d);
/* Step 3: read file parameters with jpeg_read_header() */
(void)jpeg_read_header(&cinfo, TRUE);
/*Save the data in the header*/
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW;
/*The width and height are stored in Big endian format so convert them to little endian*/
header->w = cinfo.image_width;
header->h = cinfo.image_height;
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 销毁解码器
*/
jpeg_destroy_decompress(&cinfo);
lv_fs_close(&f);
#endif
return LV_RES_OK;
}
}
else if(src_type == LV_IMG_SRC_VARIABLE)
{
}
return LV_RES_INV;
}
/*
* @日期: 2022-08-13
* @作者: leo.liu
* @注释: 当前jpg的解码个数
*/
static int jpeg_decode_total = 0;
/**
* Open a PNG 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_IMG_DECODER_OPEN_FAIL` if failed
*/
static lv_res_t decoder_open(lv_img_decoder_t *decoder, lv_img_decoder_dsc_t *dsc)
{
(void)decoder; /*Unused*/
// unsigned long long start = user_timestamp_get();
/*If it's a PNG file...*/
if (dsc->src_type == LV_IMG_SRC_FILE)
{
const char *fn = dsc->src;
if ((strcmp(lv_fs_get_ext(fn), "jpg") == 0) || (strcmp(lv_fs_get_ext(fn), "JPG") == 0) ||
(strcmp(lv_fs_get_ext(fn), "jpeg") == 0) || (strcmp(lv_fs_get_ext(fn), "JPEG") == 0))
{ /*Check the extension*/
uint32_t *param = (uint32_t *)&fn[strlen(fn) + 2];
uint32_t obj_width = *param;
param++;
uint32_t obj_hight = *param;
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 打开文件
*/
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_ERROR("lv fs open failed \n");
return LV_RES_INV;
}
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 获取图片参数
*/
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_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_fs_close(&f);
LV_LOG_ERROR("setjmp(jerr.setjmp_buffer) failed \n");
return LV_RES_INV;
}
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 创建解码器
*/
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, f.file_d);
/* Step 3: read file parameters with jpeg_read_header() */
(void)jpeg_read_header(&cinfo, TRUE);
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 设置解码后的数据格式
*/
cinfo.out_color_space = JCS_RGB;
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 先进行比例缩放
*/
if ((obj_width * obj_hight) < (cinfo.image_width * cinfo.image_height))
{
if (((abs(obj_width - cinfo.image_width)) < (abs(obj_hight - cinfo.image_height))) && (obj_hight < cinfo.image_height))
{
cinfo.scale_num = obj_hight;
cinfo.scale_denom = cinfo.image_height;
}
else
{
cinfo.scale_num = obj_hight;
cinfo.scale_denom = cinfo.image_width;
}
}
(void)jpeg_start_decompress(&cinfo);
// LV_LOG_INFO("image_width = %d out_wdith=%d -> scale:%d ", cinfo.image_width, cinfo.output_width, obj_width);
// LV_LOG_INFO("image_height = %d out_hegiht=%d -> scale:%d", cinfo.image_height, cinfo.output_height, obj_hight);
// LV_LOG_INFO("num_components = %d ", cinfo.num_components);
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 从平台中获取内存,欲建一个argb8888 的buffer
*/
MI_PHY jpg_argb8888_phy_addres = 0;
unsigned char *jpg_argb8888_var_addres = NULL;
int row_argb8888_stride = cinfo.output_width * 4;
int row_argb8888_size = cinfo.output_height * row_argb8888_stride;
MI_SYS_MMA_Alloc(NULL, row_argb8888_size, &jpg_argb8888_phy_addres);
MI_SYS_Mmap(jpg_argb8888_phy_addres, row_argb8888_size, (void **)&jpg_argb8888_var_addres, false);
/*
* @日期: 2022-08-11
* @作者: leo.liu
* @注释: 必须置零,或者会有噪点
*/
MI_SYS_MemsetPa(jpg_argb8888_phy_addres, 0x00, row_argb8888_size);
/*
* @日期: 2022-08-10
* @作者: leo.liu
* @注释: 建立一个一行的数据
*/
/* JSAMPLEs per row in output buffer */
int jpg_raw_stride_size = cinfo.output_width * cinfo.output_components;
#if 0
MI_PHY jpg_raw_phy_addres = 0;
unsigned char *jpg_raw_var_addres = NULL;
MI_SYS_MMA_Alloc(NULL, jpg_raw_stride_size, &jpg_raw_phy_addres);
MI_SYS_Mmap(jpg_raw_phy_addres, jpg_raw_stride_size, (void **)&jpg_raw_var_addres, false);
#endif
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, jpg_raw_stride_size, 1);
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.
*/
#if 0
(void)jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&jpg_raw_var_addres, 1);
MI_SYS_MemcpyPa(jpg_argb8888_phy_addres + cinfo.output_scanline * jpg_raw_stride_size, jpg_raw_phy_addres, jpg_raw_stride_size);
#endif
(void)jpeg_read_scanlines(&cinfo, (JSAMPARRAY)buffer, 1);
memcpy(&jpg_argb8888_var_addres[cinfo.output_scanline * jpg_raw_stride_size], buffer[0], jpg_raw_stride_size);
}
#if 0
/*
* @日期: 2022-08-10
* @作者: leo.liu
* @注释: 解绑销毁内存
*/
MI_SYS_Munmap(jpg_raw_var_addres, jpg_raw_stride_size);
MI_SYS_MMA_Free(jpg_raw_phy_addres);
#endif
/*
* @日期: 2022-08-09
* @作者: leo.liu
* @注释: 关闭解码器
*/
/* Step 7: Finish decompression */
(void)jpeg_finish_decompress(&cinfo);
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
lv_fs_close(&f);
/*
* @日期: 2022-08-10
* @作者: leo.liu
* @注释: 调整argb8888数据
*/
int len = cinfo.output_width * cinfo.output_height;
unsigned char *dst_data = jpg_argb8888_var_addres + cinfo.output_width * cinfo.output_height * 4 - 1;
unsigned char *src_data = jpg_argb8888_var_addres + cinfo.output_width * cinfo.output_height * 3 - 1;
for (int i = 0; i < len; i++)
{
*dst_data = 0xFF;
dst_data--;
*dst_data = *src_data;
dst_data--;
src_data--;
*dst_data = *src_data;
dst_data--;
src_data--;
*dst_data = *src_data;
dst_data--;
src_data--;
}
/*
* @日期: 2022-08-10
* @作者: leo.liu
* @注释: 这里并没有考虑16位的颜色格式
*/
MI_PHY jpg_data_phy_addres = 0;
unsigned char *jpg_data_var_addres = NULL;
int row_data_stride = obj_width * LV_COLOR_DEPTH / 8;
int row_data_size = obj_hight * row_data_stride;
MI_SYS_MMA_Alloc(NULL, row_data_size, &jpg_data_phy_addres);
MI_SYS_Mmap(jpg_data_phy_addres, row_data_size, (void **)&jpg_data_var_addres, false);
MI_SYS_MemsetPa(jpg_data_phy_addres, 0x00, row_data_size);
platform_gfx_bitblt(0, 0, cinfo.output_width, cinfo.output_height, cinfo.output_width, cinfo.output_height, row_argb8888_stride, jpg_argb8888_phy_addres, E_MI_GFX_FMT_ABGR8888,
0, 0, obj_width, obj_hight, obj_width, obj_hight, row_data_stride, jpg_data_phy_addres, E_MI_GFX_FMT_ARGB8888);
#if 0
static int fd = -1;
if (fd == -1)
{
char file_name[128] = {0};
sprintf(file_name, "/mnt/src_%dx%d", cinfo.output_width, cinfo.output_height);
fd = open(file_name, O_CREAT | O_WRONLY);
write(fd, jpg_argb8888_var_addres, cinfo.output_width * cinfo.output_height * 4);
close(fd);
sprintf(file_name, "/mnt/dst_%dx%d", obj_width, obj_hight);
fd = open(file_name, O_CREAT | O_WRONLY);
write(fd, jpg_data_var_addres, obj_width * obj_hight * 4);
close(fd);
system("sync");
}
#endif
/*
* @日期: 2022-08-10
* @作者: leo.liu
* @注释: 解绑销毁内存
*/
MI_SYS_Munmap(jpg_argb8888_var_addres, row_argb8888_size);
MI_SYS_MMA_Free(jpg_argb8888_phy_addres);
dsc->img_data = jpg_data_var_addres;
#if SAT_LV_ADD_CUSTOM
dsc->img_size = row_data_size;
#endif
// unsigned long long end = user_timestamp_get();
jpeg_decode_total++;
LV_LOG_USER("jpeg decode total:%d:%s ", jpeg_decode_total,fn);
return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/
}
}
return LV_RES_INV; /*If not returned earlier then it failed*/
}
/**
* Free the allocated resources
*/
static void decoder_close(lv_img_decoder_t *decoder, lv_img_decoder_dsc_t *dsc)
{
LV_UNUSED(decoder); /*Unused*/
if (dsc->img_data)
{
MI_PHY img_data_phy = 0;
MI_SYS_Va2Pa((void *)dsc->img_data, &img_data_phy);
MI_SYS_Munmap((void *)dsc->img_data, dsc->img_size);
MI_SYS_MMA_Free(img_data_phy);
dsc->img_data = NULL;
jpeg_decode_total--;
LV_LOG_USER("jpeg decode total:%d ", jpeg_decode_total);
}
return;
}
#endif