예제 #1
0
    def __init__(self, family, name):

        self.family = family
        self.name = name

        self.style_scheme = kit.constants.STYLES_ITF
        self.vertical_metrics_strategy = "ITF"

        current_year = datetime.date.today().year
        if self.family.initial_release_year:
            self.release_year_range = str(self.family.initial_release_year)
            if current_year > self.family.initial_release_year:
                self.release_year_range += "-{}".format(str(current_year))
        else:
            self.release_year_range = str(current_year)

        self.tables = {}
        self.tables["name"] = {
            0:
            kit.fallback(
                self.family.info.copyright,
                "Copyright {} Indian Type Foundry. All rights reserved.".
                format(self.release_year_range),
            ),
            7:
            "{} is a trademark of the Indian Type Foundry.".format(
                self.family.trademark),
            8:
            "Indian Type Foundry",
            9:
            self.family.info.openTypeNameDesigner,
            10:
            self.family.info.openTypeNameDescription,
            11:
            "https://indiantypefoundry.com",
            12:
            self.family.info.openTypeNameDesignerURL,
            13:
            "This Font Software is protected under domestic and international trademark and copyright law. You agree to identify the ITF fonts by name and credit the ITF's ownership of the trademarks and copyrights in any design or production credits.",
            14:
            "https://indiantypefoundry.com/licensing",
            19:
            self.family.script.sample_text,
        }
        self.tables["OS/2"] = {
            "fsType": kit.fallback(self.family.info.openTypeOS2Type, 0),
            "Panose": "0 0 0 0 0 0 0 0 0 0",
            "Vendor": "ITFO",
        }

        self.override()
예제 #2
0
    def __init__(
        self,
        trademark=None,
        name_script_independent=None,
        script_name="Latin",
        append_script_name=False,
        name=None,
        client_name=None,
        source_tag=None,
        initial_release_year=None,
    ):

        self.trademark = trademark
        self.name_script_independent = kit.fallback(name_script_independent,
                                                    self.trademark)
        self.script = kit.constants.SCRIPT_NAMES_TO_SCRIPTS.get(script_name)
        if name:
            self.name = name
        else:
            self.name = self.name_script_independent
            if script_name and append_script_name:
                self.name += " " + script_name
        self.name_postscript = kit.remove_illegal_chars_for_postscript_name_part(
            self.name)

        self.masters = None
        self.styles = None

        self.info = kit.patched.defcon.Font().info

        self.client_name = client_name
        self.source_tag = source_tag
        self.initial_release_year = initial_release_year
예제 #3
0
def client_override(self):
    if self.name == "Google Fonts":
        self.tables["name"].update({
            0:
            hindkit.fallback(
                self.family.info.copyright,
                "Copyright {} Struckby ([email protected])".format(
                    self.release_year_range),
            ),
            7:
            None,
            8:
            "Struckby",
            9:
            "Saumya Kishore and Sanchit Sawaria",
            11:
            "https://struckby.co",
            13:
            "This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL",
            14:
            "http://scripts.sil.org/OFL",
        })
        self.tables["OS/2"].update({
            "Vendor": None,
        })
예제 #4
0
 def __init__(
     self,
     name,
     abbr,
     tags,
     aliases=None,
     sample_text=None,
     is_indic=False,
     unicode_range_bits=None,
 ):
     self.name = name
     self.abbr = abbr
     self.tags = tags
     self.aliases = kit.fallback(aliases, [])
     self.sample_text = sample_text
     self.is_indic = is_indic
     self.unicode_range_bits = kit.fallback(unicode_range_bits, [])
예제 #5
0
 def bases_alive(self):
     return kit.fallback(
         self._bases_alive,
         [
             self.font[i]
             for i in self.font.groups.get(self.CLASS_NAME_BASES_ALIVE, [])
             if ".mU" not in i
         ],
     )
