打开字体取模软件PCtoLCD2002.exe,选项进行如下设置:
然后在下方打入需要取的汉字,点击生成字模,生成字模,存储字模的txt文件。
使用如下python代码, 将生成字模转换为字库的.h文件
txt与python文件放在同一目录下
# 说明:
# 每次生成字库的字数限制: 100及以内
# 取模字高/宽限制: 3-256
# 取模字高宽比任意
import codecs
import os
import chardet
# 获取文件编码类型
def get_encoding(file):
# 二进制方式读取,获取字节数据,检测类型
with open(file, 'rb') as f:
return chardet.detect(f.read())['encoding']
# 删除列表多余元素
def remove_list_items(list_name):
while ' ' in list_name:
list_name.remove(' ')
while '\n' in list_name:
list_name.remove('\n')
while '(' in list_name:
list_name.remove('(')
while ')' in list_name:
list_name.remove(')')
# 获取每个汉字所用的行数
def recognize_line_nums(file_list_name):
lines_num_of_index = file_list_name.index('\n')
for a in range(lines_num_of_index, len(file_list_name)):
if list(file_list_name[a + 1])[-2] == '/':
return a - lines_num_of_index + 1
break
# 获取需转换的文件
def get_file_path():
dir_list = os.listdir('./')
txt_list = []
for a in dir_list:
if a[-4:] == '.txt':
txt_list.append(a)
for b in txt_list:
print(txt_list.index(b) + 1, '\t', b)
choice = int(input('Choose file to generate.'))
path = f'./{txt_list[choice - 1]}'
return path
file_path = get_file_path()
font_height = int(input('Font Height:'))
font_width = int(input('Font Width:'))
# ANSI文件转UTF-8
if not get_encoding(file_path) == 'utf-8':
f = codecs.open(file_path, 'r', 'ansi').read()
os.remove(file_path) # 删除文件
new_file = codecs.open(file_path, 'w', 'utf-8')
new_file.write(f)
with open(file_path, 'r', encoding='utf-8') as f1:
f1_list = list(f1)
lines_num_of_index = f1_list.index('\n')
character_num = 0
index_list = []
for line in range(lines_num_of_index):
index_list += list(f1_list[line]) # 索引拼接成一个列表
remove_list_items(index_list) # 删除多余元素,方便计算
with open('./Font.h', 'w', encoding='utf-8') as f2:
f2.write('#include \n\n' )
lines_of_each_character = recognize_line_nums(f1_list)
if not lines_of_each_character == 1:
for i in range(lines_num_of_index + 1, len(f1_list) - 2, lines_of_each_character):
if character_num < 10:
f2.write(f'const unsigned char hz_{character_num} PROGMEM[] = \n')
character_num += 1
line_first_list = list(f1_list[i])
line_first_list[-2] = ','
line_first_str = ''.join(line_first_list)
f2.write(line_first_str)
i += 1
if lines_of_each_character > 2:
for each_line in range(lines_of_each_character - 2):
line_list = list(f1_list[i])
line_list[0] = ''
line_list[-2] = ','
line_str = ''.join(line_list)
f2.write(line_str)
i += 1
line2_list = list(f1_list[i])
line2_list[0] = ''
line2_list[-11] = '};'
line2_str = ''.join(line2_list)
f2.write(line2_str)
f2.write('\n')
elif 10 <= character_num < 100:
f2.write(f'const unsigned char hz_{character_num} PROGMEM[] = \n')
character_num += 1
line_first_list = list(f1_list[i])
line_first_list[-2] = ','
line_first_str = ''.join(line_first_list)
f2.write(line_first_str)
i += 1
if lines_of_each_character > 2:
for each_line in range(lines_of_each_character - 2):
line_list = list(f1_list[i])
line_list[0] = ''
line_list[-2] = ','
line_str = ''.join(line_list)
f2.write(line_str)
i += 1
line2_list = list(f1_list[i])
line2_list[0] = ''
line2_list[-12] = '};'
line2_str = ''.join(line2_list)
f2.write(line2_str)
f2.write('\n')
if lines_of_each_character == 1:
for i in range(lines_num_of_index + 1, len(f1_list) - 1, lines_of_each_character):
if character_num < 10:
f2.write(f'const unsigned char hz_{character_num} PROGMEM[] = \n')
character_num += 1
line_list = list(f1_list[i])
line_list[-11] = '};'
line_str = ''.join(line_list)
f2.write(line_str)
f2.write('\n')
elif 10 <= character_num < 100:
f2.write(f'const unsigned char hz_{character_num} PROGMEM[] = \n')
character_num += 1
line_list = list(f1_list[i])
line_list[-12] = '};'
line_str = ''.join(line_list)
f2.write(line_str)
f2.write('\n')
f2.write('\n\n')
f2.write('struct FNT_HZ // 汉字字模数据结构\n{\n')
f2.write('\tchar Index[4]; ')
f2.write('// 汉字内码索引,存放内码,如"中",在UTF-8编码下,每个汉字占3个字节,第四个是结束符0\n')
f2.write('\tconst unsigned char* hz_Id; // 点阵码数据 存放内码后对应的 点阵序列 每个字需要32个字节的点阵序列\n')
f2.write('\tunsigned char hz_heitht;\n')
f2.write('\tunsigned char hz_width;\n};')
f2.write('\n\n\n')
f2.write('PROGMEM const FNT_HZ hanzi[] =\n{\n')
if len(index_list) <= 20:
for j in range(int(len(index_list) / 2)):
# print(index_list[j * 2], index_list[j * 2 + 1])
f2.write('\t{')
f2.write(f'"{index_list[j * 2]}", hz_{index_list[j * 2 + 1]}, {font_height}, {font_width}')
f2.write('},\n')
if 20 < len(index_list) <= 290:
for j in range(10):
# print(index_list[j * 2], index_list[j * 2 + 1])
f2.write('\t{')
f2.write(f'"{index_list[j * 2]}", hz_{index_list[j * 2 + 1]}, {font_height}, {font_width}')
f2.write('},\n')
for j in range(10, int((len(index_list) - 20) / 3) + 10):
# print(index_list[(j - 10) * 3 + 20], index_list[(j - 10) * 3 + 21] + index_list[(j - 10) * 3 + 22])
f2.write('\t{')
f2.write(f'"{index_list[(j - 10) * 3 + 20]}", ')
f2.write(f'hz_{index_list[(j - 10) * 3 + 21] + index_list[(j - 10) * 3 + 22]}, {font_height}, {font_width}')
f2.write('},\n')
f2.write('};')
with open('./Function.h', 'w', encoding='utf-8') as f3:
f3.write('/*******************单个汉字显示****************/\n')
f3.write('void showMyFont(int32_t x, int32_t y, const char c[3], uint32_t color) {\n')
f3.write(f'\tfor (int k = 0; k < {character_num}; k++)// 根据字库的字数调节循环的次数\n')
f3.write('\t\tif (hanzi[k].Index[0] == c[0] && hanzi[k].Index[1] == c[1] && hanzi[k].Index[2] == c[2]) {\n')
f3.write('\t\t\ttft.drawBitmap(x, y, hanzi[k].hz_Id, hanzi[k].hz_width, hanzi[k].hz_heitht, color);')
f3.write('\n\t}\n}')
代码将生成Font.h与Function.h两个文件
Function.h中的函数可以在TFT屏幕上显示单个汉字
/*******************单个汉字显示****************/
void showMyFont(int32_t x, int32_t y, const char c[3], uint32_t color) {
for (int k = 0; k < 8; k++)// 根据字库的字数调节循环的次数
if (hanzi[k].Index[0] == c[0] && hanzi[k].Index[1] == c[1] && hanzi[k].Index[2] == c[2]) {
tft.drawBitmap(x, y, hanzi[k].hz_Id, hanzi[k].hz_width, hanzi[k].hz_heitht, color);
}
}
以下函数显示多个汉字
/*******************整句汉字显示****************/
//显示整句汉字,字库比较简单,上下、左右输出是在函数内实现
//参数说明:
//x,y显示位置 str为输入字符串 mode 0为水平,1为竖直 enable_auto_change_line自动换行
void showMyFonts(int32_t x, int32_t y, const char str[], uint32_t color, char mode, bool enable_auto_change_line) {
int x0 = x;
int y0 = y;
if (mode == 0) {
for (int i = 0; i < strlen(str); i += 3) {
if (enable_auto_change_line) {
if (x0 + hanzi[0].hz_width >= TFT_WIDTH) {
x0 = 0;
y0 = y0 + hanzi[0].hz_heitht;
}
}
showMyFont(x0, y0, str + i, color);
x0 += hanzi[0].hz_width;
}
}
if (mode == 1) {
for (int i = 0; i < strlen(str); i += 3) {
if (enable_auto_change_line) {
if (y0 + hanzi[0].hz_heitht >= TFT_HEIGHT) {
y0 = 0;
x0 = x0 + hanzi[0].hz_width;
}
}
showMyFont(x0, y0, str + i, color);
y0 += hanzi[0].hz_heitht;
}
}
}