當前位置:
首頁 > 遊戲 > 中文像素字體製作

中文像素字體製作

前段時間想做一款像素風的遊戲,中文像素字體就是一個繞不過去的問題。這裡記錄下我製作 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 的矩形繪製函數,把每個像素點繪製成一個??的正方形。省去了一些中間步驟,所以效率提升了很多,製作過程只用了幾分鐘就完成了。當然摸索這個方法的時間也用了三個晚上,好在以後重新製作的時間縮短到了幾分鐘。這裡記錄下詳細的製作步驟,以及分享下源碼。

1. 安裝 fontforge 並添加支持庫?bdflib

bdf 支持庫是為了解析 M BITMAP FONTS ,hzk12 不需要額外插件。

fontforge 安裝步驟省略,fontforge 會默認安裝上 python 運行環境到軟體目錄下面 。

下載 bdflib 的 whl 文件解壓到??目錄下就安裝好了。

2. 利用 Hzk12 生成 fontforge 工程

新建一個文件夾使用 vscode 打開, 新建 python 腳本命名為?,安裝 python 插件,設置 python 目錄為 fontforge 下的 python 環境 如圖所示:

源碼部分:

importfontforge

importbinascii

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

# print(ch, gb2312, hex_str, result, ioj)

glyph=font.createMappedChar(ioj)

pen=glyph.glyphPen()

y=11

max_x=

forrowinrect_list:

y=y-1

x=-1

foriinrow:

x=x 1

ifi:

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

defdraw_glyph(ch):

rect_list=[]*12

foriinrange(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 漢字型檔文件

withopen(hzk_path,"rb")asf:

# 找到目標漢字的偏移位置

f.seek(offset)

# 從該字模數據中讀取 24 位元組數據

font_rect=f.read(24)

# font_rect 的長度是 24,此處相當於 for k in range(16)

forkinrange(len(font_rect)// 2):

# 每行數據

row_list=rect_list[k]

forjinrange(2):

foriinrange(8):

asc=font_rect[k*2 j]

# 此處為 Python 中的按位與運算符

flag=ascKEYS[i]

# 數據規則獲取字模中數據添加到 16 行每行中 16 個位置處每個位置

row_list.append(flag)

returnrect_list

defOpenGBK():

f=open(gb2312_path,"r",encoding="UTF-8")

line=f.readline()

forindex,chinenumerate(line):

ifch=="\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()

whileline:

forindex,chinenumerate(line):

ifch=="\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 文件的路徑需要修改。

就能生成一個??的文件,雙擊使用 fontforge 打開。看看效果。

3. 利用?M BITMAP FONTS??生成 fontforge 工程

我這裡選擇的是??文件作為字模,也可以使用其他的。

與第二步相同新建一個名為??的文件,這裡依賴了第一步中安裝的??插件。

frombdflibimportreader

frombdflibimportwriter

importfontforge

defOpenBDF(path):

withopen(path,"rb")ashandle:

returnreader.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

forbdf_glyphinbdf_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()

forchinbdf_glyph.__str__():

ifch=="\n":

y=y-1

x=-1

print("")

ifch=="#":

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 下的菜單 ??-> ??->?)。然後在打開 Mplus-jf12r 的 fontforge 的窗口中 選擇菜單??-> ??然後選擇??文件,然後會彈出一個對話框詢問 是否用導入的 graph 替換本工程的同位置 graph,這裡選擇?,就是使用 mplus 的重合部分。

選擇英文和符號部分 調整下 Graph 的寬度 ,推薦 ? 菜單??->?。

推薦按下Ctrl S保存。

下一步生成 ttf 字體文件。生成之前可以先編輯下字體信息, 菜單??->??,這裡不介紹了。

5. 生成 ttf 文件

?菜單??->

設置下 TrueType 就可以點擊??了。這裡會有對話框提示:「有重合的點或者面」, 我還沒有找到比較好的辦法消除,但是並不影響使用,所以就沒有再多處理。依然點擊??生成。

好了現在打開字體看下效果。

還行吧 就是符號的部分不是很好看,也可以重新找點好看的字模用上面的方法替換下,我覺得也能用就沒換了,有需要可以自己動手了,接著看下在 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 解析 HZK16

https://zhuanlan.zhihu.com/p/54931969?

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!


請您繼續閱讀更多來自 indienova 的精彩文章:

黃梅時節家家雨,局促一室亦逍遙