Step to UEFI (158)UEFI 下的 PNG 解码

前面介绍过 PCX的解码,这次研究一下 PNG 格式的解码,有了前面的经验,这次实现起来简单多了。

首先,找一个C语言的PNG 解码库,经过比较选择了来自【参考1】的 upng。然后根据说明编写一个简单的示例:

#define DR_PCX_IMPLEMENTATION
#include "upng.h"
#include <stdlib.h>
#include <stdio.h>
#include <Protocol/GraphicsOutput.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
  { \
    0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \
  }
  
static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;

int
main (
  IN int Argc,
  IN char *Argv[]
  )
{
    int width;
    int height;
    EFI_STATUS    Status;
    EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
    int i,j;

    UINT8* RGB32;
    UINT8* pImageData;
    
    if (Argc<2) {
            printf("Please input file name\n");
            return 0;
    }
    
    upng_t* upng = upng_new_from_file(Argv[1]);
    
    if (upng == NULL) {
        printf("Open file Error\n");
        return -1;
    }
    upng_header(upng);

    width=upng_get_width(upng);
    height=upng_get_height(upng);
    printf("width %d height %d\n",width,height);
    upng_format f=upng_get_format(upng);
    printf("format %d\n",f);
    
    upng_decode(upng);

    pImageData=(UINT8 *)upng_get_buffer(upng);
    
    RGB32 = (UINT8*)AllocatePool(width*height*4); 
    for (j=0;j<height;j++) {
            for (i=0;i<width;i++) {
                RGB32[(j*width+i)*4]  = pImageData[(j*width+i)*4+2]; //Blue   
                RGB32[(j*width+i)*4+1]= pImageData[(j*width+i)*4+1]; //Green 
                RGB32[(j*width+i)*4+2]= pImageData[(j*width+i)*4]; //Red  
                RGB32[(j*width+i)*4+3]=0;
            }
    }

    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
                GraphicsOutput = NULL;
                printf("Loading Graphics_Output_Protocol error!\n");
                return EFI_SUCCESS;}

        
    GraphicsOutput->Blt(
                GraphicsOutput, 
                (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) RGB32,
                EfiBltBufferToVideo,
                0, 0, 
                0, 0, 
                width, height, 0);    
    
         free(RGB32);                
        upng_free(upng);
    return 0;
}

 

运行结果(可以在NT32模拟环境下运行):

完整代码和实例PNG测试图片:
pngtest

特别需要注意的是:解码之后的数据无法直接使用 BLT 在屏幕上显示,因此,特别重新开辟了一个内存空间进行排列。这样的操作也会导致兼容性上的问题,换其他格式的 PNG (比如:例子用的都是RGBA的,此外还有RGB格式的),会出现错误的情况。如果你发现decode之后结果很奇怪,不妨考虑一下是否是这个原因导致的。

参考:
1. https://github.com/elanthis/upng

发表评论

电子邮件地址不会被公开。 必填项已用*标注