背景,没什么好说的,有把图片从rgb和jpeg中互相搞的需求,不了解的话要想在GUI显示图片还是比较麻烦的
(以下不涉及原码,仅涉及使用方式)

首先讲一下jpeg

JPEG(Joint Photographic Experts Group)

JPEG是JPEG标准的产物,该标准由国际标准化组织(ISO)制订,是面向连续色调静止图像的一种压缩标准。 JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg。——百度百科

JPEG图片格式组成部分:SOI(文件头)+APP0(图像识别信息)+ DQT(定义量化表)+ SOF0(图像基本信息)+ DHT(定义Huffman表) + DRI(定义重新开始间隔)+ SOS(扫描行开始)+ EOI(文件尾)

一般来说,文件开头是FF D8 FF就可以知道是jpeg文件了

简单来说这是一种有损压缩的编码格式(直接读出来是不能看的),压缩能力还是比较强的,一张480600的RGB图,光是纯unsigned char来存,需要占用大概4806003字节/1024=843.75KB,编码为JPEG再存起来大概只需要10KB。比如两万张人脸图,就算只有240320,不管是存数据库还是存flash,把裸RGB存起来肯定是不行的

这是一种图像编码格式,那要在GUI上显示,就得解码。存起来又得编码。

开始

先读出来,没什么好说的

//jpeg信息用字符串来存,里面是有可能出现0的,所以需要一个len
int jpeg_write(unsigned char *jpeg, int len, char *URL)
{if (URL == NULL || jpeg == NULL)return -1;FILE *fp = fopen(URL, "w");if (fp == NULL){printf("open file fail\n");return -1;}fwrite(jpeg, len, 1, fp);fclose(fp);return 0;
}int jpeg_read(unsigned char *jpeg, int *len, char *URL)
{if (URL == NULL || jpeg == NULL || len == NULL)return -1;FILE *fp = fopen(URL, "r");if (fp == NULL){printf("open file fail\n");return -1;}*len = 0;while ((jpeg[*len++] = fgetc(fp)) != EOF);fclose(fp);return len - 1;
}

再转为RGB,需要通过libjpeg

libjpeg

libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。

以下详细介绍一下怎么去使用

