From 84ec2af495a13076ca5d0bec2f9439e9ee639a3c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Feb 2015 14:48:07 +1100 Subject: [PATCH 1/3] Allow truetype() to search for extensions other than .ttf --- PIL/ImageFont.py | 34 +++++++++++++++------------------- Tests/test_imagefont.py | 6 +++++- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/PIL/ImageFont.py b/PIL/ImageFont.py index a9c50e560..61c552b1d 100644 --- a/PIL/ImageFont.py +++ b/PIL/ImageFont.py @@ -261,38 +261,34 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None): try: return FreeTypeFont(font, size, index, encoding) except IOError: - if font.endswith(".ttf"): - ttf_filename = font - else: - ttf_filename = "%s.ttf" % font + ttf_filename = os.path.basename(font) + + dirs = [] if sys.platform == "win32": # check the windows font repository # NOTE: must use uppercase WINDIR, to work around bugs in # 1.5.2's os.environ.get() windir = os.environ.get("WINDIR") if windir: - filename = os.path.join(windir, "fonts", font) - return FreeTypeFont(filename, size, index, encoding) + dirs.append(os.path.join(windir, "fonts")) elif sys.platform in ('linux', 'linux2'): lindirs = os.environ.get("XDG_DATA_DIRS", "") if not lindirs: # According to the freedesktop spec, XDG_DATA_DIRS should # default to /usr/share lindirs = '/usr/share' - lindirs = lindirs.split(":") - for lindir in lindirs: - parentpath = os.path.join(lindir, "fonts") - for walkroot, walkdir, walkfilenames in os.walk(parentpath): - if ttf_filename in walkfilenames: - filepath = os.path.join(walkroot, ttf_filename) - return FreeTypeFont(filepath, size, index, encoding) + dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")] elif sys.platform == 'darwin': - macdirs = ['/Library/Fonts/', '/System/Library/Fonts/', - os.path.expanduser('~/Library/Fonts/')] - for macdir in macdirs: - filepath = os.path.join(macdir, ttf_filename) - if os.path.exists(filepath): - return FreeTypeFont(filepath, size, index, encoding) + dirs += ['/Library/Fonts/', '/System/Library/Fonts/', + os.path.expanduser('~/Library/Fonts/')] + + ext = os.path.splitext(ttf_filename)[1] + for dir in dirs: + for walkroot, walkdir, walkfilenames in os.walk(dir): + for walkfilename in walkfilenames: + if (ext and walkfilename == ttf_filename) or (not ext and os.path.splitext(walkfilename)[0] == ttf_filename): + fontpath = os.path.join(walkroot, walkfilename) + return FreeTypeFont(fontpath, size, index, encoding) raise diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 1b03ed13b..a7d3e5ebb 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -269,7 +269,11 @@ try: #correctness. with SimplePatcher(sys, 'platform', 'darwin'): fake_font_path = '/System/Library/Fonts/Arial.ttf' - with SimplePatcher(os.path, 'exists', lambda x: x == fake_font_path): + def fake_walker(path): + if path == '/System/Library/Fonts/': + return [(path, [], ['Arial.ttf'], )] + return [(path, [], ['some_random_font.ttf'], )] + with SimplePatcher(os, 'walk', fake_walker): self._test_fake_loading_font(fake_font_path) From 3e9e95b00aa88226c8d4b2b6e600a98a751e1e5a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Feb 2015 14:50:54 +1100 Subject: [PATCH 2/3] Changed truetype() to prefer .ttf extensions --- PIL/ImageFont.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/PIL/ImageFont.py b/PIL/ImageFont.py index 61c552b1d..92722a7fe 100644 --- a/PIL/ImageFont.py +++ b/PIL/ImageFont.py @@ -283,12 +283,21 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None): os.path.expanduser('~/Library/Fonts/')] ext = os.path.splitext(ttf_filename)[1] + firstFontWithADifferentExtension = None for dir in dirs: for walkroot, walkdir, walkfilenames in os.walk(dir): for walkfilename in walkfilenames: - if (ext and walkfilename == ttf_filename) or (not ext and os.path.splitext(walkfilename)[0] == ttf_filename): + if ext and walkfilename == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) return FreeTypeFont(fontpath, size, index, encoding) + elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename: + fontpath = os.path.join(walkroot, walkfilename) + if os.path.splitext(fontpath)[1] == '.ttf': + return FreeTypeFont(fontpath, size, index, encoding) + if not ext and firstFontWithADifferentExtension == None: + firstFontWithADifferentExtension = fontpath + if firstFontWithADifferentExtension: + return FreeTypeFont(firstFontWithADifferentExtension, size, index, encoding) raise From b75ee4c5b618c36e6fa5c7618405010081a14ea0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 1 Apr 2015 15:26:00 +1100 Subject: [PATCH 3/3] Added tests for font paths without extensions and for preferring ttf extensions --- PIL/ImageFont.py | 4 ++-- Tests/test_imagefont.py | 32 +++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/PIL/ImageFont.py b/PIL/ImageFont.py index 92722a7fe..9aa163c68 100644 --- a/PIL/ImageFont.py +++ b/PIL/ImageFont.py @@ -279,8 +279,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None): lindirs = '/usr/share' dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")] elif sys.platform == 'darwin': - dirs += ['/Library/Fonts/', '/System/Library/Fonts/', - os.path.expanduser('~/Library/Fonts/')] + dirs += ['/Library/Fonts', '/System/Library/Fonts', + os.path.expanduser('~/Library/Fonts')] ext = os.path.splitext(ttf_filename)[1] firstFontWithADifferentExtension = None diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index a7d3e5ebb..dff1bce2a 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -233,7 +233,7 @@ try: # Assert self.assert_image_equal(im, target_img) - def _test_fake_loading_font(self, path_to_fake): + def _test_fake_loading_font(self, path_to_fake, fontname): #Make a copy of FreeTypeFont so we can patch the original free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font): @@ -242,7 +242,7 @@ try: return ImageFont._FreeTypeFont(FONT_PATH, size, index, encoding) return ImageFont._FreeTypeFont(filepath, size, index, encoding) with SimplePatcher(ImageFont, 'FreeTypeFont', loadable_font): - font = ImageFont.truetype('Arial') + font = ImageFont.truetype(fontname) #Make sure it's loaded name = font.getname() self.assertEqual(('FreeMono', 'Regular'), name) @@ -252,29 +252,43 @@ try: def test_find_linux_font(self): #A lot of mocking here - this is more for hitting code and catching #syntax like errors + fontDirectory = '/usr/local/share/fonts' with SimplePatcher(sys, 'platform', 'linux'): patched_env = copy.deepcopy(os.environ) patched_env['XDG_DATA_DIRS'] = '/usr/share/:/usr/local/share/' with SimplePatcher(os, 'environ', patched_env): def fake_walker(path): - if path == '/usr/local/share/fonts': - return [(path, [], ['Arial.ttf'], )] + if path == fontDirectory: + return [(path, [], ['Arial.ttf', 'Single.otf', 'Duplicate.otf', 'Duplicate.ttf'], )] return [(path, [], ['some_random_font.ttf'], )] with SimplePatcher(os, 'walk', fake_walker): - self._test_fake_loading_font('/usr/local/share/fonts/Arial.ttf') + # Test that the font loads both with and without the extension + self._test_fake_loading_font(fontDirectory+'/Arial.ttf', 'Arial.ttf') + self._test_fake_loading_font(fontDirectory+'/Arial.ttf', 'Arial') + + # Test that non-ttf fonts can be found without the extension + self._test_fake_loading_font(fontDirectory+'/Single.otf', 'Single') + + # Test that ttf fonts are preferred if the extension is not specified + self._test_fake_loading_font(fontDirectory+'/Duplicate.ttf', 'Duplicate') @unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS") def test_find_osx_font(self): #Like the linux test, more cover hitting code rather than testing #correctness. + fontDirectory = '/System/Library/Fonts' with SimplePatcher(sys, 'platform', 'darwin'): - fake_font_path = '/System/Library/Fonts/Arial.ttf' def fake_walker(path): - if path == '/System/Library/Fonts/': - return [(path, [], ['Arial.ttf'], )] + if path == fontDirectory: + return [(path, [], ['Arial.ttf', 'Single.otf', 'Duplicate.otf', 'Duplicate.ttf'], )] return [(path, [], ['some_random_font.ttf'], )] with SimplePatcher(os, 'walk', fake_walker): - self._test_fake_loading_font(fake_font_path) + self._test_fake_loading_font(fontDirectory+'/Arial.ttf', 'Arial.ttf') + self._test_fake_loading_font(fontDirectory+'/Arial.ttf', 'Arial') + + self._test_fake_loading_font(fontDirectory+'/Single.otf', 'Single') + + self._test_fake_loading_font(fontDirectory+'/Duplicate.ttf', 'Duplicate') except ImportError: