12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202 |
- #
- # 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
|