天天看點

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庫的運用​

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庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​
Linux下libpng庫的運用​

繼續閱讀