ttf字体中文免费 中文像素字体制作
前段时间想做一款像素风格的游戏,中文像素字体是一个无法回避的问题。这里记录一下制作12像素字体的过程。
使用的软件是fontforge:
自己一个字符一个字符的做是不可能的,所以我在网上找了两个开源字体库。
1.M+位图字体
这是来自日本的完全免费字体。看起来不错,还有一些中国零件。
2.HZK-12
中文12像素字体覆盖GB2312
生产思路
受ipix中文像素字体制作的启发ttf字体中文免费,我在原作的基础上做了一些修改。原作是通过将字体导出为png,然后使用Potrace将其转换为svg图像,最后将SVG图像导入FontForge来创建的。
我直接从命令行调用fontforge,使用python脚本读取字体信息,然后调用fontforge的矩形绘制函数将每个像素绘制成100x100的正方形。省略了一些中间步骤,因此效率大大提高,生产过程只需几分钟即可完成。当然,这个方法探索了三个晚上。幸运的是ttf字体中文免费,重新创建的时间缩短到了几分钟。这里记录详细的制作步骤并分享源码。
1.安装fontforge并添加支持库bdflib
bdf支持库用于解析M+ BITMAP FONTS,hzk12不需要额外的插件。
fontforge的安装步骤省略。 Fontforge默认会在软件目录下安装python运行环境。
下载bdflib的whl文件,解压到FontForgeBuildslibpython3.8site-packages目录下并安装。
2.使用Hzk12生成fontforge项目
新建一个文件夹并用vscode打开,将新的python脚本命名为hzk_to_sfd.py,安装python插件,并将python目录设置为fontforge下的python环境如图:
源码部分:
import fontforge
import binascii
KEYS = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]
sdf_path = "HZK12.sfd"
hzk_path = "C:/Users/lo/Downloads/HZK/HZK12"
gb2312_path = "C:/Users/lo/Downloads/HZK/gb2312.txt"
def Draw(font, ch, rect_list):
gb2312 = ch.encode('gb2312')
hex_str = binascii.b2a_hex(gb2312)
result = str(hex_str, encoding='utf-8')
area = eval('0x' + result[:2]) - 0x80
index = eval('0x' + result[2:]) - 0x80
ioj = (area << 8) + index
# print(ch, gb2312, hex_str, result, ioj)
glyph = font.createMappedChar(ioj)
pen = glyph.glyphPen()
y = 11
max_x = 0
for row in rect_list:
y = y - 1
x = -1
for i in row:
x = x + 1
if i:
pen.moveTo((100 * x , 100 * y ))
pen.lineTo((100 * x , 100 * y + 100))
pen.lineTo((100 * x + 100 , 100 * y + 100))
pen.lineTo((100 * x + 100 , 100 * y ))
pen.closePath()
max_x = max(max_x,x)
# print("#")
# else:
# print(" ")
# print("n")
pen = None
glyph.removeOverlap()
glyph.width = max_x*100 + 200
def draw_glyph(ch):
rect_list = [] * 12
for i in range(12):
rect_list.append([] * 16)
# 获取中文的 gb2312 编码,一个汉字是由 2 个字节编码组成
gb2312 = ch.encode('gb2312')
# 将二进制编码数据转化为十六进制数据
hex_str = binascii.b2a_hex(gb2312)
# 将数据按 unicode 转化为字符串
result = str(hex_str, encoding='utf-8')
# 前两位对应汉字的第一个字节:区码,每一区记录 94 个字符
area = eval('0x' + result[:2]) - 0xA0
# 后两位对应汉字的第二个字节:位码,是汉字在其区的位置
index = eval('0x' + result[2:]) - 0xA0
# 汉字在 HZK16 中的绝对偏移位置,最后乘 24 是因为字库中的每个汉字字模都需要 24 字节
offset = (94 * (area-1) + (index-1)) * 24
font_rect = None
# 读取 HZK16 汉字库文件
with open(hzk_path, "rb") as f:
# 找到目标汉字的偏移位置
f.seek(offset)
# 从该字模数据中读取 24 字节数据
font_rect = f.read(24)
# font_rect 的长度是 24,此处相当于 for k in range(16)
for k in range(len(font_rect) // 2):
# 每行数据
row_list = rect_list[k]
for j in range(2):
for i in range(8):
asc = font_rect[k * 2 + j]
# 此处&为 Python 中的按位与运算符
flag = asc & KEYS[i]
# 数据规则获取字模中数据添加到 16 行每行中 16 个位置处每个位置
row_list.append(flag)
return rect_list
def OpenGBK():
f = open(gb2312_path, 'r', encoding='UTF-8')
line = f.readline()
for index, ch in enumerate(line):
if ch == "n":
continue
print(index, end=' ')
print(ch)
f.close()
def Start():
font = fontforge.font() # Open a font
font.encoding = "gb2312"
font.ascent = 1200
f = open(gb2312_path, 'r', encoding='UTF-8')
line = f.readline()
while line:
for index, ch in enumerate(line):
if ch == "n":
continue
print(ch)
rect = draw_glyph(ch)
Draw(font, ch, rect)
line = f.readline()
font.save(sdf_path)
f.close()
Start()
这里依赖两个文件HZK12和gb2312.txt,可以在源码中下载,在Vscode中运行脚本,或者在终端输入:
"c:/Program Files (x86)/FontForgeBuilds/bin/ffpython.exe" c:/Users/lo/Downloads/HZK/hzk_to_sfd.py
#当然这里的 ffpython.exe 文件和 python 文件的路径需要修改。
将会生成一个hzk12.sfd文件,双击使用fontforge打开它。看看效果。
好的,文字没有错位(hzk12前面没有英文字体,所以需要再向下滚动一点才能看到效果)接下来我们来添加英文字体。
3.使用M+ BITMAP FONTS生成fontforge项目
我这里选择的是 mplus_jf12r.bdf 文件作为字体模板,但您也可以使用其他文件。
与第二步相同,新建一个名为bdf_to_sdf.py的文件,该文件依赖于第一步安装的bdflib插件。
from bdflib import reader
from bdflib import writer
import fontforge
def OpenBDF(path):
with open(path, "rb") as handle:
return reader.read_bdf(handle)
def Start():
bdf_font = OpenBDF("C:/Users/lo/Downloads/HZK/mplus_jf12r.bdf")
sdf_font = fontforge.font()
sdf_font.encoding = "jis208"
sdf_font.ascent = 1200
for bdf_glyph in bdf_font.glyphs:
# bdf_glyph = bdf_font[12321]
x = -1
y = 10
print(bdf_glyph.codepoint)
glyph = sdf_font.createMappedChar(bdf_glyph.codepoint)
pen = glyph.glyphPen()
for ch in bdf_glyph.__str__():
if ch == 'n':
y = y - 1
x = -1
print("")
if ch == '#' :
pen.moveTo((100 * x , 100 * y ))
pen.lineTo((100 * x , 100 * y + 100))
pen.lineTo((100 * x + 100 , 100 * y + 100))
pen.lineTo((100 * x + 100 , 100 * y ))
pen.closePath()
print("#",end=" ")
else:
print(" ",end=" ")
x = x + 1
pen = None
glyph.removeOverlap()
# break
# sdf_font.autoWidth()
sdf_font.save("mplus_jf12r.sfd")
Start()
这里使用的文件像mplus_jf12r.bdf一样放置在源代码中。运行方法与第二步相同。运行后会得到一个mplus_jf12r.sfd的fontforge工程。
也没有错位,这很棒。第四步是合并这两种字体。
4. 合并字体
hzk12和mplus位图中有很多重叠的字符,因此有两种合并方法。一种是重叠部分使用hzk12字体模型,另一种是使用mplus。我选择保留 mplus 的重叠部分。
由于两者的编码格式不同,我们首先统一编码格式。一个是gb2312,一个是jis208,所以我把它们都设置为Unicode Full格式。 (fontforge下的菜单编码->重新编码->ISO 10646-1(Unicode,完整))。然后在打开Mplus-jf12r的fontforge窗口中,选择菜单Element->Merge Fonts,然后选择hzk12.sfd文件。然后会弹出一个对话框,询问是否用导入的图形替换本工程中相同位置的图形。这里选择NO,即使用mplus的重叠部分。
选择英文和符号部分来调整图表的宽度。推荐的菜单是“指标”->“自动宽度”。
建议按Ctrl+S保存。
下一步是生成 ttf 字体文件。生成之前可以编辑字体信息,菜单Element->font info,这里不再介绍。
5.生成ttf文件
菜单文件->生成字体
设置 TrueType 后,单击“生成”。会出现对话框提示:“存在重叠的点或面。”我还没有找到更好的方法来消除它们,但不影响使用,所以不再处理。还是点击Generate来生成。
好了,现在打开字体看看效果。
还可以,就是符号部分不太好看。也可以找一些好看的字体,用上面的方法替换。我觉得可以用,所以就没有换。如果需要的话,你可以自己做。然后看一下Unity中的字体。效果如何?
效果不错,没有错位的情况。
结束。
源代码和参考
源代码和TTF文件:
参考: