一. 制作EDK II可以识别的BMP图片
1.EDKII 支持BGR32作为原始数据的BMP图片
2.所以,我们需要先找到或者自己制作一张满足这个要求的BMP图片
3.这里,我们采用自己制作BMP图片的方式,制作过程分为两骤(实现代码如下):
a.用ffmpeg将.png图片转换成BGRA原始数据
b.编写一个将BGRA数据组装成BMP图片的程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HEIGHT 225
#define WIDTH 225
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER;
char ffmpeg_line[128] = {0};
void MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
/*
* Magic number for file. It does not fit in the header structure due to
* alignment requirements, so put it outside
* 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
* 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
*/
unsigned short bfType=0x4d42; //'BM'
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*4;
bfh.bfOffBits = 2/* 2B魔术字 */ + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bih.biSize = sizeof(BITMAPINFOHEADER);
printf("filesize = %u header size = %u \n", bfh.bfSize, bfh.bfOffBits);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 32; //一个像素对应的32bit
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen(filename, "w+");
if (!file)
{
printf("Could not write file\n");
return;
}
/*Write headers*/
fwrite(&bfType,sizeof(bfType),1,file);
fwrite(&bfh,sizeof(bfh),1, file);
fwrite(&bih,sizeof(bih),1, file);
fwrite(rgbbuf,width*height*4,1,file);
fclose(file);
}
int main(void)
{
unsigned int len = 0, i = 0;
unsigned char *dest = NULL;
unsigned char *dest2 = NULL;
int ret = 0;
printf("unsigned int = %ld\n", sizeof(unsigned int));
printf("unsigned short = %ld\n", sizeof(unsigned short));
dest = (char *)malloc(sizeof(unsigned char) * 4 * WIDTH * HEIGHT);
if(!dest) {
ret = -1;
goto fail;
}
dest2 = (char *)malloc(sizeof(unsigned char) * 4 * WIDTH * HEIGHT);
if(!dest2) {
ret = -1;
goto fail;
}
sprintf(ffmpeg_line, "ffmpeg -i origin.png -s %dx%d -pix_fmt bgra origin.rgb", WIDTH, HEIGHT);
ret = system(ffmpeg_line);
if(ret)
goto fail;
FILE *fp = fopen("origin.rgb", "r");
if(!fp) {
ret = 1;
goto fail;
}
ret = fseek(fp, 0, SEEK_END); //读写位置指针移动到文件尾
if(ret) {
ret = -1;
goto fail;
}
len = ftell(fp);
if(!len) {
ret = -1;
goto fail;
}
ret = fseek(fp, 0, SEEK_SET); //读写位置指针移动到文件头
if(ret) {
ret = -1;
goto fail;
}
len = fread(dest, sizeof(unsigned char), len, fp);
if(!len) {
ret = -1;
goto fail;
}
printf("bgra file len= %u\n", len);
fclose(fp);
for(i = 0; i < WIDTH; i++)
memcpy(&dest2[i * sizeof(unsigned char) * 4 * WIDTH], &dest[(HEIGHT - 1 - i) * sizeof(unsigned char) * 4 * WIDTH], sizeof(unsigned char) * 4 * WIDTH);
MySaveBmp("origin.bmp", dest2, WIDTH, HEIGHT);
ret = system("rm -rf origin.rgb");
fail:
free(dest);
free(dest2);
return ret;
}
二. 编写EDKII 应用程序读取图片并现实在虚拟机中(两种方式)
标准应用程序工程模块和Shell应用程序工程模块的联系和区别参考这两篇博客。
1.Shell应用程序工程模块
c源文件:
/** @file
This is a test for show bmp
**/
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ShellLib.h>
#include <Library/BmpSupportLib.h>
#include <IndustryStandard/Bmp.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/HiiImageEx.h>
/**
load bmp file to buffer
@param IN CHAR16 *FileName
@param IN OUT UINT8 **FileDataBuffer
@param IN OUT UINTN *DataLength
@retval EFI_SUCCESS
@retval
**/
EFI_STATUS
EFIAPI
LoadFiletoBuffer (
IN CHAR16 *FileName,
IN OUT UINT8 **FileDataBuffer,
IN OUT UINT64 *DataLength
)
{
EFI_STATUS Status;
EFI_FILE_HANDLE ReadFileHandle;
EFI_FILE_PROTOCOL *FileRoot;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
EFI_FILE_INFO *ReadFileInfo = NULL;
Status = gBS->LocateProtocol(
&gEfiSimpleFileSystemProtocolGuid,
NULL,
(VOID **)&SimpleFileSystem
);
if (EFI_ERROR(Status)) {
Print (L"not found gEfiSimpleFileSystemProtocolGuid!\n");
return Status;
}
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &FileRoot);
if (EFI_ERROR(Status)) {
Print (L"OpenVolume is error !\n");
return Status;
}
Status = FileRoot->Open(
FileRoot,
&ReadFileHandle,
FileName,
EFI_FILE_MODE_READ ,
0
);
if (EFI_ERROR (Status)) {
Print (L"open file root is error!\n");
return Status;
}
ReadFileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)ReadFileHandle);
*DataLength = ReadFileInfo->FileSize;
*FileDataBuffer = (UINT8 *)AllocateZeroPool (*DataLength);
Status = ReadFileHandle->Read (
ReadFileHandle,
DataLength,
*FileDataBuffer
);
if (EFI_ERROR (Status)) {
Print (L"Read file is error!\n");
return Status;
}
ReadFileHandle->Close (ReadFileHandle);
FileRoot->Close (FileRoot);
Print (L"Load File is Ok!\n");
return Status;
}
/**
UEFI application entry point which has an interface similar to a
standard C main function.
The ShellCEntryLib library instance wrappers the actual UEFI application
entry point and calls this ShellAppMain function.
@param Argc Argument count
@param Argv The parsed arguments
@retval 0 The application exited normally.
@retval Other An error occurred.
**/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
UINT8 *BmpDataBuffer;
UINT64 DataLength;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EepromBitmap = NULL;
UINTN GopBltSize;
UINTN Height;
UINTN Width;
//Status = gST->ConOut->EnableCursor(gST->ConOut,FALSE);
//Status = gST->ConOut->SetAttribute(gST->ConOut,EFI_WHITE|EFI_BACKGROUND_BLACK);
//Status = gST->ConOut->ClearScreen(gST->ConOut);
Status = gBS->LocateProtocol (
&gEfiGraphicsOutputProtocolGuid,
NULL,
(VOID **)&GraphicsOutput
);
if (EFI_ERROR (Status)) {
GraphicsOutput = NULL;
Print (L"locate protocol gEfiGraphicsOutputProtocolGuid is error!\n");
return Status;
}
Status = LoadFiletoBuffer (
Argv[1],
&BmpDataBuffer,
&DataLength
);
if (EFI_ERROR (Status)) {
Print (L"Load Bmp to Buffer is error!\n");
return Status;
}
//
// bmp to blt
//
Status = TranslateBmpToGopBlt (
(VOID *)BmpDataBuffer,
DataLength,
&EepromBitmap,
&GopBltSize,
&Height,
&Width
);
Print(L"height=%llu width=%llu DataLength=%llu\n", Height, Width, DataLength);
if (EFI_ERROR (Status)) {
if (EepromBitmap != NULL) {
FreePool (EepromBitmap);
}
Print (L"TranslateBmpToGopBlt is error! Status=%d\n", Status);
return Status;
}
Status = GraphicsOutput->Blt (
GraphicsOutput,
EepromBitmap,
EfiBltBufferToVideo,
0,
0,
0x0,
0x0,
Width,
Height,
Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
if (EFI_ERROR (Status)) {
Print (L"GraphicsOutput Blt is error!\n");
return Status;
}
if (EepromBitmap != NULL)
FreePool (EepromBitmap);
//Status = gST->ConOut->EnableCursor(gST->ConOut,TRUE);
return 0;
}
inf文件:
## @file
# head for bmp test
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = TestShow
FILE_GUID = 079E8E98-AE93-1111-8A71-88C869F23E09
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = ShellCEntryLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
[Sources]
TestShow.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
ShellCEntryLib
UefiLib
UefiBootServicesTableLib
BaseMemoryLib
MemoryAllocationLib
ShellLib
BmpSupportLib
[Protocols]
gEfiGraphicsOutputProtocolGuid
dsc文件:
[Defines]
PLATFORM_NAME = TestShowPkg
PLATFORM_GUID = 8365c20a-fc46-4fc8-9300-9499611f3862
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010006
SUPPORTED_ARCHITECTURES = X64
BUILD_TARGETS = DEBUG|RELEASE
[LibraryClasses]
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
[Components]
TestShowPkg/TestShow.inf
2.标准应用程序工程模块
c源文件:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/SimpleFileSystem.h>
#include <Guid/FileInfo.h>
#include <Library/BmpSupportLib.h>
#include <IndustryStandard/Bmp.h>
#include <Library/MemoryAllocationLib.h>
typedef struct
{
EFI_PHYSICAL_ADDRESS FrameBufferBase;
UINTN FrameBufferSize;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
UINT32 PixelsPerScanLine;
} VIDEO_CONFIG;
VIDEO_CONFIG VideoConfig = {0};
EFI_STATUS
EFIAPI
UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN NumHandles = 0;
EFI_HANDLE *Buffer = NULL;
/********************** 1.显示配置 *************************/
Status = gBS->LocateHandleBuffer(
ByProtocol,
&gEfiGraphicsOutputProtocolGuid,
NULL,
&NumHandles,
&Buffer
);
Print(L"Status = %d.\n", Status);
if(EFI_ERROR(Status)) {
Print(L"Failed to LocateHandleBuffer.\n");
return Status;
}
Print(L"Hello Protocol.\n");
Print(L"NumHandles = %d.\n", NumHandles);
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
Status = gBS->OpenProtocol(
Buffer[0],
&gEfiGraphicsOutputProtocolGuid,
(void **)&Gop,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if(EFI_ERROR(Status))
{
Print(L"Failed to OpenProtocol\n");
}
UINTN SizeofInfo = 0;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
for(UINTN i = 0; i < Gop->Mode->MaxMode; i++)
{
Status = Gop->QueryMode(
Gop,
i,
&SizeofInfo,
&Info
);
if(EFI_ERROR(Status))
{
Print(L"Failed To QueryMode.\n");
return Status;
}
Print(L"Mode = %d, H = %d, V = %d.\n",
i,
Info->HorizontalResolution,
Info->VerticalResolution);
}
Status = Gop->SetMode(Gop, 22);
if(EFI_ERROR(Status))
{
Print(L"Failed to SetMode.\n");
return Status;
}
/* 获取显示配置信息 */
VideoConfig.FrameBufferBase = Gop->Mode->FrameBufferBase;
VideoConfig.FrameBufferSize = Gop->Mode->FrameBufferSize;
VideoConfig.HorizontalResolution = Gop->Mode->Info->HorizontalResolution;
VideoConfig.VerticalResolution = Gop->Mode->Info->VerticalResolution;
VideoConfig.PixelsPerScanLine = Gop->Mode->Info->PixelsPerScanLine;
/************************** 2.文件系统配置 ******************************/
Status = gBS->LocateHandleBuffer(
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&NumHandles,
&Buffer
);
if(EFI_ERROR(Status))
{
Print(L"Failed to LocateHandleBuffer.\n");
return Status;
}
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
Status = gBS->OpenProtocol(
Buffer[0],
&gEfiSimpleFileSystemProtocolGuid,
(VOID **)&FileSystem,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if(EFI_ERROR(Status))
{
Print(L"Failed to OpenProtocol.\n");
return Status;
}
EFI_FILE_PROTOCOL *Root;
Status = FileSystem->OpenVolume(
FileSystem,
&Root
);
if(EFI_ERROR(Status))
{
Print(L"Failed to OpenVolume.\n");
return Status;
}
/* 打开Logo.BMP文件->esp目录下, 并记录到file handle */
CHAR16 *FileName = L"\\Logo.BMP";
EFI_FILE_PROTOCOL *LogoHandle;
Status = Root->Open(
Root,
&LogoHandle,
FileName, // L"\\Logo.bmp"
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if(EFI_ERROR(Status))
{
Print(L"Failed to Open.\n");
return Status;
}
/************************** 3.将logo文件数据读到内存 ******************************/
/* a.获取文件大小等信息 */
EFI_FILE_INFO *FileInfo;
UINTN InfoSize = sizeof(EFI_FILE_INFO) + StrLen(FileName) * 2;
Status = gBS->AllocatePool(
EfiLoaderData,
InfoSize,
(VOID **)&FileInfo
);
if(EFI_ERROR(Status))
{
Print(L"Failed to AllocatePool.\n");
return Status;
}
Status = LogoHandle->GetInfo(
LogoHandle,
&gEfiFileInfoGuid,
&InfoSize,
FileInfo
);
if(EFI_ERROR(Status))
{
Print(L"Failed to GetInfo %d.\n", Status);
return Status;
}
/* b.根据文件大小申请内存,存放文件数据 */
Print(L"Logo.BMP size = %llu name = %s\n", FileInfo->FileSize, FileInfo->FileName);
UINT8 * FileBufferAddress;
FileBufferAddress = (UINT8 *)AllocateZeroPool (FileInfo->FileSize);
/* c.读取文件数据到申请的内存 */
UINTN BmpSize = FileInfo->FileSize;
Status = LogoHandle->Read(
LogoHandle,
&BmpSize,
(VOID *)FileBufferAddress
);
if(EFI_ERROR(Status))
{
Print(L"Failed to Read.\n");
return Status;
}
/* d.释放file info信息内存 并 关闭打开的文件*/
gBS->FreePool(FileInfo);
Status = LogoHandle->Close(LogoHandle);
if(EFI_ERROR(Status))
{
Print(L"Failed to close.\n");
return Status;
}
Status = Root->Close(Root);
if(EFI_ERROR(Status))
{
Print(L"Failed to Read.\n");
return Status;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EepromBitmap = NULL;
UINTN GopBltSize;
UINTN Height;
UINTN Width;
Status = TranslateBmpToGopBlt ( // 将图形数据转换成blt
(VOID *)FileBufferAddress,
BmpSize,
&EepromBitmap,
&GopBltSize,
&Height,
&Width
);
if(EFI_ERROR(Status))
{
if (EepromBitmap != NULL)
FreePool (EepromBitmap);
Print(L"Failed to Blt Logo. %d\n", Status);
return Status;
}
Status = Gop->Blt (
Gop,
EepromBitmap,
EfiBltBufferToVideo,
0,
0,
0x0,
0x0,
Width,
Height,
Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
if (EFI_ERROR (Status)) {
Print (L"GraphicsOutput Blt is error!\n");
return Status;
}
if (EepromBitmap != NULL)
FreePool (EepromBitmap);
return Status;
}
inf文件:
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = XV6Boot
FILE_GUID = 4dc59a5b-97d9-4a08-808f-e979f47508c0
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = UefiMain
[Sources]
XV6Boot.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
BmpSupportLib
UefiLib
[Guids]
gEfiFileInfoGuid
[Protocols]
gEfiSimpleFileSystemProtocolGuid
dsc文件:
[Defines]
PLATFORM_NAME = ProtocolPkg
PLATFORM_GUID = 8365c20a-fc46-4fc8-9300-9499611f3862
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010006
SUPPORTED_ARCHITECTURES = X64
BUILD_TARGETS = DEBUG|RELEASE
[LibraryClasses]
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
[Components]
XV6BootPkg/XV6Boot.inf