本帖最后由 FeiyuYip 于 2022-6-8 09:59 编辑
最近对点阵字体比较有兴趣,所以主要参考了两个教程,实现了用python输出点阵字体需要说明的是,这种实现方法是读取字体的“字模”来生成的,而不是根据某款字的字形强转为点阵形式。
粗略地说一下字模的含义,有兴趣的可以去搜索一下
所谓字模又称HZK字模,一般见于上古时代的操作系统(如UCDOS等)或单片机行列,是由前辈们辛苦把某款字体按不同的矩阵排列,把它们收集整理成字模。
需要输出哪个字,就根据规律,在字模里寻找到这个字模的值即可。
免费的字模文件见:字模下载地址
言归正传,说一下参考的案例及
参考教程1:Python print 玩转点阵字(某乎的链接,不知道是否违规)
这篇教程用python写得很清晰明白,照猫画虎就能轻松实现16*16点阵的汉字输出。
但这样似乎还嫌不够,因为字模文件有好多个,涉及12*12,16*16,24*24,32*32,40*40,48*48等,没有理由只止步于此。
于是又找到下面这个案例:
参考教程2:点阵字库HZK32的使用方法和显示(某猴的链接,不知道是否违规)
它是实现了32*32点阵的汉字输出,耐何是C语言实现的。鄙人对C知之甚少,但搜索点阵字体生成的原理,以及参考教程1的代码,终于发现了规律。
于是修改出来如下通用性的代码:
[Python] 纯文本查看 复制代码 import binascii
import os
# 用于测试当前位是否为1
KEYS = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]
HZK_save_path = 'font'
def show_one_string(text_str, HZK_wei, HZK_file):
HZK_wei = int(HZK_wei)
rect_list = [] * HZK_wei
for i in range(HZK_wei):
rect_list.append([] * HZK_wei)
# print(rect_list)
HZK_path = f'{HZK_save_path}/{HZK_file}'
# # 当24时,任选一个效果
# if HZK_wei == 24:
# HZK_path = f'{HZK_save_path}/HZK{HZK_wei}K'
#
# if HZK_wei == 16:
# HZK_path = f'{HZK_save_path}/HZK{HZK_wei}F'
# 此时开始进入循环
for text in text_str:
gb2312 = text.encode('gb18030')
# 获取中文的gb2312编码,一个汉字是由2个字节编码组成
hex_str = binascii.b2a_hex(gb2312)
# 将二进制编码数据转化为十六进制数据
result = str(hex_str, encoding='utf-8')
# 前两位对应汉字的第一个字节:区码,每一区记录94个字符
area = eval('0x' + result[:2]) - 0xA0
# 后两位对应汉字的第二个字节:位码,是汉字在其区的位置
index = eval('0x' + result[2:]) - 0xA0
# hzk16为32字节,hzk32为32*32/8字节
offset = (94 * (area - 1) + (index - 1)) * int(HZK_wei * HZK_wei / 8)
# print(offset)
# 读取HZK汉字库文件
with open(f"{HZK_path}", "rb") as f:
# 找到目标汉字的偏移位置
f.seek(offset)
# 从该字模数据中读取字节数据
font_rect = f.read(int(HZK_wei * HZK_wei / 8))
# print(font_rect)
for k in range(HZK_wei):
# 每行数据
row_list = rect_list[k]
for j in range(int(HZK_wei / 8)):
for i in range(8):
asc = font_rect[k * int(HZK_wei / 8) + j]
# 此处&为Python中的按位与运算符,测试当前位是否为1
flag = asc & KEYS[i]
# 为1的变成为O,为0的变换为空
if flag:
flag = '0'
else:
flag = ' '
# 数据规则获取字模中数据添加到16行每行中16个位置处每个位置
row_list.append(flag)
# 根据获取到的32*32点阵信息,打印到控制台
for row in rect_list:
for i in row:
print(i, end=' ')
print()
with open(f'{text_str}.txt', 'w') as f:
for i in range(len(rect_list)):
string = str(rect_list[i]).replace('{', '').replace('}', '').replace("'", '').replace('[', '').replace(
']', '').replace(',', '') + '\n'
# string = (re.sub(r"['{},]*", '', str(rect_list[i])) + '\n').replace(':', ',')
f.write(string)
print(f'“{text_str}”点阵显示效果已经保存')
os.system('pause')
if __name__ == '__main__':
text_str = input('请输入要显示的字:' + '\n')
# text_str = '安'
HZK_wei = input('请输入点阵字体的位数:(如16/24/32/40/48)' + '\n')
# HZK_wei = 48
HZK_file = input('请输入点阵字体库文件名:见font文件夹内' + '\n')
# HZK_file = 'HZK48'
show_one_string(text_str, HZK_wei, HZK_file)
不同字模对应的不同规格的点阵字体,以及不同的字体,输入时要注意对应上,若干参考见下。
执行本程序,字模文件须放置在程序中的font文件夹内
若干不足:
字模文件内包含的文字数量及字形限制了输入文字的上限,字模文件中没有包含的文字则报错。一般而言这些字模只覆盖了gb2313编码的文字,即不能输出繁体字。有一个例外,HZK16F是对应繁体输出,输入简单字直接输出繁体字。
字形如楷体、宋体、仿宋、黑体等也不是各个规格的字模文件都包含的
扩展联想:
1.如果仅是输出点阵文件当然不太好玩,搞明白了这个思路,可以尝试制作点阵字体(像素字体)。我相信市面上流通的某些像素字体也是基于这个原理来弄的。
我目前也在研究这方面,有兴趣的朋友可以参考以下几篇案例(同样是外链,如违规则删除):
ipix中文像素字体的制作
中文像素字体制作 (重点看这篇)
如何将点阵汉字矢量化
2.基于将点阵文字制作成矢量字体的思路,通过上面的方法被证明是可行的。我又找到了上古时期UCDOS7.0文件,它里面很多字模文件:
根据这个说明,这就很多玩法了,但是我确实不知道这些字模文件怎样对应把文字提取出来,请问有没有明白的大神指导一下,或提供相关的资料、思路,多谢多谢!!
涉及字模文件分享如下:
链接:https://pan.baidu.com/s/1ErOaUvxKdpwWDzjyJFL17Q
提取码:6ukk |