前面介绍了如何截图,如果把这个过程反过来,先是读取BMP文件到内存,然后重新排列RGB,再用Blt输出到Video上就是显示BMP的过程。
根据这个原理编写程序如下:
#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() VOID egFreeImage(IN EG_IMAGE *Image) { if (Image != NULL) { if (Image->PixelData != NULL) FreePool(Image->PixelData); FreePool(Image); } } static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }; static EFI_STATUS egFindESP(OUT EFI_FILE_PROTOCOL *RootDir) { EFI_STATUS Status; return Status; } // // 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; } EFI_STATUS LoadFile( IN CHAR16 *FileName, IN UINT8 **FileData, IN UINTN *FileDataLength) { EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; EFI_FILE_PROTOCOL *Root; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; EFI_FILE_INFO *FileInfo = NULL; Status = gBS->LocateProtocol( &gEfiSimpleFileSystemProtocolGuid, NULL, (VOID **)&SimpleFileSystem); if (EFI_ERROR(Status)) { Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n"); return Status; } Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root); if (EFI_ERROR(Status)) { Print(L"OpenVolume error \r\n"); return Status; } Status = Root->Open( Root, &FileHandle, FileName, EFI_FILE_MODE_READ , 0); if (EFI_ERROR(Status)) { Print(L"Error Open NULL\n"); return Status; } FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle); Print(L"Filesize [%ld] bytes\n",FileInfo-> FileSize); *FileDataLength=(UINTN) FileInfo->FileSize; *FileData = AllocatePool((UINTN) FileInfo->FileSize); Status = FileHandle->Read(FileHandle, FileDataLength, *FileData ); if (EFI_ERROR(Status)) { Print(L"Loading file error! \n"); } Print(L"Get file size [%d]!\n",*FileDataLength); FileHandle->Close(FileHandle); return Status; } // // 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; UINT8 *FileData=NULL; UINTN FileDataLength; Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput); if (EFI_ERROR(Status)) { GraphicsOutput = NULL; Print(L"Loading Graphics_Output_Protocol error!\n"); return EFI_SUCCESS; } Status=LoadFile(L"test.bmp",&FileData,&FileDataLength); Print(L"Get file size [%d]!\n",FileDataLength); Image=egDecodeBMP(FileData, FileDataLength, 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 , 0x20, 0x0, Image->Width, Image->Height, 0); return EFI_SUCCESS; }
运行结果:
完整代码例子:
本文同样参考了之前提到的 https://github.com/chengs/UEFI 的代码,再次感谢!
请问博主有做过UEFI下的USB开发么,我尝试使用UsbSyncInterruptTransfer()方法时会报EFI_DEVICE_ERROR的错误,传的参数应该没问题,设备也没问题,因为我用libusb可以正常实现想要的功能。不知道博主有没有什么建议?谢谢!
不好意思,没做过 Uefi下的usb开发
你好,博主,请问下你的test.bmp是放在什么路径下面的,
应该是放在 fs0: 下面的