UEFI开发学习12 – 中文显示(Ⅱ)
接上一篇,继续探究UEFI的中文显示问题,主要有两个部分,一个是shell下显示中文,另一个是汉化UDK配置界面。这两个问题都是需要安装中文的,所以,首先介绍下如何安装中文字库。
安装中文字库
1.生成字库
由于字体是有版权的,商业使用需要授权,所以可以使用免费开源字体,当然我们用来学习的就无关紧要了,文末我会附上谷歌的免费字体,可自由使用。
上一篇中我已经介绍过使用我修改过的字体生成工具了,这里照样还是需要用到它( 点阵字库生成工具 直接生成UEFI字库)。启动这个工具,右下角“文件格式”选择UEFI,“编辑码表”可输入要生成的字库,文末有我从百度文库找到的常用汉字3754个(汉字有几万个,全部生成就没必要了,常用的即可),可直接载入,再设置要生成的字体名,要注意一下的是,如果默认的16号字体不能填满黑色部分,可适当调大,我用谷歌字体调到22,而宋体默认就可以了。然后再看看字体有无居中,没有的话可以适量调一下水平跟垂直偏移,最后点击保存字库。
2.安装字库
UDK的代码中有安装字库的部分,位于MdeModulePkg\Universal\Console\GraphicsConsoleDxe目录,LaffStd.c是默认字库文件,我们就在这里添加中文字库。
① 在生成的中文字库文件加上头文件
#include "GraphicsConsole.h"
最后一行添加数组大小
UINT32 mWideFontSize = sizeof (gFontWideGlyphData);
② 打开MdeModulePkg\Universal\Console\GraphicsConsoleDxe\GraphicsConsole.h,添加
extern EFI_WIDE_GLYPH gFontWideGlyphData[]; extern UINT32 mWideFontSize;
③ 打开MdeModulePkg\Universal\Console\GraphicsConsoleDxe\GraphicsConsole.c,找到RegisterFontPackage函数,照葫芦画瓢,做如下修改:
/**
  HII Database Protocol notification event handler.
  Register font package when HII Database Protocol has been installed.
  @param[in] Event    Event whose notification function is being invoked.
  @param[in] Context  Pointer to the notification function's context.
**/
VOID
EFIAPI
RegisterFontPackage (
  IN  EFI_EVENT       Event,
  IN  VOID            *Context
  )
{
  EFI_STATUS                           Status;
  EFI_HII_SIMPLE_FONT_PACKAGE_HDR      *SimplifiedFont;
  UINT32                               PackageLength;
  UINT8                                *Package;
  UINT8                                *Location;
  EFI_HII_DATABASE_PROTOCOL            *HiiDatabase;
  EFI_GUID                             mChineseFontPackageListGuid = {0x9f7bc74d, 0x0549, 0x4416, {0x86, 0x85, 0xc7, 0x16, 0xcd, 0x61, 0x0b, 0x74}};
  //
  // Locate HII Database Protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiHiiDatabaseProtocolGuid,
                  NULL,
                  (VOID **) &HiiDatabase
                  );
  if (EFI_ERROR (Status)) {
    return;
  }
  //
  // Add 4 bytes to the header for entire length for HiiAddPackages use only.
  //
  //    +--------------------------------+ <-- Package
  //    |                                |
  //    |    PackageLength(4 bytes)      |
  //    |                                |
  //    |--------------------------------| <-- SimplifiedFont
  //    |                                |
  //    |EFI_HII_SIMPLE_FONT_PACKAGE_HDR |
  //    |                                |
  //    |--------------------------------| <-- Location
  //    |                                |
  //    |     gUsStdNarrowGlyphData      |
  //    |                                |
  //    +--------------------------------+
  PackageLength   = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + mNarrowFontSize + 4;
  Package = AllocateZeroPool (PackageLength);
  ASSERT (Package != NULL);
  WriteUnaligned32((UINT32 *) Package,PackageLength);
  SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR *) (Package + 4);
  SimplifiedFont->Header.Length        = (UINT32) (PackageLength - 4);
  SimplifiedFont->Header.Type          = EFI_HII_PACKAGE_SIMPLE_FONTS;
  SimplifiedFont->NumberOfNarrowGlyphs = (UINT16) (mNarrowFontSize / sizeof (EFI_NARROW_GLYPH));
  Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);
  CopyMem (Location, gUsStdNarrowGlyphData, mNarrowFontSize);
  //
  // Add this simplified font package to a package list then install it.
  //
  mHiiHandle = HiiAddPackages (
                 &mFontPackageListGuid,
                 NULL,
                 Package,
                 NULL
                 );
  ASSERT (mHiiHandle != NULL);
  FreePool (Package);
  /*
    Add Chinese font
  */  
  PackageLength   = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + mWideFontSize + 4;
  Package = AllocateZeroPool (PackageLength);
  ASSERT (Package != NULL);
  WriteUnaligned32((UINT32 *) Package,PackageLength);
  SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR *) (Package + 4);
  SimplifiedFont->Header.Length        = (UINT32) (PackageLength - 4);
  SimplifiedFont->Header.Type          = EFI_HII_PACKAGE_SIMPLE_FONTS;
  SimplifiedFont->NumberOfWideGlyphs = (UINT16) (mWideFontSize / sizeof (EFI_WIDE_GLYPH));
  Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);
  CopyMem (Location, gFontWideGlyphData, mWideFontSize);
  //
  // Add this simplified font package to a package list then install it.
  //
  mHiiHandle = HiiAddPackages (
                 &mChineseFontPackageListGuid,
                 NULL,
                 Package,
                 NULL
                 );
  ASSERT (mHiiHandle != NULL);
  FreePool (Package);
}
④ 将字库文件加入GraphicsConsoleDxe.inf,保存重新编译Nt32Pkg。
3.测试
在SecMain.exe所在目录新建一个中文名字的文件,然后在shell用ls命令查看,中文安装成功则可以显示。
EFI APP使用中文
EFI app使用中文直接用Print就可以了,但是有个问题,c文件中出现中文会有编译报错的问题,需要参考这篇解决-> 解决VS编译中文报错 error C2001:常量中有换行符,不过还是建议用uni文件做,这样规范一些,而且还可以比较方便地实现多语言切换。实例如下:
// ShellFont.c
#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/UefiBootServicesTableLib.h>
#include  <Library/HiiLib.h>
#include  <Library/UefiHiiServicesLib.h>
#include  <Library/MemoryAllocationLib.h>
#pragma execution_character_set("utf-8")
EFI_GUID    mPackageListGuid = {0xd8ebc548, 0xd7ea, 0x46e6, {0x98, 0x0d, 0x0e, 0xa0, 0x04, 0xfd, 0xc7, 0x00}};
int main (
  IN int Argc,
  IN char **Argv
  )
{
#if 0
    EFI_HANDLE     HiiHandle;
    EFI_STRING     String;
    EFI_STATUS     Status;
    UINTN          StringSize;
    //CHAR8        * Language = "en-US";
    CHAR8        * Language = "zh-Hans";
    HiiHandle = HiiAddPackages (&mPackageListGuid, gImageHandle, ShellFontStrings, NULL);
    StringSize = 0;
    Status = gHiiString->GetString(gHiiString, Language, HiiHandle, STRING_TOKEN (STR_TITLE), String, &StringSize, NULL);
    if (Status == EFI_BUFFER_TOO_SMALL) {
        String = AllocateZeroPool (StringSize);
        Status = gHiiString->GetString (gHiiString, Language, HiiHandle, STRING_TOKEN (STR_TITLE), String, &StringSize, NULL,);
        if (EFI_ERROR(Status)) return 0;
    }
    Print(L"Test String:%s\n\r", String);
#else
    // 更简洁的写法
    EFI_HANDLE     HiiHandle;
    EFI_STRING     String;
    //CHAR8        * Language = "en-US";
    CHAR8        * Language = "zh-Hans";
    HiiHandle = HiiAddPackages (&mPackageListGuid, gImageHandle, ShellFontStrings, NULL);  
    String = HiiGetString (HiiHandle, STRING_TOKEN (STR_TITLE), Language);
    Print(L"Test String:%s  0x%X\n\r", String, *String);
    //Print(L"Test: %s\n\r", L"我是中国人");   // 使用Print直接打印
#endif
    return(0);
}
# ShellFont.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 = ShellFont FILE_GUID = 941d0b52-c64c-43a4-8fc7-2305c6a40185 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 ENTRY_POINT = ShellCEntryLib # # VALID_ARCHITECTURES = IA32 X64 IPF # [Sources] ShellFont.c ShellFont.uni [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec [LibraryClasses] LibC UefiHiiServicesLib HiiLib [Protocols] gEfiGraphicsOutputProtocolGuid
// ShellFont.uni
#langdef   en-US "English"
#langdef   zh-Hans "中文"
#string STR_TITLE           #language en-US  "This is a title"
                            #language zh-Hans  "这是一个标题"
运行结果:
注意c文件的ShellFontStrings变量,这是编译uni文件后自动生成的,名字由包名+Strings组成!通过更改Language的值可切换多种语言,所以EFI APP 也可实现多语言版本。
附件
https://gitee.com/ay123net/uefistudy
版权声明:
                                    
作者:bin                                    
链接:https://ay123.net/mystudy/887/
                                    
来源:爱影博客                                    
文章版权归作者所有,未经允许请勿转载。
                                
 
                



 
                    
共有 0 条评论