added invert color option

pull/28/head
Dan Krause 2020-04-01 09:38:35 -04:00
rodzic 5975b35883
commit 59ab110796
2 zmienionych plików z 33 dodań i 25 usunięć

Wyświetl plik

@ -80,6 +80,7 @@ $ font_to_py.py -k extended FreeSans.ttf 23 my_extended_font.py
default fonts are assumed to be variable pitch. default fonts are assumed to be variable pitch.
* -x or --xmap Specifies horizontal mapping (default is vertical). * -x or --xmap Specifies horizontal mapping (default is vertical).
* -r or --reverse Specifies bit reversal in each font byte. * -r or --reverse Specifies bit reversal in each font byte.
* -t or --invert Inverts the font color (white text on black background)
* -s or --smallest Ordinal value of smallest character to be stored. Default * -s or --smallest Ordinal value of smallest character to be stored. Default
32 (ASCII space). 32 (ASCII space).
* -l or --largest Ordinal value of largest character to be stored. Default 126. * -l or --largest Ordinal value of largest character to be stored. Default 126.
@ -90,7 +91,7 @@ $ font_to_py.py -k extended FreeSans.ttf 23 my_extended_font.py
set. See below. set. See below.
* -k or --charset_file Obtain the character set from a file. Typical use is * -k or --charset_file Obtain the character set from a file. Typical use is
for alternative character sets such as Cyrillic: the file must contain the for alternative character sets such as Cyrillic: the file must contain the
character set to be included. An example file is `cyrillic`. Another is character set to be included. An example file is `cyrillic`. Another is
`extended` which adds unicode characters `°μπωϕθαβγδλΩ` to those in the `extended` which adds unicode characters `°μπωϕθαβγδλΩ` to those in the
original ASCII set of printable characters. At risk of stating the obvious original ASCII set of printable characters. At risk of stating the obvious
this will only produce useful results if the source font file includes all this will only produce useful results if the source font file includes all

Wyświetl plik

