diff --git a/README.md b/README.md index 0bcc0c0..3a5a152 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ installed on your system: - [scipy](https://www.scipy.org) \>=0.19.0 - [freetype-py](https://github.com/rougier/freetype-py) \>=1.1 - argparse \>=1.4.0 + - [Hershey-Fonts](https://github.com/apshu/HersheyFonts) \>= 2.1.0 ### Install from Python Packaging Index @@ -75,12 +76,17 @@ installed. For Windows, follow the instructions on [this github repo](https://g - - + The library for reading Hershey Fonts comes bundled with a set of + fonts. The GUI lets you select them individually as files or all by + enabling the option "Include Default Hershey Fonts". + - Make sure you have the necessary rights to use the font. - Open a command prompt and run python3 type2nc.py or double-click the `type2nc.py` file - - Select one or more font files + - Select one or more font files and/or select the option to use the default + Hersehy fonts - create and select an output folder for the results diff --git a/setup.py b/setup.py index 2274742..f941a49 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,7 @@ install_requires=['numpy>=1.6.2', 'scipy>=0.19.0', 'freetype-py>=1.1', - 'argparse>=1.4.0'], + 'argparse>=1.4.0', + 'Hershey-Fonts>=2.1.0'], scripts=['type2nc/type2nc.py'], ) diff --git a/type2nc/locales/de/LC_MESSAGES/messages.po b/type2nc/locales/de/LC_MESSAGES/messages.po index ebb4aa0..b2ab735 100644 --- a/type2nc/locales/de/LC_MESSAGES/messages.po +++ b/type2nc/locales/de/LC_MESSAGES/messages.po @@ -17,64 +17,52 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: type2nc.py:326 type2nc.py:464 msgid "Select Font File" msgstr "Schrift-Datei" -#: type2nc.py:340 type2nc.py:479 msgid "Select Destination Folder" msgstr "Zielordner" -#: type2nc.py:354 +msgid "Include Default Hershey Fonts" +msgstr "Standart Hershey Fonts ausgeben" + msgid "Select Step Size" msgstr "Schrittweite" -#: type2nc.py:369 msgid "Create Demo Files" msgstr "Demo-Datei erstellen" -#: type2nc.py:409 msgid "Include Empty Label" msgstr "Leere LBL DEF erstellen" -#: type2nc.py:380 msgid "Generate" msgstr "Erstellen" -#: type2nc.py:397 msgid "ASCII 0x20-0x7E and Latin1 0x80-0xFF" msgstr "ASCII 0x20-0x7E und Latin1 0x80-0xFF" -#: type2nc.py:409 msgid "General Punctuation 0x2000-0x206F" msgstr "Allgemeine Satzzeichen 0x2000-0x206F" -#: type2nc.py:421 msgid "IPA Extension 0x0250-0x02AF" msgstr "IPA Extension 0x0250-0x02AF" -#: type2nc.py:433 msgid "Symbols 0x2190-0x23FF & 0x2600-0x27BF" msgstr "Symbole 0x2190-0x23FF & 0x2600-0x27BF" -#: type2nc.py:445 msgid "Lang 0x0370-0x077F & 0x4E00-0x9FFF" msgstr "Sprachen 0x0370-0x077F & 0x4E00-0x9FFF" -#: type2nc.py:472 #, python-format msgid "%d files selected" msgstr "%d Dateien ausgewählt" -#: type2nc.py:484 msgid "No folder selected" msgstr "Kein Ordner ausgewählt" -#: type2nc.py:494 msgid "Step Size" msgstr "Schrittweite" -#: type2nc.py:494 msgid "" "Step Size between 0.001 (very fine) and 0.2 (very coarse) for converting " "Splines" @@ -82,26 +70,20 @@ msgstr "" "Schrittweite zwischen 0.001 (sehr fein) and 0.2 (sehr grob) für Wandlung von " "Splines" -#: type2nc.py:497 msgid "No step size selected" msgstr "Keine Schrittweite eingegeben" -#: type2nc.py:509 type2nc.py:513 type2nc.py:517 msgid "Missing parameter" msgstr "Fehlender Parameter" -#: type2nc.py:509 msgid "No font files selected" -msgstr "Keine Schriftart asugewählt" +msgstr "Keine Schriftart ausgewählt" -#: type2nc.py:513 msgid "No output folder selected" msgstr "Kein Zielordner ausgewählt" -#: type2nc.py:563 msgid "Finished" msgstr "Fertig" -#: type2nc.py:563 msgid "Finished processing all font files" msgstr "Umwandlung aller Dateien abgeschlossen" diff --git a/type2nc/locales/en/LC_MESSAGES/messages.po b/type2nc/locales/en/LC_MESSAGES/messages.po index ac9e723..86ec06b 100644 --- a/type2nc/locales/en/LC_MESSAGES/messages.po +++ b/type2nc/locales/en/LC_MESSAGES/messages.po @@ -17,64 +17,52 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: type2nc.py:326 type2nc.py:464 msgid "Select Font File" msgstr "Select Font File" -#: type2nc.py:340 type2nc.py:479 +msgid "Include Default Hershey Fonts" +msgstr "Include Default Hershey Fonts" + msgid "Select Destination Folder" msgstr "Select Destination Folder" -#: type2nc.py:354 msgid "Select Step Size" msgstr "Select Step Size" -#: type2nc.py:369 msgid "Create Demo Files" msgstr "Create Demo Files" -#: type2nc.py:409 msgid "Include Empty Label" msgstr "Include Empty Label" -#: type2nc.py:380 msgid "Generate" msgstr "Generate" -#: type2nc.py:397 msgid "ASCII 0x20-0x7E and Latin1 0x80-0xFF" msgstr "ASCII 0x20-0x7E and Latin1 0x80-0xFF" -#: type2nc.py:409 msgid "General Punctuation 0x2000-0x206F" msgstr "General Punctuation 0x2000-0x206F" -#: type2nc.py:421 msgid "IPA Extension 0x0250-0x02AF" msgstr "IPA Extension 0x0250-0x02AF" -#: type2nc.py:433 msgid "Symbols 0x2190-0x23FF & 0x2600-0x27BF" msgstr "Symbols 0x2190-0x23FF & 0x2600-0x27BF" -#: type2nc.py:445 msgid "Lang 0x0370-0x077F & 0x4E00-0x9FFF" msgstr "Lang 0x0370-0x077F & 0x4E00-0x9FFF" -#: type2nc.py:472 #, python-format msgid "%d files selected" msgstr "%d files selected" -#: type2nc.py:484 msgid "No folder selected" msgstr "No folder selected" -#: type2nc.py:494 msgid "Step Size" msgstr "Step Size" -#: type2nc.py:494 msgid "" "Step Size between 0.001 (very fine) and 0.2 (very coarse) for converting " "Splines" @@ -82,26 +70,20 @@ msgstr "" "Step Size between 0.001 (very fine) and 0.2 (very coarse) for converting " "Splines" -#: type2nc.py:497 msgid "No step size selected" msgstr "No step size selected" -#: type2nc.py:509 type2nc.py:513 type2nc.py:517 msgid "Missing parameter" msgstr "Missing parameter" -#: type2nc.py:509 msgid "No font files selected" msgstr "No font files selected" -#: type2nc.py:513 msgid "No output folder selected" msgstr "No output folder selected" -#: type2nc.py:563 msgid "Finished" msgstr "Finished" -#: type2nc.py:563 msgid "Finished processing all font files" msgstr "Finished processing all font files" diff --git a/type2nc/type2nc.py b/type2nc/type2nc.py index e5cf0e9..03d4fab 100644 --- a/type2nc/type2nc.py +++ b/type2nc/type2nc.py @@ -13,6 +13,7 @@ import freetype import numpy as np from scipy.special import binom +from HersheyFonts import HersheyFonts class Point(): def __init__(self, x, y): @@ -63,7 +64,7 @@ def __init__(self, output_folder, target_height, step_size, unicode_numbers=None self._log.debug("using folder '%s', step size '%f'", self.__output_folder, self.__step_size) - def convert(self, font_file): + def convert_freetype(self, font_file): self._log.debug("running for font file '%s' for %d characters", font_file.resolve(strict=True), len(self.__characters)) font_face = freetype.Face(str(font_file.resolve(strict=True))) @@ -187,12 +188,71 @@ def convert(self, font_file): self._log.info("finished writing %s", nc_file_name) - def _build_char_string(self, range_list): - characters = list() - print(range_list) - for char_range in range_list: - characters.extend(char_range) - return characters + def convert_hershey(self, font_file): + hshf = HersheyFonts() + if isinstance(font_file, pathlib.Path): + self._log.debug("running for hershey font file '%s' for %d characters", font_file.resolve(strict=True), len(self.__characters)) + hshf.load_font_file(font_file) + nc_file_name = font_file.name.replace(font_file.suffix, '') + else: + self._log.debug("running for hershey default font '%s' for %d characters", font_file, len(self.__characters)) + hshf.load_default_font(font_file) + nc_file_name = font_file + + hshf.normalize_rendering(self.__target_height * 0.8) + + nc_file_name = nc_file_name.replace(' ', '_') + nc_file_path = self.__output_folder.joinpath(nc_file_name + '.H') + + scale_factor = 1.0 + + with open(nc_file_path, 'w') as ncfp: + ncfp.write("BEGIN PGM {0:s} MM\n".format(nc_file_name.upper())) + + ncfp.write(";\n; Font PGM generated by type2nc\n") + ncfp.write("; Hershey Font File: {0:s}\n".format(nc_file_name)) + ncfp.write("; Generated: {:%Y-%m-%d %H:%M:%S}\n".format(datetime.datetime.today())) + ncfp.write("; Number of characters: {0:d}\n;\n".format(len(self.__characters))) + + with open(pathlib.Path.cwd().joinpath("templates", "pgm_head_template.H")) as template_file: + ncfp.writelines(template_file) + + for char_code in self.__characters: + + count = 0 + contour_paths = list() + for glyph in hshf.glyphs_for_text(chr(char_code)): + if count > 0: + raise Exception + count += 1 + + x_advance = glyph.char_width + 1.0 + + self._log.debug("character '%s' advance X:%d", chr(char_code), x_advance) + + for stroke in glyph.strokes: + path_points = list() + for c_pair in stroke: + x_coor = c_pair[0] - glyph.left_offset + y_coor = -1 * c_pair[1] + path_points.append(Point(x=x_coor, y=y_coor)) + contour_paths.append(path_points) + self._log.debug("created %d paths for character", len(contour_paths)) + + ncfp.writelines(self._creat_font_label(chr(char_code), contour_paths, x_advance, scale_factor=scale_factor)) + + if len(contour_paths) == 0: + if self.__create_empty_labels: + self._log.debug("character '%s' was selected but is not available, add empty label", chr(char_code)) + ncfp.writelines(self._create_empty_font_label(chr(char_code), x_advance=0)) + else: + self._log.debug("character '%s' was selected but is not available, skipping", chr(char_code)) + + with open(pathlib.Path.cwd().joinpath("templates", "pgm_foot_template.H")) as template_file: + ncfp.writelines(template_file) + + ncfp.write("END PGM {0:s} MM".format(nc_file_name.upper())) + def _point_on_curve(self, point_list, distance_factor): """Get x and y coordinate for point along a bezier curve relative to @@ -337,7 +397,7 @@ def __init__(self, root): self._window_root = root root.title("Type2NC UI") width=670 - height=260 + height=300 screenwidth = root.winfo_screenwidth() screenheight = root.winfo_screenheight() alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2) @@ -365,6 +425,18 @@ def __init__(self, root): self.lbl_font_filename.place(x=200, y=current_y, width=180, height=component_height) current_y += delta_y + self.include_hershey = tk.IntVar() + self.chk_hershey = tk.Checkbutton(self._window_root) + self.chk_hershey["font"] = ft + self.chk_hershey["justify"] = "left" + self.chk_hershey["text"] = self.gt_("Include Default Hershey Fonts") + self.chk_hershey.place(x=20, y=current_y, width=180, height=component_height) + self.chk_hershey["onvalue"] = 1 + self.chk_hershey["offvalue"] = 0 + self.chk_hershey["variable"] = self.include_hershey + self.chk_hershey.deselect() + current_y += delta_y + self.btn_select_folder = tk.Button(self._window_root) self.btn_select_folder["font"] = ft self.btn_select_folder["justify"] = "center" @@ -509,7 +581,7 @@ def __init__(self, root): def btn_select_font_command(self): self._log.debug("select font button pressed") - file_types = [('Font', '*.ttf *.tte *.ttc *.otf *.dfont *.pfb')] + file_types = [('Font', '*.ttf *.tte *.ttc *.otf *.dfont *.pfb'), ('Hershey Font', '*.jhf')] font_file_list = tkfd.askopenfilename(parent=self._window_root, title=self.gt_("Select Font File"), filetypes=file_types, multiple=1) for path in font_file_list: self.selected_font_files.append(pathlib.Path(path)) @@ -551,7 +623,7 @@ def btn_select_step_command(self): def btn_generate_nc_command(self): self._log.debug("generate nc files button pressed") - if len(self.selected_font_files) == 0: + if len(self.selected_font_files) == 0 and self.include_hershey.get() == 0: tkmb.showwarning(parent=self._window_root, title=self.gt_("Missing parameter"), message=self.gt_("No font files selected")) self._log.debug("list of selected font files is empty!") return @@ -560,7 +632,7 @@ def btn_generate_nc_command(self): self._log.debug("no output path selected!") return if self.step_size is None: - tkmb.showwarning(parent=self._window_root, title=self.gt_("Missing parameter"), message=-("No step size selected")) + tkmb.showwarning(parent=self._window_root, title=self.gt_("Missing parameter"), message=self.gt_("No step size selected")) self._log.debug("no step size selected selected!") return @@ -601,9 +673,17 @@ def btn_generate_nc_command(self): conv = Type2NC(output_folder=self.output_path, target_height=10, step_size=self.step_size, unicode_numbers=character_list, create_empty_labels=include_empty) self._log.debug("start processing %d font files", len(self.selected_font_files)) + + if self.include_hershey.get() > 0: + for hershey_font in HersheyFonts().default_font_names: + conv.convert_hershey(hershey_font) + for i, ff in enumerate(self.selected_font_files): if ff.is_file(): - conv.convert(ff) + if ff.suffix.lower() in ".jhf": + conv.convert_hershey(ff) + else: + conv.convert_freetype(ff) self.pb_progress['value'] = (i + 1) * (100 / len(self.selected_font_files)) self.pb_progress.update() @@ -618,7 +698,7 @@ def btn_generate_nc_command(self): if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) + logging.basicConfig(level=logging.WARNING) logger = logging.getLogger('main') logger.debug("startup") @@ -635,11 +715,13 @@ def btn_generate_nc_command(self): if not arguments.output.is_dir(): logger.error("the output path '%s' is not a folder", arguments.output) - conv = Type2NC(output_folder=arguments.output, target_height=10, step_size=arguments.step_size) + conv = Type2NC(output_folder=arguments.output, target_height=10, step_size=arguments.step_size, create_empty_labels=arguments.create_empty_label) for ff in arguments.input: if ff.is_file(): - - conv.convert(ff) + if ff.suffix.lower() in ".jhf": + conv.convert_hershey(ff) + else: + conv.convert_freetype(ff) if arguments.create_demos: conv.generate_demo_files(arguments.input)