UEFI开发学习13 – 中文显示(Ⅲ)
副标题:给UEFI移植一个字体引擎 - FreeType2
前面两篇介绍中文显示的文章都有一个共同的做法,那就是要生成字库。今天要写的就是无需生成字库,直接提供一个字体文件即可显示中文,或者其它任意字符。
Free Type2介绍
FreeType 2是一种软件字体引擎,旨在小型,高效,高度可定制和便携式,同时能够产生高质量的输出(字形图像)。它也可以用于图形库,显示服务器,字体转换工具,文本图像生成工具以及许多其他产品。
FreeType 2是一种字体服务,不提供执行诸如文本布局或图形处理(例如,彩色文本呈现等)之类的高级功能的API。但是,它通过提供一个简单,易于使用且统一的界面来访问字体文件的内容。前面所写的文章字库都需要工具生成的,现在通过Freetype,便可以省了这个过程,可以直接调用FreeType得到字体的点阵。
官网:https://www.freetype.org/
下载:https://download.savannah.gnu.org/releases/freetype/
Free Type2移植
1. 在AppPkg\Applications新建文件夹Freetype2,下载freetype最新的压缩包(目前是freetype-2.10.4)解压出来,将include,src目录复制到此目录
2. 新建Freetype.inf,文本方式打开freetype-2.10.4\builds\windows\vc2010\freetype.vcxproj.filters,将所有.c文件路径复制到inf,最后再加上ft2build.h及其路径
3. Freetype.inf添加
[BuildOptions] MSFT:*_*_*_CC_FLAGS = /D FT2_BUILD_LIBRARY /wd4244 /wd4706 GCC:*_*_*_CC_FLAGS = -DFT2_BUILD_LIBRARY -w
4. 添加Freetype.c并加一个空main函数
5. 编译,可能有错误,但应该很容易解决的
Free Type2的使用
首先看一个不使用UEFI相关库的最简单的例子,该例子从字体文件中获取指定大小的Bitmap,然后使用字符的方式显示出来:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
int main(int argc, char **argv)
{
FT_Library library;
FT_Face face;
FT_Error error;
FT_UInt char_index;
wchar_t ch = L'永';
/* Init FT2 */
error = FT_Init_FreeType(&library);
/* Load font */
error = FT_New_Face(library, "./SourceHanSans-Normal.ttc", 0, &face);
/* Set font size */
error = FT_Set_Char_Size(face, 60 * 64, 40 * 64, 60, 40);
/* Get graphy font char index */
char_index = FT_Get_Char_Index(face, ch);
/* Load char graphy */
FT_Load_Glyph(face, char_index, FT_LOAD_COLOR);
/* Get bitmap */
if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
{
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
}
FT_UInt i, j;
FT_UInt width, height;
width = face->glyph->bitmap.width;
height = face->glyph->bitmap.rows;
for (i = 0; i < height; i ++) {
for (j = 0; j < width; j ++) {
putchar( face->glyph->bitmap.buffer[i * width + j] == 0 ? ' ': face->glyph->bitmap.buffer[i * width + j] < 128 ? '+': '*' );
}
putchar( '\n' );
}
printf("width:%d, height:%d\n", width, height);
return 0;
}
注意,程序中有中文字符,文件保存的时候编码要选择UTF-8 with BOM,否则得到的Bitmap是错误的!运行结果:
有了这个bitmap,我们就可以把它转换成BltBuffer,然后再用Blt函数绘制出来。既然是UEFI,那在.c中使用中文字符是不大规范的,而且还要保存成特殊的格式,所以可以放到uni文件中。代码如下:
#include <Uefi.h>
#include <Protocol/GraphicsOutput.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/HiiLib.h>
#include <Library/UefiHiiServicesLib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
EFI_GUID mPackageListGuid = {0xd8ebc548, 0xd7ea, 0x46e6, {0x98, 0x0d, 0x0e, 0xa0, 0x04, 0xfd, 0xc7, 0x00}};
EFI_STATUS
AllocateBltBuffer (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL * GraphicsOutput,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN Width,
IN UINTN Height,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL ** BltBuffer
)
{
EFI_STATUS Status;
*BltBuffer = AllocateZeroPool(Width * Height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
Status = GraphicsOutput->Blt(
GraphicsOutput,
*BltBuffer,
EfiBltVideoToBltBuffer,
SourceX, SourceY,
0, 0,
Width,
Height,
0
);
return Status;
}
VOID
BitmapToUefiBltBuffer (
IN UINT8 * Bitmap,
IN UINTN Width,
IN UINTN Height,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer
)
{
UINTN Rows;
UINTN Columns;
UINTN Color;
for (Rows = 0; Rows < Height; Rows ++) {
for (Columns = 0; Columns < Width; Columns ++) {
if (Bitmap[Rows * Width + Columns]) {
/* Fill with white */
Color = 0xFF;
BltBuffer[Rows * Width + Columns].Blue = Color;
BltBuffer[Rows * Width + Columns].Green = Color;
BltBuffer[Rows * Width + Columns].Red = Color;
}
}
}
}
EFI_STATUS
DrawChar (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL * GraphicsOutput,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer
)
{
EFI_STATUS Status;
Status = GraphicsOutput->Blt(
GraphicsOutput,
BltBuffer,
EfiBltBufferToVideo,
0, 0,
DestinationX, DestinationY,
Width,
Height,
0
);
return Status;
}
int main(int argc, char **argv)
{
FT_Library library;
FT_Face face;
FT_Error error;
FT_UInt charIdx;
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL * GraphicsOutput;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer;
UINTN Width, Height;
UINTN X, Y;
UINTN Index;
EFI_HANDLE HiiHandle;
EFI_STRING String;
//CHAR8 * Language = "en-US";
CHAR8 * Language = "zh-Hans";
HiiHandle = HiiAddPackages (&mPackageListGuid, gImageHandle, FreetypeStrings, NULL);
String = HiiGetString (HiiHandle, STRING_TOKEN (STR_STRING), Language);
Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
if (EFI_ERROR(Status)) {
return 0;
}
/* Init FT2 */
error = FT_Init_FreeType(&library);
/* Load font */
error = FT_New_Face(library, "./SourceHanSans-Normal.ttc", 0, &face);
X = 200;
Y = 200;
for (Index = 0; String[Index] != 0; Index ++) {
/* Set font size */
error = FT_Set_Char_Size(face, (40 + Index * 15) * 64, (40 + Index * 15) * 64, 80, 80);
/* Get graphy font char index */
charIdx = FT_Get_Char_Index(face, String[Index]);
/* Load char graphy */
FT_Load_Glyph(face, charIdx, FT_LOAD_COLOR);
/* Get bitmap */
if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
{
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
}
Width = face->glyph->bitmap.width;
Height = face->glyph->bitmap.rows;
AllocateBltBuffer(GraphicsOutput, X, Y, Width, Height, &BltBuffer);
BitmapToUefiBltBuffer(face->glyph->bitmap.buffer, Width, Height, BltBuffer);
DrawChar(GraphicsOutput, X, Y, Width, Height, BltBuffer);
X += (Width + 10);
}
return 0;
}
uni文件
#langdef en-US "English"
#langdef zh-Hans "中文"
#string STR_STRING #language en-US "They come the security"
#language zh-Hans "既来之 则安之"
结果如下:
源码
Github:https://github.com/ay123net/uefift2
Gitee:https://gitee.com/ay123net/uefift2
版权声明:
作者:bin
链接:https://ay123.net/mystudy/995/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。


共有 0 条评论