From 7a5a659ad35146060be9713279d8a06f6f826788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20P=C3=A9rez=20Cano?= Date: Wed, 8 Jan 2025 14:24:16 +0100 Subject: [PATCH 1/2] fix: add font directories for linux and custom (via envvar) --- src/pptx/text/fonts.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/pptx/text/fonts.py b/src/pptx/text/fonts.py index 5ae054a8..c42e8da7 100644 --- a/src/pptx/text/fonts.py +++ b/src/pptx/text/fonts.py @@ -43,8 +43,18 @@ def _font_directories(cls): Return a sequence of directory paths likely to contain fonts on the current platform. """ + + # Colon-separated list of paths for python-pptx to find fonts + CUSTOM_DIRS_VAR_NAME = 'PYTHON_PPTX_FONT_DIRECTORY' + custom_dirs = os.getenv(CUSTOM_DIRS_VAR_NAME) + + if custom_dirs is not None: + return custom_dirs.split(':') + if sys.platform.startswith("darwin"): return cls._os_x_font_directories() + if sys.platform.startswith("linux"): + return cls._linux_font_directories() if sys.platform.startswith("win32"): return cls._windows_font_directories() raise OSError("unsupported operating system") @@ -84,6 +94,23 @@ def _os_x_font_directories(cls): ) return os_x_font_dirs + @classmethod + def _linux_font_directories(cls): + """ + Return a sequence of directory paths in which fonts are + likely to be located on most Linux. + """ + linux_font_dirs = [ + "/usr/share/fonts", + "/usr/local/share/fonts", + ] + home = os.environ.get("HOME") + if home is not None: + linux_font_dirs.extend( + [os.path.join(home, ".local", "share", "fonts"), os.path.join(home, ".fonts")] + ) + return linux_font_dirs + @classmethod def _windows_font_directories(cls): """ From f87f0f469d95d4dab797f1edad4ebbdab4a84f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20P=C3=A9rez=20Cano?= Date: Wed, 8 Jan 2025 15:54:05 +0100 Subject: [PATCH 2/2] updated docs, and combine envvar and OS dirs --- docs/dev/analysis/txt-font-typeface.rst | 5 +++++ docs/user/install.rst | 11 +++++++++++ src/pptx/text/fonts.py | 21 +++++++++++++-------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/docs/dev/analysis/txt-font-typeface.rst b/docs/dev/analysis/txt-font-typeface.rst index 556a3c71..b27d9fab 100644 --- a/docs/dev/analysis/txt-font-typeface.rst +++ b/docs/dev/analysis/txt-font-typeface.rst @@ -10,6 +10,11 @@ Verdana to Arial. This aspect of a font is its *typeface*, as opposed to its size (e.g. 18 points) or style (e.g. bold, italic). +.. admonition:: Custom fonts folder + + |pp| will search for font files on each OS default directories. A list of custom folders can also be specified by setting the ``PYTHON_PPTX_FONT_DIRECTORY`` environment variable to a colon-separated list of the paths of each fonts folder. + + Minimum viable feature ---------------------- diff --git a/docs/user/install.rst b/docs/user/install.rst index b376d58e..3b5c7ea7 100644 --- a/docs/user/install.rst +++ b/docs/user/install.rst @@ -23,3 +23,14 @@ Dependencies * lxml * Pillow * XlsxWriter (to use charting features) + + +.. admonition:: Note: font availability on Linux + + On most Linux distros, default PowerPoint fonts are typically unavailable. Thus, you should install them manually by either: + + - Installing ``ttf-mscorefonts-installer`` package (on Ubuntu). + - Copying font files from the ``C:\Windows\Fonts`` folder of an existing Windows machine. + - Manually installing the fonts following `this guide `_. + + diff --git a/src/pptx/text/fonts.py b/src/pptx/text/fonts.py index c42e8da7..78e836d5 100644 --- a/src/pptx/text/fonts.py +++ b/src/pptx/text/fonts.py @@ -44,20 +44,25 @@ def _font_directories(cls): current platform. """ + font_dirs = [] + # Colon-separated list of paths for python-pptx to find fonts CUSTOM_DIRS_VAR_NAME = 'PYTHON_PPTX_FONT_DIRECTORY' custom_dirs = os.getenv(CUSTOM_DIRS_VAR_NAME) - if custom_dirs is not None: - return custom_dirs.split(':') + # Check it is not None, empty or whitespace + if custom_dirs and custom_dirs.strip(): + font_dirs.extend(custom_dirs.split(':')) if sys.platform.startswith("darwin"): - return cls._os_x_font_directories() - if sys.platform.startswith("linux"): - return cls._linux_font_directories() - if sys.platform.startswith("win32"): - return cls._windows_font_directories() - raise OSError("unsupported operating system") + font_dirs.extend(cls._os_x_font_directories()) + elif sys.platform.startswith("linux"): + font_dirs.extend(cls._linux_font_directories()) + elif sys.platform.startswith("win32"): + font_dirs.extend(cls._windows_font_directories()) + else: + raise OSError("unsupported operating system") + return font_dirs @classmethod def _iter_font_files_in(cls, directory):