当前位置:
首页 > 字体文章 > ttf字体中文免费 中文像素字体制作

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文件:

参考: