Spaces:
Runtime error
Runtime error
# | |
# The Python Imaging Library. | |
# $Id$ | |
# | |
# PIL raster font management | |
# | |
# History: | |
# 1996-08-07 fl created (experimental) | |
# 1997-08-25 fl minor adjustments to handle fonts from pilfont 0.3 | |
# 1999-02-06 fl rewrote most font management stuff in C | |
# 1999-03-17 fl take pth files into account in load_path (from Richard Jones) | |
# 2001-02-17 fl added freetype support | |
# 2001-05-09 fl added TransposedFont wrapper class | |
# 2002-03-04 fl make sure we have a "L" or "1" font | |
# 2002-12-04 fl skip non-directory entries in the system path | |
# 2003-04-29 fl add embedded default font | |
# 2003-09-27 fl added support for truetype charmap encodings | |
# | |
# Todo: | |
# Adapt to PILFONT2 format (16-bit fonts, compressed, single file) | |
# | |
# Copyright (c) 1997-2003 by Secret Labs AB | |
# Copyright (c) 1996-2003 by Fredrik Lundh | |
# | |
# See the README file for information on usage and redistribution. | |
# | |
import base64 | |
import math | |
import os | |
import sys | |
import warnings | |
from enum import IntEnum | |
from io import BytesIO | |
from . import Image | |
from ._deprecate import deprecate | |
from ._util import is_directory, is_path | |
class Layout(IntEnum): | |
BASIC = 0 | |
RAQM = 1 | |
def __getattr__(name): | |
for enum, prefix in {Layout: "LAYOUT_"}.items(): | |
if name.startswith(prefix): | |
name = name[len(prefix) :] | |
if name in enum.__members__: | |
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}") | |
return enum[name] | |
msg = f"module '{__name__}' has no attribute '{name}'" | |
raise AttributeError(msg) | |
try: | |
from . import _imagingft as core | |
except ImportError as ex: | |
from ._util import DeferredError | |
core = DeferredError(ex) | |
_UNSPECIFIED = object() | |
# FIXME: add support for pilfont2 format (see FontFile.py) | |
# -------------------------------------------------------------------- | |
# Font metrics format: | |
# "PILfont" LF | |
# fontdescriptor LF | |
# (optional) key=value... LF | |
# "DATA" LF | |
# binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox) | |
# | |
# To place a character, cut out srcbox and paste at dstbox, | |
# relative to the character position. Then move the character | |
# position according to dx, dy. | |
# -------------------------------------------------------------------- | |
class ImageFont: | |
"""PIL font wrapper""" | |
def _load_pilfont(self, filename): | |
with open(filename, "rb") as fp: | |
image = None | |
for ext in (".png", ".gif", ".pbm"): | |
if image: | |
image.close() | |
try: | |
fullname = os.path.splitext(filename)[0] + ext | |
image = Image.open(fullname) | |
except Exception: | |
pass | |
else: | |
if image and image.mode in ("1", "L"): | |
break | |
else: | |
if image: | |
image.close() | |
msg = "cannot find glyph data file" | |
raise OSError(msg) | |
self.file = fullname | |
self._load_pilfont_data(fp, image) | |
image.close() | |
def _load_pilfont_data(self, file, image): | |
# read PILfont header | |
if file.readline() != b"PILfont\n": | |
msg = "Not a PILfont file" | |
raise SyntaxError(msg) | |
file.readline().split(b";") | |
self.info = [] # FIXME: should be a dictionary | |
while True: | |
s = file.readline() | |
if not s or s == b"DATA\n": | |
break | |
self.info.append(s) | |
# read PILfont metrics | |
data = file.read(256 * 20) | |
# check image | |
if image.mode not in ("1", "L"): | |
msg = "invalid font image mode" | |
raise TypeError(msg) | |
image.load() | |
self.font = Image.core.font(image.im, data) | |
def getsize(self, text, *args, **kwargs): | |
""" | |
.. deprecated:: 9.2.0 | |
Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. | |
See :ref:`deprecations <Font size and offset methods>` for more information. | |
Returns width and height (in pixels) of given text. | |
:param text: Text to measure. | |
:return: (width, height) | |
""" | |
deprecate("getsize", 10, "getbbox or getlength") | |
return self.font.getsize(text) | |
def getmask(self, text, mode="", *args, **kwargs): | |
""" | |
Create a bitmap for the text. | |
If the font uses antialiasing, the bitmap should have mode ``L`` and use a | |
maximum value of 255. Otherwise, it should have mode ``1``. | |
:param text: Text to render. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
.. versionadded:: 1.1.5 | |
:return: An internal PIL storage memory instance as defined by the | |
:py:mod:`PIL.Image.core` interface module. | |
""" | |
return self.font.getmask(text, mode) | |
def getbbox(self, text, *args, **kwargs): | |
""" | |
Returns bounding box (in pixels) of given text. | |
.. versionadded:: 9.2.0 | |
:param text: Text to render. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
:return: ``(left, top, right, bottom)`` bounding box | |
""" | |
width, height = self.font.getsize(text) | |
return 0, 0, width, height | |
def getlength(self, text, *args, **kwargs): | |
""" | |
Returns length (in pixels) of given text. | |
This is the amount by which following text should be offset. | |
.. versionadded:: 9.2.0 | |
""" | |
width, height = self.font.getsize(text) | |
return width | |
## | |
# Wrapper for FreeType fonts. Application code should use the | |
# <b>truetype</b> factory function to create font objects. | |
class FreeTypeFont: | |
"""FreeType font wrapper (requires _imagingft service)""" | |
def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None): | |
# FIXME: use service provider instead | |
self.path = font | |
self.size = size | |
self.index = index | |
self.encoding = encoding | |
if layout_engine not in (Layout.BASIC, Layout.RAQM): | |
layout_engine = Layout.BASIC | |
if core.HAVE_RAQM: | |
layout_engine = Layout.RAQM | |
elif layout_engine == Layout.RAQM and not core.HAVE_RAQM: | |
warnings.warn( | |
"Raqm layout was requested, but Raqm is not available. " | |
"Falling back to basic layout." | |
) | |
layout_engine = Layout.BASIC | |
self.layout_engine = layout_engine | |
def load_from_bytes(f): | |
self.font_bytes = f.read() | |
self.font = core.getfont( | |
"", size, index, encoding, self.font_bytes, layout_engine | |
) | |
if is_path(font): | |
if sys.platform == "win32": | |
font_bytes_path = font if isinstance(font, bytes) else font.encode() | |
try: | |
font_bytes_path.decode("ascii") | |
except UnicodeDecodeError: | |
# FreeType cannot load fonts with non-ASCII characters on Windows | |
# So load it into memory first | |
with open(font, "rb") as f: | |
load_from_bytes(f) | |
return | |
self.font = core.getfont( | |
font, size, index, encoding, layout_engine=layout_engine | |
) | |
else: | |
load_from_bytes(font) | |
def __getstate__(self): | |
return [self.path, self.size, self.index, self.encoding, self.layout_engine] | |
def __setstate__(self, state): | |
path, size, index, encoding, layout_engine = state | |
self.__init__(path, size, index, encoding, layout_engine) | |
def _multiline_split(self, text): | |
split_character = "\n" if isinstance(text, str) else b"\n" | |
return text.split(split_character) | |
def getname(self): | |
""" | |
:return: A tuple of the font family (e.g. Helvetica) and the font style | |
(e.g. Bold) | |
""" | |
return self.font.family, self.font.style | |
def getmetrics(self): | |
""" | |
:return: A tuple of the font ascent (the distance from the baseline to | |
the highest outline point) and descent (the distance from the | |
baseline to the lowest outline point, a negative value) | |
""" | |
return self.font.ascent, self.font.descent | |
def getlength(self, text, mode="", direction=None, features=None, language=None): | |
""" | |
Returns length (in pixels with 1/64 precision) of given text when rendered | |
in font with provided direction, features, and language. | |
This is the amount by which following text should be offset. | |
Text bounding box may extend past the length in some fonts, | |
e.g. when using italics or accents. | |
The result is returned as a float; it is a whole number if using basic layout. | |
Note that the sum of two lengths may not equal the length of a concatenated | |
string due to kerning. If you need to adjust for kerning, include the following | |
character and subtract its length. | |
For example, instead of :: | |
hello = font.getlength("Hello") | |
world = font.getlength("World") | |
hello_world = hello + world # not adjusted for kerning | |
assert hello_world == font.getlength("HelloWorld") # may fail | |
use :: | |
hello = font.getlength("HelloW") - font.getlength("W") # adjusted for kerning | |
world = font.getlength("World") | |
hello_world = hello + world # adjusted for kerning | |
assert hello_world == font.getlength("HelloWorld") # True | |
or disable kerning with (requires libraqm) :: | |
hello = draw.textlength("Hello", font, features=["-kern"]) | |
world = draw.textlength("World", font, features=["-kern"]) | |
hello_world = hello + world # kerning is disabled, no need to adjust | |
assert hello_world == draw.textlength("HelloWorld", font, features=["-kern"]) | |
.. versionadded:: 8.0.0 | |
:param text: Text to measure. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
:return: Width for horizontal, height for vertical text. | |
""" | |
return self.font.getlength(text, mode, direction, features, language) / 64 | |
def getbbox( | |
self, | |
text, | |
mode="", | |
direction=None, | |
features=None, | |
language=None, | |
stroke_width=0, | |
anchor=None, | |
): | |
""" | |
Returns bounding box (in pixels) of given text relative to given anchor | |
when rendered in font with provided direction, features, and language. | |
Use :py:meth:`getlength()` to get the offset of following text with | |
1/64 pixel precision. The bounding box includes extra margins for | |
some fonts, e.g. italics or accents. | |
.. versionadded:: 8.0.0 | |
:param text: Text to render. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
:param stroke_width: The width of the text stroke. | |
:param anchor: The text anchor alignment. Determines the relative location of | |
the anchor to the text. The default alignment is top left. | |
See :ref:`text-anchors` for valid values. | |
:return: ``(left, top, right, bottom)`` bounding box | |
""" | |
size, offset = self.font.getsize( | |
text, mode, direction, features, language, anchor | |
) | |
left, top = offset[0] - stroke_width, offset[1] - stroke_width | |
width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width | |
return left, top, left + width, top + height | |
def getsize( | |
self, | |
text, | |
direction=None, | |
features=None, | |
language=None, | |
stroke_width=0, | |
): | |
""" | |
.. deprecated:: 9.2.0 | |
Use :py:meth:`getlength()` to measure the offset of following text with | |
1/64 pixel precision. | |
Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor. | |
See :ref:`deprecations <Font size and offset methods>` for more information. | |
Returns width and height (in pixels) of given text if rendered in font with | |
provided direction, features, and language. | |
.. note:: For historical reasons this function measures text height from | |
the ascender line instead of the top, see :ref:`text-anchors`. | |
If you wish to measure text height from the top, it is recommended | |
to use the bottom value of :meth:`getbbox` with ``anchor='lt'`` instead. | |
:param text: Text to measure. | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
.. versionadded:: 6.0.0 | |
:param stroke_width: The width of the text stroke. | |
.. versionadded:: 6.2.0 | |
:return: (width, height) | |
""" | |
deprecate("getsize", 10, "getbbox or getlength") | |
# vertical offset is added for historical reasons | |
# see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929 | |
size, offset = self.font.getsize(text, "L", direction, features, language) | |
return ( | |
size[0] + stroke_width * 2, | |
size[1] + stroke_width * 2 + offset[1], | |
) | |
def getsize_multiline( | |
self, | |
text, | |
direction=None, | |
spacing=4, | |
features=None, | |
language=None, | |
stroke_width=0, | |
): | |
""" | |
.. deprecated:: 9.2.0 | |
Use :py:meth:`.ImageDraw.multiline_textbbox` instead. | |
See :ref:`deprecations <Font size and offset methods>` for more information. | |
Returns width and height (in pixels) of given text if rendered in font | |
with provided direction, features, and language, while respecting | |
newline characters. | |
:param text: Text to measure. | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
:param spacing: The vertical gap between lines, defaulting to 4 pixels. | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
.. versionadded:: 6.0.0 | |
:param stroke_width: The width of the text stroke. | |
.. versionadded:: 6.2.0 | |
:return: (width, height) | |
""" | |
deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox") | |
max_width = 0 | |
lines = self._multiline_split(text) | |
with warnings.catch_warnings(): | |
warnings.filterwarnings("ignore", category=DeprecationWarning) | |
line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing | |
for line in lines: | |
line_width, line_height = self.getsize( | |
line, direction, features, language, stroke_width | |
) | |
max_width = max(max_width, line_width) | |
return max_width, len(lines) * line_spacing - spacing | |
def getoffset(self, text): | |
""" | |
.. deprecated:: 9.2.0 | |
Use :py:meth:`.getbbox` instead. | |
See :ref:`deprecations <Font size and offset methods>` for more information. | |
Returns the offset of given text. This is the gap between the | |
starting coordinate and the first marking. Note that this gap is | |
included in the result of :py:func:`~PIL.ImageFont.FreeTypeFont.getsize`. | |
:param text: Text to measure. | |
:return: A tuple of the x and y offset | |
""" | |
deprecate("getoffset", 10, "getbbox") | |
return self.font.getsize(text)[1] | |
def getmask( | |
self, | |
text, | |
mode="", | |
direction=None, | |
features=None, | |
language=None, | |
stroke_width=0, | |
anchor=None, | |
ink=0, | |
start=None, | |
): | |
""" | |
Create a bitmap for the text. | |
If the font uses antialiasing, the bitmap should have mode ``L`` and use a | |
maximum value of 255. If the font has embedded color data, the bitmap | |
should have mode ``RGBA``. Otherwise, it should have mode ``1``. | |
:param text: Text to render. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
.. versionadded:: 1.1.5 | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
.. versionadded:: 6.0.0 | |
:param stroke_width: The width of the text stroke. | |
.. versionadded:: 6.2.0 | |
:param anchor: The text anchor alignment. Determines the relative location of | |
the anchor to the text. The default alignment is top left. | |
See :ref:`text-anchors` for valid values. | |
.. versionadded:: 8.0.0 | |
:param ink: Foreground ink for rendering in RGBA mode. | |
.. versionadded:: 8.0.0 | |
:param start: Tuple of horizontal and vertical offset, as text may render | |
differently when starting at fractional coordinates. | |
.. versionadded:: 9.4.0 | |
:return: An internal PIL storage memory instance as defined by the | |
:py:mod:`PIL.Image.core` interface module. | |
""" | |
return self.getmask2( | |
text, | |
mode, | |
direction=direction, | |
features=features, | |
language=language, | |
stroke_width=stroke_width, | |
anchor=anchor, | |
ink=ink, | |
start=start, | |
)[0] | |
def getmask2( | |
self, | |
text, | |
mode="", | |
fill=_UNSPECIFIED, | |
direction=None, | |
features=None, | |
language=None, | |
stroke_width=0, | |
anchor=None, | |
ink=0, | |
start=None, | |
*args, | |
**kwargs, | |
): | |
""" | |
Create a bitmap for the text. | |
If the font uses antialiasing, the bitmap should have mode ``L`` and use a | |
maximum value of 255. If the font has embedded color data, the bitmap | |
should have mode ``RGBA``. Otherwise, it should have mode ``1``. | |
:param text: Text to render. | |
:param mode: Used by some graphics drivers to indicate what mode the | |
driver prefers; if empty, the renderer may return either | |
mode. Note that the mode is always a string, to simplify | |
C-level implementations. | |
.. versionadded:: 1.1.5 | |
:param fill: Optional fill function. By default, an internal Pillow function | |
will be used. | |
Deprecated. This parameter will be removed in Pillow 10 | |
(2023-07-01). | |
:param direction: Direction of the text. It can be 'rtl' (right to | |
left), 'ltr' (left to right) or 'ttb' (top to bottom). | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param features: A list of OpenType font features to be used during text | |
layout. This is usually used to turn on optional | |
font features that are not enabled by default, | |
for example 'dlig' or 'ss01', but can be also | |
used to turn off default font features for | |
example '-liga' to disable ligatures or '-kern' | |
to disable kerning. To get all supported | |
features, see | |
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | |
Requires libraqm. | |
.. versionadded:: 4.2.0 | |
:param language: Language of the text. Different languages may use | |
different glyph shapes or ligatures. This parameter tells | |
the font which language the text is in, and to apply the | |
correct substitutions as appropriate, if available. | |
It should be a `BCP 47 language code | |
<https://www.w3.org/International/articles/language-tags/>`_ | |
Requires libraqm. | |
.. versionadded:: 6.0.0 | |
:param stroke_width: The width of the text stroke. | |
.. versionadded:: 6.2.0 | |
:param anchor: The text anchor alignment. Determines the relative location of | |
the anchor to the text. The default alignment is top left. | |
See :ref:`text-anchors` for valid values. | |
.. versionadded:: 8.0.0 | |
:param ink: Foreground ink for rendering in RGBA mode. | |
.. versionadded:: 8.0.0 | |
:param start: Tuple of horizontal and vertical offset, as text may render | |
differently when starting at fractional coordinates. | |
.. versionadded:: 9.4.0 | |
:return: A tuple of an internal PIL storage memory instance as defined by the | |
:py:mod:`PIL.Image.core` interface module, and the text offset, the | |
gap between the starting coordinate and the first marking | |
""" | |
if fill is _UNSPECIFIED: | |
fill = Image.core.fill | |
else: | |
deprecate("fill", 10) | |
size, offset = self.font.getsize( | |
text, mode, direction, features, language, anchor | |
) | |
if start is None: | |
start = (0, 0) | |
size = tuple(math.ceil(size[i] + stroke_width * 2 + start[i]) for i in range(2)) | |
offset = offset[0] - stroke_width, offset[1] - stroke_width | |
Image._decompression_bomb_check(size) | |
im = fill("RGBA" if mode == "RGBA" else "L", size, 0) | |
if min(size): | |
self.font.render( | |
text, | |
im.id, | |
mode, | |
direction, | |
features, | |
language, | |
stroke_width, | |
ink, | |
start[0], | |
start[1], | |
) | |
return im, offset | |
def font_variant( | |
self, font=None, size=None, index=None, encoding=None, layout_engine=None | |
): | |
""" | |
Create a copy of this FreeTypeFont object, | |
using any specified arguments to override the settings. | |
Parameters are identical to the parameters used to initialize this | |
object. | |
:return: A FreeTypeFont object. | |
""" | |
if font is None: | |
try: | |
font = BytesIO(self.font_bytes) | |
except AttributeError: | |
font = self.path | |
return FreeTypeFont( | |
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, | |
layout_engine=layout_engine or self.layout_engine, | |
) | |
def get_variation_names(self): | |
""" | |
:returns: A list of the named styles in a variation font. | |
:exception OSError: If the font is not a variation font. | |
""" | |
try: | |
names = self.font.getvarnames() | |
except AttributeError as e: | |
msg = "FreeType 2.9.1 or greater is required" | |
raise NotImplementedError(msg) from e | |
return [name.replace(b"\x00", b"") for name in names] | |
def set_variation_by_name(self, name): | |
""" | |
:param name: The name of the style. | |
:exception OSError: If the font is not a variation font. | |
""" | |
names = self.get_variation_names() | |
if not isinstance(name, bytes): | |
name = name.encode() | |
index = names.index(name) + 1 | |
if index == getattr(self, "_last_variation_index", None): | |
# When the same name is set twice in a row, | |
# there is an 'unknown freetype error' | |
# https://savannah.nongnu.org/bugs/?56186 | |
return | |
self._last_variation_index = index | |
self.font.setvarname(index) | |
def get_variation_axes(self): | |
""" | |
:returns: A list of the axes in a variation font. | |
:exception OSError: If the font is not a variation font. | |
""" | |
try: | |
axes = self.font.getvaraxes() | |
except AttributeError as e: | |
msg = "FreeType 2.9.1 or greater is required" | |
raise NotImplementedError(msg) from e | |
for axis in axes: | |
axis["name"] = axis["name"].replace(b"\x00", b"") | |
return axes | |
def set_variation_by_axes(self, axes): | |
""" | |
:param axes: A list of values for each axis. | |
:exception OSError: If the font is not a variation font. | |
""" | |
try: | |
self.font.setvaraxes(axes) | |
except AttributeError as e: | |
msg = "FreeType 2.9.1 or greater is required" | |
raise NotImplementedError(msg) from e | |
class TransposedFont: | |
"""Wrapper for writing rotated or mirrored text""" | |
def __init__(self, font, orientation=None): | |
""" | |
Wrapper that creates a transposed font from any existing font | |
object. | |
:param font: A font object. | |
:param orientation: An optional orientation. If given, this should | |
be one of Image.Transpose.FLIP_LEFT_RIGHT, Image.Transpose.FLIP_TOP_BOTTOM, | |
Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_180, or | |
Image.Transpose.ROTATE_270. | |
""" | |
self.font = font | |
self.orientation = orientation # any 'transpose' argument, or None | |
def getsize(self, text, *args, **kwargs): | |
""" | |
.. deprecated:: 9.2.0 | |
Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. | |
See :ref:`deprecations <Font size and offset methods>` for more information. | |
""" | |
deprecate("getsize", 10, "getbbox or getlength") | |
with warnings.catch_warnings(): | |
warnings.filterwarnings("ignore", category=DeprecationWarning) | |
w, h = self.font.getsize(text) | |
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): | |
return h, w | |
return w, h | |
def getmask(self, text, mode="", *args, **kwargs): | |
im = self.font.getmask(text, mode, *args, **kwargs) | |
if self.orientation is not None: | |
return im.transpose(self.orientation) | |
return im | |
def getbbox(self, text, *args, **kwargs): | |
# TransposedFont doesn't support getmask2, move top-left point to (0, 0) | |
# this has no effect on ImageFont and simulates anchor="lt" for FreeTypeFont | |
left, top, right, bottom = self.font.getbbox(text, *args, **kwargs) | |
width = right - left | |
height = bottom - top | |
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): | |
return 0, 0, height, width | |
return 0, 0, width, height | |
def getlength(self, text, *args, **kwargs): | |
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): | |
msg = "text length is undefined for text rotated by 90 or 270 degrees" | |
raise ValueError(msg) | |
return self.font.getlength(text, *args, **kwargs) | |
def load(filename): | |
""" | |
Load a font file. This function loads a font object from the given | |
bitmap font file, and returns the corresponding font object. | |
:param filename: Name of font file. | |
:return: A font object. | |
:exception OSError: If the file could not be read. | |
""" | |
f = ImageFont() | |
f._load_pilfont(filename) | |
return f | |
def truetype(font=None, size=10, index=0, encoding="", layout_engine=None): | |
""" | |
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. | |
Pillow uses FreeType to open font files. On Windows, be aware that FreeType | |
will keep the file open as long as the FreeTypeFont object exists. Windows | |
limits the number of files that can be open in C at once to 512, so if many | |
fonts are opened simultaneously and that limit is approached, an | |
``OSError`` may be thrown, reporting that FreeType "cannot open resource". | |
A workaround would be to copy the file(s) into memory, and open that instead. | |
This function requires the _imagingft service. | |
:param font: A filename or file-like object containing a TrueType font. | |
If the file is not found in this filename, the loader may also | |
search in other directories, such as the :file:`fonts/` | |
directory on Windows or :file:`/Library/Fonts/`, | |
:file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on | |
macOS. | |
:param size: The requested size, in pixels. | |
:param index: Which font face to load (default is first available face). | |
:param encoding: Which font encoding to use (default is Unicode). Possible | |
encodings include (see the FreeType documentation for more | |
information): | |
* "unic" (Unicode) | |
* "symb" (Microsoft Symbol) | |
* "ADOB" (Adobe Standard) | |
* "ADBE" (Adobe Expert) | |
* "ADBC" (Adobe Custom) | |
* "armn" (Apple Roman) | |
* "sjis" (Shift JIS) | |
* "gb " (PRC) | |
* "big5" | |
* "wans" (Extended Wansung) | |
* "joha" (Johab) | |
* "lat1" (Latin-1) | |
This specifies the character set to use. It does not alter the | |
encoding of any text provided in subsequent operations. | |
:param layout_engine: Which layout engine to use, if available: | |
:data:`.ImageFont.Layout.BASIC` or :data:`.ImageFont.Layout.RAQM`. | |
If it is available, Raqm layout will be used by default. | |
Otherwise, basic layout will be used. | |
Raqm layout is recommended for all non-English text. If Raqm layout | |
is not required, basic layout will have better performance. | |
You can check support for Raqm layout using | |
:py:func:`PIL.features.check_feature` with ``feature="raqm"``. | |
.. versionadded:: 4.2.0 | |
:return: A font object. | |
:exception OSError: If the file could not be read. | |
""" | |
def freetype(font): | |
return FreeTypeFont(font, size, index, encoding, layout_engine) | |
try: | |
return freetype(font) | |
except OSError: | |
if not is_path(font): | |
raise | |
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: | |
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" | |
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"), | |
] | |
ext = os.path.splitext(ttf_filename)[1] | |
first_font_with_a_different_extension = None | |
for directory in dirs: | |
for walkroot, walkdir, walkfilenames in os.walk(directory): | |
for walkfilename in walkfilenames: | |
if ext and walkfilename == ttf_filename: | |
return freetype(os.path.join(walkroot, walkfilename)) | |
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 freetype(fontpath) | |
if not ext and first_font_with_a_different_extension is None: | |
first_font_with_a_different_extension = fontpath | |
if first_font_with_a_different_extension: | |
return freetype(first_font_with_a_different_extension) | |
raise | |
def load_path(filename): | |
""" | |
Load font file. Same as :py:func:`~PIL.ImageFont.load`, but searches for a | |
bitmap font along the Python path. | |
:param filename: Name of font file. | |
:return: A font object. | |
:exception OSError: If the file could not be read. | |
""" | |
for directory in sys.path: | |
if is_directory(directory): | |
if not isinstance(filename, str): | |
filename = filename.decode("utf-8") | |
try: | |
return load(os.path.join(directory, filename)) | |
except OSError: | |
pass | |
msg = "cannot find font file" | |
raise OSError(msg) | |
def load_default(): | |
"""Load a "better than nothing" default font. | |
.. versionadded:: 1.1.4 | |
:return: A font object. | |
""" | |
f = ImageFont() | |
f._load_pilfont_data( | |
# courB08 | |
BytesIO( | |
base64.b64decode( | |
b""" | |
UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAA//8AAQAAAAAAAAABAAEA | |
BgAAAAH/+gADAAAAAQAAAAMABgAGAAAAAf/6AAT//QADAAAABgADAAYAAAAA//kABQABAAYAAAAL | |
AAgABgAAAAD/+AAFAAEACwAAABAACQAGAAAAAP/5AAUAAAAQAAAAFQAHAAYAAP////oABQAAABUA | |
AAAbAAYABgAAAAH/+QAE//wAGwAAAB4AAwAGAAAAAf/5AAQAAQAeAAAAIQAIAAYAAAAB//kABAAB | |
ACEAAAAkAAgABgAAAAD/+QAE//0AJAAAACgABAAGAAAAAP/6AAX//wAoAAAALQAFAAYAAAAB//8A | |
BAACAC0AAAAwAAMABgAAAAD//AAF//0AMAAAADUAAQAGAAAAAf//AAMAAAA1AAAANwABAAYAAAAB | |
//kABQABADcAAAA7AAgABgAAAAD/+QAFAAAAOwAAAEAABwAGAAAAAP/5AAYAAABAAAAARgAHAAYA | |
AAAA//kABQAAAEYAAABLAAcABgAAAAD/+QAFAAAASwAAAFAABwAGAAAAAP/5AAYAAABQAAAAVgAH | |
AAYAAAAA//kABQAAAFYAAABbAAcABgAAAAD/+QAFAAAAWwAAAGAABwAGAAAAAP/5AAUAAABgAAAA | |
ZQAHAAYAAAAA//kABQAAAGUAAABqAAcABgAAAAD/+QAFAAAAagAAAG8ABwAGAAAAAf/8AAMAAABv | |
AAAAcQAEAAYAAAAA//wAAwACAHEAAAB0AAYABgAAAAD/+gAE//8AdAAAAHgABQAGAAAAAP/7AAT/ | |
/gB4AAAAfAADAAYAAAAB//oABf//AHwAAACAAAUABgAAAAD/+gAFAAAAgAAAAIUABgAGAAAAAP/5 | |
AAYAAQCFAAAAiwAIAAYAAP////oABgAAAIsAAACSAAYABgAA////+gAFAAAAkgAAAJgABgAGAAAA | |
AP/6AAUAAACYAAAAnQAGAAYAAP////oABQAAAJ0AAACjAAYABgAA////+gAFAAAAowAAAKkABgAG | |
AAD////6AAUAAACpAAAArwAGAAYAAAAA//oABQAAAK8AAAC0AAYABgAA////+gAGAAAAtAAAALsA | |
BgAGAAAAAP/6AAQAAAC7AAAAvwAGAAYAAP////oABQAAAL8AAADFAAYABgAA////+gAGAAAAxQAA | |
AMwABgAGAAD////6AAUAAADMAAAA0gAGAAYAAP////oABQAAANIAAADYAAYABgAA////+gAGAAAA | |
2AAAAN8ABgAGAAAAAP/6AAUAAADfAAAA5AAGAAYAAP////oABQAAAOQAAADqAAYABgAAAAD/+gAF | |
AAEA6gAAAO8ABwAGAAD////6AAYAAADvAAAA9gAGAAYAAAAA//oABQAAAPYAAAD7AAYABgAA//// | |
+gAFAAAA+wAAAQEABgAGAAD////6AAYAAAEBAAABCAAGAAYAAP////oABgAAAQgAAAEPAAYABgAA | |
////+gAGAAABDwAAARYABgAGAAAAAP/6AAYAAAEWAAABHAAGAAYAAP////oABgAAARwAAAEjAAYA | |
BgAAAAD/+gAFAAABIwAAASgABgAGAAAAAf/5AAQAAQEoAAABKwAIAAYAAAAA//kABAABASsAAAEv | |
AAgABgAAAAH/+QAEAAEBLwAAATIACAAGAAAAAP/5AAX//AEyAAABNwADAAYAAAAAAAEABgACATcA | |
AAE9AAEABgAAAAH/+QAE//wBPQAAAUAAAwAGAAAAAP/7AAYAAAFAAAABRgAFAAYAAP////kABQAA | |
AUYAAAFMAAcABgAAAAD/+wAFAAABTAAAAVEABQAGAAAAAP/5AAYAAAFRAAABVwAHAAYAAAAA//sA | |
BQAAAVcAAAFcAAUABgAAAAD/+QAFAAABXAAAAWEABwAGAAAAAP/7AAYAAgFhAAABZwAHAAYAAP// | |
//kABQAAAWcAAAFtAAcABgAAAAD/+QAGAAABbQAAAXMABwAGAAAAAP/5AAQAAgFzAAABdwAJAAYA | |
AP////kABgAAAXcAAAF+AAcABgAAAAD/+QAGAAABfgAAAYQABwAGAAD////7AAUAAAGEAAABigAF | |
AAYAAP////sABQAAAYoAAAGQAAUABgAAAAD/+wAFAAABkAAAAZUABQAGAAD////7AAUAAgGVAAAB | |
mwAHAAYAAAAA//sABgACAZsAAAGhAAcABgAAAAD/+wAGAAABoQAAAacABQAGAAAAAP/7AAYAAAGn | |
AAABrQAFAAYAAAAA//kABgAAAa0AAAGzAAcABgAA////+wAGAAABswAAAboABQAGAAD////7AAUA | |
AAG6AAABwAAFAAYAAP////sABgAAAcAAAAHHAAUABgAAAAD/+wAGAAABxwAAAc0ABQAGAAD////7 | |
AAYAAgHNAAAB1AAHAAYAAAAA//sABQAAAdQAAAHZAAUABgAAAAH/+QAFAAEB2QAAAd0ACAAGAAAA | |
Av/6AAMAAQHdAAAB3gAHAAYAAAAA//kABAABAd4AAAHiAAgABgAAAAD/+wAF//0B4gAAAecAAgAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAB | |
//sAAwACAecAAAHpAAcABgAAAAD/+QAFAAEB6QAAAe4ACAAGAAAAAP/5AAYAAAHuAAAB9AAHAAYA | |
AAAA//oABf//AfQAAAH5AAUABgAAAAD/+QAGAAAB+QAAAf8ABwAGAAAAAv/5AAMAAgH/AAACAAAJ | |
AAYAAAAA//kABQABAgAAAAIFAAgABgAAAAH/+gAE//sCBQAAAggAAQAGAAAAAP/5AAYAAAIIAAAC | |
DgAHAAYAAAAB//kABf/+Ag4AAAISAAUABgAA////+wAGAAACEgAAAhkABQAGAAAAAP/7AAX//gIZ | |
AAACHgADAAYAAAAA//wABf/9Ah4AAAIjAAEABgAAAAD/+QAHAAACIwAAAioABwAGAAAAAP/6AAT/ | |
+wIqAAACLgABAAYAAAAA//kABP/8Ai4AAAIyAAMABgAAAAD/+gAFAAACMgAAAjcABgAGAAAAAf/5 | |
AAT//QI3AAACOgAEAAYAAAAB//kABP/9AjoAAAI9AAQABgAAAAL/+QAE//sCPQAAAj8AAgAGAAD/ | |
///7AAYAAgI/AAACRgAHAAYAAAAA//kABgABAkYAAAJMAAgABgAAAAH//AAD//0CTAAAAk4AAQAG | |
AAAAAf//AAQAAgJOAAACUQADAAYAAAAB//kABP/9AlEAAAJUAAQABgAAAAH/+QAF//4CVAAAAlgA | |
BQAGAAD////7AAYAAAJYAAACXwAFAAYAAP////kABgAAAl8AAAJmAAcABgAA////+QAGAAACZgAA | |
Am0ABwAGAAD////5AAYAAAJtAAACdAAHAAYAAAAA//sABQACAnQAAAJ5AAcABgAA////9wAGAAAC | |
eQAAAoAACQAGAAD////3AAYAAAKAAAAChwAJAAYAAP////cABgAAAocAAAKOAAkABgAA////9wAG | |
AAACjgAAApUACQAGAAD////4AAYAAAKVAAACnAAIAAYAAP////cABgAAApwAAAKjAAkABgAA//// | |
+gAGAAACowAAAqoABgAGAAAAAP/6AAUAAgKqAAACrwAIAAYAAP////cABQAAAq8AAAK1AAkABgAA | |
////9wAFAAACtQAAArsACQAGAAD////3AAUAAAK7AAACwQAJAAYAAP////gABQAAAsEAAALHAAgA | |
BgAAAAD/9wAEAAACxwAAAssACQAGAAAAAP/3AAQAAALLAAACzwAJAAYAAAAA//cABAAAAs8AAALT | |
AAkABgAAAAD/+AAEAAAC0wAAAtcACAAGAAD////6AAUAAALXAAAC3QAGAAYAAP////cABgAAAt0A | |
AALkAAkABgAAAAD/9wAFAAAC5AAAAukACQAGAAAAAP/3AAUAAALpAAAC7gAJAAYAAAAA//cABQAA | |
Au4AAALzAAkABgAAAAD/9wAFAAAC8wAAAvgACQAGAAAAAP/4AAUAAAL4AAAC/QAIAAYAAAAA//oA | |
Bf//Av0AAAMCAAUABgAA////+gAGAAADAgAAAwkABgAGAAD////3AAYAAAMJAAADEAAJAAYAAP// | |
//cABgAAAxAAAAMXAAkABgAA////9wAGAAADFwAAAx4ACQAGAAD////4AAYAAAAAAAoABwASAAYA | |
AP////cABgAAAAcACgAOABMABgAA////+gAFAAAADgAKABQAEAAGAAD////6AAYAAAAUAAoAGwAQ | |
AAYAAAAA//gABgAAABsACgAhABIABgAAAAD/+AAGAAAAIQAKACcAEgAGAAAAAP/4AAYAAAAnAAoA | |
LQASAAYAAAAA//gABgAAAC0ACgAzABIABgAAAAD/+QAGAAAAMwAKADkAEQAGAAAAAP/3AAYAAAA5 | |
AAoAPwATAAYAAP////sABQAAAD8ACgBFAA8ABgAAAAD/+wAFAAIARQAKAEoAEQAGAAAAAP/4AAUA | |
AABKAAoATwASAAYAAAAA//gABQAAAE8ACgBUABIABgAAAAD/+AAFAAAAVAAKAFkAEgAGAAAAAP/5 | |
AAUAAABZAAoAXgARAAYAAAAA//gABgAAAF4ACgBkABIABgAAAAD/+AAGAAAAZAAKAGoAEgAGAAAA | |
AP/4AAYAAABqAAoAcAASAAYAAAAA//kABgAAAHAACgB2ABEABgAAAAD/+AAFAAAAdgAKAHsAEgAG | |
AAD////4AAYAAAB7AAoAggASAAYAAAAA//gABQAAAIIACgCHABIABgAAAAD/+AAFAAAAhwAKAIwA | |
EgAGAAAAAP/4AAUAAACMAAoAkQASAAYAAAAA//gABQAAAJEACgCWABIABgAAAAD/+QAFAAAAlgAK | |
AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA | |
pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG | |
AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA//// | |
+QAGAAIAzgAKANUAEw== | |
""" | |
) | |
), | |
Image.open( | |
BytesIO( | |
base64.b64decode( | |
b""" | |
iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u | |
Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9 | |
M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g | |
LeNZUworuN1cjTPIzrTX6ofHWeo3v336qPzfEwRmBnHTtf95/fglZK5N0PDgfRTslpGBvz7LFc4F | |
IUXBWQGjQ5MGCx34EDFPwXiY4YbYxavpnhHFrk14CDAAAAD//wBlAJr/AgKqRooH2gAgPeggvUAA | |
Bu2WfgPoAwzRAABAAAAAAACQgLz/3Uv4Gv+gX7BJgDeeGP6AAAD1NMDzKHD7ANWr3loYbxsAD791 | |
NAADfcoIDyP44K/jv4Y63/Z+t98Ovt+ub4T48LAAAAD//wBlAJr/AuplMlADJAAAAGuAphWpqhMx | |
in0A/fRvAYBABPgBwBUgABBQ/sYAyv9g0bCHgOLoGAAAAAAAREAAwI7nr0ArYpow7aX8//9LaP/9 | |
SjdavWA8ePHeBIKB//81/83ndznOaXx379wAAAD//wBlAJr/AqDxW+D3AABAAbUh/QMnbQag/gAY | |
AYDAAACgtgD/gOqAAAB5IA/8AAAk+n9w0AAA8AAAmFRJuPo27ciC0cD5oeW4E7KA/wD3ECMAn2tt | |
y8PgwH8AfAxFzC0JzeAMtratAsC/ffwAAAD//wBlAJr/BGKAyCAA4AAAAvgeYTAwHd1kmQF5chkG | |
ABoMIHcL5xVpTfQbUqzlAAAErwAQBgAAEOClA5D9il08AEh/tUzdCBsXkbgACED+woQg8Si9VeqY | |
lODCn7lmF6NhnAEYgAAA/NMIAAAAAAD//2JgjLZgVGBg5Pv/Tvpc8hwGBjYGJADjHDrAwPzAjv/H | |
/Wf3PzCwtzcwHmBgYGcwbZz8wHaCAQMDOwMDQ8MCBgYOC3W7mp+f0w+wHOYxO3OG+e376hsMZjk3 | |
AAAAAP//YmCMY2A4wMAIN5e5gQETPD6AZisDAwMDgzSDAAPjByiHcQMDAwMDg1nOze1lByRu5/47 | |
c4859311AYNZzg0AAAAA//9iYGDBYihOIIMuwIjGL39/fwffA8b//xv/P2BPtzzHwCBjUQAAAAD/ | |
/yLFBrIBAAAA//9i1HhcwdhizX7u8NZNzyLbvT97bfrMf/QHI8evOwcSqGUJAAAA//9iYBB81iSw | |
pEE170Qrg5MIYydHqwdDQRMrAwcVrQAAAAD//2J4x7j9AAMDn8Q/BgYLBoaiAwwMjPdvMDBYM1Tv | |
oJodAAAAAP//Yqo/83+dxePWlxl3npsel9lvLfPcqlE9725C+acfVLMEAAAA//9i+s9gwCoaaGMR | |
evta/58PTEWzr21hufPjA8N+qlnBwAAAAAD//2JiWLci5v1+HmFXDqcnULE/MxgYGBj+f6CaJQAA | |
AAD//2Ji2FrkY3iYpYC5qDeGgeEMAwPDvwQBBoYvcTwOVLMEAAAA//9isDBgkP///0EOg9z35v// | |
Gc/eeW7BwPj5+QGZhANUswMAAAD//2JgqGBgYGBgqEMXlvhMPUsAAAAA//8iYDd1AAAAAP//AwDR | |
w7IkEbzhVQAAAABJRU5ErkJggg== | |
""" | |
) | |
) | |
), | |
) | |
return f | |