libjpeg库使用

交叉编译

./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;
}

SSD20X平台移植内嵌LVGL 8.3中

#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

你可能感兴趣的:(linux,运维,服务器)