解码库版本:libpng-1.6.35
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <png.h> //解码库文件
#include <pngstruct.h> //解码库文件
#include <pnginfo.h> //解码库文件
#include <config.h> //自己定义的头文件
#define PNG_BYTES_TO_CHECK 8
/*
*函数功能 :判断一个图片数是不是png图片
*函数参数 :path是图片文件的路径名加文件名
*返回值 :如果是png则返回0,不是或出错返回-1
*/
static int is_png(char *path) {
FILE *fp = NULL;
char buf[PNG_BYTES_TO_CHECK] = {0};
/* Open the prospective PNG file. */
if ((fp = fopen(path, "rb")) == NULL)
return -1;
/* Read in some of the signature bytes */
if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
return -1;
//比较头文件标识,是png格式则返回0,不是返回非0
//png 文件头标识 (8 bytes) 89 50 4E 47 0D 0A 1A 0A
return(png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
}
/*
*函数功能:解码png图片,并将解码出来的数据存储起来
*函数参数:pPic记录源png图片,解码出来图片宽高、位深度等
*返回值 :解码正确返回0,错误返回-1
*/
static int png_analyze (struct pic_info *pPic)
{
int i, j, pos=0;
png_structp png_ptr; //定义一个png指针
png_infop info_ptr;
png_bytep* row_ptr; //实际存储rgb数据的buf,二维指针
png_byte color_type;
FILE *fp = NULL;
if ((fp = fopen(pPic->pathname, "rb")) == NULL) {
fprintf(stderr, "fopen %s error.\n", pPic->pathname);
return -1;
}
//第1步:初始化相关结构体
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{
fprintf(stderr, "init %s error.\n", pPic->pathname);
fclose(fp);
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
fprintf(stderr, "create %s error.\n", pPic->pathname);
fclose(fp);
png_destroy_read_struct(&png_ptr, NULL, NULL);
return -1;
}
//第2步:设置错误返回点
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return -1;
}
//第3步:将解码的结构体和图片文件绑定
png_init_io(png_ptr, fp);
//第4步:读文件
/*当内存足够大可以一次性读入所有的png数据,可以使用高层函数
该函数将会把所有的图片数据解码到info_ptr数据结构中*/
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, NULL);
//第5步:提取打印文件信息
pPic->width = info_ptr->width;
pPic->height = info_ptr->height;
pPic->bpp = info_ptr->pixel_depth;
color_type = info_ptr->color_type;
printf("picture resolution: %d*%d\n", pPic->width, pPic->height);
printf("picture bpp: %d\n", pPic->bpp);
printf("picture colortype: %d\n", color_type);
// 第6步: 读取真正的图像信息
row_ptr = png_get_rows(png_ptr, info_ptr);
switch (color_type) {
case PNG_COLOR_TYPE_RGB_ALPHA:
for (i = 0; i < pPic->height; i++) {
for (j = 0; j < pPic->width*4; j+=4) {
pPic->pData[pos++] = row_ptr[i][j+0]; // red
pPic->pData[pos++] = row_ptr[i][j+1]; // green
pPic->pData[pos++] = row_ptr[i][j+2]; // blue
}
}
break;
case PNG_COLOR_TYPE_RGB:
for (i = 0; i < pPic->height; i++) {
for (j = 0; j < pPic->width*3; j+=3) {
pPic->pData[pos++] = row_ptr[i][j+0]; // red
pPic->pData[pos++] = row_ptr[i][j+1]; // green
pPic->pData[pos++] = row_ptr[i][j+2]; // blue
}
}
break;
default:
break;
}
//第7步:扫尾
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(fp);
return 0;
}
int png_display (char *pathname)
{
int ret = -1;
struct pic_info pic;
//第1步:判断图片是不是jpg图片
ret = is_png(pathname);
if (ret != 0) {
return -1;
}
//第2步:显示jpg图片
pic.pathname = pathname;
pic.pData = rgb_buf;
ret = png_analyze(&pic);
if (ret != 0) {
return -1;
}
fb_draw_jpg(0, 0, &pic);
return 0;
}
下面分析一下解码函数
1.png_infop 结构体在哪儿
在png.h的484行有如下内容,png_infop被声明为了png_info 的一维指针,而png_info又是png_info_def 的声明。
typedef struct png_info_def png_info;
typedef png_info * png_infop;
typedef const png_info * png_const_infop;
typedef png_info * * png_infopp;
得到了png_info_def后,接下来追根溯源,可以找到png_info_def定义在了pnginfo.h文件中:
struct png_info_def
{
/* The following are necessary for every PNG file */
png_uint_32 width; /* width of image in pixels (from IHDR) */
png_uint_32 height; /* height of image in pixels (from IHDR) */
png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
size_t rowbytes; /* bytes needed to hold an untransformed row */
png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
/* The following three should have been named *_method not *_type */
png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
/* The following are set by png_set_IHDR, called from the application on
* write, but the are never actually used by the write code.
*/
png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */
png_byte pixel_depth; /* number of bits per pixel */
png_byte spare_byte; /* to align the data, and for future use */
..................还有很长.......长.
}
2.png_read_png()如何传参
函数原型:png_read_png(png_ptr, info_ptr, png_transforms, NULL)
读取图片文件信息有两种方法可以使用,一种是使用高层函数(high-level)读取,png_read_png()即为高层函数;另外一种是通过一系列的低层函数(low-level)接口进行读取操作,用起来相对麻烦。使用高层函数的前提是有足够的内存去存储整个图片的信息,因为高层函数内部进行了封装,所以使用起来很方便。
参数 png_transforms:可选用的值如下,如果只填参数PNG_TRANSFORM_EXPAND
,那么转换结果为四通道,包含了RGB通道和ALPHA通道;参数改为PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA
后,就可以把ALPHA通道屏蔽掉,转换之后即为RGB三通道。
/* Transform masks for the high-level interface */
#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */
#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */
#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */
#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */
#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */
#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */
#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */
#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */
#define PNG_TRANSFORM_BGR 0x0080 /* read and write */
#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */
#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */
#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */
#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */
/* Added to libpng-1.2.34 */
#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER
#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */
/* Added to libpng-1.4.0 */
#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */
/* Added to libpng-1.5.4 */
#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */
3.color_type的值有哪些
color_type的可能等于的值是由宏定义来决定的,switch判断的时候,我只判断了PNG_COLOR_TYPE_RGB_ALPHA和PNG_COLOR_TYPE_RGB两种情况,其他情况没有考虑,PNG_COLOR_TYPE_GRAY_ALPHA代表解码后的颜色类型为四通道,PNG_COLOR_TYPE_RGB代表三通道,转移数据的时候要注意这一点。
#define PNG_COLOR_TYPE_GRAY 0
#define PNG_COLOR_TYPE_RGB 2
#define PNG_COLOR_TYPE_PALETTE 3
#define PNG_COLOR_TYPE_GRAY_ALPHA 4
#define PNG_COLOR_TYPE_RGB_ALPHA 6