예제 #6
0
    def __init__(
        self,
        name,
        file_format=None,
        abstract_directory=None,
        project=None,
        family=None,
        extra_filenames=None,
    ):

        self.name = name
        self.file_format = file_format

        if project and family is None:
            self.project = project
            self.family = self.project.family
        else:
            self.project = project
            self.family = family

        if abstract_directory is None and self.project:
            self.abstract_directory = kit.Project.directories["sources"]
        else:
            self.abstract_directory = abstract_directory

        if self.family and self.family.source_tag:
            self.abstract_directory_variant = os.path.join(
                self.abstract_directory, self.family.source_tag)
            if os.path.exists(self.abstract_directory_variant):
                self.abstract_directory = self.abstract_directory_variant

        self.extra_filenames = kit.fallback(extra_filenames,
                                            self._extra_filenames)
        self.file_group = []
        for filename in self.extra_filenames[0] + [self.name
                                                   ] + self.extra_filenames[1]:
            if filename == self.name:
                self.file_group.append(self)
            else:
                f = kit.BaseFile(
                    filename,
                    file_format=self.file_format,
                    abstract_directory=self.abstract_directory,
                    family=self.family,
                )
                self.file_group.append(f)

        self.counter = 0

        self._filename = None
        self._extension = None
        self._filename_with_extension = None
        self._directory = None
        self._path = None
예제 #7
0
    def generate(self):

        lines = []

        if self.project.options["prepare_mark_positioning"]:

            f = kit.filters
            glyph_classes = [
                (WriteFeaturesMarkFDK.kCombMarksClassName, f.marks, None),
            ]
            if self.project.options["match_mI_variants"]:
                m = FeatureMatches
                glyph_classes.extend([
                    (m.CLASS_NAME_mI_VARIANTS, f.mI_variants, None),
                    (m.CLASS_NAME_BASES_ALIVE, f.bases_alive,
                     m.BASE_NAMES_ALIVE),
                    (m.CLASS_NAME_BASES_FOR_LONG_mII, f.bases_for_long_mII,
                     m.BASE_NAMES_FOR_LONG_mII),
                ])
                if self.project.options["match_mI_variants"] > 1:
                    glyph_classes.extend([
                        (m.CLASS_NAME_BASES_DEAD, f.bases_dead,
                         m.BASE_NAMES_DEAD),
                    ])

            font_0 = self.project.products[0].style.open()

            glyph_order = self.project.glyph_data.glyph_order
            for class_name, filter_function, overriding in glyph_classes:
                glyph_names = kit.fallback(
                    overriding,
                    [
                        i.name for i in font_0
                        if filter_function(self.project.family, i)
                    ],
                )
                glyph_names = self.sort_names(glyph_names, glyph_order)
                if glyph_names:
                    font_0.groups.update({class_name: glyph_names})
                lines.extend(
                    self.compose_glyph_class_def_lines(class_name,
                                                       glyph_names))
            font_0.save()

            for style in (i.style for i in self.project.products[1:]):
                font = style.open()
                font.groups.update(font_0.groups)
                font.save()

        if lines:
            with open(self.get_path(), "w") as f:
                f.writelines(i + "\n" for i in lines)
예제 #8
0
 def override(self):
     if self.name == "Google Fonts":
         self.style_scheme = kit.constants.STYLES_ITF_CamelCase
         self.vertical_metrics_strategy = "Google Fonts"
         self.tables["name"].update({
             0: kit.fallback(
                 self.family.info.copyright,
                 "Copyright {} Indian Type Foundry ([email protected])".format(self.release_year_range),
             ),
             7: None,
             13: "This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL",
             14: "http://scripts.sil.org/OFL",
         })
예제 #9
0
 def set_styles(self, scheme=None):
     scheme = kit.fallback(scheme, self.get_client_data().style_scheme)
     self.styles = [
         kit.Style(self, name, location, weight_and_width_class)
         for name, location, weight_and_width_class in scheme
     ]
     if self.masters is None:
         self.masters = []
     for master in self.masters:
         for style in self.styles:
             if style.location == master.location:
                 style.master = master
                 break
예제 #10
0
 def __init__(self, project, name=None, style=None):
     if style:
         abstract_directory = style.abstract_directory
     else:
         abstract_directory = kit.Project.directories["features"]
     super(BaseFeature, self).__init__(
         name=kit.fallback(name, self._name),
         file_format="FEA",
         project=project,
         extra_filenames=self._extra_filenames,
         abstract_directory=abstract_directory,
     )
     self.style = style
