Linux內核版本號:linux 2.6.39
交叉編譯工具 :arm-linux-gcc 4.5.1
開發板 :友善之臂Tiny6410
LCD :友善之臂S70
Libpng版本 :libpng-1.5.14
Zlib版本 :zlib-1.2.8
一、交叉編譯Zlib
Zlib是一個文件壓縮庫,在Libpng交叉編譯的時候需要使用到它的頭文件和庫,所以先編譯它。zlib-1.2.8.tar.gz 下載路徑:http://pan.baidu.com/s/1miKXynY
1、下載並解壓zlib-1.2.8.tar.gz
tar xzvf zlib-1.2.8.tar.gz
2、在zlib-1.2.8目錄下新建一個tmp目錄用於保存交叉編譯后生成的lib和include文件
mkdir tmp
3、打開Makefile文件並修改CC=arm-linux-gcc
4、執行配置命令指定生成文件存放路徑
./configure --prefix=$PWD/tmp
5、執行make
6、執行make install, 並查看tmp目錄有沒有include、lib等目錄生成
二、交叉編譯Libpng
libpng-1.5.14.tar.gz 下載路徑:http://pan.baidu.com/s/1qYgnIyC
1、下載並解壓libpng-1.5.14.tar.gz
tar xzvf libpng-1.5.14.tar.gz
2、同樣在libpng-1.5.14目錄下新建一個tmp目錄用於保存交叉編譯后生成的lib和include文件
mkdir tmp
3、執行配置命令指定生成文件存放路徑和Zlib庫文件目錄
./configure --prefix=/home/ming/windowssshar/libpng-1.5.14/tmp --host=arm-linux LIBS=-L/home/ming/windowsshar/zlib-1.2.8/tmp/lib CPPFLAGS=-I/home/ming/windowsshar/zlib-1.2.8/tmp/include
4、執行make
5、執行make install, 並查看tmp目錄有沒有include、lib等目錄生成
三、使用Libpng解碼圖片
int read_png(char* filename, char IsDoAlphaBlend) { FILE *fp; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; png_uint_32 row; int bit_depth, color_type, interlace_type, number_passes; int pass,y; char* cpPngDispAddr = NULL; char* RGB_Data = NULL; unsigned int x = 0; unsigned int pos = 0; unsigned int i = 0; int iXres = 0, iYres = 0; if ((fp = fopen(filename, "rb")) == NULL) { DEBUG_Print("open %s failed\n",filename); return 0; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return (FALSE); } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return (FALSE); } /* One of the following I/O initialization methods is REQUIRED */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* 獲取顯存地址 */ cpPngDispAddr = GetDispVedioMemAddr(); GetDispResolution(&iXres,&iYres); /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); DEBUG_Print("width ---- > [%4d]\n",width); DEBUG_Print("height ---- > [%4d]\n",height); DEBUG_Print("bit_depth ---- > [%4d]\n",bit_depth); DEBUG_Print("color_type ---- > [%4d]\n",color_type); DEBUG_Print("interlace_type ---- > [%4d]\n",interlace_type); /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ number_passes = png_set_interlace_handling(png_ptr); DEBUG_Print("number_passes ---- > [%4d]\n",number_passes); /* The easiest way to read the image: */ png_bytep row_pointers[height]; /* Clear the pointer array */ for (row = 0; row < height; row++) row_pointers[row] = NULL; for (row = 0; row < height; row++) row_pointers[row] = malloc(width * 4); /* RGBA */ for (row = 0; row < height; row++) memset(row_pointers[row], 0, width * 4); /* 分配RGB內存空間 */ RGB_Data = (char*)malloc(width * 3); memset(RGB_Data, 0, width * 3); DEBUG_Print("1 RGB_Data -- > [0x%x]\n",RGB_Data); /* Now it's time to read the image. One of these methods is REQUIRED */ /* Read the image one or more scanlines at a time */ /* The other way to read images - deal with interlacing: */ if(width > iXres) width = iXres; if(height > iYres) height = iYres; for (pass = 0; pass < number_passes; pass++) { /* 一行一行讀取並顯示 */ for (y = 0; y < height; y++) { png_read_rows(png_ptr, &row_pointers[y], NULL, 1); WriteOneLineToMem(cpPngDispAddr, (iXres - width)/2, (iXres - width)/2 + width, (iYres - height)/2 + y, &row_pointers[y][0], IsDoAlphaBlend); } } /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* At this point you have read the entire image */ /* Clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* 統一釋放內存 */ for (row = 0; row < height; row++) { free(row_pointers[row]); } free(RGB_Data); /* Close the file */ fclose(fp); /* That's it */ return (TRUE); }
這段代碼基本上是從Libpng里面的example文件移植過來,在libpng_manual.txt里面有詳細的解釋。
四、在顯示屏上顯示
1、Alpha混合(AlphaBlend)
為了使PNG圖片顯示具有透明效果,需要對前景色和背景色進行AlphaBlend
簡單AlphaBlend算法:假設前景色(要顯示的PNG圖片)RGBA分別為r1 g1 b1 alpha 背景色的RGB為r2 g2 b2 混合后的RGB為r g b
r = r1 x alpha/255.0 + r2 x (255 - alpha)/255.0
g = g1 x alpha/255.0 + g2 x (255 - alpha)/255.0
b = b1 x alpha/255.0 + b2 x (255 - alpha)/255.0
static unsigned int AlphaBlend(PT_PNG_INFO PngRGBA, PT_PNG_INFO PngBkRGB, char IsDoAlphaBlend) { unsigned char r = 0, g = 0, b = 0; r = (unsigned char)(PngRGBA->R * (PngRGBA->A / 255.0) + (PngBkRGB->R * (255 - PngRGBA->A)) / 255.0); g = (unsigned char)(PngRGBA->G * (PngRGBA->A / 255.0) + (PngBkRGB->G * (255 - PngRGBA->A)) / 255.0); b = (unsigned char)(PngRGBA->B * (PngRGBA->A / 255.0) + (PngBkRGB->B * (255 - PngRGBA->A)) / 255.0); return ((r << 16) | (g << 8) | (b)); }
PngRGBA為前景色RGBA數據結構體,PngBKRGB為背景色RGB數據結構體,返回值為混合好的RGB值。
2、在LCD上顯示圖片
static void WriteOneLineToMem(char* ptVedioMem, int iXStart, int iXEnd, int iY, unsigned char* ucpDispBuff, char IsDoAlphaBlend) { int iX = 0, iPoint = 0; unsigned int udwData = 0; int iXres, iYres; unsigned int location; T_PNG_INFO tPngRGBA = {0}; T_PNG_INFO tPngBkRGB = {0}; GetDispResolution(&iXres,&iYres); if(iXEnd > iXres) return -1; if(iY > iYres) return -1; for(iX = iXStart; iX < iXEnd; iX++) { location = iX * 4 + iY * iXres* 4; /* 獲取前景色RGBA */ tPngRGBA.R = ucpDispBuff[iPoint + 0]; tPngRGBA.G = ucpDispBuff[iPoint + 1]; tPngRGBA.B = ucpDispBuff[iPoint + 2]; tPngRGBA.A = ucpDispBuff[iPoint + 3]; /* 獲取背景色RGB */ udwData = *((unsigned int*)(ptVedioMem + location)); tPngBkRGB.R = (udwData >> 16) & 0xFF; tPngBkRGB.G = (udwData >> 8) & 0xFF; tPngBkRGB.B = udwData & 0xFF; udwData = AlphaBlend(&tPngRGBA, &tPngBkRGB, IsDoAlphaBlend); *((unsigned int*)(ptVedioMem + location)) = udwData; iPoint += 4; /* RGBA */ } return 0; }
准備兩張圖片:
背景圖 前景圖
顯示之后的效果:
完整代碼:http://pan.baidu.com/s/1boD7ZSr