整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

中文像素字体制作

段时间想做一款像素风的游戏,中文像素字体就是一个绕不过去的问题。这里记录下我制作 12 像素字体的过程。

使用的软件是 fontforge:https://fontforge.org/en-US/

自己一个字一个字的做是不可能自己做的,所以在网上找到了两个开源的字体库

1. M+ BITMAP FONTS

https://mplus-fonts.osdn.jp/mplus-bitmap-fonts/download/index.html

这是来自日本的完全免费字体,看着还蛮好看,有一部分的中文部分。

2. HZK-12

https://github.com/aguegu/BitmapFont

覆盖 GB2312 的中文 12 像素字体

制作思路

灵感来自 ipix 中文像素字体的制作 我在原作的基础上进行了一些修改。原作是将字模导出为 png 然后 Potrace 转化成 svg 图片, 最后再把 SVG 图片导入 FontForge 中就制作。

我是直接调用了命令行的 fontforge, 使用 python 脚本读取字模信息,然后调用 fontforge 的矩形绘制函数,把每个像素点绘制成一个 100x100的正方形。省去了一些中间步骤,所以效率提升了很多,制作过程只用了几分钟就完成了。当然摸索这个方法的时间也用了三个晚上,好在以后重新制作的时间缩短到了几分钟。这里记录下详细的制作步骤,以及分享下源码。

1. 安装 fontforge 并添加支持库 bdflib

bdf 支持库是为了解析 M+ BITMAP FONTS ,hzk12 不需要额外插件。

fontforge 安装步骤省略,fontforge 会默认安装上 python 运行环境到软件目录下面 。

下载 bdflib 的 whl 文件解压到

FontForgeBuilds\lib\python3.8\site-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"


