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
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库的运用的主要内容,如果未能解决你的问题,请参考以下文章