# Source code for PIL.ImageFont

    #
    # 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 os
    import sys
    from io import BytesIO

    from . import Image
    from ._util import isDirectory, isPath

    LAYOUT_BASIC = 0
    LAYOUT_RAQM = 1

    class _imagingft_not_installed:
        # module placeholder
        def __getattr__(self, id):
            raise ImportError("The _imagingft C module is not installed")

    MAX_STRING_LENGTH = 1000000

    try:
        from . import _imagingft as core
    except ImportError:
        core = _imagingft_not_installed()

    def _string_length_check(text):
        if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH:
            msg = "too many characters in string"
            raise ValueError(msg)

    # 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()
                    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):

            # read PILfont header
            if file.readline() != b"PILfont\n":
                raise SyntaxError("Not a PILfont file")
            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"):
                raise TypeError("invalid font image mode")

            image.load()

            self.font = Image.core.font(image.im, data)

        def getsize(self, text, *args, **kwargs):
            """
            Returns width and height (in pixels) of given text.

            :param text: Text to measure.

            :return: (width, height)
            """
            _string_length_check(text)
            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)

    ##
    # 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:
                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 isPath(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

            .. 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://docs.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.
            """
            _string_length_check(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://docs.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
            """
            _string_length_check(text)
            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
        ):
            """
            Returns width and height (in pixels) of given text if rendered in font with
            provided direction, features, and language.

            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.

            .. 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://docs.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)
            """
            _string_length_check(text)
            # 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,
        ):
            """
            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://docs.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)
            """
            _string_length_check(text)
            max_width = 0
            lines = self._multiline_split(text)
            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):
            """
            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
            """
            _string_length_check(text)
            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://docs.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=Image.core.fill,
            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 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://docs.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
            """
            _string_length_check(text)
            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.
            """
            return FreeTypeFont(
                font=self.path if font is None else 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)

            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:
                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.FLIP_LEFT_RIGHT, Image.FLIP_TOP_BOTTOM,
                Image.ROTATE_90, Image.ROTATE_180, or Image.ROTATE_270.
            """
            self.font = font
            self.orientation = orientation  # any 'transpose' argument, or None

        def getsize(self, text, *args, **kwargs):
            _string_length_check(text)
            w, h = self.font.getsize(text)
            if self.orientation in (Image.ROTATE_90, Image.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 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. If you are opening many fonts
        simultaneously on Windows, be aware that Windows limits the number of files
        that can be open in C at once to 512. If you approach that limit, an
        ``OSError`` may be thrown, reporting that FreeType "cannot open resource".

        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 points.
        :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`.

                         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 isPath(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 isDirectory(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(
            # 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