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 条评论