pull/28/head
Peter Hinch 2019-09-09 12:01:37 +01:00
rodzic 229ec1ba4b
commit 8f818db3c6
1 zmienionych plików z 35 dodań i 35 usunięć

Wyświetl plik

@ -260,29 +260,29 @@ class Font(dict):
def __init__(self, filename, size, minchar, maxchar, monospaced, defchar, charset): def __init__(self, filename, size, minchar, maxchar, monospaced, defchar, charset):
super().__init__() super().__init__()
self._face = freetype.Face(filename) self._face = freetype.Face(filename)
self.minchar = minchar # .crange is the inclusive range of ordinal values spanning the character set.
self.maxchar = maxchar self.crange = range(minchar, maxchar + 1)
self.monospaced = monospaced self.monospaced = monospaced
self.defchar = defchar self.defchar = defchar
# .def_charset is requested charset or '' if -c was not specified
self.def_charset = charset
# .charset has all defined characters with '' for those in range but undefined. # .charset has all defined characters with '' for those in range but undefined.
# Sort order is increasing ordinal value of the character whether defined or not. # Sort order is increasing ordinal value of the character whether defined or not,
# except that item 0 is the default char.
if defchar is None: # Binary font if defchar is None: # Binary font
self.charset = [chr(char) for char in range(minchar, maxchar + 1)] self.charset = [chr(ordv) for ordv in self.crange]
elif charset == '': elif charset == '':
self.charset = [chr(defchar)] + [chr(char) for char in range(minchar, maxchar + 1)] self.charset = [chr(defchar)] + [chr(ordv) for ordv in self.crange]
else: else:
n = sorted([ord(x) for x in chr(defchar) + charset]) cl = [ord(x) for x in chr(defchar) + charset]
self.minchar = n[0] self.crange = range(min(cl), max(cl) + 1) # Inclusive ordinal value range
self.maxchar = n[-1] cs = [chr(ordv) if chr(ordv) in charset else '' for ordv in self.crange]
self.charset = [chr(defchar)] + [chr(ordch) if chr(ordch) in charset else '' for ordch in range(n[0], n[-1] + 1)] # .charset has an item for all chars in range. '' if unsupported.
# .pop_charset has only the defined characters # item 0 is the default char. Subsequent chars are in increasing ordinal value.
self.pop_charset = [c for c in self.charset if c] self.charset = [chr(defchar)] + cs
# Populate self with defined chars only
self.update(dict.fromkeys([c for c in self.charset if c]))
self.max_width = self.get_dimensions(size) self.max_width = self.get_dimensions(size)
self.width = self.max_width if monospaced else 0 self.width = self.max_width if monospaced else 0
for char in self.pop_charset: # Populate dictionary self._assign_values() # Assign values to existing keys
self._render_char(char)
# n-pass solution to setting a precise height. # n-pass solution to setting a precise height.
def get_dimensions(self, required_height): def get_dimensions(self, required_height):
@ -297,7 +297,7 @@ class Font(dict):
# and update the overall dimensions of the resulting bitmap. # and update the overall dimensions of the resulting bitmap.
max_width = 0 max_width = 0
max_ascent = 0 max_ascent = 0
for char in self.pop_charset: for char in self.keys():
glyph = self._glyph_for_character(char) glyph = self._glyph_for_character(char)
max_ascent = max(max_ascent, glyph.ascent) max_ascent = max(max_ascent, glyph.ascent)
max_descent = max(max_descent, glyph.descent) max_descent = max(max_descent, glyph.descent)
@ -324,8 +324,8 @@ class Font(dict):
freetype.FT_LOAD_TARGET_MONO) freetype.FT_LOAD_TARGET_MONO)
return Glyph.from_glyphslot(self._face.glyph) return Glyph.from_glyphslot(self._face.glyph)
def _render_char(self, char): def _assign_values(self):
if char: for char in self.keys():
glyph = self._glyph_for_character(char) glyph = self._glyph_for_character(char)
char_width = int(max(glyph.width, glyph.advance_width)) # Actual width char_width = int(max(glyph.width, glyph.advance_width)) # Actual width
width = self.width if self.width else char_width # Space required if monospaced width = self.width if self.width else char_width # Space required if monospaced
@ -360,7 +360,7 @@ class Font(dict):
# Charset includes default char and both max and min chars, hence +2. # Charset includes default char and both max and min chars, hence +2.
if len(self.charset) <= MAXCHAR - MINCHAR + 2: if len(self.charset) <= MAXCHAR - MINCHAR + 2:
# Build normal index. Efficient for ASCII set and smaller as # Build normal index. Efficient for ASCII set and smaller as
# entries are 2 bytes. # entries are 2 bytes (-> data[0] for absent glyph)
for char in self.charset: for char in self.charset:
if char == '': if char == '':
index += bytearray((0, 0)) index += bytearray((0, 0))
@ -370,8 +370,9 @@ class Font(dict):
index += (len(data)).to_bytes(2, byteorder='little') # End index += (len(data)).to_bytes(2, byteorder='little') # End
else: else:
# Sparse index. Entries are 4 bytes but only populated if the char # Sparse index. Entries are 4 bytes but only populated if the char
# is in the charset. # has a defined glyph.
for char in [c for c in self.charset if c]: append_data(data, self.charset[0]) # data[0] is the default char
for char in sorted(self.keys()):
sparse += ord(char).to_bytes(2, byteorder='little') sparse += ord(char).to_bytes(2, byteorder='little')
sparse += (len(data)).to_bytes(2, byteorder='little') # Start sparse += (len(data)).to_bytes(2, byteorder='little') # Start
append_data(data, char) append_data(data, char)
@ -439,6 +440,14 @@ STR02V ="""
""" """
# Extra code emitted where -i is specified.
STR03 = '''
def glyphs():
for c in """{}""":
yield c, get_ch(c)
'''
def write_func(stream, name, arg): def write_func(stream, name, arg):
stream.write('def {}():\n return {}\n\n'.format(name, arg)) stream.write('def {}():\n return {}\n\n'.format(name, arg))
@ -450,26 +459,17 @@ def write_font(op_path, font_path, height, monospaced, hmap, reverse, minchar, m
return False return False
try: try:
with open(op_path, 'w', encoding='utf-8') as stream: with open(op_path, 'w', encoding='utf-8') as stream:
write_data(stream, fnt, font_path, hmap, reverse, iterate) write_data(stream, fnt, font_path, hmap, reverse, iterate, charset)
except OSError: except OSError:
print("Can't open", op_path, 'for writing') print("Can't open", op_path, 'for writing')
return False return False
return True return True
# Extra code emitted where -i is specified. def write_data(stream, fnt, font_path, hmap, reverse, iterate, charset):
STR03 = '''
def glyphs():
for c in """{}""":
yield c, get_ch(c)
'''
def write_data(stream, fnt, font_path, hmap, reverse, iterate):
height = fnt.height # Actual height, not target height height = fnt.height # Actual height, not target height
minchar = fnt.minchar minchar = min(fnt.crange)
maxchar = fnt.maxchar maxchar = max(fnt.crange)
defchar = fnt.defchar defchar = fnt.defchar
charset = fnt.def_charset
st = '' if charset == '' else ' Char set: {}'.format(charset) st = '' if charset == '' else ' Char set: {}'.format(charset)
cl = ' '.join(sys.argv) cl = ' '.join(sys.argv)
stream.write(STR01.format(os.path.split(font_path)[1], st, cl)) stream.write(STR01.format(os.path.split(font_path)[1], st, cl))
@ -481,7 +481,7 @@ def write_data(stream, fnt, font_path, hmap, reverse, iterate):
write_func(stream, 'min_ch', minchar) write_func(stream, 'min_ch', minchar)
write_func(stream, 'max_ch', maxchar) write_func(stream, 'max_ch', maxchar)
if iterate: if iterate:
stream.write(STR03.format(''.join(fnt.pop_charset))) stream.write(STR03.format(''.join(sorted(fnt.keys()))))
data, index, sparse = fnt.build_arrays(hmap, reverse) data, index, sparse = fnt.build_arrays(hmap, reverse)
bw_font = ByteWriter(stream, '_font') bw_font = ByteWriter(stream, '_font')
bw_font.odata(data) bw_font.odata(data)