悲しいことにVMWarePlayerではGraphics Output Protocolに実装不足があったのでNt32Pkgを使って試してます。
使った画像は/MdeModulePkg/Logo/Logo.bmp。
何か表示出来ればいいという程度で作ったのでBMPの処理関係はいろいろ決め打ちです。
infファイル
## @file # This is the shell application # # Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved. # # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # # ## [Defines] INF_VERSION = 0x00010006 BASE_NAME = TestApp FILE_GUID = 305671d4-c671-4792-8ada-e424a87f4632 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 ENTRY_POINT = UefiMain # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] Main.c [Packages] MdePkg/MdePkg.dec ShellPkg/ShellPkg.dec [LibraryClasses] UefiApplicationEntryPoint UefiLib [Guids] gEfiFileInfoGuid [Protocols] gEfiGraphicsOutputProtocolGuid gEfiSimpleFileSystemProtocolGuid
と、cソースファイル
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Guid/FileInfo.h>
#include <Protocol/DevicePath.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/SimpleFileSystem.h>
#define MAX_BUFFER_SIZE SIZE_1MB
EFI_SYSTEM_TABLE *gST;
EFI_BOOT_SERVICES *gBS;
#pragma pack(1)
typedef struct {
CHAR8 Type[2];
UINT32 Size;
UINT32 Reserved;
UINT32 Offset;
UINT32 CoreHeaderSize;
UINT32 Width;
UINT32 Height;
UINT16 Planes;
UINT16 BitCount;
} BITMAP_FILE_HEADER;
#pragma pack()
STATIC
EFI_STATUS
LoadBitmapFile (
IN CHAR16 *Path,
OUT VOID **BmpBuffer,
OUT UINTN *BmpSize
);
STATIC
EFI_STATUS
DrawBmp (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN VOID *BmpBuffer,
IN UINTN BmpSize
);
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status = EFI_SUCCESS;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
VOID *BmpBuffer = NULL;
UINTN BmpSize;
gST = SystemTable;
gBS = gST->BootServices;
gBS->LocateProtocol (
&gEfiGraphicsOutputProtocolGuid,
NULL,
&GraphicsOutput
);
Status = LoadBitmapFile (L"Logo.bmp", &BmpBuffer, &BmpSize);
if (EFI_ERROR (Status)) {
if (BmpBuffer != NULL) {
FreePool (BmpBuffer);
return Status;
}
}
Status = DrawBmp (GraphicsOutput, BmpBuffer, BmpSize);
if (BmpBuffer != NULL) {
FreePool (BmpBuffer);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
LoadBitmapFile (
IN CHAR16 *Path,
OUT VOID **BmpBuffer,
OUT UINTN *BmpSize
)
{
EFI_STATUS Status = EFI_SUCCESS;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFile;
EFI_FILE_PROTOCOL *Root;
EFI_FILE_PROTOCOL *File;
UINTN BufferSize;
VOID *Buffer = NULL;
Status = gBS->LocateProtocol (
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&SimpleFile
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%r on Locate EFI Simple File System Protocol.\n", Status));
return Status;
}
Status = SimpleFile->OpenVolume (SimpleFile, &Root);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%r on Open volume.\n", Status));
return Status;
}
Status = Root->Open (Root, &File, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%r on Open file.\n", Status));
return Status;
}
BufferSize = MAX_BUFFER_SIZE;
Buffer = AllocatePool (BufferSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = File->Read (
File,
&BufferSize,
Buffer
);
if (BufferSize == MAX_BUFFER_SIZE) {
DEBUG ((EFI_D_ERROR, "Buffer Size Too Small.\n"));
if (Buffer != NULL) {
FreePool (Buffer);
}
return EFI_OUT_OF_RESOURCES;
}
Buffer = ReallocatePool (BufferSize, MAX_BUFFER_SIZE, Buffer);
*BmpBuffer = Buffer;
*BmpSize = BufferSize;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
DrawBmp (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
IN VOID *BmpBuffer,
IN UINTN BmpSize
)
{
EFI_STATUS Status = EFI_SUCCESS;
BITMAP_FILE_HEADER *BitmapHeader;
UINT8 *BitmapData;
UINT32 *Palette;
UINTN Pixels;
UINTN XIndex;
UINTN YIndex;
UINTN Pos;
UINTN BltPos;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
BitmapHeader = (BITMAP_FILE_HEADER *) BmpBuffer;
DEBUG ((EFI_D_ERROR, "%d x %d\n", BitmapHeader->Width, BitmapHeader->Height));
if (BitmapHeader->CoreHeaderSize != 40) {
return EFI_UNSUPPORTED;
}
if (BitmapHeader->BitCount != 8) {
return EFI_UNSUPPORTED;
}
BitmapData = (UINT8*)BmpBuffer + BitmapHeader->Offset;
Palette = (UINT32*) ((UINT8*)BmpBuffer + 0x36);/*決め打ち*/
Pixels = BitmapHeader->Width * BitmapHeader->Height;
BltBuffer = AllocateZeroPool (
sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Pixels
);
if (BltBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (YIndex = BitmapHeader->Height; YIndex > 0; YIndex--) {
for (XIndex = 0; XIndex < BitmapHeader->Width; XIndex++) {
Pos = (YIndex - 1) * ((BitmapHeader->Width + 3) / 4) * 4 + XIndex;
BltPos = (BitmapHeader->Height - YIndex) * BitmapHeader->Width + XIndex;
BltBuffer[BltPos].Blue = (UINT8) BitFieldRead32 (Palette[BitmapData[Pos]], 0 , 7 );
BltBuffer[BltPos].Green = (UINT8) BitFieldRead32 (Palette[BitmapData[Pos]], 8 , 15);
BltBuffer[BltPos].Red = (UINT8) BitFieldRead32 (Palette[BitmapData[Pos]], 16, 23);
BltBuffer[BltPos].Reserved = (UINT8) BitFieldRead32 (Palette[BitmapData[Pos]], 24, 31);
}
}
Status = GraphicsOutput->Blt (
GraphicsOutput,
BltBuffer,
EfiBltBufferToVideo,
0 , 0 , /*Source X, Y*/
200 , 200 , /*Dest X, Y*/
BitmapHeader->Width, BitmapHeader->Height, /*Width, Height*/
0
);
FreePool (BltBuffer);
return EFI_SUCCESS;
}
実行結果はこんな感じです。
地味ではありますが、画像ファイルが表示されました。
今回はBitmapファイルのフォーマットに触れることが出来、色々と悩まされつつも楽しかったです。
標準でBMPファイルを扱えるプロトコルがあればよかったのですが、軽く調べた中では見つからず、結果として普段触らない領域に触れることが出来ました。
参考:
UEFI仕様
Bitmapフォーマット情報

0 件のコメント:
コメントを投稿