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