Linux下libpng库的运用

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下libpng库的运用相关的知识,希望对你有一定的参考价值。

PNG是一种采用无损压缩算法的位图格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。 其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。PNG文件的扩展名为.png。这篇文章介绍libpng库来解码渲染png图片格式。

libpng库下载

下载地址: http://www.linuxfromscratch.org/blfs/view/svn/general/libpng.html​​

Linux下libpng库的运用​_png


1.1 在PC机上配置编译​

[wbyq@wbyq pc_work]$ tar xvf /mnt/hgfs/linux-share-dir/libpng-1.6.37.tar.xz

[wbyq@wbyq libpng-1.6.37]$ ./configure --enable-shared --enable-static --prefix=$PWD/_install

[wbyq@wbyq libpng-1.6.37]$ make && make install

[wbyq@wbyq libpng-1.6.37]$ tree _install/

_install/

├── bin

│ ├── libpng16-config

│ ├── libpng-config -> libpng16-config

│ ├── pngfix

│ └── png-fix-itxt

├── include

│ ├── libpng16

│ │ ├── pngconf.h

│ │ ├── png.h

│ │ └── pnglibconf.h

│ ├── pngconf.h -> libpng16/pngconf.h

│ ├── png.h -> libpng16/png.h

│ └── pnglibconf.h -> libpng16/pnglibconf.h

├── lib

│ ├── libpng16.a

│ ├── libpng16.la

│ ├── libpng16.so -> libpng16.so.16.37.0

│ ├── libpng16.so.16 -> libpng16.so.16.37.0

│ ├── libpng16.so.16.37.0

│ ├── libpng.a -> libpng16.a

│ ├── libpng.la -> libpng16.la

│ ├── libpng.so -> libpng16.so

│ └── pkgconfig

│ ├── libpng16.pc

│ └── libpng.pc -> libpng16.pc

└── share

man

man3

├── libpng.3

└── libpngpf.3

man5

png.5


9 directories, 23 files


1.2 交叉编译给ARM开发板使用

[wbyq@wbyq libpng-1.6.37]$ ./configure --prefix=$PWD/arm_install CC=arm-linux-gcc --host=arm-linux --enable-shared --enable-static


1.3 png应用案例(处理了透明背景)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include <poll.h>
#include <png.h>
#include <pngconf.h>

#define LCD_DEVICE "/dev/fb0"

int lcd_fd;
struct fb_var_screeninfo vinfo;//可变参数
struct fb_fix_screeninfo finfo; //固定参数
unsigned char *lcd_mem=NULL; //LCD首地址
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;

int image_height;
int image_width;
unsigned char *image_buffer[4];
int video_fd;
void LCD_DrawPoint(u32 x,u32 y,u32 c);
u32 LCD_ReadPoint(u32 x,u32 y);


/*显示PNG文件*/
int display_png(u32 x,u32 y,char* filename)

FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, number_passes;
u32 i,j;
u32 x0;
u32 rgb24,b_rgb24;
u8 r,g,b,a;
u8 b_r,b_g,b_b;
u8 R,G,B;

if((fp = fopen(filename,"rb")) == NULL)

printf("%s 文件打开失败.\\n",filename);
return -1;

png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);
/*需要分配/初始化内存以获取图像信息*/
info_ptr = png_create_info_struct(png_ptr);
/*设置PNG图片的文件指针*/
png_init_io(png_ptr,fp);
png_read_info(png_ptr,info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL);
printf("图片宽度:[%4d]\\n",width);
printf("图片高度:[%4d]\\n",height);
printf("颜色位数:[%4d]\\n",bit_depth);

/*读取图像的最简单方法:*/
png_bytep row_pointers[height];

/*清除指针数组*/
for(i = 0; i < height; i++)

row_pointers[i] = NULL;
row_pointers[i] = malloc(width * 4); /* RGBA */
memset(row_pointers[i], 0, width * 4);

/*读取整个PNG图像*/
png_read_image(png_ptr,row_pointers);

for(i = 0; i < height; i++)

x0=x;
for(j = 0; j < width * 4; j += 4)

/*得到图片颜色*/
r=row_pointers[i][j + 0];
g=row_pointers[i][j + 1];
b=row_pointers[i][j + 2];
a=row_pointers[i][j + 3];

/*读取当前屏幕点的背景颜色*/
b_rgb24=LCD_ReadPoint(x0,y);
b_r=b_rgb24>>16&0xFF;
b_g=b_rgb24>>8&0xFF;
b_b=b_rgb24>>0&0xFF;

/*合成屏幕背景颜色*/
R = (unsigned char)(r * (a / 255.0) + (b_r * (255 - a)) / 255.0);
G = (unsigned char)(g * (a / 255.0) + (b_g * (255 - a)) / 255.0);
B = (unsigned char)(b * (a / 255.0) + (b_b * (255 - a)) / 255.0);

/*显示数据*/
rgb24=R<<16|G<<8|B;
LCD_DrawPoint(x0,y,rgb24);

/*坐标自增*/
x0++;

y++;

/* 读取文件的其余部分,并在info_ptr中获取其他块-必需*/
png_read_end(png_ptr, info_ptr);
/*读取后清理,并释放已分配的所有内存-必需*/
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* 统一释放内存 */
for(i = 0; i < height; i++)

free(row_pointers[i]);

/*关闭文件*/
fclose(fp);
return 0;



/*
函数功能: 封装画点函数
函数参数: u32 x,u32 y,u16 c
*/
void LCD_DrawPoint(u32 x,u32 y,u32 c)

u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
*lcd_p=c;



/*
函数功能: 封装读点函数
函数参数: u32 x,u32 y,u16 c
*/
u32 LCD_ReadPoint(u32 x,u32 y)

