SSD202D平台使用libjpeg和lodepng将jpg图片转换成rgb888格式的png图片

今天研究在SSD202D平台使用libjpeg和lodepng将jpg图片转换成rgb888格式的png图片,分享一下研究的结果:

1、准备工作

下载libjpeg:libjpeg

这里使用的 jpegsrc.v9.tar.gz

下载lodepng:lodepng

2、相关代码

jpeg_transfer.h

#ifndef _JPEG_TRANSFER_H
#define _JPEG_TRANSFER_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>

/* 
1、检测图片文件是否为jpeg格式
2、如果图片是baseline格式的jpeg,不处理
3、如果不是baseline格式的jpeg,将其转换成baseline格式的jpeg
*/
int jpeg_to_baseline_jpeg(const char *file_path);

// jpg转换成rgb24格式的png
int jpeg_to_rgb24_png(const char *jpg_file_path, const char * png_file_path);

#ifdef __cplusplus
}
#endif

#endif // !_JPEG_TRANSFER_H 

jpeg_transfer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "jpeglib.h"
#include <setjmp.h>
#include "lodepng.h"
#include "jpeg_transfer.h"


#define THIS_FILE "jpeg_transfer.c"


typedef struct jpeg_error_mgr_usr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
}jpeg_error_mgr_usr_t;


static char jpeg_last_error_buf[256] = {0};


static void my_error_exit(j_common_ptr cinfo)
{
	printf("[%s::%s:%d] my_error_exit\n", THIS_FILE, __FUNCTION__, __LINE__);

    if (cinfo != NULL)
    {
        jpeg_error_mgr_usr_t *error_ptr = (jpeg_error_mgr_usr_t *)cinfo->err;
        if (cinfo->err != NULL  && cinfo->err->format_message != NULL)
        {
			memset(jpeg_last_error_buf, 0, sizeof(jpeg_last_error_buf)/sizeof(jpeg_last_error_buf[0]));
            (*(cinfo->err->format_message)) (cinfo, jpeg_last_error_buf);
        }

        if (error_ptr != NULL)
        {
            longjmp(error_ptr->setjmp_buffer, 1);
        }
    }
}


// 根据文件头判断是否是jpeg文件
static int is_jpeg_file(const char *file_path)
{
    int ret = -1;

    if (file_path == NULL || file_path[0] == '\0')
    {
        return ret;
    }

    unsigned short BMP = 0x4D42, JPEG = 0xD8FF, PNG[4] = { 0x5089, 0x474E };
    FILE *fp = NULL;
    short int i = 0;
    unsigned short pis[5] = { 0 };

    fp = fopen(file_path, "r");
    if (fp == NULL)
    {
        printf("[%s::%s:%d] can not read %s\n", THIS_FILE, __FUNCTION__, __LINE__, file_path);
        return ret;
    }
    else
    {
        fread((void *)pis, 8, 1, fp);
        fclose(fp);
    }

    if (pis[0] == JPEG)
    {
        printf("[%s::%s:%d] %s is JPEG file\n", THIS_FILE, __FUNCTION__, __LINE__, file_path);
        ret = 0;
    }

    return ret;
}


