| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import base64 |
| | 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] |
| | raise AttributeError(f"module '{__name__}' has no attribute '{name}'") |
| |
|
| |
|
| | class _ImagingFtNotInstalled: |
| | |
| | def __getattr__(self, id): |
| | raise ImportError("The _imagingft C module is not installed") |
| |
|
| |
|
| | try: |
| | from . import _imagingft as core |
| | except ImportError: |
| | core = _ImagingFtNotInstalled() |
| |
|
| |
|
| | _UNSPECIFIED = object() |
| |
|
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | 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() |
| | raise OSError("cannot find glyph data file") |
| |
|
| | self.file = fullname |
| |
|
| | self._load_pilfont_data(fp, image) |
| | image.close() |
| |
|
| | def _load_pilfont_data(self, file, image): |
| |
|
| | |
| | if file.readline() != b"PILfont\n": |
| | raise SyntaxError("Not a PILfont file") |
| | file.readline().split(b";") |
| | self.info = [] |
| | while True: |
| | s = file.readline() |
| | if not s or s == b"DATA\n": |
| | break |
| | self.info.append(s) |
| |
|
| | |
| | data = file.read(256 * 20) |
| |
|
| | |
| | if image.mode not in ("1", "L"): |
| | raise TypeError("invalid font image mode") |
| |
|
| | 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 |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| |
|
| | class FreeTypeFont: |
| | """FreeType font wrapper (requires _imagingft service)""" |
| |
|
| | def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None): |
| | |
| |
|
| | 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: |
| | |
| | |
| | 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 |
| | |
| | .. code-block:: python |
| | |
| | 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 |
| | |
| | .. code-block:: python |
| | |
| | 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) |
| | |
| | .. code-block:: python |
| | |
| | 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") |
| | |
| | |
| | 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, |
| | ): |
| | """ |
| | 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 |
| | |
| | :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, |
| | )[0] |
| |
|
| | def getmask2( |
| | self, |
| | text, |
| | mode="", |
| | fill=_UNSPECIFIED, |
| | direction=None, |
| | features=None, |
| | language=None, |
| | stroke_width=0, |
| | anchor=None, |
| | ink=0, |
| | *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 |
| | |
| | :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 |
| | ) |
| | size = size[0] + stroke_width * 2, size[1] + stroke_width * 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) |
| | self.font.render( |
| | text, im.id, mode, direction, features, language, stroke_width, ink |
| | ) |
| | 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: |
| | raise NotImplementedError("FreeType 2.9.1 or greater is required") 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): |
| | |
| | |
| | |
| | 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: |
| | raise NotImplementedError("FreeType 2.9.1 or greater is required") 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: |
| | raise NotImplementedError("FreeType 2.9.1 or greater is required") 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 |
| |
|
| | 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): |
| | |
| | |
| | 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): |
| | raise ValueError( |
| | "text length is undefined for text rotated by 90 or 270 degrees" |
| | ) |
| | 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": |
| | |
| | |
| | |
| | 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: |
| | |
| | |
| | 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 |
| | raise OSError("cannot find font file") |
| |
|
| |
|
| | def load_default(): |
| | """Load a "better than nothing" default font. |
| | |
| | .. versionadded:: 1.1.4 |
| | |
| | :return: A font object. |
| | """ |
| | f = ImageFont() |
| | f._load_pilfont_data( |
| | |
| | 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 |
| |
|