-
-
Save moi15moi/f610d0f13f9a1b1667d16a48d30a3b02 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes | |
import os | |
from comtypes import COMError, GUID, HRESULT, IUnknown, STDMETHOD | |
from ctypes import byref, create_unicode_buffer, POINTER, windll, wintypes | |
from enum import IntEnum, IntFlag | |
from os.path import isfile | |
from sys import getwindowsversion | |
from typing import Set | |
from .exceptions import OSNotSupported | |
from .system_fonts import SystemFonts | |
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_FILE_TYPE(IntEnum): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_file_type | |
DWRITE_FONT_FILE_TYPE_UNKNOWN = 0 | |
DWRITE_FONT_FILE_TYPE_CFF = 1 | |
DWRITE_FONT_FILE_TYPE_TRUETYPE = 2 | |
DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION = 3 | |
DWRITE_FONT_FILE_TYPE_TYPE1_PFM = 4 | |
DWRITE_FONT_FILE_TYPE_TYPE1_PFB = 5 | |
DWRITE_FONT_FILE_TYPE_VECTOR = 6 | |
DWRITE_FONT_FILE_TYPE_BITMAP = 7 | |
DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION = DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION | |
class DWRITE_LOCALITY(IntEnum): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/ne-dwrite_3-dwrite_locality | |
DWRITE_LOCALITY_REMOTE = 0 | |
DWRITE_LOCALITY_PARTIAL = 1 | |
DWRITE_LOCALITY_LOCAL = 2 | |
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 DWRITE_INFORMATIONAL_STRING_ID(IntEnum): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_informational_string_id | |
DWRITE_INFORMATIONAL_STRING_NONE = 0 | |
DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE = 1 | |
DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS = 2 | |
DWRITE_INFORMATIONAL_STRING_TRADEMARK = 3 | |
DWRITE_INFORMATIONAL_STRING_MANUFACTURER = 4 | |
DWRITE_INFORMATIONAL_STRING_DESIGNER = 5 | |
DWRITE_INFORMATIONAL_STRING_DESIGNER_URL = 6 | |
DWRITE_INFORMATIONAL_STRING_DESCRIPTION = 7 | |
DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL = 8 | |
DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION = 9 | |
DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL = 10 | |
DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES = 11 | |
DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES = 12 | |
DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES = 13 | |
DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES = 14 | |
DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT = 15 | |
DWRITE_INFORMATIONAL_STRING_FULL_NAME = 16 | |
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME = 17 | |
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME = 18 | |
DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME = 19 | |
DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG = 20 | |
DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG = 21 | |
DWRITE_INFORMATIONAL_STRING_PREFERRED_FAMILY_NAMES = DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES | |
DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES = DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES | |
DWRITE_INFORMATIONAL_STRING_WWS_FAMILY_NAME = DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME | |
class IDWriteFontFileStream(IUnknown): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontfilestream | |
_iid_ = GUID("{6d4865fe-0ab8-4d91-8f62-5dd6be34a3e0}") | |
_methods_ = [ | |
STDMETHOD(HRESULT, "ReadFileFragment", [POINTER(wintypes.LPCVOID), wintypes.UINT, wintypes.UINT, POINTER(wintypes.LPVOID)]), | |
STDMETHOD(None, "ReleaseFileFragment", [wintypes.LPVOID]), | |
STDMETHOD(HRESULT, "GetFileSize", [POINTER(wintypes.UINT)]), | |
STDMETHOD(None, "GetLastWriteTime"), # Need to be implemented | |
] | |
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(HRESULT, "CreateStreamFromKey", [wintypes.LPCVOID, wintypes.UINT, POINTER(POINTER(IDWriteFontFileStream))]), | |
] | |
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 IDWriteFontFace1(IDWriteFontFace): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_1/nn-dwrite_1-idwritefontface1 | |
_iid_ = GUID("{a71efdb4-9fdb-4838-ad90-cfc3be8c3daf}") | |
_methods_ = [ | |
STDMETHOD(None, "GetMetrics"), # Need to be implemented | |
STDMETHOD(None, "GetGdiCompatibleMetrics"), # Need to be implemented | |
STDMETHOD(None, "GetCaretMetrics"), # Need to be implemented | |
STDMETHOD(None, "GetUnicodeRanges"), # Need to be implemented | |
STDMETHOD(None, "IsMonospacedFont"), # Need to be implemented | |
STDMETHOD(None, "GetDesignGlyphAdvances"), # Need to be implemented | |
STDMETHOD(None, "GetGdiCompatibleGlyphAdvances"), # Need to be implemented | |
STDMETHOD(None, "GetKerningPairAdjustments"), # Need to be implemented | |
STDMETHOD(None, "HasKerningPairs"), # Need to be implemented | |
STDMETHOD(None, "GetRecommendedRenderingMode"), # Need to be implemented | |
STDMETHOD(None, "GetVerticalGlyphVariants"), # Need to be implemented | |
STDMETHOD(None, "HasVerticalGlyphVariants"), # Need to be implemented | |
] | |
class IDWriteFontFace2(IDWriteFontFace1): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_2/nn-dwrite_2-idwritefontface2 | |
_iid_ = GUID("{d8b768ff-64bc-4e66-982b-ec8e87f693f7}") | |
_methods_ = [ | |
STDMETHOD(None, "IsColorFont"), # Need to be implemented | |
STDMETHOD(None, "GetColorPaletteCount"), # Need to be implemented | |
STDMETHOD(None, "GetPaletteEntryCount"), # Need to be implemented | |
STDMETHOD(None, "GetPaletteEntries"), # Need to be implemented | |
STDMETHOD(None, "GetRecommendedRenderingMode"), # Need to be implemented | |
] | |
class IDWriteFontFace3(IDWriteFontFace2): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontface3 | |
_iid_ = GUID("{D37D7598-09BE-4222-A236-2081341CC1F2}") | |
_methods_ = [ | |
STDMETHOD(None, "GetFontFaceReference"), # Need to be implemented | |
STDMETHOD(None, "GetPanose"), # 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, "GetFamilyNames"), # Need to be implemented | |
STDMETHOD(None, "GetFaceNames"), # Need to be implemented | |
STDMETHOD(HRESULT, "GetInformationalStrings", [wintypes.UINT, POINTER(POINTER(IDWriteLocalizedStrings)), POINTER(wintypes.BOOL)]), | |
STDMETHOD(None, "HasCharacter"), # Need to be implemented | |
STDMETHOD(None, "GetRecommendedRenderingMode"), # Need to be implemented | |
STDMETHOD(None, "IsCharacterLocal"), # Need to be implemented | |
STDMETHOD(None, "IsGlyphLocal"), # Need to be implemented | |
STDMETHOD(None, "AreCharactersLocal"), # Need to be implemented | |
STDMETHOD(None, "AreGlyphsLocal"), # 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(None, "GetFaceNames"), # Need to be implemented | |
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 IDWriteFontFaceReference(IUnknown): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontfacereference | |
_iid_ = GUID("{5E7FA7CA-DDE3-424C-89F0-9FCD6FED58CD}") | |
_methods_ = [ | |
STDMETHOD(HRESULT, "CreateFontFace", [POINTER(POINTER(IDWriteFontFace3))]), | |
STDMETHOD(None, "CreateFontFaceWithSimulations"), # Need to be implemented | |
STDMETHOD(None, "Equals"), # Need to be implemented | |
STDMETHOD(None, "GetFontFaceIndex"), # Need to be implemented | |
STDMETHOD(wintypes.UINT, "GetSimulations"), | |
STDMETHOD(HRESULT, "GetFontFile", [POINTER(POINTER(IDWriteFontFile))]), | |
STDMETHOD(None, "GetLocalFileSize"), # Need to be implemented | |
STDMETHOD(None, "GetFileSize"), # Need to be implemented | |
STDMETHOD(None, "GetFileTime"), # Need to be implemented | |
STDMETHOD(wintypes.UINT, "GetLocality"), | |
STDMETHOD(None, "EnqueueFontDownloadRequest"), # Need to be implemented | |
STDMETHOD(None, "EnqueueCharacterDownloadRequest"), # Need to be implemented | |
STDMETHOD(None, "EnqueueGlyphDownloadRequest"), # Need to be implemented | |
STDMETHOD(None, "EnqueueFileFragmentDownloadRequest"), # Need to be implemented | |
] | |
class IDWriteFontSet(IUnknown): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontset | |
_iid_ = GUID("{53585141-D9F8-4095-8321-D73CF6BD116B}") | |
_methods_ = [ | |
STDMETHOD(wintypes.UINT, "GetFontCount"), | |
STDMETHOD(HRESULT, "GetFontFaceReference", [wintypes.UINT, POINTER(POINTER(IDWriteFontFaceReference))]), | |
STDMETHOD(None, "FindFontFaceReference"), # Need to be implemented | |
STDMETHOD(None, "FindFontFace"), # Need to be implemented | |
STDMETHOD(None, "GetPropertyValues"), # Need to be implemented | |
STDMETHOD(None, "GetPropertyValues"), # Need to be implemented | |
STDMETHOD(None, "GetPropertyValues"), # Need to be implemented | |
STDMETHOD(None, "GetPropertyOccurrenceCount"), # Need to be implemented | |
STDMETHOD(None, "GetMatchingFonts"), # Need to be implemented | |
STDMETHOD(None, "GetMatchingFonts"), # Need to be implemented | |
] | |
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(None, "GetFamilyNames"), # Need to be implemented | |
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 IDWriteFactory1(IDWriteFactory): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_1/nn-dwrite_1-idwritefactory1 | |
_iid_ = GUID("{30572f99-dac6-41db-a16e-0486307e606a}") | |
_methods_ = [ | |
STDMETHOD(None, "GetEudcFontCollection"), # Need to be implemented | |
STDMETHOD(None, "CreateCustomRenderingParams1"), # Need to be implemented | |
] | |
class IDWriteFactory2(IDWriteFactory1): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_2/nn-dwrite_2-idwritefactory2 | |
_iid_ = GUID("{0439fc60-ca44-4994-8dee-3a9af7b732ec}") | |
_methods_ = [ | |
STDMETHOD(None, "GetSystemFontFallback"), # Need to be implemented | |
STDMETHOD(None, "CreateFontFallbackBuilder"), # Need to be implemented | |
STDMETHOD(None, "TranslateColorGlyphRun"), # Need to be implemented | |
STDMETHOD(None, "CreateCustomRenderingParams2"), # Need to be implemented | |
STDMETHOD(None, "CreateGlyphRunAnalysis"), # Need to be implemented | |
] | |
class IDWriteFactory3(IDWriteFactory2): | |
# https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefactory3 | |
_iid_ = GUID("{9A1B41C3-D3BB-466A-87FC-FE67556A3B65}") | |
_methods_ = [ | |
STDMETHOD(None, "CreateGlyphRunAnalysis"), # Need to be implemented | |
STDMETHOD(None, "CreateCustomRenderingParams3"), # Need to be implemented | |
STDMETHOD(None, "CreateFontFaceReference"), # Need to be implemented | |
STDMETHOD(None, "CreateFontFaceReference"), # Need to be implemented | |
STDMETHOD(HRESULT, "GetSystemFontSet", [POINTER(POINTER(IDWriteFontSet))]), | |
STDMETHOD(None, "CreateFontSetBuilder"), # Need to be implemented | |
STDMETHOD(None, "CreateFontCollectionFromFontSet"), # Need to be implemented | |
STDMETHOD(None, "GetSystemFontCollection3"), # Need to be implemented | |
STDMETHOD(None, "GetFontDownloadQueue"), # Need to be implemented | |
] | |
class WindowsFonts(SystemFonts): | |
_DWriteCreateFactory = None | |
VALID_FONT_FORMATS = [ | |
DWRITE_FONT_FILE_TYPE.DWRITE_FONT_FILE_TYPE_CFF, | |
DWRITE_FONT_FILE_TYPE.DWRITE_FONT_FILE_TYPE_TRUETYPE, | |
DWRITE_FONT_FILE_TYPE.DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION, | |
DWRITE_FONT_FILE_TYPE.DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION, | |
] | |
def get_system_fonts_filename() -> Set[str]: | |
windows_version = getwindowsversion() | |
if WindowsVersionHelpers.is_windows_10_or_greater(windows_version): | |
fonts_filename = WindowsFonts._get_fonts_filename_windows_10_or_more() | |
elif WindowsVersionHelpers.is_windows_vista_sp2_or_greater(windows_version): | |
fonts_filename = WindowsFonts._get_fonts_filename_windows_vista_sp2_or_more() | |
else: | |
raise OSNotSupported("FindSystemFontsFilename only works on Windows Vista SP2 or more") | |
return fonts_filename | |
@staticmethod | |
def _get_fonts_filename_windows_10_or_more() -> Set[str]: | |
""" | |
Return an set of all the installed fonts filename. | |
""" | |
if WindowsFonts._DWriteCreateFactory is None: | |
WindowsFonts._load_DWriteCreateFactory() | |
fonts_filename = set() | |
dwrite_factory = POINTER(IDWriteFactory3)() | |
WindowsFonts._DWriteCreateFactory(DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_ISOLATED, IDWriteFactory3._iid_, byref(dwrite_factory)) | |
font_set = POINTER(IDWriteFontSet)() | |
dwrite_factory.GetSystemFontSet(byref(font_set)) | |
for i in range(font_set.GetFontCount()): | |
font_face_reference = POINTER(IDWriteFontFaceReference)() | |
font_set.GetFontFaceReference(i, byref(font_face_reference)) | |
locality = font_face_reference.GetLocality() | |
if locality != DWRITE_LOCALITY.DWRITE_LOCALITY_LOCAL: | |
continue | |
font_file = POINTER(IDWriteFontFile)() | |
font_face_reference.GetFontFile(byref(font_file)) | |
loader = POINTER(IDWriteFontFileLoader)() | |
font_file.GetLoader(byref(loader)) | |
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)) | |
try: | |
local_loader = loader.QueryInterface(IDWriteLocalFontFileLoader) | |
except COMError: | |
print("An error occured") | |
font_face = POINTER(IDWriteFontFace3)() | |
font_face_reference.CreateFontFace(byref(font_face)) | |
family_names = POINTER(IDWriteLocalizedStrings)() | |
exists = wintypes.BOOL() | |
font_face.GetInformationalStrings( | |
DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, | |
byref(family_names), | |
byref(exists) | |
) | |
if not exists: | |
raise ValueError("Could not fetch the family names") | |
index = wintypes.UINT() | |
exists = wintypes.BOOL() | |
family_names.FindLocaleName("en-us", byref(index), byref(exists)) | |
if not exists: | |
index = 0 | |
length = wintypes.UINT() | |
family_names.GetStringLength(index, byref(length)) | |
family_names_buffer = create_unicode_buffer(length.value + 1) | |
family_names.GetString(index, family_names_buffer, len(family_names_buffer)) | |
print(f"Family name = {family_names_buffer.value}") | |
font_file_stream = POINTER(IDWriteFontFileStream)() | |
loader.CreateStreamFromKey(font_file_reference_key, font_file_reference_key_size, byref(font_file_stream)) | |
file_size = wintypes.UINT() | |
font_file_stream.GetFileSize(byref(file_size)) | |
fragment_start = wintypes.LPCVOID() | |
fragment_context = wintypes.LPVOID() | |
font_file_stream.ReadFileFragment(byref(fragment_start), 0, file_size, byref(fragment_context)) | |
buffer_type = ctypes.c_char * file_size.value | |
buffer = buffer_type.from_address(fragment_start.value) | |
dir_path = r"C:\Users\moi15moi\Documents" | |
filename = os.path.join(dir_path, f"{family_names_buffer.value}.ttf") | |
with open(filename, 'wb') as file: | |
# Read bytes directly from memory using ctypes | |
# Write the bytes to the file | |
file.write(buffer) | |
font_file_stream.ReleaseFileFragment(fragment_context) | |
print(f"Font saved at {filename}") | |
continue | |
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)) | |
font_filename = buffer.value | |
if isfile(font_filename): | |
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)) | |
if DWRITE_FONT_FILE_TYPE(font_file_type.value) in WindowsFonts.VALID_FONT_FORMATS: | |
fonts_filename.add(buffer.value) | |
return fonts_filename | |
@staticmethod | |
def _get_fonts_filename_windows_vista_sp2_or_more() -> Set[str]: | |
""" | |
Return an set of all the installed fonts filename. | |
""" | |
if WindowsFonts._DWriteCreateFactory is None: | |
WindowsFonts._load_DWriteCreateFactory() | |
fonts_filename = set() | |
dwrite_factory = POINTER(IDWriteFactory)() | |
WindowsFonts._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)) | |
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 | |
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)) | |
if DWRITE_FONT_FILE_TYPE(font_file_type.value) not in WindowsFonts.VALID_FONT_FORMATS: | |
continue | |
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)) | |
fonts_filename.add(buffer.value) | |
return fonts_filename | |
@staticmethod | |
def _load_DWriteCreateFactory(): | |
WindowsFonts._DWriteCreateFactory = windll.dwrite.DWriteCreateFactory | |
WindowsFonts._DWriteCreateFactory.restype = HRESULT | |
WindowsFonts._DWriteCreateFactory.argtypes = [wintypes.UINT, GUID, POINTER(POINTER(IUnknown))] | |
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) | |
@staticmethod | |
def is_windows_10_or_greater(windows_version) -> bool: | |
# From https://www.lifewire.com/windows-version-numbers-2625171 | |
return WindowsVersionHelpers.is_windows_version_or_greater(windows_version, 10, 0, 10240) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment