如何在 fontconfig 中设置每个 Unicode 范围/代码点的字体?

Posted

技术标签:

【中文标题】如何在 fontconfig 中设置每个 Unicode 范围/代码点的字体?【英文标题】:How to set font per Unicode range / codepoint in fontconfig? 【发布时间】:2018-05-10 03:06:44 【问题描述】:

我最近想出了如何在 Linux 上使用fontconfig 为 serif、sans-serif 和等宽字体设置系统默认字体;基本上,您将 XML 配置文件保存到 ~/.config/fontconfig/fonts.conf,内容如下:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

<match>
  <test qual="any" name="family"><string>serif</string></test>
  <edit name="family" binding="strong" mode="prepend_first">
    <string>Gentium</string>
    <string>Sun-ExtA</string>
    <string>HanaMinA</string>
    <string>HanaMinB</string>
    </edit>
  </match>

</fontconfig>

binding="strong" mode="prepend_first" 属性确保匹配规则优先于其他设置,并且字体名称的顺序确保在字体不包含给定代码点/字符的情况下,尝试列表中的下一个字体 (此列表自上而下适用;恕我直言,它确实应该是后期绑定更强的逻辑,但无论如何)。

这种配置的好处在于它可以在文本编辑器和终端模拟器中运行。

但是,仍然存在问题:在很多情况下,给定字体确实包含给定字形,但对于该代码点,另一种字体会更可取;例如,Sun-ExtA 是 CJK 字符的一个很好的默认字体,但它也涵盖了很多非 CJK 字符,并且有一些有问题的字形。

假设我不喜欢〇 U+3007 IDEOGRAPHIC NUMBER ZEROSun-ExtA 中的出现,而宁愿使用HanaMinA,我怎么能用fontconfig 做到这一点?显然,我不能将HanaMinA 的条目优先于Sun-ExtA,因为这会影响所有两种字体中包含的字形。

我的预感是应该有一个涉及元素 &lt;charset&gt; 的解决方案(根据 fontconfig user documentation,“该元素至少包含一个或多个 Unicode 代码点的元素”)和/或&lt;range&gt;(“该元素包含范围表示的两个元素”——可能表示一系列 Unicode 代码点)。不过,我找不到一个如何使用这些元素的示例。

是否可以将 fontconfig 配置为对单个 Unicode 代码点或一系列代码点使用特定字体?

【问题讨论】:

【参考方案1】:

在扫描模式中,在 &lt;edit&gt; 标记中包含 &lt;minus&gt; 元素可让您从字符集中减去。

这主要是为从字体中删除“坏”或有问题的字符而设计的,但更进一步,您可以编写一个 &lt;test&gt; 来匹配除您要使用的字体之外的所有字体:

<match target="scan">
  <test name="family" compare="not_eq">
    <string>VL Gothic</string>
  </test>
  <edit name="charset" mode="assign">
    <minus>
      <name>charset</name>
      <range>
        <int>0x0021</int>
        <int>0x00FF</int>
      </range>
    </minus>
  </edit>
</match>

类似的配置也可用于从字体中删除整个langs。

据我所知,这在以前没有真正记录在案,我发现了它from a redhat bug

【讨论】:

首先,这个答案包含一个错误:fontconfig 抱怨“范围”周围缺少“字符集”。而且,不幸的是,它似乎不适用于 fontconfig 2.13 或干扰其他东西。所有应用程序(包括浏览器和终端仿真器)仍然呈现“已删除”的字符,其中应将其删除:( 这个 sn-p 对我有用,但我能得到的最好的结果是删除字符的矩形。有没有人真的能够让 fontconfig 回退到另一种字体? 对我来说,类似的情况不适用于 fontconfig 2.13.1,除非在&lt;range&gt; 部分周围添加&lt;charset&gt; 标签,即&lt;charset&gt;&lt;range&gt;&lt;int&gt;0x0021&lt;/int&gt;&lt;int&gt;0x00FF&lt;/int&gt;&lt;/range&gt;&lt;/charset&gt;,(也可以使用多个范围。) 我不得不使用target="font" 而不是"scan" 来完成这项工作。【参考方案2】:

您可以使用以下方法在 fontconfig 中提升特定语言环境的字体:

   <match>
    <test name="lang">
      <string>[RFC-3066 language code]</string>
    </test>
    <test name="family">
      <string>[genericname]</string>
    </test>
    <edit name="family" mode="prepend">
      <string>[fontname]</string>
    </edit>
  </match>
   <alias>
    <family>[fontname]</family>
     <default>
      <family>[genericname]</family>
     </default>
   </alias>

需要谨慎使用 fontconfig 优先级,以便在您不想要的字体之前和常见的拉丁/希腊/西里尔字体之后提升字体(因为 CJK 拉丁字形往往很糟糕)。

当然,这假设您的软件环境能够在您在需要此覆盖的语言环境中读/写时发出 fontconfig 信号。

【讨论】:

以上是关于如何在 fontconfig 中设置每个 Unicode 范围/代码点的字体?的主要内容,如果未能解决你的问题,请参考以下文章

如何在每个函数中设置仅索引一个项目

如何在 Hadoop 流中设置每个节点的最大减速器数量?

Flexbox布局:如何在多行中设置每个项目相同的宽度? [复制]

如何在本地网络中设置每个人都可以看到的本地域?

python - 如何在python中的旭日形图的所有层中设置每个类别的颜色?

如何在 Flutter 中设置 Firebase Analytics 自定义事件,而不在每个屏幕中传递“分析/观察者”对象