From eaf71b28dccc364ff585d130a94adc9003f7fc8d Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Dec 2025 23:29:05 +1100 Subject: [PATCH 1/4] Allow for duplicate style ids --- src/_imagingft.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_imagingft.c b/src/_imagingft.c index d0af25b30e3..a371173d61c 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -1287,7 +1287,6 @@ font_getvarnames(FontObject *self) { } PyList_SetItem(list_names, j, list_name); list_names_filled[j] = 1; - break; } } } From b2b7dc2b82914e617e9ca5ba1d4ad58c11c83c0d Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 31 Dec 2025 13:43:32 +1100 Subject: [PATCH 2/4] Only return unique names --- Tests/fonts/AdobeVFPrototypeDuplicates.ttf | Bin 0 -> 6696 bytes Tests/fonts/LICENSE.txt | 2 +- Tests/test_imagefont.py | 15 +++++++++++++++ src/PIL/ImageFont.py | 8 ++++++-- 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 Tests/fonts/AdobeVFPrototypeDuplicates.ttf diff --git a/Tests/fonts/AdobeVFPrototypeDuplicates.ttf b/Tests/fonts/AdobeVFPrototypeDuplicates.ttf new file mode 100644 index 0000000000000000000000000000000000000000..acf0bc156c8bec3c79de96968766795951b3a8fb GIT binary patch literal 6696 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 None: ] +def test_variation_duplicates() -> None: + font = ImageFont.truetype("Tests/fonts/AdobeVFPrototypeDuplicates.ttf") + assert font.get_variation_names(), [ + b"ExtraLight", + b"Light", + b"Regular", + b"Semibold", + b"Bold", + b"Black", + b"Black Medium Contrast", + b"Black High Contrast", + b"Default", + ] + + def _check_text(font: ImageFont.FreeTypeFont, path: str, epsilon: float) -> None: im = Image.new("RGB", (100, 75), "white") d = ImageDraw.Draw(im) diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 2e8ace98dda..d11f7bf01ad 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -675,8 +675,12 @@ def get_variation_names(self) -> list[bytes]: :returns: A list of the named styles in a variation font. :exception OSError: If the font is not a variation font. """ - names = self.font.getvarnames() - return [name.replace(b"\x00", b"") for name in names] + names = [] + for name in self.font.getvarnames(): + name = name.replace(b"\x00", b"") + if name not in names: + names.append(name) + return names def set_variation_by_name(self, name: str | bytes) -> None: """ From 99c9925077996b57d62167442f273b1f1f972144 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Wed, 31 Dec 2025 21:49:59 +1100 Subject: [PATCH 3/4] Corrected test Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Tests/test_imagefont.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 27858ac199e..1c7e4b0c4d5 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -744,7 +744,7 @@ def test_variation_get(font: ImageFont.FreeTypeFont) -> None: def test_variation_duplicates() -> None: font = ImageFont.truetype("Tests/fonts/AdobeVFPrototypeDuplicates.ttf") - assert font.get_variation_names(), [ + assert font.get_variation_names() == [ b"ExtraLight", b"Light", b"Regular", From 1150acf097311a70c36ec5e35d745fa71dea1b07 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 31 Dec 2025 21:50:23 +1100 Subject: [PATCH 4/4] Corrected test --- Tests/test_imagefont.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 1c7e4b0c4d5..d0b458d6b77 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -702,7 +702,7 @@ def test_variation_get(font: ImageFont.FreeTypeFont) -> None: font.get_variation_axes() font = ImageFont.truetype("Tests/fonts/AdobeVFPrototype.ttf") - assert font.get_variation_names(), [ + assert font.get_variation_names() == [ b"ExtraLight", b"Light", b"Regular",