要在单片机内自由显示文字,必须准备相应的字库。之前也发文介绍过:
在esp32(esp8266) 提供软字库显示中文的解决方案_esp32中文字库-CSDN博客
包括已经开源的项目:
https://github.com/StarCompute/tftziku
这种字体获取思路是:把GB2312字符集输出到一块画布上,然后获取画布的像素点,依照像素点的值解析成0或者1。单片机的输出类似如下:
对于字符的显示基本没有问题,但是如果你仔细看就会察觉到这里面有瑕疵:
“2”显示不完整,3的显示不标准。
造成这一问题的原因是因为字符被输出到画布的时候都会边缘模糊,每个像素都是RGB的,哪怕我们使用的字体颜色是纯黑black也同样有这个问题,所以在实际生成这个字库的时候使用了某个值来判断,例如:
if dotpix[0] > 90 and dotpix[1] > 90 and dotpix[2] > 90:
# img.getpixel()
ss += " 1"
chars += "1"
else:
ss += " "
chars += "0"
上面的dotpix是dotpix = img.getpixel((d, i)) 从画布获取的对应像素点,dotpix是个RGB的像素点,这个90是一遍一遍尝试过后相对最优的取值。
这个判断值如果给的太大,字库会存在残缺,反之出现严重的粘连,笔画越密集的地方越容易出问题。
这个问题困扰了好久,尝试过各种方案都无法解决,你们从网上能找到的字符像素化很多都是HZK16这种宋体16号的字库,如果要使用其他楷体,雅黑等等以及不同字号的时候就无解了。
哥有强迫症,隔一段时间就尝试找一下方案,各种调整参数,反正各种折腾下来这个时间跨度有一年以上了,直到今天又看了一下,还是不行,然后深入了一下:
im = Image.new('RGB', (256, 256), (0, 0, 0))
在这个Image对象的new方法中深入了一下,看到了
im = Image()
if mode == "P" and isinstance(color, (list, tuple)) and len(color) in [3, 4]:
# RGB or RGBA value for a P image
from . import ImagePalette
im.palette = ImagePalette.ImagePalette()
color = im.palette.getcolor(color)
这个mode,除了RGB和RGBA外居然还有一个P,虽然不懂这个P到底是干啥的,但是大胆尝试了一下:
im = Image.new('P', (256, 256), (0, 0, 0))
这一改就发现之前的dotpix = img.getpixel((d, i)) 工作不正常,以前是个RGB的像素点,现在居然这个像素点直接返回了0或者1,我靠,一下就猜测可能这次对了。
以前是:
dotpix = img.getpixel((d, i))
if dotpix[0] > 90 and dotpix[1] > 90 and dotpix[2] > 90:
# img.getpixel()
ss += " 1"
chars += "1"
else:
ss += " "
chars += "0"
现在是:
dotpix = img.getpixel((d, i))
chars+=str(dotpix)
验证如下:
111
1 1
1 1
1
1
1
1
11111
对比一下像素方式生产的结果:
1 1 1
1 1
1 1
1
1
1
1 1 1 1
最后重新生成的字库显示如下:
这个就是完全正常的,和PCtoLCD2018的输出是一模一样的 。
两种不同模式生成的字放大很多倍后进行对比:
前面是RGB模式,后面是P模式,简单的看就是一个锯齿的问题,其实并不是这么简单,因为这其实又涉及到两种图的基本构成,所以并不是简单的锯齿化这个问题。
详细代码就不贴出来了,了解了原理怎么都可以写出代码来。