1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > linux下libpng库的安装以及使用

linux下libpng库的安装以及使用

时间:2020-08-12 23:35:32

相关推荐

linux下libpng库的安装以及使用

前几天手里的智能锁项目 , 收到产品的建议(命令)说 , 就是人脸识别成功的时候 , 不要只显示摄像头捕捉到的图像 , 要弄个酷炫一点的背景, 背景里图片中间有个圆圈, 人脸就放到圆圈里也就是类似这样。。

当然, 这是我思考了好几个小时的结果, 开始想不明白要怎么实现,其实想通了也很简单, 三个步骤

A 把背景图像的RGB读出来 out_buf

B 把摄像头采集到的图像读出来(分辨率和背景图像一样) , in_buf

C 如果out_buf当前像素点是黑色不变, 否则填充in_buf到out_buf

有了思路了 , 就要付诸行动 , 花了好几个小时来了解了一下PNG图片的格式 , 又找到一个资料比较全的库 , 就各种找资料 , 把png的读写跑了一遍, 特意记录一下

关于PNG文件格式这里不讨论 , 有兴趣的朋友直接百度"PNG文件格式"会得到自己想要的答案

一: 安装PNG库文件

因为PNG文件需要用到zlib进行编解码, 所以用到libpng的同时也需要zlib加密解密

本文使用的是libpng版本和zlib版本如下:

下载地址:

/projects/libpng/files/

下载完之后如下命令顺序执行:

libpng:#解压tar -xzvf libpng-1.6.26.tar.gz && cd libpng-1.6.26#安装./configuremake checksudo make installsudo ldconfigzlib:#解压:tar -xf zlib-1.2.11.tar.xz && cd zlib-1.2.11#安装./configure sudo make installsudo make

安装成功如下图 :

运行pkg-config libpng16 zlib --libs --cflags得到正确的头文件和链接库的位置

二 : 使用libpng

libpng有一套自己的流程如下:

1:初始化png_structp结构体 (用于和打开的文件指针绑定)

2:初始化png_infop结构体 (此结构体包含各种图片信息)

3:设置错误返回点 (如果是Libpng内部出现错误, 则会跳到你设置的错误返回点处执行)

4:绑定文件IO流到png_structp结构体 (打开的文件和png_structp结构体实例进行绑定)

5:写入需要生成PNG图像的信息, 信息内容包括尺寸, 位深度,颜色类型,是否交错, 换行等等,按照格式逐个填写就行了

6:写入实际的RGB数据到绑定好的png_structp结构体

7:写入文件尾部信息

8:清理工作 (释放申请的内存, 注销png_structp结构体)

