UEFI开发学习10 – 中文显示(Ⅰ)
前言
UDK的源码中默认是不支持中文字体显示的,有需要的话需要自己添加。显示中文字库的方法有两种,分别适用于不同的场景。第一种是将中文字库转换成数组,然后使用
点阵原理
以上提到的两种方法中都需要生成中文字库,怎么生成呢?原理是什么?
生成的话较简单,使用我之前发布的工具即可(https://ay123.net/share/865/),这里主要是认识一下字库生成的原理。以生成“十”字的字库来说,首先确定生成字体的大小,如宽10,高10,单位是像素,如下图:
图中为1的部分表示在这个10x10的阵列中存在一个像素点,用一个10x10的C语言数组可表示为
array[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
这样我们便可以用EFI_GRAPHICS_OUTPUT_PROTOCOL->Blt()这个函数将“十”一点一点画出来了。下面我们用字库生成工具生成一个,发现是这样的(选择不同的字体,字库会有不同的差异):
static const unsigned char bits[][20]=
{
//U+5341(十)
0x00,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x7F,0x80,0x08,0x00,0x08,0x00,0x08,0x00,
0x08,0x00,0x00,0x00,
};
整理一下:
static const unsigned char bits[][20]=
{
//U+5341(十)
0x00,0x00,
0x04,0x00,
0x08,0x00,
0x08,0x00,
0x7F,0x80,
0x08,0x00,
0x08,0x00,
0x08,0x00,
0x08,0x00,
0x00,0x00,
};
这是使用一个byte表示8个点,所以是这种写法,将16进制转换成2进制的话是一样的。一个byte不足表示一行10个点怎么办呢?那就再加一个byte,所以看到的数组每行有两个byte表示。
再看一下,将数组的第二行0x04,0x00转换为二进制后:0000 0100, 0000 0000,程序该怎么读取这个点呢?是从左边逐个取值(高位在前)还是右边逐个取值(低位在前)呢?顺序不一样,画出来的结果也是不同的。这个在生成工具是可配置的,如下图:
这里设置时高位在前,所以按从左到右逐个取值画图就可以了。工具还有一个扫描方式,水平扫描和垂直扫描,水平扫描是一行阵列组成n个byte,画点的时候是从左到右,而垂直扫描则是一列组成n个byte,按从上到下的顺序画点,我们按照默认设置即可。
实例1,画点阵字库
1). 使用字库生成工具,在编码表输入“上善若水”,配置如下图,然后保存字库,文件名为"FontLib.c"
2). 在AppPkg新建一个Font模块,并将FontLib.c加入该文件夹,如图:
3). 打开FontLib.c,将数组前的static去掉,否则在Font.c将无法访问,编译出错,因为静态变量是无法跨文件访问的
4). Font.c程序如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/GraphicsOutput.h>
#define FONT_HEIGHT 55
#define FONT_WIDTH 60
#define FONT_ARRAY_SIZE 440
#define FONT_LINE_COUNT (FONT_ARRAY_SIZE / FONT_HEIGHT)
#define FONT_COUNT 4
extern unsigned char bits[][440];
VOID DrawByte(
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
UINT8 Byte,
UINTN X,
UINTN Y,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
UINT8 i;
for (i = 0; i < 8; i ++) {
if (Byte & 0x80) {
GraphicsOutput->Blt(GraphicsOutput, &Color, EfiBltVideoFill, 0, 0, X, Y, 1, 1, 0);
}
/* 从高位到低位逐个取值 */
Byte <<= 1;
X ++;
}
}
VOID DrawFont(
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
UINT8 *FontBitMap,
UINT8 Height,
UINT8 LineCout,
UINTN X,
UINTN Y,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
UINT8 i, j;
UINTN BackupX;
BackupX = X;
for(i = 0; i < Height; i ++) {
X = BackupX;
/* 画一行,每行8个byte */
for(j = 0; j < LineCout; j ++) {
DrawByte(GraphicsOutput, FontBitMap[i * LineCout + j], X, Y, Color);
X += LineCout;
}
Y ++;
}
}
int main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
UINTN ScreenWidth, ScreenHeight, i;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ColorWhite = { 0xFF, 0xFF, 0xFF, 0 };
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ColorBlue = { 0xFF, 0x00, 0x00, 0 };
Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
ScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
ScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
/* 将屏幕填充为白色 */
Status = GraphicsOutput->Blt(
GraphicsOutput,
&ColorWhite,
EfiBltVideoFill,
0, 0,
0, 0,
ScreenWidth, ScreenHeight,
0
);
for (i = 0; i < FONT_COUNT; i ++) {
DrawFont(GraphicsOutput, bits[i], FONT_HEIGHT, FONT_LINE_COUNT, 100 + FONT_WIDTH * i, 100, ColorBlue);
}
return(0);
}
Font.inf
## @file # A simple, basic, EDK II native, "hello" application. # # Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> # 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. # # 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 = Font FILE_GUID = a912fa98-7f0e-4a03-b908-b757b806ec83 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 ENTRY_POINT = ShellCEntryLib # # VALID_ARCHITECTURES = IA32 X64 IPF # [Sources] Font.c FontLib.c [Packages] MdePkg/MdePkg.dec [LibraryClasses] LibC [Protocols] gEfiGraphicsOutputProtocolGuid
最后结果如下:
上面的演示中居然还能看到一点点动画效果,这是由于多个画点的原因导致的,效率较低。下面再按照我这篇文章所讲的->UEFI开发学习9 - 高效画图,修改下代码,如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/GraphicsOutput.h>
#include <Library/MemoryAllocationLib.h>
#define FONT_HEIGHT 55
#define FONT_WIDTH 60
#define FONT_ARRAY_SIZE 440
#define FONT_LINE_COUNT (FONT_ARRAY_SIZE / FONT_HEIGHT)
#define FONT_COUNT 4
extern unsigned char bits[][440];
VOID DrawByte(
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
UINT8 Byte,
UINTN X,
UINTN Y,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
UINT8 i;
for (i = 0; i < 8; i ++) {
if (Byte & 0x80) {
GraphicsOutput->Blt(GraphicsOutput, &Color, EfiBltVideoFill, 0, 0, X, Y, 1, 1, 0);
}
/* 从高位到低位逐个取值 */
Byte <<= 1;
X ++;
}
}
VOID DrawFont(
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
UINT8 *FontBitMap,
UINT8 Height,
UINT8 LineCout,
UINTN X,
UINTN Y,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
UINT8 i, j;
UINTN BackupX;
BackupX = X;
for(i = 0; i < Height; i ++) {
X = BackupX;
/* 画一行,每行8个byte */
for(j = 0; j < LineCout; j ++) {
DrawByte(GraphicsOutput, FontBitMap[i * LineCout + j], X, Y, Color);
X += LineCout;
}
Y ++;
}
}
VOID DrawFontBuffer(
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
UINT8 *FontBitMap,
UINT8 Height,
UINT8 Width,
UINTN X,
UINTN Y,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FontBuf;
UINTN i, k;
UINTN BitIndex, LineBit;
BitIndex = 0;
LineBit = 0;
FontBuf = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (Height * Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
for (i = 0; i < FONT_ARRAY_SIZE; i ++) {
for (k = 0; k < 8; k ++) {
if ((FontBitMap[i] << k) & 0x80) {
FontBuf[BitIndex] = Color;
}
BitIndex ++;
if (++ LineBit == Width) {
LineBit = 0;
break;
}
}
}
GraphicsOutput->Blt(GraphicsOutput, FontBuf, EfiBltBufferToVideo, 0, 0, X, Y, Width, Height, 0);
}
int main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
UINTN ScreenWidth, ScreenHeight, i;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ColorWhite = { 0xFF, 0xFF, 0xFF, 0 };
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ColorBlue = { 0xFF, 0x00, 0x00, 0 };
Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
ScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
ScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
/* 将屏幕填充为白色 */
Status = GraphicsOutput->Blt(
GraphicsOutput,
&ColorWhite,
EfiBltVideoFill,
0, 0,
0, 0,
ScreenWidth, ScreenHeight,
0
);
for (i = 0; i < FONT_COUNT; i ++) {
//DrawFont(GraphicsOutput, bits[i], FONT_HEIGHT, FONT_LINE_COUNT, 100 + FONT_WIDTH * i, 100, ColorBlue);
DrawFontBuffer(GraphicsOutput, bits[i], FONT_HEIGHT, FONT_WIDTH, 100 + FONT_WIDTH * i, 100, ColorBlue);
}
return(0);
}
运行结果看不到任何延迟了,如下:
思考:结合上方的程序,如何将文字的背景色黑色改为其它颜色?
代码
https://gitee.com/ay123net/uefistudy
版权声明:
作者:bin
链接:https://ay123.net/mystudy/uefi/869/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。






共有 0 条评论