LCDGFX LCD display driver  1.2.0
Lightweight graphics library for SSD1306, SSD1325, SSD1327, SSD1331, SSD1351, SH1106, SH1107, IL9163, ST7735, ST7789, ILI9341, PCD8544 displays over I2C/SPI
fontgenerator.py
1 #!/usr/bin/python
2 # -*- coding: UTF-8 -*-
3 # MIT License
4 #
5 # Copyright (c) 2018-2020, Alexey Dynda
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in all
15 # copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
24 #
25 
35 
36 import re
37 import sys
38 import codecs
39 from modules import glcdsource
40 from modules import fontgenerator
41 
42 def print_help_and_exit():
43  sys.stderr.write("Usage: ttf_fonts.py [args] > outputFile\n")
44  sys.stderr.write("args:\n")
45  sys.stderr.write(" --ttf S use ttf name as source\n")
46  sys.stderr.write(" --glcd S use glcd file as as source\n")
47  sys.stderr.write(" -s <N> font size (this is not pixels!) \n")
48  sys.stderr.write(" -SB <N> limit size in pixels to value (pixels will be cut)\n")
49  sys.stderr.write(" -fh fixed height\n")
50  sys.stderr.write(" -fw fixed width\n")
51  sys.stderr.write(" -g <S> <E> [W] add chars group to the font\n")
52  sys.stderr.write(" where <S> - first char hex or binary code, or char symbol\n")
53  sys.stderr.write(" <E> - chars count minus 1 (integer), or char symbol\n")
54  sys.stderr.write(" <W> - optional exact width in pixels for this group\n")
55  sys.stderr.write(" (new format only). Narrow chars are padded and\n")
56  sys.stderr.write(" centered; wider chars are cropped. Do not mix\n")
57  sys.stderr.write(" with -fw.\n")
58  sys.stderr.write(" -f old old format 1.7.6 and below\n")
59  sys.stderr.write(" -f new new format 1.7.8 and above\n")
60  sys.stderr.write(" -d Print demo text to console\n")
61  sys.stderr.write(" -t text Use text as demo text\n")
62  sys.stderr.write(" --demo-only Prints demo text to console and exits\n")
63  sys.stderr.write(" --output-file Saves the output to a file directly\n")
64  sys.stderr.write("Examples:\n")
65  sys.stderr.write(" [convert ttf font to old format]\n")
66  sys.stderr.write(" ttf_fonts.py --ttf FreeSans.ttf -s 8 -f old > font.h\n")
67  sys.stderr.write(" [convert ttf font to new format with demo text and print to console]\n")
68  sys.stderr.write(" ttf_fonts.py --ttf FreeSans.ttf -d -f new\n")
69  sys.stderr.write(" [convert GLCD font generated file to new format]\n")
70  sys.stderr.write(" ttf_fonts.py --glcd font.c -f new > font.h\n")
71  exit(1)
72 
73 if len(sys.argv) < 2:
74  print_help_and_exit()
75 
76 fsize = 8
77 fold = False
78 flimit_bottom = 0
79 fwidth = False
80 fheight = False
81 fname = ""
82 fgroups = []
83 TTF = False
84 GLCD = False
85 demo_text = False
86 demo_text_ = "World!q01"
87 generate_font = True
88 source = None
89 output_file = None
90 
91 # parse args
92 idx = 1
93 while idx < len(sys.argv):
94  opt = sys.argv[idx]
95  if opt == "--ttf":
96  TTF = True
97  idx += 1
98  fname = sys.argv[idx]
99  elif opt == "--glcd":
100  GLCD = True
101  idx += 1
102  fname = sys.argv[idx]
103  elif opt == "-s":
104  idx += 1
105  fsize = int(sys.argv[idx])
106  elif opt == "-SB":
107  idx +=1
108  flimit_bottom = int(sys.argv[idx])
109  elif opt == "-fh":
110  fheight = True
111  elif opt == "-fw":
112  fwidth = True
113  elif opt == "-f":
114  idx += 1
115  if sys.argv[idx] == "old":
116  fold = True
117  elif opt == "-g":
118  idx += 1
119  _start_char = sys.argv[idx]
120  if re.search(r'0x\d*', _start_char) is not None:
121  code = int(_start_char, 16)
122  if sys.version_info < (3, 0):
123  _start_char = unichr(code)
124  else:
125  _start_char = chr(code)
126  elif _start_char.isdigit() and len(_start_char) > 1:
127  if sys.version_info < (3, 0):
128  _start_char = unichr(int(_start_char))
129  else:
130  _start_char = chr(int(_start_char))
131  else:
132  if sys.version_info < (3, 0):
133  _start_char = _start_char.decode("utf-8")
134  idx += 1
135  _end_char = sys.argv[idx]
136  if _end_char.isdigit():
137  char_count = int(_end_char)
138  if char_count > 255:
139  sys.stderr.write("Number of characters in single block cannot be more than 255\n")
140  exit(1)
141  if sys.version_info < (3, 0):
142  _end_char = unichr(ord(_start_char) + int(_end_char))
143  else:
144  _end_char = chr(ord(_start_char) + int(_end_char))
145  else:
146  if sys.version_info < (3, 0):
147  _end_char = _end_char.decode("utf-8")
148  if ord(_end_char) - ord(_start_char) + 1 > 255:
149  sys.stderr.write("Number of characters in single block cannot be more than 255\n")
150  exit(1)
151  # Optional per-group exact width (new format only). It is only consumed
152  # when the next token is a bare integer, so a following "-g"/other flag
153  # is never mistaken for a width.
154  _group_width = None
155  if idx + 1 < len(sys.argv) and sys.argv[idx + 1].isdigit():
156  idx += 1
157  _group_width = int(sys.argv[idx])
158  fgroups.append( (_start_char, _end_char, _group_width) )
159  elif opt == "-d":
160  demo_text = True
161  elif opt == "-t":
162  idx += 1
163  demo_text_ = sys.argv[idx]
164  elif opt == "--demo-only":
165  generate_font = False
166  demo_text = True
167  elif opt == "--output-file":
168  idx += 1
169  output_file = sys.argv[idx]
170  else:
171  sys.stderr.write("Unknown option: {0}".format(opt))
172  print_help_and_exit()
173  idx += 1
174 
175 if TTF:
176  from modules import ttfsource
177  source = ttfsource.TTFSource(fname, fsize)
178  if len(fgroups) == 0:
179  if sys.version_info < (3, 0):
180  fgroups.append((' ', unichr(127), None))
181  else:
182  fgroups.append((' ', chr(127), None))
183  for g in fgroups:
184  source.add_chars(g[0], g[1])
185  if g[2] is not None:
186  source.set_group_width(source.groups_count() - 1, g[2])
187 
188 if GLCD:
189  source = glcdsource.GLCDSource(fname, fsize, "utf8")
190 
191 if source is None:
192  print_help_and_exit()
193 
194 if fwidth:
195  source.expand_chars_h()
196 if fheight:
197  source.expand_chars_v()
198 if flimit_bottom > 0:
199  source.deflate_chars_bottom( flimit_bottom )
200 
201 font = fontgenerator.Generator( source )
202 if fold:
203  source.expand_chars()
204  demo_array = []
205  if demo_text:
206  if sys.version_info < (3, 0):
207  demo_array = source.getString(demo_text_.decode("utf-8"))
208  else:
209  demo_array = source.getString(demo_text_)
210  if generate_font:
211  font.generate_fixed_old(demo_array, output_file)
212 else:
213  demo_array = []
214  if demo_text:
215  if sys.version_info < (3, 0):
216  demo_array = source.getString(demo_text_.decode("utf-8"))
217  else:
218  demo_array = source.getString(demo_text_)
219  if generate_font:
220  font.generate_new_format(demo_array, output_file)