예제 #11
0
 def filename(self):
     return kit.fallback(self._filename, self.full_name_postscript)
예제 #12
0
 def filename(self):
     return kit.fallback(self._filename, self.name)
예제 #13
0
 def set_masters(self, scheme=None):
     scheme = kit.fallback(scheme, [("Light", 0), ("Bold", 100)])
     self.masters = [
         kit.Master(self, name, location) for name, location in scheme
     ]
예제 #14
0
 def full_name_postscript(self):
     return kit.fallback(
         self._full_name_postscript,
         self.family.name_postscript + "-" + self.name_postscript,
     )
예제 #15
0
 def extension(self):
     return kit.fallback(
         self._extension,
         self.file_format.lower() if self.file_format else None,
     )
예제 #16
0
 def filename_with_extension(self):
     return kit.fallback(
         self._filename_with_extension,
         self.filename + (("." + self.extension) if self.extension else ""),
     )
예제 #17
0
 def full_name(self):
     return kit.fallback(self._full_name, self.family.name + " " + self.name)
예제 #18
0
    def _finalize_options(self):

        parser = argparse.ArgumentParser(
            description=
            "execute `AFDKOPython build.py` to run stages as specified in build.py, or append arguments to override."
        )
        parser.add_argument(
            "--test",
            action="store_true",
            help="run a minimum and fast build process.",
        )
        parser.add_argument(
            "--stages",
            action="store",
            help=
            '"1" for "prepare_masters", "2" for "prepare_styles", "3" for "prepare_features", and "4" for "compile".',
        )
        parser.add_argument(
            "--options",
            action="store",
            help=
            '"0" for none, "1" for "makeinstances", "2" for "checkoutlines", and "3" for "autohint".',
        )
        self.args = parser.parse_args()

        if self.args.stages:
            stages = str(self.args.stages)
            self.options["prepare_masters"] = "1" in stages
            self.options["prepare_styles"] = "2" in stages
            self.options["prepare_features"] = "3" in stages
            self.options["compile"] = "4" in stages
        if self.args.options:
            options = str(self.args.options)
            self.options["run_makeinstances"] = "1" in options
            self.options["run_checkoutlines"] = "2" in options
            self.options["run_autohint"] = "3" in options
        if self.args.test:
            self.options["run_makeinstances"] = False
            self.options["run_checkoutlines"] = False
            self.options["run_autohint"] = False
            self.options["build_ttf"] = False

        styles = self.family.styles
        if self.family.masters:
            if not self.options["run_makeinstances"]:
                styles = [i for i in self.family.styles if i.master]
        else:
            self.options["prepare_masters"] = False
            self.options["run_makeinstances"] = False

        if not styles:
            self.options["prepare_styles"] = False

        self.products = [i.produce(self, file_format="OTF") for i in styles]
        if self.options["build_ttf"]:
            self.products.extend(
                i.produce(self, file_format="TTF", subsidiary=True)
                for i in styles)

        if not self.products:
            self.options["compile"] = False

        for product in self.products:
            directory_parts = [
                "TEST" if self.args.test else None,
                self.family.name_postscript,
                self.fontrevision,
                self.target_tag,
                product.file_format,
            ]
            product.abstract_directory = os.path.join(
                product.abstract_directory,
                "-".join([_f for _f in directory_parts if _f]),
            )

        if self.options["match_mI_variants"]:
            self.abbrs_of_scripts_to_match_mI_variants = [
                kit.constants.SCRIPT_NAMES_TO_SCRIPTS[i].abbr
                for i in kit.fallback(
                    self.options["match_mI_variants_for_scripts"],
                    [self.family.script.name],
                )
            ]
            if len(self.abbrs_of_scripts_to_match_mI_variants) == 1:
                self.script_abbr_current = self.abbrs_of_scripts_to_match_mI_variants[
                    0]
            else:
                raise NotImplementedError(
                    "[NOT IMPLEMENTED] Can't match mI variants for more than one script."
                )
예제 #19
0
 def get_directory(self, temp=True):
     directory = self.abstract_directory
     if temp:
         directory = kit.Project.temp(directory)
     return kit.fallback(self._directory, directory)
예제 #20
0
 def filename(self):
     return kit.fallback(self._filename, "font")
