diff --git a/Makefile.in b/Makefile.in index 1401531a..e4a9c952 100644 --- a/Makefile.in +++ b/Makefile.in @@ -818,17 +818,17 @@ $(simsun.ttc): $(simsun.ttf) $(nsimsun.ttf) $(msgothic.ttc): $(msgothic.ttf) $(mspgothic.ttf) $(msuigothic.ttf) afdko otf2otc -o $@ $^ -$(micross.ttf): $(noto_sans.ttf) $(noto_sans_arabic.ttf) $(noto_sans_armenian.ttf) $(noto_sans_bengali.ttf) $(noto_sans_coptic.ttf) \ +$(micross.ttf): $(FONTS)/scripts/merge.py $(noto_sans.ttf) $(noto_sans_arabic.ttf) $(noto_sans_armenian.ttf) $(noto_sans_bengali.ttf) $(noto_sans_coptic.ttf) \ $(noto_sans_georgian.ttf) $(noto_sans_gujarati.ttf) $(noto_sans_hebrew.ttf) $(noto_sans_khmer.ttf) $(noto_sans_tamil.ttf) \ $(noto_sans_thaana.ttf) $(noto_sans_thai.ttf) - $(FONTFORGE) -script $(MERGEFONTSSCRIPT) $(noto_sans.ttf) $(noto_sans_arabic.ttf) $(noto_sans_armenian.ttf) $(noto_sans_bengali.ttf) \ + $(FONTS)/scripts/merge.py $(noto_sans.ttf) $(noto_sans_arabic.ttf) $(noto_sans_armenian.ttf) $(noto_sans_bengali.ttf) \ $(noto_sans_coptic.ttf) $(noto_sans_georgian.ttf) $(noto_sans_gujarati.ttf) $(noto_sans_hebrew.ttf) $(noto_sans_khmer.ttf) \ $(noto_sans_tamil.ttf) $(noto_sans_thaana.ttf) $(noto_sans_thai.ttf) "MicrosoftSansSerif" "Microsoft Sans Serif" "Regular" $(micross.ttf) -$(nirmala.ttf): $(noto_sans.ttf) $(noto_sans_bengaliui.ttf) $(noto_sans_devanagariui.ttf) $(noto_sans_gujaratiui.ttf) $(noto_sans_gurmukhiui.ttf) \ +$(nirmala.ttf): $(FONTS)/scripts/merge.py $(noto_sans.ttf) $(noto_sans_bengaliui.ttf) $(noto_sans_devanagariui.ttf) $(noto_sans_gujaratiui.ttf) $(noto_sans_gurmukhiui.ttf) \ $(noto_sans_kannadaui.ttf) $(noto_sans_malayalamui.ttf) $(noto_sans_meeteimayek.ttf) $(noto_sans_olchiki.ttf) $(noto_sans_oriyaui.ttf) \ $(noto_sans_sinhalaui.ttf) $(noto_sans_sorasompeng.ttf) $(noto_sans_tamilui.ttf) $(noto_sans_teluguui.ttf) - $(FONTFORGE) -script $(MERGEFONTSSCRIPT) $(noto_sans.ttf) $(noto_sans_bengaliui.ttf) $(noto_sans_devanagariui.ttf) $(noto_sans_gujaratiui.ttf) \ + $(FONTS)/scripts/merge.py $(noto_sans.ttf) $(noto_sans_bengaliui.ttf) $(noto_sans_devanagariui.ttf) $(noto_sans_gujaratiui.ttf) \ $(noto_sans_gurmukhiui.ttf) $(noto_sans_kannadaui.ttf) $(noto_sans_malayalamui.ttf) $(noto_sans_meeteimayek.ttf) $(noto_sans_olchiki.ttf) \ $(noto_sans_oriyaui.ttf) $(noto_sans_sinhalaui.ttf) $(noto_sans_sorasompeng.ttf) $(noto_sans_tamilui.ttf) $(noto_sans_teluguui.ttf) \ "NirmalaUI" "Nirmala UI" "Regular" $(nirmala.ttf) diff --git a/fonts/scripts/merge.py b/fonts/scripts/merge.py new file mode 100755 index 00000000..0acb77d2 --- /dev/null +++ b/fonts/scripts/merge.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python3 + +# Based on merge_noto.py and merge_fonts.py from the nototools +# (https://github.com/googlefonts/nototools), with the following +# copyright notice: + +# Copyright 2014-2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# The font name changing logic is taken from +# https://github.com/chrissimpkins/fontname.py/blob/master/fontname.py, +# with the following copyright notice: + +# Copyright 2019 Christopher Simpkins +# MIT License + +"""Merges a number of Noto fonts and then sets a given name to the +result. + +""" + +import sys +import tempfile +import os + +from fontTools import merge +from fontTools import ttLib +from fontTools.ttLib.tables import otTables + +def read_line_metrics(font): + metrics = { + "ascent": font["hhea"].ascent, + "descent": font["hhea"].descent, + "usWinAscent": font["OS/2"].usWinAscent, + "usWinDescent": font["OS/2"].usWinDescent, + "sTypoAscender": font["OS/2"].sTypoAscender, + "sTypoDescender": font["OS/2"].sTypoDescender, + "sxHeight": font["OS/2"].sxHeight, + "sCapHeight": font["OS/2"].sCapHeight, + "sTypoLineGap": font["OS/2"].sTypoLineGap, + } + return metrics + + +def set_line_metrics(font, metrics): + font["hhea"].ascent = metrics["ascent"] + font["hhea"].descent = metrics["descent"] + font["OS/2"].usWinAscent = metrics["usWinAscent"] + font["OS/2"].usWinDescent = metrics["usWinDescent"] + font["OS/2"].sTypoAscender = metrics["sTypoAscender"] + font["OS/2"].sTypoDescender = metrics["sTypoDescender"] + font["OS/2"].sxHeight = metrics["sxHeight"] + font["OS/2"].sCapHeight = metrics["sCapHeight"] + font["OS/2"].sTypoLineGap = metrics["sTypoLineGap"] + +def has_gsub_table(fontfile): + font = ttLib.TTFont(fontfile) + return "GSUB" in font + +SCRIPT_TO_OPENTYPE_SCRIPT_TAG = { + # Retrieved from Opentype 1.9 delta specs. Prerelease scripttags used out of necessity. https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags + "Carian": "cari", + "CypriotSyllabary": "cprt", + "CyproMinoan": "cpmn", + "Deseret": "dsrt", + "Glagolitic": "glag", + "EgyptianHieroglyphs": "egyp", + "ImperialAramaic": "armi", + "LinearA": "lina", + "LinearB": "linb", + "Lisu": "lisu", + "Lycian": "lyci", + "Lydian": "lydi", + "Ogham": "ogam", + "OldItalic": "ital", + "OldPersian": "xpeo", + "OldSouthArabian": "sarb", + "OldTurkic": "orkh", + "OldSogdian": "sogo", + "OldNorthArabian": "narb", + "OldHungarian": "hung", + "Osmanya": "osma", + "Phoenician": "phnx", + "SumeroAkkadianCuneiform": "xsux", + "Ugaritic": "ugar", + "OlChiki": "olck", + "TaiLe": "tale", + "Cuneiform": "xsux", + "Cypriot": "cprt", + "Runic": "runr", + "Shavian": "shaw", + "Vai": "vai ", + "Yi": "yi ", + "AnatolianHieroglyphs": "hluw", + "Bamum": "bamu", + "ByzantineMusic": "byzm", + "Gothic": "goth", + "ImperialAramaic": "armi", + "InscriptionalPahlavi": "phli", + "InscriptionalParthian": "prti", + "Khojki": "khoj", + "MathematicalAlphanumericSymbols": "math", + "MeroiticCursive": "merc", + "MeroiticHieroglyphs": "mero", + "MusicalSymbols": "musc", + "Palmyrene": "palm", + "Rejang": "rjng", + "Samaritan": "samr", + "Carian": "cari", + "Ahom": "ahom", + "Adlam": "adlm", + "Dogra": "dogr", + "Lisu": "lisu", + "Mandaean": "mand", + "Manichaean": "mani", + "Tifinagh": "tfng", + "Wancho": "wcho", + "Yezidi": "yezi", + "Cherokee": "cher", + "Chorasmian": "chrs", + "PahawhHmong": "hmng", + "Phagspa": "phag", + "Sundanese": "sund", + "WarangCiti": "wara", + "SylotiNagri": "sylo", + "PsalterPahlavi": "phlp", + "CaucasianAlbanian": "aghb", + "Medefaidrin": "medf", + "MeiteiMayek": "mtei", + "MendeKikakui": "mend", + "Mro": "mroo", + "Multani": "mult", + "Nabataean": "nbat", + "Nandinagari": "nand", + "Newa": "newa", + "NewTaiLue": "talu", + "Nushu": "nshu", + "NyiakengPuachueHmong": "hmnp", + "OldPermic": "perm", + "SoraSompeng": "sora", + "Soyombo": "soyo", + "SylotiNagri": "sylo", + "Tagbanwa": "tagb", + "Tagalog": "tglg", + "Takri": "takr", + "TaiTham": "lana", + "TaiViet": "tavt", + "Tangut": "tang", + "Thaana": "thaa", + "UgariticCuneiform": "ugar", + "ZanabazarSquare": "zanb", + "SignWriting": "sgnw", + "OldUyghur": "ougr", + "Tangsa": "tnsa", + "Toto": "toto", + "Vithkuqi": "vith", + "Duployan": "dupl", + "Hatran": "hatr", + # These last two would only merge using the long script name including the 'NotoSerif' part + "NotoSerifYezidi": "yezi", + "NotoSerifNyiakengPuachueHmong": "hmnp", +} + +def get_opentype_script_tag(fontfile): + fontfile = os.path.basename(fontfile) + if fontfile.startswith("NotoSans"): + fontfile = fontfile[8:] + fontfile = fontfile[: fontfile.index("-")] + return SCRIPT_TO_OPENTYPE_SCRIPT_TAG[fontfile] + +def add_gsub_to_font(fontfile): + """Adds an empty GSUB table to a font.""" + font = ttLib.TTFont(fontfile) + gsub_table = ttLib.getTableClass("GSUB")("GSUB") + gsub_table.table = otTables.GSUB() + gsub_table.table.Version = 1.0 + gsub_table.table.ScriptList = otTables.ScriptList() + gsub_table.table.ScriptCount = 1 + gsub_table.table.LookupList = otTables.LookupList() + gsub_table.table.LookupList.LookupCount = 0 + gsub_table.table.LookupList.Lookup = [] + gsub_table.table.FeatureList = otTables.FeatureList() + gsub_table.table.FeatureList.FeatureCount = 0 + gsub_table.table.LookupList.FeatureRecord = [] + + script_record = otTables.ScriptRecord() + script_record.ScriptTag = get_opentype_script_tag(fontfile) + script_record.Script = otTables.Script() + script_record.Script.LangSysCount = 0 + script_record.Script.LangSysRecord = [] + + default_lang_sys = otTables.DefaultLangSys() + default_lang_sys.FeatureIndex = [] + default_lang_sys.FeatureCount = 0 + default_lang_sys.LookupOrder = None + default_lang_sys.ReqFeatureIndex = 65535 + script_record.Script.DefaultLangSys = default_lang_sys + + gsub_table.table.ScriptList.ScriptRecord = [script_record] + + font["GSUB"] = gsub_table + + target_file = tempfile.gettempdir() + "/" + os.path.basename(fontfile) + font.save(target_file) + return target_file + +def main(): + output_filename = sys.argv[-1] + weight = sys.argv[-2] + font_name = sys.argv[-3] + ps_name = sys.argv[-4] + input_filenames = sys.argv[1:-4] + + # Add a GSUB table to the fonts that do not have one + for index, filename in enumerate(input_filenames): + if not has_gsub_table(filename): + input_filenames[index] = add_gsub_to_font(filename) + + # Merge the fonts together + merger = merge.Merger() + font = merger.merge(input_filenames) + + # Use the line metrics defined by the first font + metrics = read_line_metrics(ttLib.TTFont(input_filenames[0])) + set_line_metrics(font, metrics) + + # Rename the result + for record in font['name'].names: + if record.nameID == 1: + record.string = font_name + elif record.nameID == 4: + record.string = "{} {}".format(font_name, weight) + elif record.nameID == 6: + record.string = "{}-{}".format(ps_name, weight.replace(' ', '')) + + font.save(output_filename) + +if __name__ == '__main__': + main() diff --git a/fonts/scripts/mergefonts.pe b/fonts/scripts/mergefonts.pe deleted file mode 100644 index 500c7380..00000000 --- a/fonts/scripts/mergefonts.pe +++ /dev/null @@ -1,29 +0,0 @@ -if ($argc < 6) - Error ("Expected arguments - Font1, Font2, Font3, ..., FontName, FullName, FontWeight, OutputFilename") -endif - -FONTNAME = ToString($argv[$argc - 4]) -FULLNAME = ToString($argv[$argc - 3]) -FONTWEIGHT = ToString($argv[$argc - 2]) -SRCFONTNAME = ToString($argv[1]) -DESTFONTNAME = ToString($argv[$argc - 1]) - -Open(SRCFONTNAME) - -i = 2 -while (i < $argc - 4) - MergeFonts($argv[i]) - i = i + 1 -endloop - -SetFontNames(FONTNAME, FULLNAME, FULLNAME, FONTWEIGHT, "", "1.0.0") -Generate(DESTFONTNAME) -Close() - -Open(DESTFONTNAME) -Reencode("unicode") -SelectWorthOutputting() -SelectInvert() -BuildAccented() -Generate(DESTFONTNAME) -Close()