Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .codacy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
# Codacy configuration file
# https://docs.codacy.com/repositories-configure/codacy-configuration-file/
# Analyze only doctr/ and references/ — everything else is excluded.

exclude_paths:
- ".github/**"
- "api/**"
- "demo/**"
- "docs/**"
- "notebooks/**"
- "scripts/**"
- "tests/**"
# Root-level files (setup.py, pyproject.toml, README.md, ...)
- "*.*"
69 changes: 53 additions & 16 deletions doctr/utils/fonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,71 @@

import logging
import platform
from functools import lru_cache

from PIL import ImageFont

__all__ = ["get_font"]

_FONT_CANDIDATES: dict[str, tuple[str, ...]] = {
"Linux": (
"DejaVuSans.ttf",
"NotoSans-Regular.ttf",
"LiberationSans-Regular.ttf",
"FreeSans.ttf",
"FreeMono.ttf", # legacy default
),
"Darwin": (
"Arial Unicode.ttf",
"Helvetica.ttc",
"Arial.ttf", # legacy default
),
"Windows": (
"arial.ttf", # legacy default
"segoeui.ttf",
"tahoma.ttf",
),
}


@lru_cache(maxsize=1)
def _resolve_default_font_family() -> str | None:
"""Find the first available candidate font for this platform."""
candidates = _FONT_CANDIDATES.get(platform.system(), _FONT_CANDIDATES["Linux"])
for family in candidates:
try:
ImageFont.truetype(family, 10)
return family
except OSError:
continue
return None


def get_font(font_family: str | None = None, font_size: int = 13) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
"""Resolves a compatible ImageFont for the system

Args:
font_family: the font family to use
font_family: the font family (or path to a font file) to use. If None,
the best available system font is picked automatically.
font_size: the size of the font upon rendering

Returns:
the Pillow font
"""
# Font selection
if font_family is None:
try:
font = ImageFont.truetype("FreeMono.ttf" if platform.system() == "Linux" else "Arial.ttf", font_size)
except OSError: # pragma: no cover
font = ImageFont.load_default() # type: ignore[assignment]
logging.warning(
"unable to load recommended font family. Loading default PIL font,"
"font size issues may be expected."
"To prevent this, it is recommended to specify the value of 'font_family'."
)
else: # pragma: no cover
font = ImageFont.truetype(font_family, font_size)

return font
if font_family is not None:
return ImageFont.truetype(font_family, font_size)

default_family = _resolve_default_font_family()
if default_family is not None:
return ImageFont.truetype(default_family, font_size)

# Last resort: Pillow's built-in font.
try:
return ImageFont.load_default(size=font_size)
except TypeError: # pragma: no cover
logging.warning(
"Unable to load any recommended font family. Loading default PIL font, "
"font size issues may be expected. "
"To prevent this, it is recommended to specify the value of 'font_family'."
)
return ImageFont.load_default()
Loading
Loading