예제 #21
0
    def import_from_font(
        self,
        source_path,
        target_path = None,
        import_glyphs = True,
        glyph_names_included = None,
        glyph_names_excluded = None,
        glyph_renaming_map = None,
        import_anchors = False,
        import_kerning = False,
        import_blue_zones = False,
        import_x_and_cap_heights = False,
    ):

        g_names_included = kit.fallback(glyph_names_included, [])
        g_names_excluded = kit.fallback(glyph_names_excluded, [])
        g_names_included = set(g_names_included)
        g_names_excluded = set(g_names_excluded)

        if glyph_renaming_map is not None:
            self.glyph_renaming_map.update(glyph_renaming_map)

        if import_glyphs and source_path.endswith((".ufo", ".vfb")):
            source_file = BaseFont(
                family = self.family,
                abstract_directory = kit.Project.directories["misc"],
                file_format = source_path[-3:].upper(),
            )
            source_file._path = source_path
            source_font = source_file.open()
        elif import_kerning and source_path.endswith(".fea"):
            kern_fea_reader = getKerningPairsFromFEA.FEAKernReader([source_path])
            source_font = kit.patched.defcon.Font()
            source_font.groups.update(kern_fea_reader.kernClasses)
            kern_classes_reversed = {tuple(v): k for k, v in kern_fea_reader.kernClasses.items()}
            if len(kern_fea_reader.kernClasses) != len(kern_classes_reversed):
                raise SystemExit()
            for enum, (left, right), value in reversed(kern_fea_reader.foundKerningPairs):
                pair = []
                for side in left, right:
                    parts = side.split()
                    if tuple(parts) in kern_classes_reversed:
                        parts = [kern_classes_reversed[tuple(parts)]]
                    pair.append(parts)
                pairs = list(itertools.product(*pair))
                for pair in pairs:
                    source_font.kerning[pair] = int(value)
        else:
            raise SystemExit("The format of {} is not supported.".format(source_path))

        if target_path:
            self._path = target_path
        target_font = self.open()

        if import_blue_zones:

            source_blue_values = source_font.info.postscriptBlueValues
            source_other_blues = source_font.info.postscriptOtherBlues
            target_blue_values = target_font.info.postscriptBlueValues
            target_other_blues = target_font.info.postscriptOtherBlues

            blue_values = [min(source_blue_values[0], target_blue_values[0]), 0]
            blue_values.extend(source_blue_values[2:4] + target_blue_values[2:4] + source_blue_values[6:10])
            other_blues = source_other_blues

            target_font.info.postscriptBlueValues = blue_values
            target_font.info.postscriptOtherBlues = other_blues
            print(source_other_blues, source_blue_values)
            print(target_other_blues, target_blue_values)
            print(other_blues, blue_values)

        if import_x_and_cap_heights:
            self.x_height = source_font.info.xHeight
            self.cap_height = source_font.info.capHeight

        if g_names_included:
            g_names_importing = g_names_included
        else:
            g_names_importing = set(source_font.keys())

        g_names_importing_renamed = {
            self.glyph_renaming_map.get(i, i) for i in g_names_importing
        }

        if import_glyphs and g_names_importing:
            print("\n[NOTE] Importing glyphs from `{}` to `{}`:".format(source_path, self.name))
            if g_names_excluded:
                g_names_importing.difference_update(g_names_excluded)
                print("Excluding: {}".format(", ".join(g_names_excluded)))
            g_names_importing_renamed
            g_names_already_existing = g_names_importing_renamed.intersection(set(target_font.keys()))
            if g_names_already_existing:
                g_names_importing.difference_update(g_names_already_existing)
                print("Already existing; will not overwrite: {}".format(", ".join(g_names_already_existing)))
            g_names_importing = (
                [i for i in source_font.glyphOrder if i in g_names_importing] +
                [i for i in g_names_importing if i not in source_font.glyphOrder]
            )
            for source_g_name in g_names_importing:
                source_g = source_font[source_g_name]
                if not import_anchors:
                    source_g.clearAnchors()
                for component in source_g.components:
                    if component.baseGlyph not in g_names_importing:
                        source_g.decomposeComponent(component)
                        print("(decomposed {} in {})".format(component.baseGlyph, source_g_name), end=" ")
                target_g_name = self.glyph_renaming_map.get(source_g_name, source_g_name)
                target_font.newGlyph(target_g_name)
                target_g = target_font[target_g_name]
                target_g.copyDataFromGlyph(source_g)
                if target_g_name == source_g_name:
                    print(target_g_name, end=", ")
                else:
                    print("{} -> {}".format(source_g_name, target_g_name), end=", ")
            print()

        # TODO: Component reference and glyph group reference both need to be updated.

        if import_kerning and source_font.kerning:
            target_font.groups.update(source_font.groups)
            target_font.kerning.update(source_font.kerning)
            print("\n[NOTE] Imported kerning.")
