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 failedn',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