Title: [MNT]: findSystemFonts - Use system API instead to look into folder · Issue #24001 · matplotlib/matplotlib · GitHub
Open Graph Title: [MNT]: findSystemFonts - Use system API instead to look into folder · Issue #24001 · matplotlib/matplotlib
X Title: [MNT]: findSystemFonts - Use system API instead to look into folder · Issue #24001 · matplotlib/matplotlib
Description: Summary Currently, findSystemFonts look at all the file in the specified folders for macos and windows. This is not a very good method, because a font in a "Font folder" does not necessarily need to be picked up. A very good example of t...
Open Graph Description: Summary Currently, findSystemFonts look at all the file in the specified folders for macos and windows. This is not a very good method, because a font in a "Font folder" does not necessarily need t...
X Description: Summary Currently, findSystemFonts look at all the file in the specified folders for macos and windows. This is not a very good method, because a font in a "Font folder" does not necessar...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/24001
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[MNT]: findSystemFonts - Use system API instead to look into folder","articleBody":"### Summary\r\n\r\nCurrently, [findSystemFonts](https://github.com/matplotlib/matplotlib/blob/36f27457d7781c0dbb6da3b875e98f0a3fac0f64/lib/matplotlib/font_manager.py#L348-L378) look at all the file in the [specified folders](https://github.com/matplotlib/matplotlib/blob/36f27457d7781c0dbb6da3b875e98f0a3fac0f64/lib/matplotlib/font_manager.py#L130-L167) for macos and windows.\r\n\r\nThis is not a very good method, because a font in a \"Font folder\" does not necessarily need to be picked up.\r\nA very good example of that is in this issue: #22859\r\n\r\nThis is why I propose to use CoreText (for mac) and DirectWrite (for Windows).\r\nThese are API provided by Apple and Microsoft.\r\n\r\n### Proposed fix\r\n\r\n### CoreText - For MAC\r\n\r\nIn this example, I use this library: https://pypi.org/project/pyobjc-framework-CoreText/\r\n```py\r\nimport CoreText\r\n\r\nfontURLs = CoreText.CTFontManagerCopyAvailableFontURLs()\r\nfontPath = set()\r\n\r\nfor i in range(CoreText.CFArrayGetCount(fontURLs)):\r\n url = CoreText.CFArrayGetValueAtIndex(fontURLs, i)\r\n\r\n fontPath.add(str(url.path()))\r\n```\r\n\r\n### DirectWrite - For Windows\r\n\r\nI don't know much C/C++, so I can't give an good example.\r\nOn recent Windows build, it is pretty simple to get the font path with DirectWrite, but since matplotlib seems to support Windows 7, we would maybe need to use the \"complex\" solution.\r\n\r\nBut, here is how I understand it (I have no proof that it works):\r\n\r\n#### Logic for to support only Windows 10:\r\n- [GetSystemFontCollection](https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nf-dwrite_3-idwritefactory3-getsystemfontcollection)\r\n- [GetFontSet](https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nf-dwrite_3-idwritefontcollection1-getfontset)\r\n- For loop with [GetFontCount](https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nf-dwrite_3-idwritefontset-getfontcount)\r\n - [GetFontFaceReference ](https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nf-dwrite_3-idwritefontset-getfontfacereference)\r\n - [GetFontFile](https://learn.microsoft.com/en-us/windows/win32/api/dwrite_3/nf-dwrite_3-idwritefontfacereference-getfontfile)\r\n - [GetReferenceKey](https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfile-getreferencekey)\r\n - [GetFilePathFromKey](https://learn.microsoft.com/en-us/windows/win32/directwrite/idwritelocalfontfileloader-getfilepathfromkey)\r\n\r\nHere is an \"pseudo-code\" of how I see it.\r\n```py\r\nfont_collection = GetSystemFontCollection()\r\nfont_set = font_collection.GetFontSet()\r\n\r\nfor i in range(font_set.GetFontCount()):\r\n\tfont_face_reference = font_set.GetFontFaceReference(i)\r\n\tfont_file = font_face_reference.GetFontFile()\r\n\treference_key, reference_key_size = font_file.GetReferenceKey()\r\n\tpath = GetFilePathFromKey(reference_key, reference_key_size)\r\n```\r\n\r\n#### Logic for Windows Vista to this day:\r\n- [GetSystemFontCollection](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefactory-getsystemfontcollection)\r\n- Do a for loop with [GetFontFamilyCount](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontcollection-getfontfamilycount)\r\n\t- [GetFontFamily](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontcollection-getfontfamily)\r\n\t- [GetMatchingFonts](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfamily-getmatchingfonts) - The param weight, stretch, style can be anything. These param seems to only change the order or the return list.\r\n\t- Do a for loop with [GetFontCount](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontlist-getfontcount)\r\n\t\t- [GetFont](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontlist-getfont)\r\n\t\t- [CreateFontFace](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefont-createfontface)\r\n\t\t- [GetFiles](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontface-getfiles)\r\n\t\t- [GetReferenceKey](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfile-getreferencekey)\r\n\t\t- [GetFilePathFromKey](https://docs.microsoft.com/en-us/windows/win32/directwrite/idwritelocalfontfileloader-getfilepathfromkey)\r\n\r\n```py\r\nfont_collection = GetSystemFontCollection()\r\n \r\nfor i in range(font_collection.GetFontFamilyCount()):\r\n\tfont_family = font_collection.GetFontFamily(i)\r\n\tmatching_fonts = GetMatchingFonts(ANY_WEIGHT, ANY_STRETCH, ANY_STYLE)\r\n\t\r\n\tfor j in range(matching_fonts.GetFontCount()):\r\n\t\tfont = matching_fonts.GetFont(j)\r\n\t\tfont_face = font.CreateFontFace()\r\n\t\t\r\n\t\tfor file in font_face.GetFiles():\r\n\t\t\treference_key, reference_key_size = font_file.GetReferenceKey()\r\n\t\t\tpath = GetFilePathFromKey(reference_key, reference_key_size)\r\n```\r\n\r\nI have try to see if the GDI api could help us to get the path of the fonts, but from what I can see, it is not an available feature: https://learn.microsoft.com/en-us/windows/win32/gdi/font-and-text-functions\r\n\r\n### FontConfig (Bonus) - For Linux\r\nCurrently, [matplotlib parse the result from subprocess](https://github.com/matplotlib/matplotlib/blob/36f27457d7781c0dbb6da3b875e98f0a3fac0f64/lib/matplotlib/font_manager.py#L327-L337).\r\n\r\nIt would be an good idea to directly use FontConfig. See this answer from stackoverflow to know how to do it: https://stackoverflow.com/a/14634033\r\n\r\nI did not found any FontConfig bindings library that are still maintained, so it would need to be implemented with Cython.","author":{"url":"https://github.com/moi15moi","@type":"Person","name":"moi15moi"},"datePublished":"2022-09-24T23:05:04.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":12},"url":"https://github.com/24001/matplotlib/issues/24001"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:e2c09c81-b3f6-9ae8-bd08-3d80bb59b0f9 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8442:32982F:282D50:364155:6A51BA96 |
| html-safe-nonce | 21aedc202eb27a2e5e0d6bcc9ad5c1a73b80e3520ecb5ee5a4ac3ae91aafe7a6 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4NDQyOjMyOTgyRjoyODJENTA6MzY0MTU1OjZBNTFCQTk2IiwidmlzaXRvcl9pZCI6IjYwNTY3NzA5NDQyNTY1NTU2NzAiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 19a1ea89a1a7ee7639c6d7a1b1385d909122234dc6379bcea9d5b28d94834e9f |
| hovercard-subject-tag | issue:1384836230 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/matplotlib/matplotlib/24001/issue_layout |
| twitter:image | https://opengraph.githubassets.com/1c99784d0a1da5fb2ca6bf1614c2fcbe1c0be07f3de9652a82920c2c4a3187bd/matplotlib/matplotlib/issues/24001 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/1c99784d0a1da5fb2ca6bf1614c2fcbe1c0be07f3de9652a82920c2c4a3187bd/matplotlib/matplotlib/issues/24001 |
| og:image:alt | Summary Currently, findSystemFonts look at all the file in the specified folders for macos and windows. This is not a very good method, because a font in a "Font folder" does not necessarily need t... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | moi15moi |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| go-import | github.com/matplotlib/matplotlib git https://github.com/matplotlib/matplotlib.git |
| octolytics-dimension-user_id | 215947 |
| octolytics-dimension-user_login | matplotlib |
| octolytics-dimension-repository_id | 1385122 |
| octolytics-dimension-repository_nwo | matplotlib/matplotlib |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1385122 |
| octolytics-dimension-repository_network_root_nwo | matplotlib/matplotlib |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 7aed05249554b889eb33d002851a973eebcc7e91 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width