def __init__(self, file=None, shareTables=False, **kwargs):
		fonts = self.fonts = []
		if file is None:
			return

		assert 'fontNumber' not in kwargs, kwargs

		closeStream = False
		if not hasattr(file, "read"):
			file = open(file, "rb")
			closeStream = True

		tableCache = {} if shareTables else None

		header = readTTCHeader(file)
		for i in range(header.numFonts):
			font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
			fonts.append(font)

		# don't close file if lazy=True, as the TTFont hold a reference to the original
		# file; the file will be closed once the TTFonts are closed in the
		# TTCollection.close(). We still want to close the file if lazy is None or
		# False, because in that case the TTFont no longer need the original file
		# and we want to avoid 'ResourceWarning: unclosed file'.
		if not kwargs.get("lazy") and closeStream:
			file.close()
    def __init__(self, file=None, shareTables=False, **kwargs):
        fonts = self.fonts = []
        if file is None:
            return

        assert 'fontNumber' not in kwargs, kwargs

        if not hasattr(file, "read"):
            file = open(file, "rb")

        tableCache = {} if shareTables else None

        header = readTTCHeader(file)
        for i in range(header.numFonts):
            font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
            fonts.append(font)
示例#3
0
def numFontsTTC(fontPath: PathLike):
    from fontTools.ttLib.sfnt import readTTCHeader
    with open(fontPath, "rb") as f:
        header = readTTCHeader(f)
    return header.numFonts
示例#4
0
def dir_font_info(
    fonts_dir: str = "",
    info_file_dir: str = "font_info",
    info_filename: str = "font_info.json",
):

    available_font_extension_set: set = [
        ".ttf",
        ".ttc",
        ".otf",
        ".woff",
        ".woff2",
    ]

    if not fonts_dir:
        if os.name != "nt":
            raise OSError("only available in Windows")
        windows_fonts_dir: str = os.path.join(os.environ["SystemRoot"],
                                              "Fonts")
        fonts_dir = windows_fonts_dir

    FONTTOOLS_NAME_ID_FAMILY = 1
    FONTTOOLS_NAME_ID_NAME = 4
    FONTTOOLS_PLATFORM_ID_WINDOWS = 3
    LCID_EN = 1033

    update_font_info_bool: bool = True

    info_file_dir = os.path.abspath(info_file_dir)

    if not os.path.isdir(info_file_dir):
        os.makedirs(info_file_dir)

    info_filepath: str = os.path.join(info_file_dir, info_filename)

    font_info_dict: dict = dict(font_info_list=[])
    if os.path.isfile(info_filepath):
        font_info_dict = load_config(info_filepath)

    all_font_filename_list: list = [
        filename for filename in os.listdir(fonts_dir)
        if any(filename.lower().endswith(ext)
               for ext in available_font_extension_set)
    ]
    all_font_filepath_list: list = [
        os.path.join(fonts_dir, filename)
        for filename in all_font_filename_list
    ]

    info_existed_font_filepath_set: set = set(
        single_font_info_dict["filepath"]
        for single_font_info_dict in font_info_dict["font_info_list"])

    if set(all_font_filepath_list) == info_existed_font_filepath_set:
        update_font_info_bool = False

    if update_font_info_bool:
        font_info_dict = dict(font_info_list=[])
        for font_path in all_font_filepath_list:
            font_num: int = 1

            with open(font_path, "rb") as file:
                font_sfnt_version: str = ""

                file.seek(0)
                font_sfnt_version = file.read(4)
                file.seek(0)

                if font_sfnt_version == b"ttcf":
                    header = readTTCHeader(file)
                    font_num = header.numFonts

                    file.seek(header.offsetTable[0])
                    data = file.read(sfntDirectorySize)
                    if len(data) != sfntDirectorySize:
                        font_error_warning_str: str = (
                            f"{font_path} is Not a Font Collection "
                            "(not enough data), skip.")
                        g_logger.log(logging.WARNING, font_error_warning_str)
                        warnings.warn(font_error_warning_str, RuntimeWarning)
                        continue
                    data_dict: dict = sstruct.unpack(sfntDirectoryFormat, data)
                    font_sfnt_version = data_dict["sfntVersion"]
                elif font_sfnt_version == b"wOFF":
                    font_num = 1

                    data = file.read(woffDirectorySize)
                    if len(data) != woffDirectorySize:
                        font_error_warning_str: str = (
                            f"{font_path} is Not a WOFF font "
                            "(not enough data), skip.")
                        g_logger.log(logging.WARNING, font_error_warning_str)
                        warnings.warn(font_error_warning_str, RuntimeWarning)
                        continue
                    data_dict: dict = sstruct.unpack(woffDirectoryFormat, data)
                    font_sfnt_version = data_dict["sfntVersion"]
                else:
                    font_num = 1

                    data = file.read(sfntDirectorySize)
                    if len(data) != sfntDirectorySize:
                        font_error_warning_str: str = (
                            f"{font_path} is Not a TrueType or OpenType font "
                            "(not enough data), skip.")
                        g_logger.log(logging.WARNING, font_error_warning_str)
                        warnings.warn(font_error_warning_str, RuntimeWarning)
                        continue
                    data_dict: dict = sstruct.unpack(sfntDirectoryFormat, data)
                    font_sfnt_version = data_dict["sfntVersion"]

                font_sfnt_version_tag = Tag(font_sfnt_version)

                if font_sfnt_version_tag not in (
                        "\x00\x01\x00\x00",
                        "OTTO",
                        "true",
                ):
                    print(font_sfnt_version)
                    print(font_sfnt_version_tag)
                    font_error_warning_str: str = (
                        f"{font_path} is Not a TrueType or OpenType font "
                        "(bad sfntVersion), skip.")
                    g_logger.log(logging.WARNING, font_error_warning_str)
                    warnings.warn(font_error_warning_str, RuntimeWarning)
                    continue

            for font_num_index in range(font_num):
                tt_font = ttLib.TTFont(font_path, fontNumber=font_num_index)
                family_list: list = []
                for name_record in tt_font["name"].names:
                    if (name_record.nameID == FONTTOOLS_NAME_ID_FAMILY
                            and name_record.platformID
                            == FONTTOOLS_PLATFORM_ID_WINDOWS):
                        record_str: str = ""
                        try:
                            record_str = name_record.toStr()
                        except UnicodeDecodeError:
                            encoding: str = chardet.detect(
                                name_record.string)["encoding"]
                            if encoding:
                                record_str = name_record.string.decode(
                                    encoding)
                            else:
                                continue
                        family_list.append(record_str)

                family_list = list(set(family_list))

                single_font_info_dict: dict = dict(
                    filepath=font_path,
                    family_list=family_list,
                    index=font_num_index,
                    file_font_num=font_num,
                )
                font_info_dict["font_info_list"].append(single_font_info_dict)

        save_config(info_filepath, font_info_dict)
    return font_info_dict["font_info_list"]