Java/Scala:如何找到可用的 ubuntu 系统字体,这些字体可以呈现不太常见的 unicode

Java/Scala: How to find available ubuntu system fonts which can render less common unicode

我正在编写一个 java/scala 程序,它可以为各种不同的语言(如中文、波斯语、泰米尔语)生成 pdf 文件。我正在使用 itext。

工作流程是我将一些外语文本复制并粘贴到我构建的 UI 中,单击 "Generate",然后它会创建并保存一个格式精美的 pdf,其中包含该文本。

我的程序是可扩展的,因为可以添加更多的语言(目前支持大约 8 种),但这需要添加更多的字体,并且手动下载和测试新字体非常耗时并且不能很好地扩展。另外,很难知道一种字体是否支持所有字符(例如中文),如果奇怪的字符被丢弃,我不会在视觉上注意到。

如果我的应用程序可以在我的系统中搜索可以呈现该文本的现有字体,那就太好了。此应用程序只会 运行 在我的计算机上,所以我不担心可移植性问题。

例如,libreoffice 可以毫无问题地呈现中文和波斯语。是否可以找到并重复使用 libreoffice 使用的任何字体?还是我的浏览器? Libreoffice 本身似乎使用某种自动字体重定向,因为如果我在字体为 Liberation Serif 时粘贴一些中文,它仍然设法呈现中文。与我在互联网上找到的免费字体相比,我也更喜欢 Libreoffice 字体。看起来很专业,我更信任它。

我还没有找到任何好的文档来解释 Ubuntu and/or Libreoffice 是如何神奇地处理这个问题的,而且我不知道有什么好的工具可以在我的系统中搜索现有字体能够呈现某些代码点。 Ubuntu 有字体查看器程序,但不能按代码点搜索。

我使用的是 14.04 LTS 和 itext 5.0.6。 Scala 或 Java 代码片段都可以。

提前致谢!

-洛汗

我最终构建了一个实用程序,它递归地在字体目录中搜索可以呈现一段文本的字体。 (关键方法是font.canDisplay(Char)

在 Ubuntu 上,一个好的目标目录是 /usr/share/fonts/truetype

在找到的字体中,我的实用程序将使用该字体呈现文本,这样我就可以看到我喜欢哪种字体的外观(然后可以通过 UI 选择一个)。

为了找到特定目录中的所有字体,我使用了类似这样的代码(我删除了 UI 代码以使其更像一个脚本):

val rootFontsDir = {
  val fontsDirPath = "/usr/share/fonts/truetype/" // Customise this
  val dir = new File(fontsDirPath)
  if (!dir.exists())
    throw new RuntimeException(s"Nothing found at path: '$fontsDirPath'")
  if (!dir.isDirectory)
    throw new RuntimeException(s"Object at path: '$fontsDirPath' isn't a directory")
  dir
}

def findFontFilesInDir(dir: File): Seq[File] = {
  val files = dir.listFiles()
  val subDirs = files.filter(_.isDirectory)
  val fontFiles = files.filter(_.isFile).filter(_.getName.endsWith(".ttf"))

  val subDirFontFiles = subDirs.flatMap(findFontFilesInDir)

  subDirFontFiles ++ fontFiles
}

case class FontInfo(font: Font, file: File)

val allFontInfo = findFontFilesInDir(rootFontsDir).map {
  case fontFile => FontInfo(Font.createFont(Font.TRUETYPE_FONT, fontFile), fontFile)
}

拥有 allFontInfo 后,您可以搜索可以轻松呈现某些文本的字体:

val sampleText = "尺度衡量人"

val matchingFontInfo = allFontInfo.filter(fontInfo => sampleText.forall(char => fontInfo.font.canDisplay(char)))

然后循环查看结果以查看字体是什么:

matchingFontInfo.foreach {
  case FontInfo(font, file) =>
    println(s"Text: '$sampleText' can be rendered by font '${font.getFontName}' found at '${file.getPath}'")
}

或者,如果您想实际查看它的渲染效果以便进行视觉比较:

matchingFontInfo.zipWithIndex.map {
  case (FontInfo(baseFont, file), index) =>
    val largerFont = baseFont.deriveFont(Font.PLAIN, 24)
    val label = new JLabel(s"[$index] ${baseFont.getFontName} : ${sampleText} (${file.getPath})")
    label.setFont(largerFont)
    // Add the label into a UI component ...
}

在我的代码中,示例文本是通过 UI 输入的,而不是像上面那样进行硬编码,我将所有标签吐出到 JFrame.