使用Libpng库实现Tiny6410显示PNG图片

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
",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]
",width);
    DEBUG_Print("height         ---- > [%4d]
",height);
    DEBUG_Print("bit_depth      ---- > [%4d]
",bit_depth);
    DEBUG_Print("color_type     ---- > [%4d]
",color_type);
    DEBUG_Print("interlace_type ---- > [%4d]
",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]
",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]
",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

原文地址:https://www.cnblogs.com/ape-ming/p/5561643.html