Step to UEFI (222)BmpSupportLib

很早之前的文章介绍过如何在 Shell 下实实现 BMP 的显示【参考1】。从原理上来说就是读取 BMP 文件,然后进行解析,最后按照 BLT 要求的格式重新排列,最终用EfiBltBufferToVideo就可以显示出来。

最近在查看 EDK202008 的代码时,偶然发现了2个新增的函数在BmpSupportLib.h 文件中。从名称上看一个是将 BMP 转化为 BLT要求的GopBlt格式,另外一个是将 GopBlt 转为 BMP 的。

/**
  Translate a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
  is passed in a GopBlt buffer will be allocated by this routine using
  EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be
  used if it is big enough.

  @param [in]      BmpImage      Pointer to BMP file.
  @param [in]      BmpImageSize  Number of bytes in BmpImage.
  @param [in, out] GopBlt        Buffer containing GOP version of BmpImage.
  @param [in, out] GopBltSize    Size of GopBlt in bytes.
  @param [out]     PixelHeight   Height of GopBlt/BmpImage in pixels.
  @param [out]     PixelWidth    Width of GopBlt/BmpImage in pixels.

  @retval RETURN_SUCCESS            GopBlt and GopBltSize are returned.
  @retval RETURN_INVALID_PARAMETER  BmpImage is NULL.
  @retval RETURN_INVALID_PARAMETER  GopBlt is NULL.
  @retval RETURN_INVALID_PARAMETER  GopBltSize is NULL.
  @retval RETURN_INVALID_PARAMETER  PixelHeight is NULL.
  @retval RETURN_INVALID_PARAMETER  PixelWidth is NULL.
  @retval RETURN_UNSUPPORTED        BmpImage is not a valid *.BMP image.
  @retval RETURN_BUFFER_TOO_SMALL   The passed in GopBlt buffer is not big
                                    enough.  The required size is returned in
                                    GopBltSize.
  @retval RETURN_OUT_OF_RESOURCES   The GopBlt buffer could not be allocated.

**/
RETURN_STATUS
EFIAPI
TranslateBmpToGopBlt (
  IN     VOID                           *BmpImage,
  IN     UINTN                          BmpImageSize,
  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL  **GopBlt,
  IN OUT UINTN                          *GopBltSize,
  OUT    UINTN                          *PixelHeight,
  OUT    UINTN                          *PixelWidth
  );

/**
  Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics
  image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by
  this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is
  passed in it will be used if it is big enough.

  @param [in]      GopBlt        Pointer to GOP blt buffer.
  @param [in]      PixelHeight   Height of GopBlt/BmpImage in pixels.
  @param [in]      PixelWidth    Width of GopBlt/BmpImage in pixels.
  @param [in, out] BmpImage      Buffer containing BMP version of GopBlt.
  @param [in, out] BmpImageSize  Size of BmpImage in bytes.

  @retval RETURN_SUCCESS            BmpImage and BmpImageSize are returned.
  @retval RETURN_INVALID_PARAMETER  GopBlt is NULL.
  @retval RETURN_INVALID_PARAMETER  BmpImage is NULL.
  @retval RETURN_INVALID_PARAMETER  BmpImageSize is NULL.
  @retval RETURN_UNSUPPORTED        GopBlt cannot be converted to a *.BMP image.
  @retval RETURN_BUFFER_TOO_SMALL   The passed in BmpImage buffer is not big
                                    enough.  The required size is returned in
                                    BmpImageSize.
  @retval RETURN_OUT_OF_RESOURCES   The BmpImage buffer could not be allocated.

**/
RETURN_STATUS
EFIAPI
TranslateGopBltToBmp (
  IN     EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *GopBlt,
  IN     UINT32                         PixelHeight,
  IN     UINT32                         PixelWidth,
  IN OUT VOID                           **BmpImage,
  IN OUT UINT32                         *BmpImageSize
  );

为此,编写一个测试程序进行测试,因为编译环境是 EDK201903 其中并没有对应的库,所以直接将上面提到的库从 EDK202008 中提取出来直接使用,同时还有一个SafeIntLib的库:

#include  <Uefi.h>
#include  <Library/BaseLib.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>

#include "BmpSupportLib.h"

extern  EFI_BOOT_SERVICES   *gBS;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;

INTN
EFIAPI
main (
  IN UINTN Argc,
  IN CHAR8 **Argv
  )
{
        FILE            *fp;
        long            BmpSize;
        char            *pBmpImage;
        
        UINTN           BltSize;
        UINTN           Height;
        UINTN           Width;
        EFI_STATUS      Status;
        EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
        EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
        
        // Check parameter
        if (Argc<2) {
                printf("Please input a file name\n");
        } else {
                // Open file
                fp=fopen(Argv[1],"rb");
                if (fp==NULL) {
                        printf("Can't open file [%s]\n",Argv[1]);
                        return EFI_SUCCESS;
                }
                
                // Get file size
                fseek(fp,0,SEEK_END);
                BmpSize=ftell(fp);
                printf("File size is [%d]\n",BmpSize);
                
                // Create a memory for BMP file
                pBmpImage=malloc(BmpSize);
                if (pBmpImage==NULL) {
                        printf("Memory allocate error\n");
                        fclose(fp);
                        return EFI_SUCCESS;
                }
                
                // Load BMP to memory
                fseek(fp,0,SEEK_SET);
                fread(pBmpImage, sizeof(char), BmpSize, fp);
                fclose(fp);
                
                Status = gBS->LocateProtocol(
                            &GraphicsOutputProtocolGuid, 
                            NULL,
                            (VOID **) &GraphicsOutput);
                if (EFI_ERROR(Status)) {
                    GraphicsOutput = NULL;
                    Print(L"Loading Graphics_Output_Protocol error!\n");
                    return EFI_SUCCESS;
                }
    
                // Translate BMP to  GopBlt
                Blt = NULL;
                Width = 0;
                Height = 0;
                Status = TranslateBmpToGopBlt (
                           pBmpImage,
                           BmpSize,
                           &Blt,
                           &BltSize,
                           &Height,
                           &Width
                           );
                if (EFI_ERROR (Status)) {
                  Print(L"TranslateBmpToGopBlt error!\n");
                  return Status;
                }

                // Show the GopBlt to screen
                Status = GraphicsOutput->Blt (
                             GraphicsOutput,
                             Blt,
                             EfiBltBufferToVideo,
                             0, // Source X
                             0, // Source Y
                             0x140, // Destination X
                             0, // Destination Y
                             Width,
                             Height,
                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
                             );
                if (EFI_ERROR (Status)) {
                  Print(L"GraphicsOutput->Blt error! [%r]\n",Status);
                  return Status;
                }
                free(pBmpImage);
    }

    return EFI_SUCCESS;
}

测试结果(NT32虚拟机)

NT32 模拟环境下测试 BmpSupportLib

源代码和编译后的 X64 代码可以在这里下载:

参考:

1. https://www.lab-z.com/showbmp/

发表回复

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