列出所有系统字体作为字典。 |蟒蛇

问题描述 投票:0回答:2

我想将所有系统字体(

c://Windows//Fonts
内)作为字典,因为我需要区分粗体和斜体等。尽管通过
os.listdir
或在终端中列出目录内容时,无法判断哪种字体是什么。 (或者至少在大多数情况下)此外,即使您想迭代所有字体,您也几乎无法判断它是“常规”字体还是变体。

因此 Windows 列出该文件夹如下:

每个“字体文件夹”看起来像(取决于它们不同的样式):

最后,这是我通过 list 命令得到的(大多数情况下不可读且无法使用):

所以这是我希望能够实现的输出(或类似的):

path = "C://Windows//Fonts"
# do some magic
dictionary = {
     'Arial':'Regular': 'Arial-Regular.ttf','Bold':'Arial-Bold.ttf',
     'Carlito:'Regular':' 8514fix.fon','Bold':'someweirdotherfile.fon'
}

到目前为止我得到的唯一的东西是裸露安装的字体名称而不是它们的文件名。 因此,如果有任何方法可以获取字典形式的内容或获取字体的文件名,请友善地给我一个提示:)

python-3.x windows dictionary fonts
2个回答
2
投票

我知道你两年前发表了这篇文章,但碰巧我编写了一段代码,可以实现你所要求的类似功能。我只花了 1.5 个月的时间进行编程(这是我在 stackoverflow 上的第一个答案),所以可能它可以在很多方面进行改进,但也许会有一些人,我会帮助编写代码或提供想法他们会怎么写。

from fontTools import ttLib
import os
from os import walk
import json

path = "C://Windows//Fonts"

fonts_path = []
for (dirpath, dirnames, filenames) in walk(fr'{path}\Windows\Fonts'):
    for i in filenames:
        if any(i.endswith(ext) for ext in ['.ttf', '.otf', '.ttc', '.ttz', '.woff', '.woff2']):
            fonts_path.append(dirpath.replace('\\\\', '\\') + '\\' + i)

def getFont(font, font_path):
    x = lambda x: font['name'].getDebugName(x)
    if x(16) is None:
        return x(1), x(2), font_path
    if x(16) is not None:
        return x(16), x(17), font_path
    else:
        pass

fonts = []

for i in range(len(fonts_path)):
        j = fonts_path[i]
        if not j.endswith('.ttc'):
            fonts.append(getFont(ttLib.TTFont(j), j))
        if j.endswith('.ttc'):
            try:
                for k in range(100):
                    fonts.append(getFont(ttLib.TTFont(j, fontNumber=k), j))
            except:
                pass

fonts_dict = {}

no_dups = []
for i in fonts:
    index_0 = i[0]
    if index_0 not in no_dups:
        no_dups.append(index_0)

for i in fonts:
    for k in no_dups:
        if i[0] == k:
            fonts_dict[k] = json.loads('{\"' + str(i[1]) + '\" : \"' + str(i[2]).split('\\')[-1] + '\"}')
            for j in fonts:
                if i[0] == j[0]:
                    fonts_dict[k][j[1]] = j[2].split('\\')[-1]

print(json.dumps(fonts_dict, indent=2))

一些示例输出(我把它弄短了,否则它会太大):

{
 "CAC Moose PL": {
    "Regular": "CAC Moose PL.otf"
  },
  "Calibri": {
    "Bold Italic": "calibriz.ttf",
    "Regular": "calibri.ttf",
    "Bold": "calibrib.ttf",
    "Italic": "calibrii.ttf",
    "Light": "calibril.ttf",
    "Light Italic": "calibrili.ttf"
  },
  "Cambria": {
    "Bold Italic": "cambriaz.ttf",
    "Regular": "cambria.ttc",
    "Bold": "cambriab.ttf",
    "Italic": "cambriai.ttf"
  },
  "Cambria Math": {
    "Regular": "cambria.ttc"
  },
  "Candara": {
    "Bold Italic": "Candaraz.ttf",
    "Regular": "Candara.ttf",
    "Bold": "Candarab.ttf",
    "Italic": "Candarai.ttf",
    "Light": "Candaral.ttf",
    "Light Italic": "Candarali.ttf"
  },
  "Capibara Mono B PL": {
    "Regular": "Capibara Mono B PL.otf"
  }
}

