Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
860
venv/Lib/site-packages/PIL/ImageFont.py
Normal file
860
venv/Lib/site-packages/PIL/ImageFont.py
Normal file
|
@ -0,0 +1,860 @@
|
|||
#
|
||||
# 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")
|
||||
|
||||
|
||||
try:
|
||||
from . import _imagingft as core
|
||||
except ImportError:
|
||||
core = _imagingft_not_installed()
|
||||
|
||||
|
||||
# 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)
|
||||
"""
|
||||
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 _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 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.
|
||||
|
||||
: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)
|
||||
"""
|
||||
size, offset = self.font.getsize(text, False, direction, features, language)
|
||||
return (
|
||||
size[0] + stroke_width * 2 + offset[0],
|
||||
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)
|
||||
"""
|
||||
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
|
||||
"""
|
||||
return self.font.getsize(text)[1]
|
||||
|
||||
def getmask(
|
||||
self,
|
||||
text,
|
||||
mode="",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=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. 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
|
||||
|
||||
: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,
|
||||
)[0]
|
||||
|
||||
def getmask2(
|
||||
self,
|
||||
text,
|
||||
mode="",
|
||||
fill=Image.core.fill,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=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. 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
|
||||
|
||||
: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
|
||||
"""
|
||||
size, offset = self.font.getsize(
|
||||
text, mode == "1", direction, features, language
|
||||
)
|
||||
size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
|
||||
im = fill("L", size, 0)
|
||||
self.font.render(
|
||||
text, im.id, mode == "1", direction, features, language, stroke_width
|
||||
)
|
||||
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):
|
||||
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:
|
||||
`ImageFont.LAYOUT_BASIC` or `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
|
Loading…
Add table
Add a link
Reference in a new issue