23. 显示png图片¶
PNG(Portable Network Graphics)是一种新兴的网络图像格式。1999年,Unisys公司进一步中止了对自由软件和非商用软件开发者的GIF专利免费许可,从而使PNG格式获得了更多的关注。PNG是目前保证最不失真的格式,采用LZ77算法的派生算法进行压缩,能把图像文件压缩到极限 以利于网络传输,但又能保留所有与图像品质有关的信息。 PNG同样支持透明图片的制作,图23_1 就是一种透明的png格式的图片。
图 23‑1 png图片
23.1. 显示png图片(数据在内部存储空间)¶
下表列出了PNG 绘制API函数。
表格 23‑1 PNG 绘制API
函数  | 
描述  | 
|---|---|
PNG_Open()  | 
获取PNG_DEC句柄  | 
PNG_GetBitmap()  | 
把图片转换成bitmap  | 
PNG_Close()  | 
释放绘图句柄  | 
23.1.1. PNG 绘制API¶
23.1.1.1. PNG_Open¶
PNG_Open来获取PNG_DEC句柄,函数原型见 代码清单23_1。
1  |  PNG_DEC* PNG_Open(const u8 *png_dat,int png_size);
 | 
png_dat:图片所在的缓冲区,使用软件生成的图片数组的数组名;
png_size:图片数组的大小,可以使用sizeof获取数组的大小。
23.1.2. 显示png图片实验¶
学习了绘制上述的PNG图片绘制API之后,我们开始编写代码,将 图23_1 显示在屏幕上。
23.1.2.1. 代码分析¶
窗口回调函数
WM_CREATE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34  |  case WM_CREATE: //窗口创建时,会自动产生该消息,在这里做一些初始化的操作或创建子窗口
 {
    u8 *jpeg_buf;
    u32 jpeg_size;
    JPG_DEC *dec;
    GetClientRect(hwnd,&rc); //获得窗口的客户区矩形
    /* 根据图片数据创建PNG_DEC句柄 */
    png_dec = PNG_Open((u8 *)redfish, redfish_size());
    /* 把图片转换成bitmap */
    PNG_GetBitmap(png_dec, &png_bm);
    res = FS_Load_Content(DEMO_JPEG_FILE_NAME, (char **)&jpeg_buf, &jpeg_size);
    if(res)
    {
        /* 根据图片数据创建JPG_DEC句柄 */
        dec = JPG_Open(jpeg_buf, jpeg_size);
        /* 读取图片文件信息 */
        JPG_GetImageSize(&pic_width, &pic_height,dec);
        /* 创建内存对象 */
        hdc_mem =CreateMemoryDC(SURF_SCREEN,pic_width,pic_height);
        /* 绘制至内存对象 */
        JPG_Draw(hdc_mem, 0, 0, dec);
        /* 关闭JPG_DEC句柄 */
        JPG_Close(dec);
    }
    /* 释放图片内容空间 */
    RES_Release_Content((char **)&jpeg_buf);
    return TRUE;
 }
 | 
在WM_CREATE消息中,调用PNG_Open创建PNG_DEC句柄,以后的一切操作都可以使用PNG_DEC句柄来实现,同时通过PNG_GetBitmap将图片转换成bitmap,存放在png_bm结构体变量中。 这里我们使用JPG图片作为背景,更好地突出 图23_1 是张带透明度的图片。 使用FS_Load_Content函数从SD卡读取sea.jpg的图片数据。JPG_Open创建一个新的图片句柄,同时绘制图片数组到MemoryDC中。
WM_ERASEBKGND
1 2 3 4 5 6  |  case WM_ERASEBKGND:
 {
    HDC hdc=(HDC)wParam;
    BitBlt(hdc,0,0,pic_width,pic_height,hdc_mem,0,0,SRCCOPY); //将MEMDC输出到窗口中。
    return TRUE;
}
 | 
WM_ERASEBKGND消息中,使用BitBlt块传输函数将背景图片,绘制到屏幕HDC上。
WM_PAINT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  |  case WM_PAINT: //窗口需要绘制时,会自动产生该消息.
 {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc0;
    int x=0,y=0;
    hdc =BeginPaint(hwnd,&ps);
    ////用户的绘制内容...
    GetClientRect(hwnd,&rc0);
    for(y=0; y<rc0.h; y+=png_bm.Height)
    {
        for(x=0; x<rc0.w; x+=png_bm.Width)
        {
            /* 显示图片 */
            DrawBitmap(hdc, x, y, &png_bm, NULL);
        }
    }
    EndPaint(hwnd,&ps);
    break;
 }
 | 
