From e90871f210b5d281da5c238b9e67917fe9222585 Mon Sep 17 00:00:00 2001 From: Alexander Voss Date: Mon, 29 Apr 2024 10:04:43 +0200 Subject: [PATCH] Fixed social plugin crashing on Windows when downloading fonts (#7085) (#7117) * fix: social plugin fonts on Windows (squidfunk #7085) * fix: managed to edit in material instead of src * added resource mgmt for ByteIO, comments * formatted comment * Fix for Social plugin crashes when font autoloading is disabled (#7118) --- material/plugins/social/plugin.py | 31 ++++++++++++++++++------------- src/plugins/social/plugin.py | 31 ++++++++++++++++++------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/material/plugins/social/plugin.py b/material/plugins/social/plugin.py index ba914101a..edbb91d1d 100644 --- a/material/plugins/social/plugin.py +++ b/material/plugins/social/plugin.py @@ -46,7 +46,7 @@ from io import BytesIO from mkdocs.commands.build import DuplicateFilter from mkdocs.exceptions import PluginError from mkdocs.plugins import BasePlugin -from mkdocs.utils import copy_file +from mkdocs.utils import write_file from shutil import copyfile from tempfile import NamedTemporaryFile @@ -444,11 +444,17 @@ class SocialPlugin(BasePlugin[SocialConfig]): svg2png(bytestring = data, write_to = file, scale = 10) return Image.open(file) - # Retrieve font + # Retrieve font either from the card layout option or from the Material + # font defintion. If no font is defined for Material or font is False + # then choose a default. def _load_font(self, config): name = self.config.cards_layout_options.get("font_family") if not name: - name = config.theme.get("font", {}).get("text", "Roboto") + material_name = config.theme.get("font", False) + if material_name is False: + name = "Roboto" + else: + name = material_name.get("text", "Roboto") # Resolve relevant fonts font = {} @@ -522,19 +528,18 @@ class SocialPlugin(BasePlugin[SocialConfig]): with requests.get(match) as res: res.raise_for_status() - # Create a temporary file to download the font - with NamedTemporaryFile() as temp: - temp.write(res.content) - temp.flush() - - # Extract font family name and style - font = ImageFont.truetype(temp.name) + # Extract font family name and style using the content in the + # response via ByteIO to avoid writing a temp file. Done to fix + # problems with passing a NamedTemporaryFile to + # ImageFont.truetype() on Windows, see https://t.ly/LiF_k + with BytesIO(res.content) as fontdata: + font = ImageFont.truetype(fontdata) name, style = font.getname() name = " ".join([name.replace(family, ""), style]).strip() - - # Move fonts to cache directory target = os.path.join(path, family, f"{name}.ttf") - copy_file(temp.name, target) + + # write file to cache + write_file(res.content, target) # ----------------------------------------------------------------------------- # Data diff --git a/src/plugins/social/plugin.py b/src/plugins/social/plugin.py index ba914101a..edbb91d1d 100644 --- a/src/plugins/social/plugin.py +++ b/src/plugins/social/plugin.py @@ -46,7 +46,7 @@ from io import BytesIO from mkdocs.commands.build import DuplicateFilter from mkdocs.exceptions import PluginError from mkdocs.plugins import BasePlugin -from mkdocs.utils import copy_file +from mkdocs.utils import write_file from shutil import copyfile from tempfile import NamedTemporaryFile @@ -444,11 +444,17 @@ class SocialPlugin(BasePlugin[SocialConfig]): svg2png(bytestring = data, write_to = file, scale = 10) return Image.open(file) - # Retrieve font + # Retrieve font either from the card layout option or from the Material + # font defintion. If no font is defined for Material or font is False + # then choose a default. def _load_font(self, config): name = self.config.cards_layout_options.get("font_family") if not name: - name = config.theme.get("font", {}).get("text", "Roboto") + material_name = config.theme.get("font", False) + if material_name is False: + name = "Roboto" + else: + name = material_name.get("text", "Roboto") # Resolve relevant fonts font = {} @@ -522,19 +528,18 @@ class SocialPlugin(BasePlugin[SocialConfig]): with requests.get(match) as res: res.raise_for_status() - # Create a temporary file to download the font - with NamedTemporaryFile() as temp: - temp.write(res.content) - temp.flush() - - # Extract font family name and style - font = ImageFont.truetype(temp.name) + # Extract font family name and style using the content in the + # response via ByteIO to avoid writing a temp file. Done to fix + # problems with passing a NamedTemporaryFile to + # ImageFont.truetype() on Windows, see https://t.ly/LiF_k + with BytesIO(res.content) as fontdata: + font = ImageFont.truetype(fontdata) name, style = font.getname() name = " ".join([name.replace(family, ""), style]).strip() - - # Move fonts to cache directory target = os.path.join(path, family, f"{name}.ttf") - copy_file(temp.name, target) + + # write file to cache + write_file(res.content, target) # ----------------------------------------------------------------------------- # Data