diff --git a/README.md b/README.md index 0ff2c51b333c2c28107358ff7808e7e2c9d2b0d2..72c07cf5fd500f087e2828bd9d2bd5e07f575ae1 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ o: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00B\x00B\x00B\x0 ...@........@... ``` -#### 使用开发板测试 +#### 使用开发板测试 1 推荐使用 [AMPY Batch Tool](https://gitee.com/walkline/a-batch-tool) (`ab`工具) 进行文件上传和调试操作 @@ -212,14 +212,17 @@ Choose a file: 1 >>> ``` -也可以使用相关软件上传如下代码到开发板,运行`fontlib.py`即可 +#### 使用开发板测试 2 + +这是把`fontlib.py`文件中非`MicroPython`代码精简掉,并编译为字节码再运行测试的方法 ```bash -drivers/ssd1306.py -client/combined.bin -fontlib.py +# 上传文件 +$ ab abconfig-mpy ``` +因为上传文件中已经包含了`main.py`,所以直接复位就可以看到效果了 + ### 关于速度 > 以当前字库文件举例: diff --git a/abconfig-mpy b/abconfig-mpy new file mode 100644 index 0000000000000000000000000000000000000000..91ece2da0b45ac45f6b585c5ce5838baa2af57fe --- /dev/null +++ b/abconfig-mpy @@ -0,0 +1,5 @@ +client/combined.bin +# client/customize.bin +drivers/ssd1306.py +libs/fontlib.mpy +main.py diff --git a/fontlib.py b/fontlib.py index 8323ff3febdd01233df9ae3c3903a900dc64a072..838543394aedd9a6497accf46aaae703fdbd74a7 100644 --- a/fontlib.py +++ b/fontlib.py @@ -100,10 +100,23 @@ class FontLib(object): elif self.__is_gb2312(unicode): gb2312_index = struct.pack('= 0: + if seek_offset % 2 == 0: + return seek_offset + else: + continue + else: + return -1 + for offset in range(self.__header.index_table_address, self.__header.ascii_start, 1000): font_file.seek(offset) - char_index_offset = font_file.read(1000).find(gb2312_index) + char_index_offset = __seek(font_file.read(1000), gb2312_index) if char_index_offset >= 0: char_index_offset += offset break diff --git a/libs/fontlib.mpy b/libs/fontlib.mpy new file mode 100644 index 0000000000000000000000000000000000000000..2090a2c1e95d51749bb5ccc9a8ec3ff8b76f2206 Binary files /dev/null and b/libs/fontlib.mpy differ diff --git a/libs/fontlib.py b/libs/fontlib.py new file mode 100644 index 0000000000000000000000000000000000000000..a5be34e86332fe37e8484cfdd65ed51a5e130644 --- /dev/null +++ b/libs/fontlib.py @@ -0,0 +1,161 @@ +""" +The MIT License (MIT) +Copyright © 2021 Walkline Wang (https://walkline.wang) +Gitee: https://gitee.com/walkline/micropython-new-fontlib +""" +import gc +import struct + + +class FontLibHeaderException(Exception): + pass + +class FontLibException(Exception): + pass + +class FontLibHeader(object): + LENGTH = 24 + + def __init__(self, header_data): + if len(header_data) != FontLibHeader.LENGTH: + raise FontLibHeaderException('Invalid header length') + + self.identify,\ + self.file_size,\ + self.font_height,\ + self.characters,\ + self.has_index_table,\ + self.scan_mode,\ + self.byte_order,\ + self.ascii_start,\ + self.gb2312_start,\ + _ = struct.unpack('<4sIBHBBBII2s', header_data) + + if self.identify not in (b'FMUX', b'FMUY'): + raise FontLibHeaderException('Invalid font file') + + self.data_size = ((self.font_height - 1) // 8 + 1) * self.font_height + + if self.has_index_table: + self.index_table_address = FontLibHeader.LENGTH + else: + self.index_table_address = 0 + + +class FontLib(object): + SCAN_MODE_HORIZONTAL = BYTE_ORDER_LSB = 0 + SCAN_MODE_VERTICAL = BYTE_ORDER_MSB = 1 + SCAN_MODE = {SCAN_MODE_HORIZONTAL: 'Horizontal', SCAN_MODE_VERTICAL: 'Vertical'} + BYTE_ORDER = {BYTE_ORDER_LSB: 'LSB', BYTE_ORDER_MSB: 'MSB'} + + def __init__(self, font_filename): + self.__font_filename = font_filename + self.__header = None + + with open(self.__font_filename, 'rb') as font_file: + self.__header = FontLibHeader(memoryview(font_file.read(FontLibHeader.LENGTH))) + self.__placeholder_buffer = self.__get_character_unicode_buffer(font_file, {ord('?')})[ord('?')] + + gc.collect() + + def __is_ascii(self, char_code): + return 0x20 <= char_code <= 0x7f + + def __is_gb2312(self, char_code): + return 0x80 <= char_code <= 0xffef + + def __get_character_unicode_buffer(self, font_file, unicode_set): + buffer_list = {} + + for unicode in unicode_set: + if self.__is_ascii(unicode): + char_offset = self.__header.ascii_start + (unicode - 0x20) * self.__header.data_size + elif self.__is_gb2312(unicode): + gb2312_index = struct.pack('= 0: + if seek_offset % 2 == 0: + return seek_offset + else: + continue + else: + return -1 + + for offset in range(self.__header.index_table_address, self.__header.ascii_start, 1000): + font_file.seek(offset) + + char_index_offset = __seek(font_file.read(1000), gb2312_index) + if char_index_offset >= 0: + char_index_offset += offset + break + else: + buffer_list[unicode] = self.__placeholder_buffer + continue + + char_offset = self.__header.gb2312_start + (char_index_offset - self.__header.index_table_address) / 2 * self.__header.data_size + else: + buffer_list[unicode] = self.__placeholder_buffer + continue + + font_file.seek(int(char_offset)) + info_data = font_file.read(self.__header.data_size) + + buffer_list[unicode] = info_data + + gc.collect() + return buffer_list + + def get_characters(self, characters: str): + with open(self.__font_filename, 'rb') as font_file: + unicode_set = set() + for char in characters: + unicode_set.add(ord(char)) + + return self.__get_character_unicode_buffer(font_file, unicode_set) + + @property + def scan_mode(self): + return self.__header.scan_mode + + @property + def byte_order(self): + return self.__header.byte_order + + @property + def data_size(self): + return self.__header.data_size + + @property + def file_size(self): + return self.__header.file_size + + @property + def font_height(self): + return self.__header.font_height + + @property + def characters(self): + return self.__header.characters + + def info(self): + print('\ +HZK Info: {}\n\ + file size : {}\n\ + font height : {}\n\ + data size : {}\n\ + scan mode : {}\n\ + byte order : {}\n\ + characters : {}\n'.format( + self.__font_filename, + self.file_size, + self.font_height, + self.data_size, + FontLib.SCAN_MODE[self.scan_mode], + FontLib.BYTE_ORDER[self.byte_order], + self.characters + )) diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..bbe664aeb959192cead15f06ac765cbb3474f274 --- /dev/null +++ b/main.py @@ -0,0 +1,179 @@ +""" +The MIT License (MIT) +Copyright © 2021 Walkline Wang (https://walkline.wang) +Gitee: https://gitee.com/walkline/micropython-new-fontlib +""" +from utime import ticks_us, ticks_diff, sleep +from machine import I2C, Pin +from drivers.ssd1306 import SSD1306_I2C +import framebuf +from libs.fontlib import FontLib + + +class FontLibTest(object): + def __init__(self, oled=None): + self.__fontlib = None + self.__buffer_format = None + self.__oled = oled + self.__oled_width = None + self.__oled_height = None + + if self.__oled: + self.__oled_width = self.__oled.width + self.__oled_height = self.__oled.height + + def load_font(self, font_file): + start_time = ticks_us() + self.__fontlib = FontLib(font_file) + print('### load font file: {} ms'.format(ticks_diff(ticks_us(), start_time) / 1000)) + self.__fontlib.info() + self.__buffer_format = self.__get_format() + + def run_test1(self, chars=None): + if self.__oled is None or chars is None: + return + + start_time = ticks_us() + buffer_dict = self.__fontlib.get_characters(chars) + diff_time = ticks_diff(ticks_us(), start_time) / 1000 + print('### get {} chars: {} ms, avg: {} ms'.format(len(chars), diff_time, diff_time / len(chars))) + + x = y = 0 + width = height = self.__fontlib.font_height + + start_time = ticks_us() + for char in chars: + if ord(char) == 10: + x = 0 + y += height + continue + + buffer = buffer_dict[ord(char)] + + if x > ((self.__oled_width // width - 1) * width): + x = 0 + y += height + + if y > ((self.__oled_height // height - 1) * height): + x = 0 + y = 0 + sleep(1.5) + self.__oled.fill(0) + self.__oled.show() + + self.__show(buffer, width, height, x, y, self.__buffer_format) + x += width + diff_time = ticks_diff(ticks_us(), start_time) / 1000 + print('### show {} chars: {} ms, avg: {} ms'.format(len(chars), diff_time, diff_time / len(chars))) + + def run_test2(self, chars=None): + if self.__oled is None or chars is None: + return + + x = y = 0 + width = height = self.__fontlib.font_height + + start_time = ticks_us() + for char in chars: + buffer_dict = self.__fontlib.get_characters(char) + + if ord(char) == 10: + x = 0 + y += height + continue + + buffer = buffer_dict[ord(char)] + + if x > ((self.__oled_width // width - 1) * width): + x = 0 + y += height + + if y > ((self.__oled_height // height - 1) * height): + x = 0 + y = 0 + sleep(1.5) + self.__oled.fill(0) + self.__oled.show() + + self.__show(buffer, width, height, x, y, self.__buffer_format) + x += width + diff_time = ticks_diff(ticks_us(), start_time) / 1000 + print('### show {} chars: {} ms, avg: {} ms'.format(len(chars), diff_time, diff_time / len(chars))) + + def run_test3(self, chars=None): + if self.__oled is None or chars is None: + return + + start_time = ticks_us() + buffer_dict = self.__fontlib.get_characters(chars) + diff_time = ticks_diff(ticks_us(), start_time) / 1000 + print('### get {} chars: {} ms, avg: {} ms'.format(len(chars), diff_time, diff_time / len(chars))) + + x = y = 0 + width = height = self.__fontlib.font_height + + for char in chars: + if ord(char) == 10: + x = 0 + y += height + continue + + buffer = buffer_dict[ord(char)] + + if x > ((self.__oled_width // width - 1) * width): + x = 0 + y += height + + if y > ((self.__oled_height // height - 1) * height): + self.__oled.show() + sleep(3) + self.__oled.fill(0) + self.__oled.show() + x = y = 0 + + self.__show(buffer, width, height, x, y, self.__buffer_format, False) + x += width + + self.__oled.show() + + def __get_format(self): + format = framebuf.MONO_VLSB + + if self.__fontlib.scan_mode == FontLib.SCAN_MODE_HORIZONTAL: + format = framebuf.MONO_HMSB if self.__fontlib.byte_order == FontLib.BYTE_ORDER_MSB else framebuf.MONO_HLSB + + return format + + def __show(self, buffer, width, height, x, y, format, show=True): + fb = framebuf.FrameBuffer(bytearray(buffer), width, height, format) + oled.blit(fb, x, y) + if show: oled.show() + + +chars =\ +'''  问题,到底应该如何实现。 +  既然如此,我们都知道,只要有意义,那么就必须慎重考虑。 +  现在,解决问题的问题,是非常非常重要的。 +  所以,在这种困难的抉择下,本人思来想去,寝食难安。 +  要想清楚,问题,到底是一种怎么样的存在。 +  一般来说,生活中,若问题出现了,我们就不得不考虑它出现了的事实。 +  维龙曾经说过,要成功不需要什么特别的才能,只要把你能做的小事做得好就行了。 +  这似乎解答了我的疑惑。 +  这种事实对本人来说意义重大,相信对这个世界也是有一定意义的。 +''' +chars2 = '几凡也习丰井无勿正轧占田它地因网乔乒仿次军她巡寿找批走抗扭估体伯饮即妙到贤忠咏使周兔泡陕' + + +if __name__ == '__main__': + i2c = I2C(0, scl=Pin(18), sda=Pin(19)) + slave_list = i2c.scan() + + if slave_list: + oled = SSD1306_I2C(128, 64, i2c) + + runner = FontLibTest(oled) + runner.load_font('client/combined.bin') + + runner.run_test1(chars) # 一次性读取所有字符数据然后逐个显示 + # runner.run_test2(chars) # 一次读取并显示一个字符数据 + # runner.run_test3(chars) # 一次读取一屏并显示