@ -126,7 +126,7 @@ class Bitmap(object):
dstpixel += row_offset dstpixel += row_offset
# Horizontal mapping generator function # Horizontal mapping generator function
def get_hbyte(self, reverse): def get_hbyte(self, reverse, invert):
for row in range(self.height): for row in range(self.height):
col = 0 col = 0
while True: while True:
@ -142,11 +142,14 @@ class Bitmap(object):
# Normal map MSB of byte 0 is (0, 0) # Normal map MSB of byte 0 is (0, 0)
byte |= self.pixels[row * self.width + col] << (7 - bit) byte |= self.pixels[row * self.width + col] << (7 - bit)
if bit == 7: if bit == 7:
yield byte if invert:
yield 0xFF - byte
else:
yield byte
col += 1 col += 1
# Vertical mapping # Vertical mapping
def get_vbyte(self, reverse): def get_vbyte(self, reverse, invert):
for col in range(self.width): for col in range(self.width):
row = 0 row = 0
while True: while True:
@ -162,7 +165,10 @@ class Bitmap(object):
# Normal map MSB of byte 0 is (0, 7) # Normal map MSB of byte 0 is (0, 7)
byte |= self.pixels[row * self.width + col] << bit byte |= self.pixels[row * self.width + col] << bit
if bit == 7: if bit == 7:
yield byte if invert:
yield 0xFF - byte
else:
yield byte
row += 1 row += 1
@ -332,7 +338,7 @@ class Font(dict):
for char in self.keys(): for char in self.keys():
glyph = self._glyph_for_character(char) glyph = self._glyph_for_character(char)
# https://github.com/peterhinch/micropython-font-to-py/issues/21 # https://github.com/peterhinch/micropython-font-to-py/issues/21
# Handle negative glyph.left correctly (capital J), # Handle negative glyph.left correctly (capital J),
# also glyph.width > advance (capital K and R). # also glyph.width > advance (capital K and R).
if glyph.left >= 0: if glyph.left >= 0:
char_width = int(max(glyph.advance_width, glyph.width + glyph.left)) char_width = int(max(glyph.advance_width, glyph.width + glyph.left))
@ -350,22 +356,22 @@ class Font(dict):
outbuffer.bitblt(glyph.bitmap, row, left) outbuffer.bitblt(glyph.bitmap, row, left)
self[char] = [outbuffer, width, char_width] self[char] = [outbuffer, width, char_width]
def stream_char(self, char, hmap, reverse): def stream_char(self, char, hmap, reverse, invert):
outbuffer, _, _ = self[char] outbuffer, _, _ = self[char]
if hmap: if hmap:
gen = outbuffer.get_hbyte(reverse) gen = outbuffer.get_hbyte(reverse, invert)
else: else:
gen = outbuffer.get_vbyte(reverse) gen = outbuffer.get_vbyte(reverse, invert)
yield from gen yield from gen
def build_arrays(self, hmap, reverse): def build_arrays(self, hmap, reverse, invert):
data = bytearray() data = bytearray()
index = bytearray() index = bytearray()
sparse = bytearray() sparse = bytearray()
def append_data(data, char): def append_data(data, char):
width = self[char][1] width = self[char][1]
data += (width).to_bytes(2, byteorder='little') data += (width).to_bytes(2, byteorder='little')
data += bytearray(self.stream_char(char, hmap, reverse)) data += bytearray(self.stream_char(char, hmap, reverse, invert))
# self.charset is contiguous with chars having ordinal values in the # self.charset is contiguous with chars having ordinal values in the
# inclusive range specified. Where the specified character set has gaps # inclusive range specified. Where the specified character set has gaps
@ -391,12 +397,12 @@ class Font(dict):
append_data(data, char) append_data(data, char)
return data, index, sparse return data, index, sparse
def build_binary_array(self, hmap, reverse, sig): def build_binary_array(self, hmap, reverse, invert, sig):
data = bytearray((0x3f + sig, 0xe7, self.max_width, self.height)) data = bytearray((0x3f + sig, 0xe7, self.max_width, self.height))
for char in self.charset: for char in self.charset:
width = self[char][2] width = self[char][2]
data += bytes((width,)) data += bytes((width,))
data += bytearray(self.stream_char(char, hmap, reverse)) data += bytearray(self.stream_char(char, hmap, reverse, invert))
return data return data
# PYTHON FILE WRITING # PYTHON FILE WRITING
@ -447,14 +453,14 @@ def get_ch(ch):
STR02H =""" STR02H ="""
next_offs = doff + 2 + ((width - 1)//8 + 1) * {0} next_offs = doff + 2 + ((width - 1)//8 + 1) * {0}
return _mvfont[doff + 2:next_offs], {0}, width return _mvfont[doff + 2:next_offs], {0}, width
""" """
# Code emitted for vertically mapped fonts. # Code emitted for vertically mapped fonts.
STR02V =""" STR02V ="""
next_offs = doff + 2 + (({0} - 1)//8 + 1) * width next_offs = doff + 2 + (({0} - 1)//8 + 1) * width
return _mvfont[doff + 2:next_offs], {0}, width return _mvfont[doff + 2:next_offs], {0}, width
""" """
# Extra code emitted where -i is specified. # Extra code emitted where -i is specified.
@ -468,7 +474,7 @@ def glyphs():
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))
def write_font(op_path, font_path, height, monospaced, hmap, reverse, minchar, maxchar, defchar, charset, iterate): def write_font(op_path, font_path, height, monospaced, hmap, reverse, invert, minchar, maxchar, defchar, charset, iterate):
try: try:
fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar, charset) fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar, charset)
except freetype.ft_errors.FT_Exception: except freetype.ft_errors.FT_Exception:
@ -476,13 +482,13 @@ 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, charset) write_data(stream, fnt, font_path, hmap, reverse, invert, 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
def write_data(stream, fnt, font_path, hmap, reverse, iterate, charset): def write_data(stream, fnt, font_path, hmap, reverse, invert, iterate, charset):
height = fnt.height # Actual height, not target height height = fnt.height # Actual height, not target height
minchar = min(fnt.crange) minchar = min(fnt.crange)
maxchar = max(fnt.crange) maxchar = max(fnt.crange)
@ -500,7 +506,7 @@ def write_data(stream, fnt, font_path, hmap, reverse, iterate, charset):
write_func(stream, 'max_ch', maxchar) write_func(stream, 'max_ch', maxchar)
if iterate: if iterate:
stream.write(STR03.format(''.join(sorted(fnt.keys())))) stream.write(STR03.format(''.join(sorted(fnt.keys()))))
data, index, sparse = fnt.build_arrays(hmap, reverse) data, index, sparse = fnt.build_arrays(hmap, reverse, invert)
bw_font = ByteWriter(stream, '_font') bw_font = ByteWriter(stream, '_font')
bw_font.odata(data) bw_font.odata(data)
bw_font.eot() bw_font.eot()
@ -525,7 +531,7 @@ def write_data(stream, fnt, font_path, hmap, reverse, iterate, charset):
# 1 0 0x40 0xe7 # 1 0 0x40 0xe7
# 0 1 0x41 0xe7 # 0 1 0x41 0xe7
# 1 1 0x42 0xe7 # 1 1 0x42 0xe7
def write_binary_font(op_path, font_path, height, hmap, reverse): def write_binary_font(op_path, font_path, height, hmap, reverse, invert):
try: try:
fnt = Font(font_path, height, 32, 126, True, None, '') # All chars have same width fnt = Font(font_path, height, 32, 126, True, None, '') # All chars have same width
except freetype.ft_errors.FT_Exception: except freetype.ft_errors.FT_Exception:
@ -536,7 +542,7 @@ def write_binary_font(op_path, font_path, height, hmap, reverse):
sig += 2 sig += 2
try: try:
with open(op_path, 'wb') as stream: with open(op_path, 'wb') as stream:
data = fnt.build_binary_array(hmap, reverse, sig) data = fnt.build_binary_array(hmap, reverse, invert, sig)
stream.write(data) stream.write(data)
except OSError: except OSError:
print("Can't open", op_path, 'for writing') print("Can't open", op_path, 'for writing')
@ -579,6 +585,8 @@ if __name__ == "__main__":
help='Horizontal (x) mapping') help='Horizontal (x) mapping')
parser.add_argument('-r', '--reverse', action='store_true', parser.add_argument('-r', '--reverse', action='store_true',
help='Bit reversal') help='Bit reversal')
parser.add_argument('-t', '--invert', action='store_true',
help='Invert font color (white text on black background)')
parser.add_argument('-f', '--fixed', action='store_true', parser.add_argument('-f', '--fixed', action='store_true',
help='Fixed width (monospaced) font') help='Fixed width (monospaced) font')
parser.add_argument('-b', '--binary', action='store_true', parser.add_argument('-b', '--binary', action='store_true',
@ -630,7 +638,7 @@ if __name__ == "__main__":
print('Writing binary font file.') print('Writing binary font file.')
if not write_binary_font(args.outfile, args.infile, args.height, if not write_binary_font(args.outfile, args.infile, args.height,
args.xmap, args.reverse): args.xmap, args.reverse, args.invert):
sys.exit(1) sys.exit(1)
else: else:
if not os.path.splitext(args.outfile)[1].upper() == '.PY': if not os.path.splitext(args.outfile)[1].upper() == '.PY':
@ -665,9 +673,8 @@ if __name__ == "__main__":
cset = ''.join(cs) # Back to string cset = ''.join(cs) # Back to string
print('Writing Python font file.') print('Writing Python font file.')
if not write_font(args.outfile, args.infile, args.height, args.fixed, if not write_font(args.outfile, args.infile, args.height, args.fixed,
args.xmap, args.reverse, args.smallest, args.largest, args.xmap, args.reverse, args.invert, args.smallest,
args.errchar, cset, args.iterate): args.largest, args.errchar, cset, args.iterate):
sys.exit(1) sys.exit(1)
print(args.outfile, 'written successfully.') print(args.outfile, 'written successfully.')