代码如下 :

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <png.h>#define PNG_BYTES_TO_CHECK8#define HAVE_ALPHA1#define NOT_HAVE_ALPHA0typedef struct _pic_data pic_data;struct _pic_data {int width, height; //长宽int bit_depth; //位深度int alpha_flag;//是否有透明通道unsigned char *rgba;//实际rgb数据};int check_is_png(FILE **fp, const char *filename) //检查是否png文件{char checkheader[PNG_BYTES_TO_CHECK]; //查询是否png头*fp = fopen(filename, "rb");if (*fp == NULL) {printf("open failed ...1\n");return 0;}if (fread(checkheader, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) //读取png文件长度错误直接退出return 0;return png_sig_cmp(checkheader, 0, PNG_BYTES_TO_CHECK); //0正确, 非0错误}int decode_png(const char *filename, pic_data *out) //取出png文件中的rgb数据{png_structp png_ptr; //png文件句柄png_infopinfo_ptr;//png图像信息句柄int ret;FILE *fp;if (check_is_png(&fp, filename) != 0) {printf("file is not png ...\n");return -1;}printf("launcher[%s] ...\n", PNG_LIBPNG_VER_STRING); //打印当前libpng版本号//1: 初始化libpng的数据结构 :png_ptr, info_ptrpng_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr);//2: 设置错误的返回点setjmp(png_jmpbuf(png_ptr));rewind(fp); //等价fseek(fp, 0, SEEK_SET);//3: 把png结构体和文件流io进行绑定 png_init_io(png_ptr, fp);//4:读取png文件信息以及强转转换成RGBA:8888数据格式png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); //读取文件信息int channels, color_type; channels = png_get_channels(png_ptr, info_ptr); //通道数量color_type = png_get_color_type(png_ptr, info_ptr);//颜色类型out->bit_depth = png_get_bit_depth(png_ptr, info_ptr);//位深度out->width = png_get_image_width(png_ptr, info_ptr);//宽out->height = png_get_image_height(png_ptr, info_ptr);//高//if(color_type == PNG_COLOR_TYPE_PALETTE)//png_set_palette_to_rgb(png_ptr);//要求转换索引颜色到RGB//if(color_type == PNG_COLOR_TYPE_GRAY && out->bit_depth < 8)//png_set_expand_gray_1_2_4_to_8(png_ptr);//要求位深度强制8bit//if(out->bit_depth == 16)//png_set_strip_16(png_ptr);//要求位深度强制8bit//if(png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS))//png_set_tRNS_to_alpha(png_ptr);//if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)//png_set_gray_to_rgb(png_ptr);//灰度必须转换成RGprintf("channels = %d color_type = %d bit_depth = %d width = %d height = %d ...\n",channels, color_type, out->bit_depth, out->width, out->height);int i, j, k;int size, pos = 0;int temp;//5: 读取实际的rgb数据png_bytepp row_pointers; //实际存储rgb数据的bufrow_pointers = png_get_rows(png_ptr, info_ptr); //也可以分别每一行获取png_get_rowbytes();size = out->width * out->height; //申请内存先计算空间if (channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { //判断是24位还是32位out->alpha_flag = HAVE_ALPHA; //记录是否有透明通道size *= (sizeof(unsigned char) * 4); //size = out->width * out->height * channelout->rgba = (png_bytep)malloc(size);if (NULL == out->rgba) {printf("malloc rgba faile ...\n");png_destroy_read_struct(&png_ptr, &info_ptr, 0);fclose(fp);return -1;}//从row_pointers里读出实际的rgb数据出来temp = channels - 1;for (i = 0; i < out->height; i++) for (j = 0; j < out->width * 4; j += 4) for (k = temp; k >= 0; k--)out->rgba[pos++] = row_pointers[i][j + k];} else if (channels == 3 || color_type == PNG_COLOR_TYPE_RGB) { //判断颜色深度是24位还是32位out->alpha_flag = NOT_HAVE_ALPHA;size *= (sizeof(unsigned char) * 3);out->rgba = (png_bytep)malloc(size);if (NULL == out->rgba) {printf("malloc rgba faile ...\n");png_destroy_read_struct(&png_ptr, &info_ptr, 0);fclose(fp);return -1;}//从row_pointers里读出实际的rgb数据temp = (3 * out->width);for (i = 0; i < out->height; i ++) {for (j = 0; j < temp; j += 3) {out->rgba[pos++] = row_pointers[i][j+2];out->rgba[pos++] = row_pointers[i][j+1];out->rgba[pos++] = row_pointers[i][j+0];}}} else return -1; //6:销毁内存png_destroy_read_struct(&png_ptr, &info_ptr, 0);fclose(fp);//此时, 我们的out->rgba里面已经存储有实际的rgb数据了//处理完成以后free(out->rgba)return 0;}int RotationRight90(unsigned char * src, int srcW, int srcH, int channel) //顺时针旋转90度{unsigned char * tempSrc = NULL; //临时的buf用来记录原始的图像(未旋转之前的图像)int mSize = srcW * srcH * sizeof(char) * channel;int i = 0;int j = 0;int k = 0;int l = 3;int desW = 0;int desH = 0;desW = srcH;desH = srcW;tempSrc = (unsigned char *)malloc(sizeof(char) * srcW * srcH * channel);memcpy(tempSrc, src, mSize); //拷贝原始图像至tempbuffor(i = 0; i < desH; i ++){for(j = 0; j < desW; j ++){for(k = 0; k < channel; k ++){src[(i * desW + j) * channel + k] = tempSrc[((srcH - 1 - j) * srcW + i) * channel + k]; //替换像素}}}free(tempSrc);return 0;}int write_png_file(const char *filename , pic_data *out) //生成一个新的png图像{png_structp png_ptr;png_infop info_ptr;png_byte color_type;png_bytep * row_pointers;FILE *fp = fopen(filename, "wb");if (NULL == fp) {printf("open failed ...2\n");return -1;}//1: 初始化libpng结构体 png_ptr= png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);if (!png_ptr) {printf("png_create_write_struct failed ...\n");return -1;}//2: 初始化png_infop结构体 , //此结构体包含了图像的各种信息如尺寸,像素位深, 颜色类型等等info_ptr = png_create_info_struct(png_ptr);if (!info_ptr) {printf("png_create_info_struct failed ...\n");return -1;}//3: 设置错误返回点if (setjmp(png_jmpbuf(png_ptr))) {printf("error during init_io ...\n");return -1;}//4:绑定文件IO到Png结构体png_init_io(png_ptr, fp);if (setjmp(png_jmpbuf(png_ptr))) {printf("error during init_io ...\n");return -1;}if (out->alpha_flag == HAVE_ALPHA) color_type = PNG_COLOR_TYPE_RGB_ALPHA;else color_type = PNG_COLOR_TYPE_RGB;//5:设置以及写入头部信息到Png文件png_set_IHDR(png_ptr, info_ptr, out->width, out->height, out->bit_depth,color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);png_write_info(png_ptr, info_ptr);if (setjmp(png_jmpbuf(png_ptr))) {printf("error during init_io ...\n");return -1;}int channels, temp;int i, j, pos = 0;if (out->alpha_flag == HAVE_ALPHA) {channels = 4;temp = (4 * out->width);printf("have alpha ...\n");} else {channels = 3;temp = (3 * out->width);printf("not have alpha ...\n");}// 顺时针旋转90度 , 旋转完了一定要把width 和height调换 不然得到的图像是花的 旋转三次就是逆时针旋转一次//RotationRight90(out->rgba, out->width, out->height, channels);//RotationRight90(out->rgba, out->height, out->width, channels);//RotationRight90(out->rgba, out->width, out->height, channels);row_pointers = (png_bytep*)malloc(out->height * sizeof(png_bytep));for (i = 0; i < out->height; i++) {row_pointers[i] = (png_bytep)malloc(temp* sizeof(unsigned char));for (j = 0; j < temp; j += channels) {if (channels == 4) {row_pointers[i][j+3] = out->rgba[pos++];row_pointers[i][j+2] = out->rgba[pos++];row_pointers[i][j+1] = out->rgba[pos++];row_pointers[i][j+0] = out->rgba[pos++];} else {row_pointers[i][j+2] = out->rgba[pos++];row_pointers[i][j+1] = out->rgba[pos++];row_pointers[i][j+0] = out->rgba[pos++];}}}//6: 写入rgb数据到Png文件png_write_image(png_ptr, (png_bytepp)row_pointers);if (setjmp(png_jmpbuf(png_ptr))) {printf("error during init_io ...\n");return -1;}//7: 写入尾部信息png_write_end(png_ptr, NULL);//8:释放内存 ,销毁png结构体for (i = 0; i < out->height; i ++)free(row_pointers[i]);free(row_pointers);png_destroy_write_struct(&png_ptr, &info_ptr);fclose(fp);return 0;}int main(int argc, char **argv){pic_data out;if (argc == 3) {decode_png(argv[1], &out);write_png_file(argv[2], &out);free(out.rgba);} else {puts("please input two file, \nargv[1]:source.png argv[2]:dest.png");}return 0;}

编译需要链接已经安装好的libpng 和 zlib库

gcc test.c `pkg-config libpng16 zlib --libs --cflags`

功能就是简单得读取PNG格式图片, 再生成(写入)一个新的一模一样的图片 , 代码中把图片旋转注释了 , 亲测也是可用的。

最后送上一张随便百度的PNG格式图片, 还有一张就是项目的图片(无视本人)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。