前面介绍了如何 Load 一幅 BMP 图片然后显示出来,然后就有一个问题:如何把这个图片也放在 EFI 文件中? 毕竟放在一起会显得更加专业。在【参考1】上,也有朋友问了同样的问题,博主的建议是“写个脚本直接把图片变成像素数组,直接弄,这样很简单”。下面就来实验一下。
首先,需要找一个将图片转为 C Header的工具。我找到的是 Bin2C 这个工具【参考2】. 用下面的命令即可完成转换,生成 show.h
bin2c -o show.h Untitled.bmp
转换之后 show.h 大概就是下面这个样子
然后,修改之前显示 BMP 的那个程序,用 include 来引用用到的 BMP 数据, 去掉 Load 文件的过程,直接使用内存地址。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Protocol/LoadedImage.h>
#define MAX_FILE_SIZE (1024*1024*1024)
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
extern EFI_RUNTIME_SERVICES *gRT;
extern EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
extern EFI_HANDLE gImageHandle;
static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
#pragma pack(1)
//Copied from C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
UINT8 Blue;
UINT8 Green;
UINT8 Red;
UINT8 Reserved;
} EFI_UGA_PIXEL;
/* This should be compatible with EFI_UGA_PIXEL */
typedef struct {
UINT8 b, g, r, a;
} EG_PIXEL;
typedef struct {
CHAR8 CharB;
CHAR8 CharM;
UINT32 Size;
UINT16 Reserved[2];
UINT32 ImageOffset;
UINT32 HeaderSize;
UINT32 PixelWidth;
UINT32 PixelHeight;
UINT16 Planes; // Must be 1
UINT16 BitPerPixel; // 1, 4, 8, or 24
UINT32 CompressionType;
UINT32 ImageSize; // Compressed image size in bytes
UINT32 XPixelsPerMeter;
UINT32 YPixelsPerMeter;
UINT32 NumberOfColors;
UINT32 ImportantColors;
} BMP_IMAGE_HEADER;
typedef struct {
UINTN Width;
UINTN Height;
BOOLEAN HasAlpha;
EG_PIXEL *PixelData;
} EG_IMAGE;
#pragma pack()
//const unsigned char Untitled_bmp[289654]
#include "show.h"
VOID egFreeImage(IN EG_IMAGE *Image)
{
if (Image != NULL) {
if (Image->PixelData != NULL)
FreePool(Image->PixelData);
FreePool(Image);
}
}
//
// Basic image handling
//
EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
{
EG_IMAGE *NewImage;
NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
if (NewImage == NULL)
return NULL;
NewImage->PixelData = (EG_PIXEL *) AllocatePool(
Width * Height * sizeof(EG_PIXEL));
if (NewImage->PixelData == NULL) {
FreePool(NewImage);
return NULL;
}
NewImage->Width = Width;
NewImage->Height = Height;
NewImage->HasAlpha = HasAlpha;
return NewImage;
}
//
// Load BMP image
//
EG_IMAGE * egDecodeBMP
(
IN UINT8 *FileData,
IN UINTN FileDataLength,
IN BOOLEAN WantAlpha)
{
EG_IMAGE *NewImage;
BMP_IMAGE_HEADER *BmpHeader;
EFI_UGA_PIXEL *BmpColorMap;
UINTN x, y;
UINT8 *ImagePtr;
UINT8 *ImagePtrBase;
UINTN ImageLineOffset;
UINT8 ImageValue=0, AlphaValue;
EG_PIXEL *PixelPtr;
UINTN Index, BitIndex;
// read and check header
if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)
return NULL;
BmpHeader = (BMP_IMAGE_HEADER *) FileData;
if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')
return NULL;
if (BmpHeader->CompressionType != 0)
return NULL;
if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&
BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24)
return NULL;
// calculate parameters
ImageLineOffset = BmpHeader->PixelWidth;
if (BmpHeader->BitPerPixel == 24)
ImageLineOffset *= 3;
else if (BmpHeader->BitPerPixel == 1)
ImageLineOffset = (ImageLineOffset + 7) >> 3;
else if (BmpHeader->BitPerPixel == 4)
ImageLineOffset = (ImageLineOffset + 1) >> 1;
if ((ImageLineOffset % 4) != 0)
ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
// check bounds
if (BmpHeader->ImageOffset +
ImageLineOffset * BmpHeader->PixelHeight > FileDataLength)
return NULL;
// allocate image structure and buffer
NewImage = egCreateImage(BmpHeader->PixelWidth,
BmpHeader->PixelHeight, WantAlpha);
if (NewImage == NULL)
return NULL;
AlphaValue = WantAlpha ? 255 : 0;
// convert image
BmpColorMap = (EFI_UGA_PIXEL *)(FileData + sizeof(BMP_IMAGE_HEADER));
ImagePtrBase = FileData + BmpHeader->ImageOffset;
for (y = 0; y < BmpHeader->PixelHeight; y++) {
ImagePtr = ImagePtrBase;
ImagePtrBase += ImageLineOffset;
PixelPtr = NewImage->PixelData +
(BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth;
switch (BmpHeader->BitPerPixel) {
case 1:
for (x = 0; x < BmpHeader->PixelWidth; x++) {
BitIndex = x & 0x07;
if (BitIndex == 0)
ImageValue = *ImagePtr++;
Index = (ImageValue >> (7 - BitIndex)) & 0x01;
PixelPtr->b = BmpColorMap[Index].Blue;
PixelPtr->g = BmpColorMap[Index].Green;
PixelPtr->r = BmpColorMap[Index].Red;
PixelPtr->a = AlphaValue;
PixelPtr++;
}
break;
case 4:
for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) {
ImageValue = *ImagePtr++;
Index = ImageValue >> 4;
PixelPtr->b = BmpColorMap[Index].Blue;
PixelPtr->g = BmpColorMap[Index].Green;
PixelPtr->r = BmpColorMap[Index].Red;
PixelPtr->a = AlphaValue;
PixelPtr++;
Index = ImageValue & 0x0f;
PixelPtr->b = BmpColorMap[Index].Blue;
PixelPtr->g = BmpColorMap[Index].Green;
PixelPtr->r = BmpColorMap[Index].Red;
PixelPtr->a = AlphaValue;
PixelPtr++;
}
if (x < BmpHeader->PixelWidth) {
ImageValue = *ImagePtr++;
Index = ImageValue >> 4;
PixelPtr->b = BmpColorMap[Index].Blue;
PixelPtr->g = BmpColorMap[Index].Green;
PixelPtr->r = BmpColorMap[Index].Red;
PixelPtr->a = AlphaValue;
PixelPtr++;
}
break;
case 8:
for (x = 0; x < BmpHeader->PixelWidth; x++) {
Index = *ImagePtr++;
PixelPtr->b = BmpColorMap[Index].Blue;
PixelPtr->g = BmpColorMap[Index].Green;
PixelPtr->r = BmpColorMap[Index].Red;
PixelPtr->a = AlphaValue;
PixelPtr++;
}
break;
case 24:
for (x = 0; x < BmpHeader->PixelWidth; x++) {
PixelPtr->b = *ImagePtr++;
PixelPtr->g = *ImagePtr++;
PixelPtr->r = *ImagePtr++;
PixelPtr->a = AlphaValue;
PixelPtr++;
}
break;
}
}
return NewImage;
}
int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
EG_IMAGE *Image;
Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid,
NULL, (VOID **) &GraphicsOutput);
if (EFI_ERROR(Status)) {
GraphicsOutput = NULL;
Print(L"Loading Graphics_Output_Protocol error!\n");
return EFI_SUCCESS;
}
Image=egDecodeBMP((UINT8 *)&Untitled_bmp, Untitled_bmp_size, FALSE);
Print(L"Image height [%d]:width[%d]",
Image->Height,
Image->Width);
GraphicsOutput->Blt(
GraphicsOutput,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) Image->PixelData,
EfiBltBufferToVideo,
0,
0 ,
0x100,
0x20,
Image->Width,
Image->Height, 0);
return EFI_SUCCESS;
}
运行结果:
Bin2C 下载(内含原始图片)
源代码下载
参考:
1.http://www.cppblog.com/djxzh/archive/2015/02/08/209766.html 补充《UEFI原理与编程》中关于Edk2的调试
2. http://sourceforge.net/projects/bin2c/

