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

2024-09-20  

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


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。