defDraw(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

defOpenGBK:
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


defStart:

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

defOpenBDF(path):
with open(path, "rb") as handle:
return reader.read_bdf(handle)

defStart:

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 步就是把这两个字体合并一下了。

4. 合并字体

hzk12 和 mplus bitmap 中有很多重合的字,所以有两种合并方式,一个是重合的部分使用 hzk12 的字模,一个是使用 mplus 的。我选择保留 mplus 的重合部分。

由于两者编码格式不同所以先统一下编码格式,一个是 gb2312 一个是 jis208,所以我这全都设置成 Unicode Full 的格式。(fontforge 下的菜单 Encoding->reencode->ISO 10646-1 ( Unicode, Full ))。然后在打开 Mplus-jf12r 的 fontforge 的窗口中 选择菜单Element->Merge Fonts然后选择hzk12.sfd文件,然后会弹出一个对话框询问 是否用导入的 graph 替换本工程的同位置 graph,这里选择NO,就是使用 mplus 的重合部分。

选择英文和符号部分 调整下 Graph 的宽度 ,推荐 菜单 Metrics->Auto Width

推荐按下

下一步生成 ttf 字体文件。生成之前可以先编辑下字体信息, 菜单 Element->font info,这里不介绍了。

5. 生成 ttf 文件

菜单 File->Generate Fonts

设置下 TrueType 就可以点击 Generate了。这里会有对话框提示:“有重合的点或者面”, 我还没有找到比较好的办法消除,但是并不影响使用,所以就没有再多处理。依然点击Generate生成。

好了现在打开字体看下效果。

还行吧 就是符号的部分不是很好看,也可以重新找点好看的字模用上面的方法替换下,我觉得也能用就没换了,有需要可以自己动手了,接着看下在 Unity 中的效果怎么样吧。

效果不错 没有错位。

结束。

源码及参考

源码以及 TTF 文件: https://github.com/Luckeee/mplus_hzk_12

参考:

  • ipix 中文像素字体的制作https://indienova.com/u/purestudio/blogread/20097

  • 如何将点阵汉字矢量化https://indienova.com/indie-game-development/vectorize-chinese-bitmap-font/

  • Python 解析 HZK16https://zhuanlan.zhihu.com/p/54931969

、标签的分类:双标签和单标签

双标签:就是成对出现的,类似于这种 <html> </html>

单标签:就是可以单个使用的,类似于 <br> 换行标签 或 <hr>水平线标签。

二、标签属性的作用:

标签的属性是用来定义文字或字符的 颜色、宽高、粗细、大小、等,这个是标签属性的作用。


三、标签属性的特性:

1、每一个标签都有自己的属性,单标签和双标签都有。

2、一个标签可以有多个属性。

3、每个属性都有对应的值,值要用单或双引号引起来。

4、多个属性之间使用空格隔开。

5、属性没有顺序之分。

6、字体属性值,必须是系统可以识别的字体,一般为系统自带字体。

7、HTML5 中 font 属性已经弃用。

源代码:↓

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<!--网页抬头-->

<title>中央气象局</title>

</head>

<body>

<!--水平线的宽度是500像素,这个width就是标签属性-->

<hr width="500">

<!--下面这个是多个标签属性,多个属性之间用空格隔开-->

<font color="red" face="黑体" size="7">标签属性</font>

</body>

</html>

字是网页展示的重要内容之一,所以对文字的修饰也是CSS重点关注的一部分, CSS提供了以下常用的样式属性来修饰文字。

color 属性

color 用来设置文字颜色。

设置方式支持以下几种格式

  • 英语颜色单词形式,如: red(红)、black(黑)、orange(橙色)等。
<style>
  .box {
    color: red;
  }
</style>


<div class="box">文字颜色</div>
  • 十六进制表示法, 设计软件中通用的表示方法。
  • 例如:ff00000; ff 即为十进制255;每种颜色分为 0~255的数字。
  • 如果表示颜色值重复 例如:#ffaabb 可以简写为#fab.。
  • 黑色为 #000 ,白色为 #fff。
  • 以#ff0000为例,两两分组,分别表示三原色:红、绿、蓝。


<style>
  .box {
    color: #ff0000;
  }
  .box1 {
    color: #f00;
  }
</style>


<div class="box">文字颜色</div>
<div class="box1">简写形式</div>
  • RGB 表示法
  • 例如: color: rgb(255,0,0); rgb 内部的三个值,依次代表三原色 红、绿、蓝。
  • 其中 rgb(0,0,0) 代表黑色, rgb(255,255,255) 表示白色。


<style>
  .box {
    color: rgb(255, 0, 0);
  }
</style>
<div class="box">文字颜色</div>
  • RGBA 表示法, 在RGB的表示方法的基础上增加了透明度(最后一个参数代表透明度)。0-表示透明 1-表示实心。透明度是介于[0,1]之间的值。
  • RGBA 从 IE9开始兼容。
<style>
.box {
  color: rgba(255, 0, 0, 0.5);
}
</style>




<div class="box">文字颜色</div>


font-size 属性

font-size 属性用来设置字体大小,单位通常为px 也可以为em,rem

单位的解释

  • px:像素
  • em: 相对元素字体的倍数
  • rem:相对html字体的倍数, 例如:html标签 设置为font-size为100px , div 设置font-size为1.5 rem 实际表现为:150px。
<style>
  .box {
    font-size: 30px;
  }
</style>


<div class="box">文字大小</div>


font-weight 属性

设置字体的粗细程度,常用的属性有 normal 和 bold 两个值。

可以用以下值表示,也可以用数字表示。

意义

normal

正常粗细,和400值相等

bold

加粗,与700数值相等

lighter

比 正常粗细还细, 不常用

bolder

比 加粗还粗,不常用

100 200 300 400 500 600 700 800 900

使用数字定义字体粗细

inherit

从父元素继承字体粗细


<style>
.box_normal {
  font-weight: normal;
}
.box_bold {
  font-weight: bold;
}


.box_lighter {
  font-weight: lighter;
}


.box_bolder {
  font-weight: bolder;
}


.box_number {
  font-weight: 600;
}
</style>


<body>
  <div class="box_normal">font-weight演示:正常粗细</div>
  <div class="box_bold">font-weight演示,加粗</div>
  <div class="box_lighter">font-weight演示,更细</div>
  <div class="box_bolder">font-weight演示, 更粗</div>
  <div class="box_number">font-weight演示, 数字</div>
</body>


font-style 属性

设置字体的倾斜程度

意义

normal

正常字体, 不带倾斜效果

italic

倾斜字体(常用,使用倾斜字体)

oblique

倾斜字体(用常规字体模拟倾斜,不常用)


<style>
  .box1 {
    font-style: normal;
  }
  .box2 {
    font-style: italic;
  }
  .box3 {
    font-style: oblique;
  }
</style>
<body>
  <div class="box1">正常字体</div>
  <div class="box2">倾斜字体</div>
  <div class="box3">倾斜字体2</div>
</body>


text-decoration 属性

设置文本的修饰线的样式

示例

意义

none

无线(a标签去除下划线会用到)

underline;

下划线

line-through;

删除线

…等等

还有很多,可自行百度


<style>
  .decoration-none {
    text-decoration: none;
  }
  .decoration-underline {
    text-decoration: underline;
  }
  .decoration-line-through {
    text-decoration: line-through;
  }
</style>
<body>
  <div class="decoration-none">无线修饰</div>
  <div class="decoration-underline">下划线</div>
  <div class="decoration-line-through">删除线</div>
</body>


font-family 属性

指定使用的字体族,操作系统一般自带很多字体;

例如:window操作系统中的 ‘微软雅黑’ ,黑体等。

字体文件的格式有很多,比如 eot,woff2,woff,ttf,svg等。

font-family 可以一次指定多个字体, 后面的字体属于后备字体,只有前面的字体没有找到,才会使用后面的字体。


<style>
  div {
      font-family: serif, "Time New Roman", "微软雅黑"
  }
</style>
<body>
  <div>字体</div>
</body>


自定义字体

某些时候,我们的字体比较个性化,或者我们的字体是一个图标字体(一种用符号表示图片的方式)。那么此时,需要我们使用 @font-face 自定义字体

自定义的字体一般是随着网页发布在服务器端,操作系统中并没有。

推荐一个比较好用的字体库网站:https://www.iconfont.cn/(具体使用方式请自行百度)。