//一般只需要包含这个库的头文件就行
#include <jpeglib.h>
//如果要自定义错误处理功能,则还需要这个
#include <setjmp.h>//******************** part 1 ********************
//以下功能是错误处理相关。如果不进行自定义错误处理,在出错时则会直接exit掉main。而内存不足等问题是十分常见的
typedef struct _user_jpeg_error_mgr
{struct jpeg_error_mgr jpg_err;  /* old jpeg error */jmp_buf setjmp_buffer;          /* for return to caller */
} USER_JPEG_ERROR_MGR;METHODDEF(void) user_jpeg_error_exit(j_common_ptr cinfo)
{/* output error msg and jump to setjmp_buffer */USER_JPEG_ERROR_MGR* usr_jpg_err = (USER_JPEG_ERROR_MGR *)cinfo->err;(*cinfo->err->output_message)(cinfo);longjmp(usr_jpg_err->setjmp_buffer, 1);
}
//****************** end part 1 ******************int jpeg_decode(unsigned char *in_buff, int in_buff_size, unsigned char **out_buff, int *out_buff_size, int *jpeg_width, int *jpeg_height, int *color_space, int *components)
{if (NULL == in_buff            //输入的jpeg图像信息|| NULL == out_buff        //解码后的图像信息|| NULL == out_buff_size   //输出图像的大小|| NULL == color_space     //带出解码后的颜色空间|| NULL == components      //带出解码后的颜色通道数|| NULL == jpeg_width      //带出解码后图像的宽|| NULL == jpeg_height)    //带出解码后图像的高{printf("some param is NULL\n");return -1;}//******************** part 2 ********************
//参数准备//分配jpeg对象结构体空间,并初始化struct jpeg_decompress_struct cinfo;jpeg_create_decompress(&cinfo);//错误处理结构体对象,并初始化USER_JPEG_ERROR_MGR jerr;cinfo.err = jpeg_std_error(&jerr.jpg_err);jerr.jpg_err.error_exit = user_jpeg_error_exit;if (setjmp(jerr.setjmp_buffer)){jpeg_destroy_decompress(&cinfo);return -1;}//指定需要解码的数据源jpeg_mem_src(&cinfo, in_buff, in_buff_size);/* 这里是使用了内存中读好的RGB信息,也可以现场读文件,再使用jpeg_stdio_src,记得fclose* FILE * infile;* if ((infile = fopen("test.jpg", "rb")) == NULL)* {*      printf("fopen fail");*      return 0;* }* jpeg_stdio_src(&cinfo, infile);*///获取解码文件信息。将图像的缺省信息填充到cinfo结构中以便程序使用//包含宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等jpeg_read_header(&cinfo, TRUE);//为输出图像设定参数/* 可以通过分子分母来设定输出比例,仅支持1/1、1/2、1/4、1/8。如下可以设置原图1/2的图像* cinfo.scale_num=1;* cinfo.scale_denom=2;*///设置颜色空间。真彩色 JCS_RGB,通道数为3、灰度图 JCS_GRAYSCALE,通道数为1、带透明通道JCS_EXT_RGBA,通道数为4,等。可以主动设置为其他样式//这里设置成4可以减少字节对齐问题,如果读出来是RGB,是3个3个读,就需要申请能被4整除的 行内存块cinfo.out_color_space = JCS_EXT_RGBA;//cinfo.jpeg_color_space;cinfo.out_color_components = 4;//cinfo.num_components;//申请空间,带出数据*color_space = cinfo.out_color_space;*components = cinfo.out_color_components;*jpeg_width = cinfo.image_width;*jpeg_height = cinfo.image_height;int adjust = cinfo.image_width * cinfo.out_color_components % 4;*out_buff_size = (cinfo.image_width * cinfo.out_color_components + adjust) * cinfo.image_height;*out_buff = NULL;*out_buff = malloc(*out_buff_size);if (NULL == *out_buff){printf("malloc out_buff_size %d failed\n", *out_buff_size);return -1;}
//****************** end part 2 ******************//******************** part 3 ********************
/* 执行* 解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素* 对应的各颜色或灰度通道数据是依次存储,比如一个24-bit RGB真彩色的图像中,一个scanline中的数据存储模* 式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsigned char,定义于* jmorecfg.h中。除了JSAMPLE,图像还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。*/JSAMPROW row_pointer;//根据设定的参数开始解码jpeg_start_decompress(&cinfo);//每一行的大小int row_stride = cinfo.image_width * cinfo.out_color_components + adjust;//按照每一行来扫描,填充进输出空间里。output_scanline表示已经读出的行数while (cinfo.output_scanline < cinfo.output_height){//把缓冲区的首地址放到这里row_pointer =(unsigned char *) &(*out_buff)[cinfo.output_scanline * row_stride];jpeg_read_scanlines(&cinfo, &row_pointer, 1);}//结束解码jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);
//****************** end part 3 ******************return 0;
}

编码流程上差不多

int jpeg_encode(unsigned char *in_buff, int width, int height, int in_component, unsigned char **out_buff, int *out_buff_size)
{if (NULL == in_buff || NULL == out_buff || NULL == out_buff_size){printf("some param is NULL\n");return -1;}//定义一个通道数至颜色类型的映射int comp_to_type[] = {0, JCS_GRAYSCALE, 0, JCS_RGB, JCS_EXT_RGBA};struct jpeg_compress_struct cinfo = {0};jpeg_create_compress(&cinfo);PIO_JPEG_ERROR_MGR jerr;cinfo.err = jpeg_std_error(&jerr.jpg_err);jerr.jpg_err.error_exit = pio_jpeg_error_exit;if (setjmp(jerr.setjmp_buffer)){jpeg_destroy_compress(&cinfo);return -1;}jpeg_mem_dest(&cinfo, out_buff, out_buff_size);cinfo.image_width = width;cinfo.image_height = height;in_component = in_component == 0 ? 4 : in_component;//默认使用RGBA和4通道cinfo.in_color_space = comp_to_type[in_component];cinfo.input_components = in_component;jpeg_set_defaults(&cinfo);//该函数会自动设置除去上面4个参数外的其他参数为默认值JSAMPROW row_pointer;jpeg_start_compress(&cinfo, TRUE);int row_stride = cinfo.image_width * cinfo.input_components;while (cinfo.next_scanline < cinfo.image_height){row_pointer = (unsigned char *) &in_buff[cinfo.next_scanline * row_stride];jpeg_write_scanlines(&cinfo, &row_pointer, 1);}jpeg_finish_compress(&cinfo);jpeg_destroy_compress(&cinfo);return 0;
}

至此实现了RGB图像和jpeg文件互转
上述俩函数中均会为out_buff申请内存,需要外部释放。解码时可见主动申请内存,编码时在jpeg_mem_dest中申请内存

PNG(Portable Network Graphics)

png是一种采用无损压缩算法的位图格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。——百度百科

憋扯这没用的直接开搞

libpng

libpng是一款C语言编写的比较底层的读写PNG文件的跨平台的库

//头文件没什么好说的
#include <png.h>//写png文件
int png_fwrite(unsigned char *in_buff, int width, int height, int components, const char *URL)
{if (NULL == in_buff || NULL == URL){printf("some param is NULL\n");return -1;}//定义一个通道数至颜色类型的映射,1为PNG_COLOR_TYPE_GRAY、3为PNG_COLOR_TYPE_RGB、4为PNG_COLOR_TYPE_RGBAint comp_to_type[] = {0, PNG_COLOR_TYPE_GRAY, 0, PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGBA};// 第一步,初始化libpng库png_structp png_ptr = NULL;           // 首先创建两个结构体指针,这两个可以写成全局变量来用png_infop info_ptr = NULL;          // 每这两个结构体对应一个PNG文件,同时操作多个需要定义多个png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);if (!png_ptr){printf("Failed to initialize PNG writer.\n");return -1;}info_ptr = png_create_info_struct(png_ptr);if (!info_ptr){printf("Failed to initialize PNG writer.\n");png_destroy_write_struct(&png_ptr, NULL);return -1;}int iRetVal = 0;if (iRetVal = setjmp(png_jmpbuf(png_ptr)))   // 安装错误处理跳转点{                       //当libpng内部出现错误的时候,libpng会调用longjmp直接跳转到这里运行。printf("Failed to write PNG image. errcode = %d\n", iRetVal);png_destroy_write_struct(&png_ptr, &info_ptr);  // 这个函数可以两个结构体一起释放,也可以单独。结束对某个PNG文件的操作后需要调用return -1;}// 第二步,操作文件FILE *fp = fopen(URL, "wb");if (!fp){png_destroy_write_struct(&png_ptr, &info_ptr);return -1;}png_init_io(png_ptr, fp);           // 打开文件后,让libpng和这个文件流绑定起来//第三步,设置PNG文件属性、写入PNG文件头、写入PNG文件png_set_IHDR(png_ptr, info_ptr,width, height,           // 图像尺寸8,               // 颜色深度,每个颜色成分占用位数,PNG_COLOR_TYPE_GRAY、PNG_COLOR_TYPE_RGB、PNG_COLOR_TYPE_RGBA都是8comp_to_type[components], // 颜色类型,通道为1是PNG_COLOR_TYPE_GRAY、3为PNG_COLOR_TYPE_RGB、4为PNG_COLOR_TYPE_RGBAPNG_INTERLACE_NONE,       // 不交错。PNG_INTERLACE_ADAM7表示这个PNG是交错格式,在网络上传输能以最大速度显示出图像的大致样子PNG_COMPRESSION_TYPE_BASE,  // 压缩方式,可选择PNG_COMPRESSION_TYPE_BASE、PNG_COMPRESSION_TYPE_DEFAULTPNG_FILTER_TYPE_BASE);      // 暂不清楚,可选择PNG_FILTER_TYPE_BASE、PNG_FILTER_TYPE_DEFAULT,和压缩方式同步png_set_packing(png_ptr);          // 设置打包信息png_write_info(png_ptr, info_ptr);     // 写入文件头//到这里,已经通过fp写入了PNG的文件头//第四步,逐行写入/* 写图的方法之一是调用png_write_image(png_ptr,行指针数组的指针);这个你不需要考虑交错文件的写入的遍数。而如果你需要手动写入每一行的数据,你需要调用png_write_row(png_ptr,一行像素的指针);来进行逐行的像素值写入。如果你设置了交错格式的PNG,你需要多写入几遍图形数据,你需要调用png_set_interlace_handling(png_ptr);来得知你需要写入的遍数。如果你没有设置交错格式的PNG,你只需要写入一遍。文件内的排布和jpeg一样,设定PNG_COLOR_TYPE_RGB的话,每一行是RGBRGBRGB...PNG_COLOR_TYPE_RGBA的话就是RGBARGBARGBA...使用png_write_row的话,第二个参数为每一行像素,一行行写就行了使用png_write_image,需要定义一个指针数组,每个元素指向每一行像素,调用一次全部写完*/int i = 0;png_byte *row_pointers[height];for (i = 0; i < height; i++){row_pointers[i] = in_buff + i * width * components;//每个行指针指向每一行像素的首地址}png_write_image(png_ptr, row_pointers);//第五步,关闭、销毁png_write_end(png_ptr,info_ptr); //写入文件尾png_destroy_write_struct(&png_ptr,&info_ptr); //结束对这个PNG的访问if (fp) fclose(fp);return 0;
}

读png比较复杂,使用上未能覆盖所有情况,以下代码仅参考

typedef struct _pic_data
{int width, height; /* 尺寸 */int bit_depth;  /* 位深 */int flag;   /* 一个标志,表示是否有alpha通道 */unsigned char **rgba; /* 图片数组 */
} pic_data;
/**********************************************************************/
#define PNG_BYTES_TO_CHECK 4
#define HAVE_ALPHA 1
#define NO_ALPHA 0int detect_png(char *filepath, pic_data *out)
/* 用于解码png图片 */
{FILE *pic_fp;pic_fp = fopen(filepath, "rb");if(pic_fp == NULL) /* 文件打开失败 */return -1;/* 初始化各种结构 */png_structp png_ptr;png_infop  info_ptr;char        buf[PNG_BYTES_TO_CHECK];int        temp;png_ptr  = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);info_ptr = png_create_info_struct(png_ptr);setjmp(png_jmpbuf(png_ptr)); // 这句很重要temp = fread(buf,1,PNG_BYTES_TO_CHECK,pic_fp);temp = png_sig_cmp((void*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK);/*检测是否为png文件*/if (temp!=0) return 1;rewind(pic_fp);/*开始读文件*/png_init_io(png_ptr, pic_fp);// 读文件了png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);int color_type,channels;/*获取宽度,高度,位深,颜色类型*/channels      = png_get_channels(png_ptr, info_ptr); /*获取通道数*/out->bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* 获取位深 */color_type    = png_get_color_type(png_ptr, info_ptr); /*颜色类型*/int i,j;int size, pos = 0;/* row_pointers里边就是rgba数据 */png_bytep* row_pointers;row_pointers = png_get_rows(png_ptr, info_ptr);out->width = png_get_image_width(png_ptr, info_ptr);out->height = png_get_image_height(png_ptr, info_ptr);size = out->width * out->height; /* 计算图片的总像素点数量 */if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA){/*如果是RGB+alpha通道,,或者RGB+其它字节*/size *= (4*sizeof(unsigned char)); /* 每个像素点占4个字节内存 */out->flag = HAVE_ALPHA;    /* 标记 */out->rgba = (unsigned char**) malloc(size);if(out->rgba == NULL){/* 如果分配内存失败 */fclose(pic_fp);puts("错误(png):无法分配足够的内存供存储数据!");return 1;}temp = (4 * out->width);/* 每行有4 * out->width个字节 */for(i = 0; i < out->height; i++){for(j = 0; j < temp; j += 4){/* 一个字节一个字节的赋值 */out->rgba[0][pos] = row_pointers[i][j]; // redout->rgba[1][pos] = row_pointers[i][j+1]; // greenout->rgba[2][pos] = row_pointers[i][j+2];  // blueout->rgba[3][pos] = row_pointers[i][j+3]; // alpha++pos;}}}else if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB){/* 如果是RGB通道 */size *= (3*sizeof(unsigned char)); /* 每个像素点占3个字节内存 */out->flag = NO_ALPHA;    /* 标记 */out->rgba = (unsigned char**) malloc(size);if(out->rgba == NULL){/* 如果分配内存失败 */fclose(pic_fp);puts("错误(png):无法分配足够的内存供存储数据!");return 1;}temp = (3 * out->width);/* 每行有3 * out->width个字节 */for(i = 0; i < out->height; i++){for(j = 0; j < temp; j += 3){/* 一个字节一个字节的赋值 */out->rgba[0][pos] = row_pointers[i][j]; // redout->rgba[1][pos] = row_pointers[i][j+1]; // greenout->rgba[2][pos] = row_pointers[i][j+2];  // blue++pos;}}}else return 1;/* 撤销数据占用的内存 */png_destroy_read_struct(&png_ptr, &info_ptr, 0);return 0;
}