예제 #22
0
 def get_path(self, temp=True):
     return kit.fallback(
         self._path,
         os.path.join(self.get_directory(temp=temp),
                      self.filename_with_extension),
     )
예제 #23
0
 def bases_dead(self):
     return kit.fallback(self._bases_dead, [
         self.font[i]
         for i in self.font.groups.get(self.CLASS_NAME_BASES_DEAD, [])
     ])
예제 #24
0
 def style_linking_family_name(self):
     return kit.fallback(self._style_linking_family_name, self.full_name)
예제 #25
0
    def __init__(
        self,
        family,
        target_tag=None,
        release_commit=None,  # (65535, 999)
        fontrevision="1.000",
        options={},
    ):

        self.family = family
        self.family.project = self

        self.target_tag = kit.fallback(target_tag, self.family.source_tag)

        if release_commit:
            release, commit = release_commit
            self.version = Version(release, commit, 1)
            self.version_last = Version(None, None, None)
            version_record_path = kit.relative_to_cwd("version{}.txt".format(
                "-" + self.target_tag if self.target_tag else ""))
            try:
                with open(version_record_path, "r") as f:
                    for line in f.read().splitlines():
                        k, _, v = line.partition(" ")
                        setattr(self.version_last, k, int(v))
            except IOError as e:
                if e.errno == errno.ENOENT:
                    pass
                else:
                    raise
            if (self.version.release,
                    self.version.commit) == (self.version_last.release,
                                             self.version_last.commit):
                self.version.build = self.version_last.build + 1
            with open(version_record_path, "w") as f:
                for k in ["release", "commit", "build"]:
                    f.write("{} {}\n".format(k, getattr(self.version, k)))
            self.fontrevision = "{}.{}".format(
                self.version.release,
                str(self.version.commit).zfill(3),
            )
            self.version_string = "{}b{}".format(
                self.fontrevision,
                self.version.build,
            )
        else:
            self.version = None
            self.version_last = None
            self.fontrevision = fontrevision
            self.version_string = None

        # (light_min, light_max), (bold_min, bold_max)
        self.adjustment_for_matching_mI_variants = None

        self.abbrs_of_scripts_to_match_mI_variants = []
        self.script_abbr_current = None

        self.options = {
            "prepare_masters": True,
            "prepare_styles": True,
            "prepare_features": True,
            "compile": True,
            "prepare_kerning": False,
            "prepare_mark_positioning": False,
            "prepare_mark_to_mark_positioning": True,
            "match_mI_variants": 0,
            "match_mI_variants_for_scripts": None,
            "position_marks_for_mI_variants": False,
            "run_makeinstances": True,
            "do_normalize": True,
            "run_checkoutlines": True,
            "run_autohint": False,
            "build_ttf": False,
            "override_GDEF": True,
            "override_x_and_cap_heights": False,
            "do_style_linking": False,
            "use_mac_name_records": False,
            "use_os_2_version_4": False,
            "prefer_typo_metrics": False,
            "is_width_weight_slope_only": False,
            "additional_unicode_range_bits": [],
            "additional_code_pages": [],
        }

        self.options.update(options)

        self.glyph_data = kit.GlyphData()

        self.designspace = kit.DesignSpace(self)
        self.fmndb = kit.Fmndb(self)

        self._finalize_options()
예제 #26
0
 def name_postscript(self):
     return kit.fallback(self._name_postscript, kit.remove_illegal_chars_for_postscript_name_part(self.name))