Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using font_variant on a font whose path is defined by BytesIO fails #6209

Closed
14ROVI opened this issue Apr 14, 2022 · 4 comments · Fixed by #6234
Closed

Using font_variant on a font whose path is defined by BytesIO fails #6209

14ROVI opened this issue Apr 14, 2022 · 4 comments · Fixed by #6234
Labels

Comments

@14ROVI
Copy link

14ROVI commented Apr 14, 2022

What did you do?

Opened a font using

font = ImageFont.truetype(
    BytesIO(pkgutil.get_data(__package__, path)),
    size
)

then tried to edit the font using font_variant.

# 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

# does work
font = font.font_variant(
    font=BytesIO(font.path.getvalue()),
    size=font.size+10
)

Aditionally

# 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

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
@radarhere
Copy link
Member

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.

@radarhere
Copy link
Member

@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.

@14ROVI
Copy link
Author

14ROVI commented Apr 21, 2022

@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

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.

@radarhere
Copy link
Member

Ah, ok, I didn't have a correct understanding of your situation. I thought you were passing in the path using BytesIO, not the font contents.

Rather than seeking to the beginning (it is theoretically possible that the file-like object passed in wasn't at zero the first time), my solution would be to just re-use the bytes already read. I've created #6234 to resolve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants