前面介绍了如何 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/