int jpeg_to_baseline_jpeg(const char *file_path)
{
	int ret = -1;
	
    if (is_jpeg_file(file_path) != 0)
    {
        return ret;
    }

    struct jpeg_decompress_struct out_cinfo = {0};
    struct jpeg_error_mgr_usr jpeg_err = {0};

	FILE * infile = NULL;
	JSAMPARRAY buffer;
	unsigned char *tmp = NULL;
	int row_stride = 0;
	unsigned char *output_buffer = NULL;
	unsigned int out_image_width = 0;
	unsigned int out_image_height = 0;
	int out_image_components = 0;
	J_COLOR_SPACE image_in_color_space = JCS_UNKNOWN;

    //打开指定图像文件
	infile = fopen(file_path, "rb");
	if (infile == NULL)
	{
		printf("[%s::%s:%d] file %s open failed!!!\n", THIS_FILE, __FUNCTION__, __LINE__, file_path);
		return ret;
	}

	//绑定标准错误处理结构
	out_cinfo.err = jpeg_std_error(&jpeg_err.pub);
	jpeg_err.pub.error_exit = my_error_exit; // 自定义错误处理函数

	if (setjmp(jpeg_err.setjmp_buffer))
	{
		/*
        在正常情况下,setjmp将返回0,而如果程序出现错误,即调用my_error_exit
		然后程序将再次跳转于此,同时setjmp将返回在my_error_exit中由longjmp第二个参数设定的值1
		并执行以下代码
        */
		printf("[%s::%s:%d] jpegLastErrorMsg:%s\n", THIS_FILE, __FUNCTION__, __LINE__, jpeg_last_error_buf);
		//out_cinfo.err->msg_code;
		jpeg_destroy_decompress(&out_cinfo);

        if (infile)
        {
            fclose(infile);
            infile = NULL;
        }
		
		return ret;
	}

	//初始化JPEG解码对象
	jpeg_create_decompress(&out_cinfo);

    // 指定数据源
	jpeg_stdio_src(&out_cinfo, infile);

	//读取图像信息,即jpeg图片文件参数
	(void)jpeg_read_header(&out_cinfo, TRUE);

	// 如果原文件就是baseline格式的,就不需要转换
	if (out_cinfo.is_baseline == 1) // Baseline SOF0 encountered 
	{
        if (infile)
        {
            fclose(infile);
            infile = NULL;
        }
        
		jpeg_destroy_decompress(&out_cinfo);
		ret = 0;
		
        printf("[%s::%s:%d] picture %s baseline jpeg\n", THIS_FILE, __FUNCTION__, __LINE__, file_path);
		return ret;
	}
    
    printf("[%s::%s:%d] picture %s progressive jpeg\n", THIS_FILE, __FUNCTION__, __LINE__, file_path);

	//开始解压缩图像
	(void)jpeg_start_decompress(&out_cinfo);

	out_image_width = out_cinfo.output_width;
	out_image_height = out_cinfo.output_height;
	out_image_components = out_cinfo.output_components;
	image_in_color_space = out_cinfo.out_color_space;

	printf("[%s::%s:%d] out_image_components:%d, image_in_color_space:%d\n", THIS_FILE, __FUNCTION__, __LINE__, out_image_components, image_in_color_space);
	
	//分配缓冲区空间
	row_stride = out_cinfo.output_width * out_cinfo.output_components; // 每一行的步长
	buffer = (*out_cinfo.mem->alloc_sarray)((j_common_ptr)&out_cinfo, JPOOL_IMAGE, row_stride, 1);
    if (buffer == NULL)
    {
        jpeg_destroy_decompress(&out_cinfo);
		
		if (infile != NULL)
		{
			fclose(infile);
			infile = NULL;
		}

		ret = -1;
        return ret;
    }

	output_buffer = (unsigned char *)malloc(row_stride * out_cinfo.output_height);
    if (output_buffer == NULL)
    {
        jpeg_destroy_decompress(&out_cinfo);
        
		if (infile != NULL)
		{
			fclose(infile);
			infile = NULL;
		}

		ret = -1;
        return ret;
    }

	memset(output_buffer, 0, row_stride * out_cinfo.output_height);
	tmp = output_buffer;

	//读取数据
	while (out_cinfo.output_scanline < out_cinfo.output_height)  //scanline表示当前已读取行数,此循环依次读取图片所有数据
	{
		(void)jpeg_read_scanlines(&out_cinfo, buffer, 1);//将数据一行一行读取
		memcpy(tmp, *buffer, row_stride);
		tmp += row_stride;
	}

	//结束解压缩操作
	(void)jpeg_finish_decompress(&out_cinfo);

	//释放资源
	jpeg_destroy_decompress(&out_cinfo);

	// 关闭文件
    if (infile != NULL)
    {
        fclose(infile);
        infile = NULL;
    }

	//变量定义
	struct jpeg_compress_struct input_cinfo;
	struct jpeg_error_mgr_usr input_jerr;
	FILE *outfile = NULL;
	JSAMPROW row_pointer[1];

	//指定目标输出图像文件
    outfile = fopen(file_path, "wb");
    if (outfile == NULL)
	{
        if (output_buffer != NULL)
        {
            free(output_buffer);
            output_buffer = NULL;
        }
		
        ret = -1;
		return ret;
	}

	//绑定标准错误处理结构
	input_cinfo.err = jpeg_std_error(&input_jerr.pub);
	input_jerr.pub.error_exit = my_error_exit;

	if (setjmp(input_jerr.setjmp_buffer))
	{
		/*
        在正常情况下,setjmp将返回0,而如果程序出现错误,即调用my_error_exit
		然后程序将再次跳转于此,同时setjmp将返回在my_error_exit中由longjmp第二个参数设定的值1
		并执行以下代码
        */
		printf("[%s::%d] jpegLastErrorMsg : %s\n", __FUNCTION__, __LINE__, jpeg_last_error_buf);
        jpeg_destroy_compress(&input_cinfo);
		
        if (outfile != NULL)
        {
            fclose(outfile);
            outfile = NULL;
        }

        if (output_buffer != NULL)
        {
            free(output_buffer);
            output_buffer = NULL;
        }

		ret = -1;
		return ret;
	}

	//初始化JPEG对象
	jpeg_create_compress(&input_cinfo);

	// 指定输出对象
    jpeg_stdio_dest((struct jpeg_compress_struct *)&input_cinfo, outfile);

	//设定压缩参数
	input_cinfo.image_width = out_image_width;
	input_cinfo.image_height = out_image_height;
	input_cinfo.input_components = out_image_components;
	input_cinfo.in_color_space = image_in_color_space;

    jpeg_set_defaults((struct jpeg_compress_struct *)&input_cinfo);

	//此处设压缩比为70%,强制使用baseline格式
    jpeg_set_quality((struct jpeg_compress_struct *)&input_cinfo, 70, TRUE);

	//开始压缩
    jpeg_start_compress((struct jpeg_compress_struct *)&input_cinfo, TRUE);

	//写入数据
	while (input_cinfo.next_scanline < input_cinfo.image_height)
	{
		row_pointer[0] = &output_buffer[input_cinfo.next_scanline*out_image_components*out_image_width];
        (void)jpeg_write_scanlines((struct jpeg_compress_struct *)&input_cinfo, (JSAMPROW *)&row_pointer, 1);
	}

	//压缩完毕
    jpeg_finish_compress((struct jpeg_compress_struct *)&input_cinfo);

    //释放资源
    if (outfile != NULL)
    {
        fclose(outfile);
        outfile = NULL;
    }

	jpeg_destroy_compress((struct jpeg_compress_struct *)&input_cinfo);
	
    if (output_buffer != NULL)
    {
        free(output_buffer);
        output_buffer = NULL;
    }

	return 0;
}