如果有人需要字体的完整路径,那么您唯一需要更改的是删除最后一个 for 循环中的 .split('\')[-1] ,然后输出将是这样的:

  "Arial": {
    "Black": "C:\\Windows\\Fonts\\ariblk.ttf",
    "Regular": "C:\\Windows\\Fonts\\arial.ttf",
    "Bold": "C:\\Windows\\Fonts\\arialbd.ttf",
    "Bold Italic": "C:\\Windows\\Fonts\\arialbi.ttf",
    "Italic": "C:\\Windows\\Fonts\\ariali.ttf"
  }

一些后记。 Windows 中的字体存储在两个文件夹中。一种用于全局字体(为所有用户安装)和用户特定字体。全局字体存储在“C:\Windows\Fonts”中,但用户本地字体存储在“C:\Users\username\AppData\Local\Microsoft\Windows\Fonts”中,因此请记住这一点。可以简单地通过

os.getlogin()
将用户名设为变量。

我决定忽略 .fon 字体,因为它们(对我来说)非常有问题。

一些代码解释:

fonts_path = []

for (dirpath, dirnames, filenames) in walk(fr'{path}\Windows\Fonts'):
    for i in filenames:
        if any(i.endswith(ext) for ext in ['.ttf', '.otf', '.ttc', '.ttz', '.woff', '.woff2']):
            fonts_path.append(dirpath.replace('\\\\', '\\') + '\\' + i)

仅从 Windows 的全局字体文件夹中获取 .ttf、otf、ttc、ttz、woff 和 woff2 字体,并使用所有字体路径制作列表(fonts_path)。

def getFont(font, font_path):
    x = lambda x: font['name'].getDebugName(x)
    if x(16) is None:
        return x(1), x(2), font_path
    if x(16) is not None:
        return x(16), x(17), font_path
    else:
        pass

因此,该函数基于在

ttLib.TTFont(font_path)
函数中从 fontTools 库和字体路径获得的 ttLib.TTFont 文件,检查字体的调试名称。调试名称是字体的预定义元数据,包含字体名称、字体系列等信息。您可以在此处阅读相关内容:https://learn.microsoft.com/en-us/typography/opentype/spec/name #name-ids。因此,完整字体名称的示例使用为:

NameID = 4
font = ttLib.TTFont(font_path)
font_full_name = font['name'].getDebugName(NameID)
print(font_full_name)

Example output: Candara Bold Italic

基本上我们只需要家族字体名称和字体名称。唯一的问题是,某些字体在 NameID 1 和 2 上具有

None
值,因此根据字体,值取自 NameID 1、2 或 16、17。之后,每个字体都以这种方式打包为元组:(font_family ,字体名称,字体路径)

fonts = []

for i in range(len(fonts_path)):
        j = fonts_path[i]
        if not j.endswith('.ttc'):
            fonts.append(getFont(ttLib.TTFont(j), j))
        if j.endswith('.ttc'):
            try:
                for k in range(100):
                    fonts.append(getFont(ttLib.TTFont(j, fontNumber=k), j))
            except:
                pass

.ttc 字体需要特殊处理,因为 .ttc 字体格式包含不止一种字体,所以我们必须指定我们要使用哪种字体,所以

ttLib.TTFont(font_path)
的语法还需要一个参数:
fontNumber
,所以它变成:
ttLib.TTFont(font_path, fontNumber=font_index)

之后,我们按顺序列出了完整的元组:(font_family,font_name,font_path)

no_dups = []
for i in fonts:
    index_0 = i[0]
    if index_0 not in no_dups:
        no_dups.append(index_0)

我们创建所有字体系列(存储在元组的索引 0 中)的列表(名为:no_dups),没有重复。

fonts_dict = {}

for i in fonts:
    for k in no_dups:
        if i[0] == k:
            fonts_dict[k] = json.loads('{\"' + str(i[1]) + '\" : \"' + str(i[2]).split('\\')[-1] + '\"}')
            for j in fonts:
                if i[0] == j[0]:
                    fonts_dict[k][j[1]] = j[2].split('\\')[-1]

此代码将所有字体系列创建为字典,然后以字体系列字典的值是另一个字典的方式更改值。 所以它是这样操纵的:

  1. 在列表中:

    [..., 'Cambria', ...]

  2. 每次制作具有一个值的字典:

    {...}, "Cambria": {"Bold Italic": "calibriz.ttf"}, {...}

  3. 向子词典中添加更多带有值的键:

    {...}, "Cambria": {"Bold Italic": "calibriz.ttf", "Regular": "cambria.ttc"}, {...}

它一直这样做,直到所有内容都分配给字典。

最后:

 print(json.dumps(fonts_dict, indent=2))

以格式良好的方式打印结果。

希望我能帮助别人。


0
投票

对我来说,最好的解决方案是使用 DirecWrite,它是 Windows API 来操作字体。它不涉及使用任何黑客手段来获取您需要的信息。

使用 DirectWrite 获取所需信息的方法有很多种,但这里介绍的是兼容 Windows 最高版本的方法。

依赖关系:

import json
from pathlib import Path
from comtypes import COMError, GUID, IUnknown, STDMETHOD
from ctypes import byref, create_unicode_buffer, HRESULT, POINTER, windll, wintypes
from dataclasses import asdict, dataclass
from enum import IntEnum, IntFlag
from sys import getwindowsversion
from typing import List, Set


@dataclass
class FontFace:
    file_path: List[str] # See this link to know why we need a list: https://stackoverflow.com/questions/41161152/when-can-an-idwritefontface-have-more-than-one-file
    face_name: str


@dataclass
class FontFamily:
    family_name: str
    fonts: List[FontFace]


class DWRITE_FACTORY_TYPE(IntEnum):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_factory_type
    DWRITE_FACTORY_TYPE_SHARED = 0
    DWRITE_FACTORY_TYPE_ISOLATED = 1


class DWRITE_FONT_SIMULATIONS(IntFlag):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_simulations
    DWRITE_FONT_SIMULATIONS_NONE = 0x0000
    DWRITE_FONT_SIMULATIONS_BOLD = 0x0001
    DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002


class IDWriteFontFileLoader(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontfileloader
    _iid_ = GUID("{727cad4e-d6af-4c9e-8a08-d695b11caa49}")
    _methods_ = [
        STDMETHOD(None, "CreateStreamFromKey"),  # Need to be implemented
    ]


class IDWriteLocalFontFileLoader(IDWriteFontFileLoader):
    # https://learn.microsoft.com/en-us/windows/win32/directwrite/idwritelocalfontfileloader
    _iid_ = GUID("{b2d9f3ec-c9fe-4a11-a2ec-d86208f7c0a2}")
    _methods_ = [
        STDMETHOD(HRESULT, "GetFilePathLengthFromKey", [wintypes.LPCVOID, wintypes.UINT, POINTER(wintypes.UINT)]),
        STDMETHOD(HRESULT, "GetFilePathFromKey", [wintypes.LPCVOID, wintypes.UINT, POINTER(wintypes.WCHAR), wintypes.UINT]),
        STDMETHOD(None, "GetLastWriteTimeFromKey"),  # Need to be implemented
    ]


class IDWriteFontFile(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontfile
    _iid_ = GUID("{739d886a-cef5-47dc-8769-1a8b41bebbb0}")
    _methods_ = [
        STDMETHOD(HRESULT, "GetReferenceKey", [POINTER(wintypes.LPCVOID), POINTER(wintypes.UINT)]),
        STDMETHOD(HRESULT, "GetLoader", [POINTER(POINTER(IDWriteFontFileLoader))]),
        STDMETHOD(HRESULT, "Analyze", [POINTER(wintypes.BOOL), POINTER(wintypes.UINT), POINTER(wintypes.UINT), POINTER(wintypes.UINT)]),
    ]


class IDWriteLocalizedStrings(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritelocalizedstrings
    _iid_ = GUID("{08256209-099a-4b34-b86d-c22b110e7771}")
    _methods_ = [
        STDMETHOD(wintypes.UINT, "GetCount"),
        STDMETHOD(HRESULT, "FindLocaleName", [POINTER(wintypes.WCHAR), POINTER(wintypes.UINT), POINTER(wintypes.BOOL)]),
        STDMETHOD(HRESULT, "GetLocaleNameLength", [wintypes.UINT, POINTER(wintypes.UINT)]),
        STDMETHOD(HRESULT, "GetLocaleName", [wintypes.UINT, POINTER(wintypes.WCHAR), wintypes.UINT]),
        STDMETHOD(HRESULT, "GetStringLength", [wintypes.UINT, POINTER(wintypes.UINT)]),
        STDMETHOD(HRESULT, "GetString", [wintypes.UINT, POINTER(wintypes.WCHAR), wintypes.UINT]),
    ]


class IDWriteFontFace(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontface
    _iid_ = GUID("{5f49804d-7024-4d43-bfa9-d25984f53849}")
    _methods_ = [
        STDMETHOD(None, "GetType"),  # Need to be implemented
        STDMETHOD(HRESULT, "GetFiles", [POINTER(wintypes.UINT), POINTER(POINTER(IDWriteFontFile))]),
        STDMETHOD(None, "GetIndex"),  # Need to be implemented
        STDMETHOD(None, "GetSimulations"),  # Need to be implemented
        STDMETHOD(None, "IsSymbolFont"),  # Need to be implemented
        STDMETHOD(None, "GetMetrics"),  # Need to be implemented
        STDMETHOD(None, "GetGlyphCount"),  # Need to be implemented
        STDMETHOD(None, "GetDesignGlyphMetrics"),  # Need to be implemented
        STDMETHOD(None, "GetGlyphIndices"),  # Need to be implemented
        STDMETHOD(None, "TryGetFontTable"),  # Need to be implemented
        STDMETHOD(None, "ReleaseFontTable"),  # Need to be implemented
        STDMETHOD(None, "GetGlyphRunOutline"),  # Need to be implemented
        STDMETHOD(None, "GetRecommendedRenderingMode"),  # Need to be implemented
        STDMETHOD(None, "GetGdiCompatibleMetrics"),  # Need to be implemented
        STDMETHOD(None, "GetGdiCompatibleGlyphMetrics"),  # Need to be implemented
    ]


class IDWriteFont(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefont
    _iid_ = GUID("{acd16696-8c14-4f5d-877e-fe3fc1d32737}")
    _methods_ = [
        STDMETHOD(None, "GetFontFamily"),  # Need to be implemented
        STDMETHOD(None, "GetWeight"),  # Need to be implemented
        STDMETHOD(None, "GetStretch"),  # Need to be implemented
        STDMETHOD(None, "GetStyle"),  # Need to be implemented
        STDMETHOD(None, "IsSymbolFont"),  # Need to be implemented
        STDMETHOD(HRESULT, "GetFaceNames", [POINTER(POINTER(IDWriteLocalizedStrings))]),
        STDMETHOD(None, "GetInformationalStrings"),  # Need to be implemented
        STDMETHOD(wintypes.UINT, "GetSimulations"),
        STDMETHOD(None, "GetMetrics"),  # Need to be implemented
        STDMETHOD(None, "HasCharacter"),  # Need to be implemented
        STDMETHOD(HRESULT, "CreateFontFace", [POINTER(POINTER(IDWriteFontFace))]),
    ]


class IDWriteFontList(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontlist
    _iid_ = GUID("{1a0d8438-1d97-4ec1-aef9-a2fb86ed6acb}")
    _methods_ = [
        STDMETHOD(None, "GetFontCollection"),  # Need to be implemented
        STDMETHOD(wintypes.UINT, "GetFontCount"),
        STDMETHOD(HRESULT, "GetFont", [wintypes.UINT, POINTER(POINTER(IDWriteFont))]),
    ]


class IDWriteFontFamily(IDWriteFontList):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontfamily
    _iid_ = GUID("{da20d8ef-812a-4c43-9802-62ec4abd7add}")
    _methods_ = [
        STDMETHOD(HRESULT, "GetFamilyNames", [POINTER(POINTER(IDWriteLocalizedStrings))]),
        STDMETHOD(None, "GetFirstMatchingFont"),  # Need to be implemented
        STDMETHOD(None, "GetMatchingFonts"),  # Need to be implemented
    ]


class IDWriteFontCollection(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontcollection
    _iid_ = GUID("{a84cee02-3eea-4eee-a827-87c1a02a0fcc}")
    _methods_ = [
        STDMETHOD(wintypes.UINT, "GetFontFamilyCount"),
        STDMETHOD(HRESULT, "GetFontFamily", [wintypes.UINT, POINTER(POINTER(IDWriteFontFamily))]),
        STDMETHOD(None, "FindFamilyName"),  # Need to be implemented
        STDMETHOD(None, "GetFontFromFontFace"),  # Need to be implemented
    ]


class IDWriteFactory(IUnknown):
    # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefactory
    _iid_ = GUID("{b859ee5a-d838-4b5b-a2e8-1adc7d93db48}")
    _methods_ = [
        STDMETHOD(HRESULT, "GetSystemFontCollection", [POINTER(POINTER(IDWriteFontCollection)), wintypes.BOOLEAN]),
        STDMETHOD(None, "CreateCustomFontCollection"),  # Need to be implemented
        STDMETHOD(None, "RegisterFontCollectionLoader"),  # Need to be implemented
        STDMETHOD(None, "UnregisterFontCollectionLoader"),  # Need to be implemented
        STDMETHOD(None, "CreateFontFileReference"),  # Need to be implemented
        STDMETHOD(None, "CreateCustomFontFileReference"),  # Need to be implemented
        STDMETHOD(None, "CreateFontFace"),  # Need to be implemented
        STDMETHOD(None, "CreateRenderingParams"),  # Need to be implemented
        STDMETHOD(None, "CreateMonitorRenderingParams"),  # Need to be implemented
        STDMETHOD(None, "CreateCustomRenderingParams"),  # Need to be implemented
        STDMETHOD(None, "RegisterFontFileLoader"),  # Need to be implemented
        STDMETHOD(None, "UnregisterFontFileLoader"),  # Need to be implemented
        STDMETHOD(None, "CreateTextFormat"),  # Need to be implemented
        STDMETHOD(None, "CreateTypography"),  # Need to be implemented
        STDMETHOD(None, "GetGdiInterop"),  # Need to be implemented
        STDMETHOD(None, "CreateTextLayout"),  # Need to be implemented
        STDMETHOD(None, "CreateGdiCompatibleTextLayout"),  # Need to be implemented
        STDMETHOD(None, "CreateEllipsisTrimmingSign"),  # Need to be implemented
        STDMETHOD(None, "CreateTextAnalyzer"),  # Need to be implemented
        STDMETHOD(None, "CreateNumberSubstitution"),  # Need to be implemented
        STDMETHOD(None, "CreateGlyphRunAnalysis"),  # Need to be implemented
    ]


class Kernel32:
    def __init__(self):
        kernel32 = windll.kernel32

        # https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename
        self.GetUserDefaultLocaleName = kernel32.GetUserDefaultLocaleName
        self.GetUserDefaultLocaleName.restype = wintypes.INT
        self.GetUserDefaultLocaleName.argtypes = [wintypes.LPWSTR, wintypes.INT]
        self.GetUserDefaultLocaleName.errcheck = self.errcheck_is_result_0

        self.LOCALE_NAME_MAX_LENGTH = 85


    def GetUserDefaultLocaleNameFunc(self) -> str:
        locale_buffer = create_unicode_buffer(self.LOCALE_NAME_MAX_LENGTH)
        try:
            self.GetUserDefaultLocaleName(locale_buffer, self.LOCALE_NAME_MAX_LENGTH)
        except ValueError:
            return "en-us"

        return locale_buffer.value


    @staticmethod
    def errcheck_is_result_0(result, func, args):
        if result == 0:
            raise ValueError(f"Error encountered with {func.__name__}.")
        return result


class DirectWrite:
    def __init__(self):
        dwrite = windll.dwrite

        # https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-dwritecreatefactory
        self.DWriteCreateFactory = dwrite.DWriteCreateFactory
        self.DWriteCreateFactory.restype = HRESULT
        self.DWriteCreateFactory.argtypes = [wintypes.UINT, GUID, POINTER(POINTER(IUnknown))]


    def get_str_from_localized_strings(self, localized_strings) -> str:
        # From https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritelocalizedstrings#remarks

        kernel32 = Kernel32()
        locale_name = kernel32.GetUserDefaultLocaleNameFunc()

        index = wintypes.UINT()
        exists = wintypes.BOOL()
        localized_strings.FindLocaleName(locale_name, byref(index), byref(exists))

        if not exists:
            localized_strings.FindLocaleName("en-us", byref(index), byref(exists))

        if not exists:
            index = 0

        length = wintypes.UINT()
        localized_strings.GetStringLength(index, byref(length))

        localized_strings_buffer = create_unicode_buffer(length.value + 1)
        localized_strings.GetString(index, localized_strings_buffer, len(localized_strings_buffer))

        return localized_strings_buffer.value


class WindowsVersionHelpers:
    @staticmethod
    def is_windows_version_or_greater(windows_version, major: int, minor: int, build: int) -> bool:
        """
        Parameters:
            windows_version: An object from getwindowsversion.
            major (int): The minimum major OS version number.
            minor (int): The minimum minor OS version number.
            build (int): The minimum build version number.
        Returns:
            True if the specified version matches or if it is greater than the version of the current Windows OS. Otherwise, False.
        """

        if windows_version.major > major:
            return True
        elif windows_version.major == major and windows_version.minor > minor:
            return True
        else:
            return (
                windows_version.major == major
                and windows_version.minor == minor
                and windows_version.build >= build
            )

    @staticmethod
    def is_windows_vista_sp2_or_greater(windows_version) -> bool:
        # From https://www.lifewire.com/windows-version-numbers-2625171
        return WindowsVersionHelpers.is_windows_version_or_greater(windows_version, 6, 0, 6002)


def get_system_fonts_families() -> Set[str]:
    windows_version = getwindowsversion()

    if not WindowsVersionHelpers.is_windows_vista_sp2_or_greater(windows_version):
        raise OSError("This program only works on Windows Vista SP2 or more")

    dwrite = DirectWrite()
    fonts_families: List[FontFamily] = []

    dwrite_factory = POINTER(IDWriteFactory)()
    dwrite.DWriteCreateFactory(DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_ISOLATED, IDWriteFactory._iid_, byref(dwrite_factory))

    sys_collection = POINTER(IDWriteFontCollection)()
    dwrite_factory.GetSystemFontCollection(byref(sys_collection), False)

    for i in range(sys_collection.GetFontFamilyCount()):
        family = POINTER(IDWriteFontFamily)()
        sys_collection.GetFontFamily(i, byref(family))

        family_names = POINTER(IDWriteLocalizedStrings)()
        family.GetFamilyNames(byref(family_names))
        family_names_str = dwrite.get_str_from_localized_strings(family_names)

        faces: List[FontFace] = []
        for j in range(family.GetFontCount()):
            try:
                font = POINTER(IDWriteFont)()
                family.GetFont(j, byref(font))
            except COMError:
                # If the file doesn't exist, DirectWrite raise an exception
                continue

            simulations = font.GetSimulations()
            if simulations != DWRITE_FONT_SIMULATIONS.DWRITE_FONT_SIMULATIONS_NONE:
                continue

            face_file_path: List[Path] = []

            face_name = POINTER(IDWriteLocalizedStrings)()
            font.GetFaceNames(byref(face_name))
            face_name_str = dwrite.get_str_from_localized_strings(face_name)

            font_face = POINTER(IDWriteFontFace)()
            font.CreateFontFace(byref(font_face))

            file_count = wintypes.UINT()
            font_face.GetFiles(byref(file_count), None)

            font_files = (POINTER(IDWriteFontFile) * file_count.value)()
            font_face.GetFiles(byref(file_count), font_files)

            for font_file in font_files:
                font_file_reference_key = wintypes.LPCVOID()
                font_file_reference_key_size = wintypes.UINT()
                font_file.GetReferenceKey(byref(font_file_reference_key), byref(font_file_reference_key_size))

                loader = POINTER(IDWriteFontFileLoader)()
                font_file.GetLoader(byref(loader))

                local_loader = loader.QueryInterface(IDWriteLocalFontFileLoader)

                is_supported_font_type = wintypes.BOOL()
                font_file_type = wintypes.UINT()
                font_face_type = wintypes.UINT()
                number_of_faces = wintypes.UINT()
                font_file.Analyze(byref(is_supported_font_type), byref(font_file_type), byref(font_face_type), byref(number_of_faces))

                path_len = wintypes.UINT()
                local_loader.GetFilePathLengthFromKey(font_file_reference_key, font_file_reference_key_size, byref(path_len))

                buffer = create_unicode_buffer(path_len.value + 1)
                local_loader.GetFilePathFromKey(font_file_reference_key, font_file_reference_key_size, buffer, len(buffer))

                face_file_path.append(str(Path(buffer.value).resolve()))
            faces.append(FontFace(face_file_path, face_name_str))
        fonts_families.append(FontFamily(family_names_str, faces))
    return fonts_families


def main():
    font_families = get_system_fonts_families()

    font_families_dict = [asdict(font_family) for font_family in font_families]
    json_string = json.dumps(font_families_dict, indent=4)
    print(json_string)


if __name__ == "__main__":
    main()

输出

[
    {
        "family_name": "Sugar Lab",
        "fonts": [
            {
                "file_path": [
                    "C:\\Users\\jerem\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Night Birds.ttf"
                ],
                "face_name": "Regular"
            }
        ]
    },
    {
        "family_name": "Mona",
        "fonts": [
            {
                "file_path": [
                    "C:\\Users\\jerem\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Mona.ttf"
                ],
                "face_name": "Regular"
            }
        ]
    },
    {
        "family_name": "Jester",
        "fonts": [
            {
                "file_path": [
                    "C:\\Users\\jerem\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Jester Original.ttf"
                ],
                "face_name": "Regular"
            }
        ]
    },
]
© www.soinside.com 2019 - 2024. All rights reserved.