干掉丑陋的点阵字

从很早很早以前开始,我就琢磨着干掉 Windows 中文版必备的中易宋体(simsun.ttc)里头的点阵字(见链接 012345,其中 1~4 是用 MacType 渲染的,5 是 Win10 自己渲染的)。由于各种原因,这个中易宋体成了事实上的中文默认字体,只要文字没有被明确的指定其他中文字体,基本不出意外都是显示中易宋体,显示的时候大多字号都不大,基本都是古老的点阵字。以前的 Windows 字体渲染方式不够强大,基本都要上MacType,Win10 采用了新的渲染方式,现代程序如果不使用宋体,字体显示效果蛮不错的,于是这次试着直接干掉 Win10 系统里的中易宋体点阵字,把使用宋体的现代程序,以及一些传统程序上宋体的显示效果优化一下。

主要思路

  1. 使用修改过的 Google Noto Serif CJK 字体来代替中易宋体,需要用工具替换掉 simsun.ttc;
  2. 修改注册表里的字体链,在对应的字体链注1中“SIMSUN.TTC,SimSun”之前加上一行想要使用的修改过的字体注2,可新安装字体,无需替换已有的字体。

这两项修改没有依存关系。前者主要对付直接使用宋体的情况,后者主要对付窗体使用的字体通过字体链调用宋体的情况,不过修改前者会一并影响所有在字体链中写了宋体的字体。如果设置了字体链的非中文字体是 Sans 类型,而其字体链中用来显示中文的宋体又是个 Serif 类型的话,感觉总是差了那么一点,个人建议改字体最好要类型统一。

效果如下。

效果(点击看原图)

替换宋体,修改前
替换宋体,修改后
修改字体链,修改前
修改字体链,修改后

注1:字体链在注册表的位置为:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink,一般修改 Microsoft Sans Serif 和Tahoma 两个即可,这两个是 Windows 两个重要虚拟字体(MS Shell Dlg 和 MS Shell Dlg 2)的默认字体。Lucida Sans Unicode 用的也比较多,可以以一并修改。修改前记得导出备份,改动比较多但的效果不理想时,导入备份即可恢复。

注2:比如使用字体 A,该字体的字体名称是 B,则加上“A,B”,A和B可以通过注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts 来查,比如中易宋体的 A 是“simsun.ttc”,B 是“SimSun”或者“NSimSun”。

后记

关于替换字体

中易宋体打印到纸上效果还是不错的,一般工作上也常用这个做文档主字体。本不想替换,只把字体里的点阵删掉,这样不影响打印,如果随便换个“好看”的字体,文档就版面基本会乱,打印出来也很不一样。可惜中易宋体的矢量字符实在太细,间架结构也比较紧,屏幕显示很暗淡模糊,看起来太费眼睛了,所以不得已选择了一个没有点阵的适合屏幕显示的宋体来替换。有一些字体包含的字符可能不能覆盖国标 18030 的中文字符集,生僻字会用其他字体显示(有点像链接里这种效果),所以选字体尽量选字比较全的,比如前文的 Google 的 Noto Serif CJK,不过这个字体打印出来不如中易宋体好看,很是让人纠结。

关于修改字体

前文建议使用修改过的字体,主要原因有两个:

  1. 字体高度可能不合适

    像 Google 的这套 Noto Serif CJK 字体,为了照顾多语言环境,加入了很多扩展拉丁字符,这些字符的修饰符会往上往下撑出去不少空间。直接用现成字体的结果是中文字符变得很小,如下图(点击看原图)。

    改字体链,使用了没有修改过的 Google Noto Sans SC 字体

    要想汉字显示的好看,必须得减小字体的高度,把撑出去的尺寸调小点。修改的时候可以取个巧,程序员编程如果使用宋体(直接或间接),会以这个字体为准设计界面元素尺寸、位置,如果按照宋体的字体尺寸来修改,理论上可以达到和宋体一样的视觉效果。减小字体高度可能导致拉丁文的字符显示不全,不过有字体链的前置字体顶班,所以这不是个问题,不少扩展拉丁文字符中国序员基本不会去使用。但不过要是想单独使用修改过的字体,最好把 ASCII 的那些常用符号修改一下,有些字符在基线以下还有很长的腿,比如 gjpq,会超过字体下边界而显示不全,甚至括号斜杠都会超。另外,并不是字体高度越小,中文字符高度占比越大就越好,这样搞可能会导致字体过大而不协调,也可能使得字符串长度超过程序员预留的空间而显示不全,尺寸什么的还是比照着宋体来就好。

  2. 字体无缝替换需要

    需要让字体在系统眼里变得跟中易宋体一样以实现无缝替换,这要修改字体的字体族、字体 ID 那些东西,而不是简单的重命名字体文件。另外,simsun.ttc 包含宋体和新宋体两个字体,自己做的 ttc 最好也包含宋体和新宋体两个字体,否则没法保证无缝替换,可能会出现一些奇怪的现象(未测试)。

