Skip to content

Instantly share code, notes, and snippets.

@moi15moi
Last active March 3, 2024 16:36
Show Gist options
  • Save moi15moi/f610d0f13f9a1b1667d16a48d30a3b02 to your computer and use it in GitHub Desktop.
Save moi15moi/f610d0f13f9a1b1667d16a48d30a3b02 to your computer and use it in GitHub Desktop.
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