u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
return *lcd_p;


int main(int argc,char **argv)

int err;
if(argc!=2)

printf("./app <xxx.png>\\n");
return 0;


/*1. 打开设备文件*/
lcd_fd=open(LCD_DEVICE,O_RDWR);
if(lcd_fd<0)

printf("%s 设备文件打开失败.\\n",LCD_DEVICE);
return 0;

/*2. 获取可变参数*/
ioctl(lcd_fd,FBIOGET_VSCREENINFO,&vinfo);
printf("x=%d,y=%d,pixel=%d\\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);

/*3. 获取固定参数*/
ioctl(lcd_fd,FBIOGET_FSCREENINFO,&finfo);
printf("smem_len=%d\\n",finfo.smem_len);
printf("line_length=%d\\n",finfo.line_length);

/*4. 映射LCD地址*/
lcd_mem=mmap(NULL,finfo.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
if(lcd_mem==NULL)

printf("映射LCD地址失败.\\n");
return -1;

//memset(lcd_mem,0xFFFFFF,finfo.smem_len);

/*5. 显示PN图片*/
display_png(0,0,argv[1]);

close(lcd_fd);
return 0;

1.4 png应用案例(未处理透明背景)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include <poll.h>
#include <png.h>
#include <pngconf.h>

#define LCD_DEVICE "/dev/fb0"

int lcd_fd;
struct fb_var_screeninfo vinfo;//可变参数
struct fb_fix_screeninfo finfo; //固定参数
unsigned char *lcd_mem=NULL; //LCD首地址
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;

int image_height;
int image_width;
unsigned char *image_buffer[4];
int video_fd;
void LCD_DrawPoint(u32 x,u32 y,u32 c);


/*显示PNG文件*/
int display_png(u32 x,u32 y,char* filename)

FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, number_passes;
u32 i,j;
u32 x0;
u32 rgb24;
u8 r,g,b;

if((fp = fopen(filename,"rb")) == NULL)

printf("%s 文件打开失败.\\n",filename);
return -1;

png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);
/*需要分配/初始化内存以获取图像信息*/
info_ptr = png_create_info_struct(png_ptr);
/*设置PNG图片的文件指针*/
png_init_io(png_ptr,fp);
png_read_info(png_ptr,info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL);
printf("图片宽度:[%4d]\\n",width);
printf("图片高度:[%4d]\\n",height);
printf("颜色位数:[%4d]\\n",bit_depth);

/*读取图像的最简单方法:*/
png_bytep row_pointers[height];

/*清除指针数组*/
for(i = 0; i < height; i++)

row_pointers[i] = NULL;
row_pointers[i] = malloc(width * 4); /* RGBA */
memset(row_pointers[i], 0, width * 4);

/*读取整个PNG图像*/
png_read_image(png_ptr,row_pointers);

for(i = 0; i < height; i++)

x0=x;
for(j = 0; j < width * 4; j += 4)

r=row_pointers[i][j + 0];
g=row_pointers[i][j + 1];
b=row_pointers[i][j + 2];
/*显示数据*/
rgb24=r<<16|g<<8|b;
LCD_DrawPoint(x0++,y,rgb24);

y++;

/* 读取文件的其余部分,并在info_ptr中获取其他块-必需*/
png_read_end(png_ptr, info_ptr);
/*读取后清理,并释放已分配的所有内存-必需*/
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* 统一释放内存 */
for(i = 0; i < height; i++)

free(row_pointers[i]);

/*关闭文件*/
fclose(fp);
return 0;



/*
函数功能: 封装画点函数
函数参数: u32 x,u32 y,u16 c
*/
void LCD_DrawPoint(u32 x,u32 y,u32 c)

u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
*lcd_p=c;



/*
函数功能: 封装读点函数
函数参数: u32 x,u32 y,u16 c
*/
u32 LCD_ReadPoint(u32 x,u32 y)

u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
return *lcd_p;


int main(int argc,char **argv)

int err;
if(argc!=2)

printf("./app <xxx.png>\\n");
return 0;


/*1. 打开设备文件*/
lcd_fd=open(LCD_DEVICE,O_RDWR);
if(lcd_fd<0)

printf("%s 设备文件打开失败.\\n",LCD_DEVICE);
return 0;

/*2. 获取可变参数*/
ioctl(lcd_fd,FBIOGET_VSCREENINFO,&vinfo);
printf("x=%d,y=%d,pixel=%d\\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);

/*3. 获取固定参数*/
ioctl(lcd_fd,FBIOGET_FSCREENINFO,&finfo);
printf("smem_len=%d\\n",finfo.smem_len);
printf("line_length=%d\\n",finfo.line_length);

/*4. 映射LCD地址*/
lcd_mem=mmap(NULL,finfo.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
if(lcd_mem==NULL)

printf("映射LCD地址失败.\\n");
return -1;

memset(lcd_mem,0xFFFFFF,finfo.smem_len);

/*5. 显示PN图片*/
display_png(0,0,argv[1]);

close(lcd_fd);
return 0;

下面是开发板上显示的PNG图片:

Linux下libpng库的运用​_libpng_02

Linux下libpng库的运用​_png_03


Linux下libpng库的运用​_libpng_04

Linux下libpng库的运用​_png_05

Linux下libpng库的运用​_png_06

Linux下libpng库的运用​_libpng_07

Linux下libpng库的运用​_png_08

Linux下libpng库的运用​_libpng_09








以上是关于Linux下libpng库的运用的主要内容,如果未能解决你的问题,请参考以下文章

Windows下zlib库和libPng库的编译和使用

QT+OpenGL(03)--libpng库的编译

Linux下GIF库移植与运用

libpng12.so.0的作用

libpng+VS2012(VS2015)的使用

Linux libgd库的安装