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://wwa.lanzous.com/b0dkh7gdc

密码:b18z

版权声明:
作者:bin
链接:https://ay123.net/mystudy/887/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>