WM_CREATE消息里面,我们使用PNG_GetBitmap函数将图片转换成位图,存放在png_bm结构体变量中,因此,在WM_PAINT中,调用DrawBitmap就可以完成显示PNG格式的图片。
WM_DESTROY
1 2 3 4 5 6 7  |  case WM_DESTROY: //窗口销毁时,会自动产生该消息,在这里做一些资源释放的操作.
 {
    /* 关闭PNG_DEC句柄 */
    PNG_Close(png_dec);
    DeleteDC(hdc_mem);
    return PostQuitMessage(hwnd); //调用PostQuitMessage,使用主窗口结束并退出消息循环.
 }
 | 
当窗口关闭时,意味着我们不再使用PNG_DEC句柄和png_bm结构体变量,此时就可以调用PNG_Close函数,将PNG_DEC句柄释放,同时释放MEMDC的内存空间,如代码清单 23‑7。
23.2. 显示外部png图片¶
由于png图片是调用位图的API来进行绘制的,本节的知识点与绘制外部bmp的内容大同小异,这里就不讲解绘图的API了,有疑问的话,可以查看绘制外部bmp图片的章节。
23.2.1. 显示外部png图片实验¶
23.2.1.1. 代码分析¶
窗口回调函数
WM_CREATE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39  |  case WM_CREATE: //窗口创建时,会自动产生该消息,在这里做一些初始化的操作或创建子窗口
 {
    u8 *png_buf;
    u32 png_size;
    u8 *jpg_buf;
    u32 jpg_size;
    GetClientRect(hwnd,&rc); //获得窗口的客户区矩形
    #if(RES_PIC_DEMO)
    /* 资源设备中加载 */
    res = RES_Load_Content(DEMO_PNG_FILE_NAME, (char **)&png_buf, &png_size);
    #else
    /* SD文件系统加载 */
    res = FS_Load_Content(DEMO_PNG_FILE_NAME, (char **)&png_buf, &png_size);
    #endif
    if(res)
    {
        /* 根据图片数据创建PNG_DEC句柄 */
        png_dec = PNG_Open(png_buf, png_size);
        /* 把图片转换成bitmap */
        PNG_GetBitmap(png_dec, &png_bm);
    }
    /* 释放图片内容空间 */
    RES_Release_Content((char **)&png_buf);
    res = FS_Load_Content(DEMO_JPEG_FILE_NAME, (char **)&jpg_buf, &jpg_size);
    if(res)
    {
        jdec = JPG_Open(jpg_buf, jpg_size);
        JPG_GetImageSize(&pic_width, &pic_height, jdec);
        hdc_mem = CreateMemoryDC(SURF_SCREEN,pic_width,pic_height);
        JPG_Draw(hdc_mem,0,0,jdec);
        JPG_Close(jdec);
    }
    /* 释放图片内容空间 */
    RES_Release_Content((char **)&jpg_buf);
    return TRUE;
}
 | 
RES_PIC_DEMO宏定义决定程序从什么位置读取PNG图片,代码中的RES_PIC_DEMO为0,即从SD卡读取图片数据。根据读取成功的图片数据,调用PNG_Open函数创建图片句柄,通过PNG_GetBitmap转换为位图格式,存放在png_bm结构体中,完成之后释放PNG图片句柄。
这里也使用sea.jpg作为窗口背景,使用FS_Load_Content读取SD卡中的sea.jpg图片数据,存放在jpg_buf中。创建一个MemoryDC,大小为图片的尺寸,将图片数据绘制到MemoryDC中,最后释放图片所占用的内存和JPG图片句柄。
WM_PAINT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25  |  case WM_PAINT: //窗口需要绘制时,会自动产生该消息.
 {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc0;
    int x=0,y=0;
    hdc =BeginPaint(hwnd,&ps);
    ////用户的绘制内容...
    GetClientRect(hwnd,&rc0);
    /* 若正常加载了图片 */
    if(res)
    {
        for(y=0; y<rc0.h; y+=png_bm.Height)
        {
            for(x=0; x<rc0.w; x+=png_bm.Width)
            {
                /* 显示图片 */
                DrawBitmap(hdc, x, y, &png_bm, NULL);
            }
        }
    }
    EndPaint(hwnd,&ps);
    break;
 }
 | 
WM_PAINT消息中, PNG图片已经转换成位图,存放在png_bm结构体中,调用DrawBitmap来显示图片。WM_PAINT消息绘制前,需要调用BeginPaint函数,结束时需要使用EndPaint函数。
WM_DESTROY
1 2 3 4 5 6  |  case WM_DESTROY: //窗口销毁时,会自动产生该消息,在这里做一些资源释放的操作.
 {
    /* 关闭PNG_DEC句柄 */
    PNG_Close(png_dec);
    return PostQuitMessage(hwnd); //调用PostQuitMessage,使用主窗口结束并退出消息循环.
 }
 | 
退出窗口时,需要调用PNG_Close来释放PNG_DEC句柄。
最后,将设计的主窗口函数加入到GUI_AppMain函数中。