static int is_png_file(const char * file_path)
{
    int ret = -1;

    if (file_path != NULL && file_path[0] != '\0')
    {
        FILE * file = NULL;
        unsigned short header[5] = { 0 };
        unsigned short png_header[4] = { 0x5089, 0x474E, 0x0A0D, 0x0A1A };

        file = fopen(file_path, "r");
        if (file != NULL)
        {
            fread(header, 8, 1, file);
            fclose(file);

            if (png_header[0]==header[0] && 
                png_header[1]==header[1] && 
                png_header[2]==header[2] && 
                png_header[3]==header[3])    
            {
                ret = 0;
            }
        }
        else
        {
            printf("[%s:%d] file %s open failed\n", __FUNCTION__, __LINE__, file_path);
            ret = -1;
        }
    }

    return ret;
}


typedef struct _image_data 
{
    unsigned char *pixels;
    unsigned int img_width;
    unsigned int img_height;
    unsigned int img_color_components;
    unsigned int img_color_space;
}image_data_t;


int jpeg_to_rgb24_png(const char *jpg_file_path, const char * png_file_path)
{
    int ret = -1;
    struct jpeg_decompress_struct out_cinfo = {0};
    struct jpeg_error_mgr_usr jpeg_err = {0};
    FILE * infile = NULL;
    JSAMPARRAY buffer;
    unsigned int row_stride = 0;
    image_data_t img_data = { 0 };

    if (lb_is_jpeg_file(jpg_file_path) != 0)
    {
        return ret;
    }

    //打开指定图像文件
    infile = fopen(jpg_file_path, "rb");
    if (infile == NULL)
    {
        printf("[%s::%s:%d] file %s open failed!!!\n", THIS_FILE, __FUNCTION__, __LINE__, jpg_file_path);
        return ret;
    }

    //绑定标准错误处理结构
    out_cinfo.err = jpeg_std_error(&jpeg_err.pub);
    jpeg_err.pub.error_exit = my_error_exit; // 自定义错误处理函数

    if (setjmp(jpeg_err.setjmp_buffer))
    {
        /*
        在正常情况下,setjmp将返回0,而如果程序出现错误,即调用my_error_exit
        然后程序将再次跳转于此,同时setjmp将返回在my_error_exit中由longjmp第二个参数设定的值1
        并执行以下代码
        */
        printf("[%s::%s:%d] jpegLastErrorMsg:%s\n", THIS_FILE, __FUNCTION__, __LINE__, jpeg_last_error_buf);
        //out_cinfo.err->msg_code;
        jpeg_destroy_decompress(&out_cinfo);

        if (infile)
        {
            fclose(infile);
            infile = NULL;
        }
        
        return ret;
    }

    //初始化JPEG解码对象
    jpeg_create_decompress(&out_cinfo);

    // 指定数据源
    jpeg_stdio_src(&out_cinfo, infile);

    //读取图像信息,即jpeg图片文件参数
    (void)jpeg_read_header(&out_cinfo, TRUE);

    if (out_cinfo.is_baseline == 1) // Baseline SOF0 encountered 
    {
        printf("[%s::%s:%d] picture %s baseline jpeg\n", THIS_FILE, __FUNCTION__, __LINE__, jpg_file_path);
    }
    else
    {
        printf("[%s::%s:%d] picture %s progressive jpeg\n", THIS_FILE, __FUNCTION__, __LINE__, jpg_file_path);
    }

    //开始解压缩图像
    (void)jpeg_start_decompress(&out_cinfo);

    img_data.img_width = out_cinfo.output_width;
    img_data.img_height = out_cinfo.output_height;
    img_data.img_color_components = out_cinfo.output_components;
    img_data.img_color_space = out_cinfo.out_color_space;
    row_stride =  img_data.img_width * img_data.img_color_components; // 每一行的步长
    printf("[%s::%s:%d] width:%d, height:%d, components:%d, color_space:%d\n", THIS_FILE, __FUNCTION__, __LINE__, img_data.img_width, img_data.img_height, img_data.img_color_components, img_data.img_color_space);
    
    //分配缓冲区空间
    if ( (*out_cinfo.mem->alloc_sarray) == NULL)
    {
        printf("[%s::%s:%d] alloc_sarray is NULL\n", THIS_FILE, __FUNCTION__, __LINE__);
        
        jpeg_destroy_decompress(&out_cinfo);
        
        if (infile != NULL)
        {
            fclose(infile);
            infile = NULL;
        }

        ret = -1;
        return ret;
    }

    buffer = (*out_cinfo.mem->alloc_sarray)((j_common_ptr)&out_cinfo, JPOOL_IMAGE, row_stride, 1);
    if (buffer == NULL)
    {
        jpeg_destroy_decompress(&out_cinfo);
        
        if (infile != NULL)
        {
            fclose(infile);
            infile = NULL;
        }

        ret = -1;
        return ret;
    }

    img_data.pixels = (unsigned char *)malloc(row_stride * img_data.img_height);
    if (img_data.pixels == NULL)
    {
        jpeg_destroy_decompress(&out_cinfo);
        
        if (infile != NULL)
        {
            fclose(infile);
            infile = NULL;
        }

        ret = -1;
        return ret;
    }

    memset(img_data.pixels, 0, row_stride * out_cinfo.output_height);
    unsigned char * ptr = img_data.pixels;
    while (out_cinfo.output_scanline < out_cinfo.output_height)  //读取数据 scanline表示当前已读取行数,此循环依次读取图片所有数据
    {
        (void)jpeg_read_scanlines(&out_cinfo, buffer, 1);//将数据一行一行读取
        memcpy(ptr, *buffer, row_stride);
        ptr += row_stride;
    }

    //结束解压缩操作
    (void)jpeg_finish_decompress(&out_cinfo);

    //释放资源
    jpeg_destroy_decompress(&out_cinfo);

    // 关闭文件
    if (infile != NULL)
    {
        fclose(infile);
        infile = NULL;
    }

    if (img_data.img_color_components == 3) // 位深度:3x8=24 RGB888
    {
        unsigned int error = lodepng_encode24_file(png_file_path, img_data.pixels, img_data.img_width, img_data.img_height);
        if (error != 0) 
        {
            printf("[%s::%s:%d] error %u: %s\n", THIS_FILE, __FUNCTION__, __LINE__, error, lodepng_error_text(error));
            ret = -1;
        }
        else
        {
            ret = 0;
        }
    }
    else if (img_data.img_color_components == 4) // 位深度:4x8=32 ARGB8888
    {
        //TODO::
        printf("[%s::%s:%d] img_color_components:%u\n", THIS_FILE, __FUNCTION__, __LINE__, img_data.img_color_components);
    }

    if (img_data.pixels != NULL)
    {
        free(img_data.pixels);
        img_data.pixels = NULL;
    }

    return ret;
}


/*
编译
arm-linux-gnueabihf-gcc jpeg_transfer.c lodepng.c -o jpeg_transfer -L. -ljpeg -Wl,-rpath=. -DTEST_ENA=1
*/
#if defined(TEST_ENA) && (TEST_ENA != 0) 
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        printf("args should be tow, such as: ./program_name 1.jpg 2.png\n");
        return 0;
    }

    jpeg_to_rgb24_png(argv[1], argv[2]);
	
    return 0;
}
#endif

3、编译和运行效果

arm-linux-gnueabihf-gcc jpeg_transfer.c lodepng.c -o jpeg_transfer -L. -ljpeg -Wl,-rpath=. -DTEST_ENA=1

 

相关代码:code

参考文献:音视频入门-16-使用libjpeg-trubo处理JPEG图片

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值