一些特例

之前尝试过把 simsun.ttc 的两个字体的点阵都去掉了,但如此修改会使得在控制台使用点阵字体时把中文显示成粗糙的只有英文字符那么宽的点阵字,推测控制台使用点阵字体遇到中文字符(CP936)时会调用这个 CP936 的默认字体“新宋体”的点阵,但由于点阵已经被去掉了,于是在新宋体字体链的后续字体里找,最后可能在某个有点阵的非等宽字体里找到了中文点阵并显示出来,效果可想而知。解决办法要么是在修改 simsun.ttc 时保留新宋体,要么是在控制台使用非点阵字体(比如系统默认安装了的黑体,或者特殊的自定义字体)。既然本文目的是去掉丑陋的点阵,那自然就要用修改控制台使用字体的办法了。

对于前文修改字体链给某些字体加上了心仪的中文字体的情况,如果碰巧被修改字体链的字体 A 是等宽字体(如文本编辑器常用的 consolas),而所选的中文字体 B 不是等宽字体,那么在程序中使用字体 A 时,会把中文字符显示成与字体 A 同宽。解决办法是字体 B 选用等宽字体,或者修改字体信息把字体 B 改成等宽。

我喜欢在控制台以及文本编辑器中都使用等宽字体,那么上述两种情况可以使用同一种字体来搞定,比如黑体。但黑体显示出来的效果实在是不怎么好看,使用微软雅黑 + consolas 的组合字体会好不少,网上能够搜到这个字体,一般叫做 Microsoft YaHei Mono。不过用这个字体有个坑,它的中文字符宽度(2048)并不是英文字符宽度(1126)的 2 倍,在大多数情况下文本显示对不齐!这可要了老命了。所以还是要继续使用修改字体大法,稍后另一篇文里来聊一聊这里头的门道。

ps. 后来经过证实(参考),之前提到把 simsun.ttc 的两个字体的点阵去掉过后会导致控制台等需要使用点阵字显示中文的地方,把中文显示成只有英文字符那么宽,实际上是 fontforge 的问题,fontforge 去点阵后生成新字体会修改字体信息,新的字体已经不是简单的没有点阵了,改用 FontCreator 来删点阵,上述现象就消失了,据此修改了正文。

ps2. 通过调整 ClearType 的参数,能够使得中易宋体显示得比较黑,看起来没那么费劲,所以也可以不用另找字体来代替,只需要用 FontCreator 把点阵删掉即可。这样既能干掉丑陋的点阵字,又能不影响文档的排版和打印,要知道很多文档里连英文部分也用了宋体,宋体的英文部分很难保证能找到宽度一样的代替品,如果按本文开头说的用 Google Noto Serif CJK 字体来替换中易宋体,除了字形不太一样外还会导致排版变化,这个是不希望看到的。

聊一聊吧

7条评论

  1. 需要文中提到的修改过的字体,请留言,记得不要在评论内容里写邮件地址。

  2. 对于那些没法用上述办法解决显示的老一辈程序,不用也罢。

  3. 求一个修改后的字体啊!
    发邮箱也行!
    跪谢大佬!

说点啥呗

电子邮件地址不会被公开。 必填项已用*标注