evuefonttool.py 5.49 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
#
#  FreeType high-level python API - Copyright 2011-2015 Nicolas P. Rougier
#  Distributed under the terms of the new BSD license.
#
# -----------------------------------------------------------------------------
'''
Glyph bitmap monochrome rendering
'''
import json
import struct
import sys
import pprint
from pathlib import Path
import mimetypes
from freetype import Face

class EvueFontTool(object):
    FONT_DPI = 100

    def __init__(self, freetypefile, output_dir, sizes=[10,20,30]):
        super().__init__()
        self.freetypefile = freetypefile
        self.sizes = sizes
        self.face = Face(self.freetypefile)
        self.infos = []
        self.output_dir = Path(output_dir)
        if not self.output_dir.exists():
            self.output_dir.mkdir()
            # raise Exception("{} not exists".format(output_dir))

    @property
    def fontInfo(self):
        return {
            'family': str(self.face.family_name, 'utf-8'),
            'style': str(self.face.style_name, 'utf-8'),
            'charmaps': [charmap.encoding_name for charmap in self.face.charmaps],
            'face_number': self.face.num_faces,
            'glyph_number': self.face.num_glyphs,
            'available_sizes': list(map(lambda x: { 'width': x.width, 'height': x.height, 'size': x.size }, self.face.available_sizes)),
            'units_per_em': self.face.units_per_EM,
            'ascender': self.face.ascender,
            'descender': self.face.descender,
            'height': self.face.height,
            'max_advance_width': self.face.max_advance_width,
            'max_advance_height': self.face.max_advance_height,
            'underline_position': self.face.underline_position,
            'underline_thickness': self.face.underline_thickness,
            'has_horizontal': self.face.has_horizontal,
            'has_vertical': self.face.has_vertical,
            'has_kerning': self.face.has_kerning,
            'is_fixed_width': self.face.is_fixed_width,
            'is_scalable': self.face.is_scalable
        }

    def charInfo(self, cur_char):
        self.face.load_char(cur_char)
        char_info = {
            'glyph': ord(cur_char),
            'left': self.face.glyph.bitmap_left,
            'top': self.face.glyph.bitmap_top,
            'advance': self.face.glyph.advance.x / 64,
            'cols': self.face.glyph.bitmap.width,
            'rows': self.face.glyph.bitmap.rows,
            'count': len(self.face.glyph.bitmap.buffer),
        }
69
        return char_info, self.face.glyph.bitmap.buffer
70 71 72 73 74 75 76

    def dump(self, used_string):
        # 遍历每一个字体
        dump_json = {
            'name': self.fontInfo.get("family"),
            'info': self.fontInfo,
            'text': used_string,
77
            'charInfo': {},
78 79 80 81 82 83 84 85 86 87
            'size': self.sizes,
            'bitmap': {
                'total': 0
            }
        }
        for cur_char in used_string:
            # 遍历每一个字体设定的大小值
            for size in self.sizes:
                # 设置字体大小
                self.face.set_char_size(size * 64, 0, self.FONT_DPI, 0)
88
                char_info, bitmap = self.charInfo(cur_char)
89
                self.infos.append(char_info)
90 91 92 93 94 95 96

                size_key = str(size)
                if size_key not in dump_json['charInfo']:
                    dump_json['charInfo'][size_key] = {}
                else:
                    dump_json['charInfo'][size_key].update({str(char_info.get('glyph')): char_info})

97 98 99 100 101 102
                # 文件命名规则:./<output_dir>/<font-size>/<unicode-number>.bin
                target_dir = self.output_dir.joinpath(str(size)).joinpath("{}.bin".format(char_info.get('glyph')))
                if not target_dir.parent.exists():
                    target_dir.parent.mkdir()

                with open(target_dir.resolve().as_posix(), 'wb+') as f:
103
                    f.write(struct.pack("%dB" % char_info['count'], *bitmap))
104 105 106 107 108 109 110 111 112 113 114 115

                dump_json['bitmap'].update({
                    size: dump_json.get('bitmap').get(size, 0) + target_dir.stat().st_size
                })

        for key in dump_json['bitmap']:
            if key != 'total':
                dump_json['bitmap']['total'] += dump_json['bitmap'][key]

        pprint.pprint(dump_json)
        # 在输出目录下,生成一个json索引文件
        with open(self.output_dir.joinpath("fonts.json").resolve().as_posix(), "wb+") as f:
116
            f.write(json.dumps(dump_json, ensure_ascii=False).encode('utf-8'))
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

    def load(self, file):
        pass

    def show(self, info):
        import numpy
        import matplotlib.pyplot as plt
        data = info['bitmap']
        rows = info['rows']
        width = info['cols']
        # for i in range(rows):
        #     data.extend(bitmap.buffer[i*pitch:i*pitch+width])
        Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width)
        plt.imshow(Z, interpolation='nearest', cmap=plt.cm.gray)
        plt.show()
    
    def test(self, used_string):
        for cur_char in used_string:
            char_info = self.charInfo(cur_char)
            self.infos.append(char_info)
            self.show(char_info)


if __name__ == '__main__':
141
    # print(mimetypes.guess_type(sys.argv[1])[0])
142
    evueFontTool = EvueFontTool(sys.argv[1], sys.argv[2])
143
    text = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890中国'
144 145 146
    # evueFontTool.test(text)
    evueFontTool.dump(text)
    pprint.pprint(evueFontTool.fontInfo)