前言
如何使用 libpng 库进行图片解码应用开发。
一、libpng是什么?
libpng是一个开源的、跨平台的图像处理库,用于处理和支持PNG(Portable Network Graphics)图像格式。PNG是一种无损压缩的图像格式,广泛用于互联网上的图像传输和存储。libpng提供了一系列的API和函数,使开发者可以在自己的应用程序中读取、写入和操作PNG图像文件。libpng还支持处理其他常见图像格式,如BMP和JPEG。它是一个功能强大且使用广泛的图像处理库,被许多软件和应用程序所使用。png相对其他格式可以保存设透明度信息。
二、使用步骤
1.引入库及头文件
make 文件添加对应的库文件:
#png-lib
LIBS+= $(DIR_PRJ)/miniPrinter/lib/png/lib/libpng16.a
LIBS+= $(DIR_PRJ)/miniPrinter/lib/png/lib/libz.a
引入头文件
#include "png.h" //解码库文件
#include "pngconf.h" //解码库文件
#include "pnglibconf.h" //解码库文件
2.解码过程
代码如下:
int decode_png(char* name)
{
static struct timeval start_time, stop_time;
int i, j;
int m_width, m_height;
png_infop info_ptr; //图片信息的结构体
png_structp png_ptr; //初始化结构体,初始生成,调用api时注意传入
FILE* file = fopen(name, "rb"); //打开的文件名
printf("%s, %d\n", __FUNCTION__, __LINE__);
if(file==0)
{
printf("%s, %d,%s open faile \n", __FUNCTION__, __LINE__, name);
return -1;
}
gettimeofday(&start_time, NULL); //获取时间
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); //创建初始化libpng库结构体
info_ptr = png_create_info_struct(png_ptr); //创建图片信息结构体
setjmp(png_jmpbuf(png_ptr)); //设置错误的返回点
// 这句很重要
png_init_io(png_ptr, file); //把文件加载到libpng库结构体中
// 读文件了
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); //读文件内容到info_ptr中
gettimeofday(&stop_time, NULL); //获取时间
printf("decode_png time:%d ms\n", stop_time.tv_usec/1000 - start_time.tv_usec/1000);
// 得到文件的宽高色深
if ((png_ptr != NULL) && (info_ptr != NULL))
{
m_width = png_get_image_width(png_ptr, info_ptr);
m_height = png_get_image_height(png_ptr, info_ptr); //通过png库中的api获取图片的宽度和高度
printf("%s, %d, m_width =%d, m_height = %d\n", __FUNCTION__, __LINE__, m_width, m_height);
}
int color_type = png_get_color_type(png_ptr, info_ptr); //通过api获取color_type
printf("%s, %d, color_type = %d\n", __FUNCTION__, __LINE__, color_type);
int bit_depth = png_get_bit_depth(png_ptr,info_ptr);
printf("%s, %d, bit_depth = %d\n", __FUNCTION__, __LINE__, bit_depth);
int bitNum = bit_depth;
if( color_type )bitNum *= ((color_type & PNG_COLOR_MASK_COLOR)?3:0) + ((color_type & PNG_COLOR_MASK_ALPHA)?1:0);
bitNum = bitNum / 8;
printf("%s, %d, bitNum = %d\n", __FUNCTION__, __LINE__, bitNum);
int size = m_height * m_width * bitNum;
unsigned char* bgra = NULL;
bgra = (unsigned char*)malloc(size);
if (NULL == bgra)
{
printf("%s, %d, bgra == NULL\n", __FUNCTION__, __LINE__);
return NULL;
}
int pos = 0;
// row_pointers里边就是传说中的rgb数据了
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
// 拷贝!!注意,如果你读取的png没有A通道,就要3位3位的读。还有就是注意字节对其的问题,最简单的就是别用不能被4整除的宽度就行了。读过你实在想用,就要在这里加上相关的对齐处理。
int byteNum;
char bytes;
for (i = 0; i < m_height; i++)
{
for (j = 0; j < (bitNum * m_width); j += bitNum)
{
#if 1
bgra[pos++] = row_pointers[i][j + 2]; // blue
bgra[pos++] = row_pointers[i][j + 1]; // green
bgra[pos++] = row_pointers[i][j]; // red
bgra[pos++] = row_pointers[i][j + 3]; // alpha
// printf("%s, b:%d, g:%d, r:%d, a:%d\n", __FUNCTION__,
// row_pointers[i][j + 2], row_pointers[i][j + 1],row_pointers[i][j],row_pointers[i][j + 3]);
#endif
}
}
#if 1
char tmp[10] = { 0 };
//保存rgb裸流文件咯,省时省力
FILE* f = fopen("save-png.bin", "wb");
#if 1
for (i = 0; i < size; i++)
{
// printf("%s, %d, bgra[%d] = %d\n", __FUNCTION__, __LINE__, i, bgra[i]);
sprintf(tmp, "0x%x,", bgra[i]);
fwrite(tmp, strlen(tmp), 1, f);
}
#endif
fwrite(bgra, size, 1, f);
fclose(f);
#endif
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(file);
return 0;
}
解码生成的格式是rgb格式并不能直接读取。如果要看效果可以通过以下在线工具进行查看
https://imagetostl.com/cn/view-rgba-online
总结
要注意这里使用libz.a,否则编译不过的。