以下读取更方便,但是有一些新版本适配的问题,有些函数没有,比如png_read_png

png_infop info_ptr;
png_bytepp row_pointers;void read_png(char *file_name)
{FILE *fp = fopen(file_name, "rb");png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);png_infop info_ptr = png_create_info_struct(png_ptr);png_init_io(png_ptr, fp);png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);row_pointers = png_get_rows(png_ptr, info_ptr);png_destroy_read_struct(&png_ptr, &info_ptr, NULL);fclose(fp);
}

把RGB搞到内存中,就可以进行各类操作了,显示,翻转等等

libjpeg、libpng使用方法相关推荐

  1. linux centos 系统php支持jpeg的安装方法

    linux php支持jpeg首先要安裝libjpeg,运行下面的命令: yum install libjpeg* libpng* freetype* gd* 耐心等待完成,重启(service ht ...

  2. c语言libjpeg处理图像,解决使用 libjpeg 保存图片时因磁盘写入失败导致程序退出的有关问题...

    0. libjpeg 介绍 libjpeg 是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码.JPEG编码和其他的JPEG功能的实现.这个库由独立JPEG工作组维护. 参考:http://z ...

  3. libjpeg与turbo libjpeg的使用

    LibJpeg作为常用开源库,已有很多相关介绍. 其中值得一提的是,早先的版本里没有对内存中的Jpeg图像编解码的接口,而是使用Jpeg_stdio_src和jpeg_stdio_dest,这两个都是 ...

  4. CentOS6.3编译安装Nginx1.4.7 + MySQL5.5.25a + PHP5.3.28

    2019独角兽企业重金招聘Python工程师标准>>> [准备工作] 01 #在编译安装lnmp之前,首先先卸载已存在的rpm包. 02 rpm -e httpd 03 rpm -e ...

  5. PHP编译遇到的问题

    编译php的时候遇到的问题: 编译代码: ./configure --prefix=/server/php-5.4-nginx --with-config-file-path=/server/php- ...

  6. Nginx+Keeplived双机热备(主从模式)

    Nginx+Keeplived双机热备(主从模式) 参考资料: http://www.cnblogs.com/kevingrace/p/6138185.html 双机高可用一般是通过虚拟IP(漂移IP ...

  7. Zabbix监控系统安装与使用

    一.Zabbix简介: zabbix是完全开源的工具,整合了cacti和nagios等特性 cacti:snmp nagios:linux 主机:nrpe    设备:snmp 附:SNMP(udp1 ...

  8. linux 双mysql_MySQL双主互备+Keepalived高可用架构实现案例

    一.环境介绍 1.1.规划 序号 类别 版本 主机名 IP 端口 备注 1 OS CentOS release 6.9 (Final) (minimal) my1 172.16.210.180 830 ...

  9. centos 多个mysql,Centos中安装多个MySQL数据的配置实例

    这篇文章主要为大家详细介绍了Centos中安装多个MySQL数据的配置实例,具有一定的参考价值,可以用来参考一下. 感兴趣的小伙伴,下面一起跟随512笔记的小编小韵来看看吧! 注:本文档做了两个MYS ...

  10. linux系统下替换图片,Linux(ubuntu系统)下使用FreeImage库

    Linux(ubuntu系统)下使用FreeImage库 Linux(ubuntu系统)下使用FreeImage库 最近在搞一个图像处理的项目,需要用到FreeImage,之前在Windows下用过, ...

最新文章

  1. scrapy爬虫框架初相识
  2. MPLS *** 高级教程(张洋讲解演示版)
  3. 因xhost命令和DISPLAY环境变量操作不当导致无法启动Oracle图形化安装界面
  4. C#语言基础——结构体和枚举类型
  5. android doc例程---Notepad Tutorial学习要点!
  6. sqlite查询空日期类型_SQLite比较日期
  7. php 导出excel类,php 导出excel类
  8. latex参考文献BibTeX的使用方法
  9. [20150705]从AWR抽取有问题的sql语句.txt
  10. java struts 拦截器_java框架篇---struts实现拦截器
  11. 如何借助ArrayAdapter和Spinner实现下拉列表
  12. python将h264文件视频转为mp4格式
  13. 远程计算机没反映6678,6678 PCIe 与FPGA LINK UP 后 不能获得FPGA的DEVICE_ID和VENDDR_ID
  14. Tensorflow入门(二)文本自动生成
  15. 2022-2027年中国开采沙石行业发展监测及投资战略研究报告
  16. Ubuntu最全问题汇总(好东西分享了)
  17. Installation of packages ‘stringi’ had non-zero exit status
  18. 【Java位运算】使用快速幂方法求指数的值
  19. git下载指定tag版本
  20. ucos+ucgui(2)

热门文章

  1. clover直接进windows_从u盘启动安装mac os,没有显示clover,直接进入windows
  2. matlab 多属性权重,多属性决策的权重确定方法及matlab 程序
  3. GridView边框样式简单美化
  4. Centos7二进制安装Mysql8.0.20
  5. win7系统激活(GPT分区)
  6. 大型综合办公管理系统源码(OA+HR+CRM)源码免费分享
  7. xp系统安装ftp服务器,xp系统安装ftp服务器
  8. mysql 如何去掉毫秒_MySQL 关于毫秒的处理-阿里云开发者社区
  9. Vista v12.0 Win32-ISO 1DVD(地震数据处理)
  10. java毕业设计基于javaweb+mysql数据库实现的在线学习网站|在线课堂含论文+开题报告