首页 > 学院 > 开发设计 > 正文

libpng的png_read_info和png_read_image使用

2019-11-08 02:19:22
字体:
来源:转载
供稿:网友

常用接口

libpng库解析图片主要用的函数大致有: png_sig_cmp(sig, 0, 8); png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL); png_create_info_struct(png_ptr); setjmp(png_jmpbuf(png_ptr)); png_init_io(png_ptr, trfile); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_rowbytes(png_ptr,info_ptr); png_read_image(png_ptr, row_pointers);

初始化PNG数据

加载png图片

png_structp png_ptr;png_infop info_ptr;FILE * trfile;void Load(char * fileName){ trfile = fopen(name,"rb"); BYTE sig[9] = {0}; fread(sig, 1, 8, trfile); int result ; result = png_sig_cmp(sig, 0, 8); png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); esult = setjmp(png_jmpbuf(png_ptr)); png_init_io(png_ptr, trfile); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr);}

png_sig_cmp(sig, 0, 8): it will return 0 (false) if the bytes match the corresponding bytes of the PNG signature; 验证PNG文件的正确性完整性; 如果你已经使用png_sig_cmp函数来检查了png数据,需要调用png_set_sig_bytes函数来告诉libpng库,这样库处理数据的时候将会跳过相应的数据

png_set_sig_bytes(png_ptr, 8); Tell lib we have already handled the first “8” magic bytes. Handling more than 8 bytes from the beginning of the file is an error. 设置读取PNG文件的指针偏移量,不能超过8位(用于配置png_sig_cmp的使用);

setjmp(png_jmpbuf(png_ptr)) When libpng encounters an error, it expects to longjmp back to your routine; 设置发生错误时返回错误时调用的位置; 用setjmp/longjmp函数来处理异常。libpng库默认集成这种机制来完成异常处理; 如果设置了用户自定义的错误处理函数,libpng将会调用用户自定义错误处理函数,而不会返回到这个设置了默认返回点的调用点上;

输出PNG文件的长宽位深度数据

经过上面的Load后可以打印相关的png数据,这里定义一个结构体存放更清晰

typedef struct { int pixelDepth; int imageWidth; int imageHeight;}PngImageInfo;void GetImageInfo(PngImageInfo* pInfo){ pInfo->pixelDepth = info_ptr->pixel_depth; pInfo->imageWidth = info_ptr->width; pInfo->imageHeight = info_ptr->height;}

解码位深度为24bit和32bit的PNG文件

下面开始解码png数据到一个数组中,用于进行绘制到显存下

unsigned long* GetPngData(int dstW, int dstH){ unsigned long pDst[dstW * dstH * 4]; // 解析后的数据,24位和32位的图每个像素占空间ARGB个1byte png_bytep row_pointers[dstH]; for (int row = 0; row < dstH; row++){ row_pointers[row] = NULL; } for (int row = 0; row < dstH; row++){ //png_get_rowbytes(png_ptr,info_ptr)==834==278*3(本例程使用的是24位深度的PNG图片) row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr,info_ptr)); } png_read_image(png_ptr, row_pointers); if(info_ptr->pixel_depth == 24) { int pixelR,pixelG,pixelB; unsigned char * pSrc; int i, j; int top = 0; //画布y轴上偏移量 int left = 0; //画布x轴上偏移量 for(j=0;j<dstH;j++){ pSrc = row_pointers[top+j] + left * 3; for(i=0;i<dstW;i++){ pixelR = *pSrc++; pixelG = *pSrc++; pixelB = *pSrc++; pDst[i] = 0xFF000000 | (pixelR << 16) | (pixelG << 8) | pixelB; } pDst += dstW;// 加上图片的横向像素点(即纵向下移一个像素单位) } } for (int row = 0; row < info_ptr->height; row++){ png_free(png_ptr,row_pointers[row]); } return pDst; // 返回指针是不科学的 但是这里仅仅是举例说明}

这里插播一下关于32位的位深度的PNG图片的解析:

if(info_ptr->pixel_depth == 32){ unsigned long pixelR,pixelG,pixelB,pixelA; unsigned char * pSrc; int i, j; for(j=0;j<dstH;j++){ pSrc = row_pointers[top+j] + left * 4; for(i=0;i<dstW;i++) { pixelR = *pSrc++; pixelG = *pSrc++; pixelB = *pSrc++; pixelA = *pSrc++; pDst[i] = (pixelA<< 24) | (pixelR << 16) | (pixelG << 8) | pixelB; } pDst += dstW; }}

绘制解码后的PNG文件数据

上面的Draw函数已经获取到解码后的png数据,接下来只需要把数据放入到内存对应的区域就能把图片显示出来了:

// 硬件地址unsigned long* GetDisplayMemoryAddr(){ int* h_hsPR = open("/dev/frame", O_RDWR, 0); unsigned long* pDst = (unsigned long*)mmap(0, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED,h_hspr, 0); return pDst;}// 图片大小 278*182// 画布大小(屏幕大小) 800*480void CopyPngDataToDisplayDriver(){ unsigned long*pDst = GetDisplayMemoryAddr(); unsigned long*pSrc = GetPngData(278, 182); for(int i=0; i<182; i++) { memcpy(pDst,pSrc,278 * 4); //pDst[dstW*dstH*4] pDst += 800; pSrc += 278; } ioctl(h_hspr,IOCTL_Y,NULL); ioctl(h_hspr,IOCTL_X,NULL);}

效果为: 这里写图片描述

本次例程使用的是交叉编译到全志的开发板中进行测试 PNG图片文件数据:278*182,位深度24


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表