Repository: python-pillow/Pillow

Problem statement:
Using font_variant on a font whose path is defined by BytesIO fails
### What did you do?
Opened a font using
```py
font = ImageFont.truetype(
    BytesIO(pkgutil.get_data(__package__, path)),
    size
)
```
then tried to edit the font using font_variant. 
```py
# doesn't work, it raises "OSError: cannot open resource"
font = font.font_variant(size=font.size+10)
```
However, by doing a bit more code i managed to get it to work
```py
# does work
font = font.font_variant(
    font=BytesIO(font.path.getvalue()),
    size=font.size+10
)
```
Aditionally
```py
# does work
font.path.seek(0)
font = font.font_variant(
    size=font.size+10
)
```
I assume this is something todo with font_variant parsing in `font.path` to the init of a new font object and as `BytesIO` is already read, it can't be read again. To fix this it could have a check if its a file like object and seek to the begining again?

### What did you expect to happen?
I expected the font to be successfully changed

### What actually happened?
It raised the error
```py
line 101, in get_font_size
    font = font.font_variant(size=font.size+10)
line 715, in font_variant
    return FreeTypeFont(
line 230, in __init__
    load_from_bytes(font)
line 211, in load_from_bytes
    self.font = core.getfont(
OSError: cannot open resource
```

### What are your OS, Python and Pillow versions?

* OS: Windows 11
* Python: 3.10
* Pillow: 9.1.0


Hints:
https://pillow.readthedocs.io/en/stable/reference/ImageFont.html#PIL.ImageFont.truetype
> Load a TrueType or OpenType font from a file or file-like object, and create a font object. This function loads a font object from the given file or file-like object, and creates a font object for a font of the given size.

While I'm not able to replicate your problem (when I try, I receive an error at `ImageFont.truetype()` as well, not just at `font_variant()`), Pillow would be seeing your `BytesIO` object and thinking that you are passing in the contents of the font file, not the path.
@14ROVI did that answer your question? What I'm trying to say is that the situation you describe shouldn't work at all, not just fail for variants. This is not the intended use.

If you would like us to investigate why it's working for you at all, please let us know what font you are using.
@radarhere Thank you for investigating. BytesIO is a file like object which supports the reading and writing needed for loading the font hence loading the font initally works. However, when trying to use `ImageFont.font_variant()` on that font it fails. This is because the font "file" has already been read. It's not really a massive issue as it can be fixed by using `file.seek(0)` before using `font_variant` but it was annoying as it would make sense to not have to bother with that to change the size of the font.
![image](https://user-images.githubusercontent.com/29734170/164485901-d58e5ea0-8f1d-4096-b00c-ea1e9b6f993c.png)

With this example you may ask *why do it this way* to which i respond not in this example but if you have to load resources off of the internet or some other method where you dont have a file path, it would be nicer to not have to bother.

I hope this explains it better. please let me know if ive missed the point of `font_variant` however.

Patch:
diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py
--- a/src/PIL/ImageFont.py
+++ b/src/PIL/ImageFont.py
@@ -711,8 +711,13 @@ def font_variant(
 
         :return: A FreeTypeFont object.
         """
+        if font is None:
+            try:
+                font = BytesIO(self.font_bytes)
+            except AttributeError:
+                font = self.path
         return FreeTypeFont(
-            font=self.path if font is None else font,
+            font=font,
             size=self.size if size is None else size,
             index=self.index if index is None else index,
             encoding=self.encoding if encoding is None else encoding,


Test patch:
diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py
--- a/Tests/test_imagefont.py
+++ b/Tests/test_imagefont.py
@@ -65,9 +65,12 @@ def _font_as_bytes(self):
         return font_bytes
 
     def test_font_with_filelike(self):
-        ImageFont.truetype(
+        ttf = ImageFont.truetype(
             self._font_as_bytes(), FONT_SIZE, layout_engine=self.LAYOUT_ENGINE
         )
+        ttf_copy = ttf.font_variant()
+        assert ttf_copy.font_bytes == ttf.font_bytes
+
         self._render(self._font_as_bytes())
         # Usage note:  making two fonts from the same buffer fails.
         # shared_bytes = self._font_as_bytes()