Refactoring: Move
Move font picker into new font module
This commit is contained in:
parent
9480d58a8a
commit
de9b3bad93
82
synthesis/text/font.py
Normal file
82
synthesis/text/font.py
Normal file
@ -0,0 +1,82 @@
|
||||
import itertools
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from funcy import lmap, complement, keep, first, lzip
|
||||
from loguru import logger
|
||||
|
||||
from synthesis.random import rnd
|
||||
|
||||
|
||||
class RandomFontPicker:
|
||||
def __init__(self, font_dir=None, return_default_font=False):
|
||||
fonts = get_fonts(font_dir)
|
||||
fonts_lower = [font.lower() for font in fonts]
|
||||
domestic_fonts_mask = lmap(complement(self.looks_foreign), fonts_lower)
|
||||
self.fonts = list(itertools.compress(fonts, domestic_fonts_mask))
|
||||
self.fonts_lower = list(itertools.compress(fonts_lower, domestic_fonts_mask))
|
||||
|
||||
self.test_image = Image.new("RGB", (200, 200), (255, 255, 255))
|
||||
self.draw = ImageDraw.Draw(self.test_image)
|
||||
self.return_default_font = return_default_font
|
||||
|
||||
def looks_foreign(self, font):
|
||||
# This filters out foreign fonts (e.g. 'Noto Serif Malayalam')
|
||||
return len(font.split("-")[0]) > 10
|
||||
|
||||
def pick_random_font_available_on_system(self, includes=None, excludes=None) -> ImageFont: # FIXME: Slow!
|
||||
|
||||
if self.return_default_font:
|
||||
return ImageFont.load_default()
|
||||
|
||||
includes = [i.lower() for i in includes] if includes else []
|
||||
excludes = [i.lower() for i in excludes] if excludes else []
|
||||
|
||||
logger.debug(f"Picking font by includes={includes} and excludes={excludes}.")
|
||||
|
||||
def includes_pattern(font):
|
||||
return not includes or any(include in font for include in includes)
|
||||
|
||||
def excludes_pattern(font):
|
||||
return not excludes or not any(exclude in font for exclude in excludes)
|
||||
|
||||
self.shuffle_fonts()
|
||||
|
||||
mask = lmap(lambda f: includes_pattern(f) and excludes_pattern(f), self.fonts_lower)
|
||||
fonts = itertools.compress(self.fonts, mask)
|
||||
fonts = keep(map(self.load_font, fonts))
|
||||
# fonts = filter(self.font_is_renderable, fonts) # FIXME: this does not work
|
||||
|
||||
font = first(fonts)
|
||||
logger.info(f"Using font: {font.getname()}")
|
||||
return font
|
||||
|
||||
def shuffle_fonts(self):
|
||||
l = lzip(self.fonts, self.fonts_lower)
|
||||
rnd.shuffle(l)
|
||||
self.fonts, self.fonts_lower = lzip(*l)
|
||||
|
||||
def pick_random_mono_space_font_available_on_system(self) -> ImageFont:
|
||||
return self.pick_random_font_available_on_system(includes=["mono"], excludes=["oblique"])
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def load_font(self, font: str):
|
||||
logger.trace(f"Loading font: {font}")
|
||||
try:
|
||||
return ImageFont.truetype(font, size=11)
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def font_is_renderable(self, font):
|
||||
text_size = self.draw.textsize("Test String", font=font)
|
||||
return text_size[0] > 0 and text_size[1]
|
||||
|
||||
|
||||
def get_fonts(path: Path = None) -> List[str]:
|
||||
path = path or Path("/usr/share/fonts")
|
||||
fonts = list(path.rglob("*.ttf"))
|
||||
fonts = [font.name for font in fonts]
|
||||
return fonts
|
||||
77
test/fixtures/page_generation/page.py
vendored
77
test/fixtures/page_generation/page.py
vendored
@ -8,7 +8,6 @@ from copy import deepcopy
|
||||
from enum import Enum
|
||||
from functools import lru_cache, partial
|
||||
from math import sqrt
|
||||
from pathlib import Path
|
||||
from typing import Tuple, Iterable, List
|
||||
|
||||
import blend_modes
|
||||
@ -31,6 +30,7 @@ from synthesis.partitioner.page_partitioner import PagePartitioner
|
||||
from synthesis.random import rnd
|
||||
from synthesis.segment.content_rectangle import ContentRectangle
|
||||
from synthesis.segment.random_content_rectangle import RandomContentRectangle
|
||||
from synthesis.text.font import RandomFontPicker
|
||||
from synthesis.text.line_formatter.identity import IdentityLineFormatter
|
||||
from synthesis.text.line_formatter.paragraph import ParagraphLineFormatter
|
||||
|
||||
@ -50,13 +50,10 @@ from funcy import (
|
||||
rest,
|
||||
lsplit,
|
||||
lfilter,
|
||||
lzip,
|
||||
keep,
|
||||
repeatedly,
|
||||
mapcat,
|
||||
omit,
|
||||
project,
|
||||
complement,
|
||||
chunks,
|
||||
)
|
||||
|
||||
@ -674,78 +671,6 @@ def dump_plt_to_image(rectangle):
|
||||
return image
|
||||
|
||||
|
||||
class RandomFontPicker:
|
||||
def __init__(self, font_dir=None, return_default_font=False):
|
||||
fonts = get_fonts(font_dir)
|
||||
fonts_lower = [font.lower() for font in fonts]
|
||||
domestic_fonts_mask = lmap(complement(self.looks_foreign), fonts_lower)
|
||||
self.fonts = list(itertools.compress(fonts, domestic_fonts_mask))
|
||||
self.fonts_lower = list(itertools.compress(fonts_lower, domestic_fonts_mask))
|
||||
|
||||
self.test_image = Image.new("RGB", (200, 200), (255, 255, 255))
|
||||
self.draw = ImageDraw.Draw(self.test_image)
|
||||
self.return_default_font = return_default_font
|
||||
|
||||
def looks_foreign(self, font):
|
||||
# This filters out foreign fonts (e.g. 'Noto Serif Malayalam')
|
||||
return len(font.split("-")[0]) > 10
|
||||
|
||||
def pick_random_font_available_on_system(self, includes=None, excludes=None) -> ImageFont: # FIXME: Slow!
|
||||
|
||||
if self.return_default_font:
|
||||
return ImageFont.load_default()
|
||||
|
||||
includes = [i.lower() for i in includes] if includes else []
|
||||
excludes = [i.lower() for i in excludes] if excludes else []
|
||||
|
||||
logger.debug(f"Picking font by includes={includes} and excludes={excludes}.")
|
||||
|
||||
def includes_pattern(font):
|
||||
return not includes or any(include in font for include in includes)
|
||||
|
||||
def excludes_pattern(font):
|
||||
return not excludes or not any(exclude in font for exclude in excludes)
|
||||
|
||||
self.shuffle_fonts()
|
||||
|
||||
mask = lmap(lambda f: includes_pattern(f) and excludes_pattern(f), self.fonts_lower)
|
||||
fonts = itertools.compress(self.fonts, mask)
|
||||
fonts = keep(map(self.load_font, fonts))
|
||||
# fonts = filter(self.font_is_renderable, fonts) # FIXME: this does not work
|
||||
|
||||
font = first(fonts)
|
||||
logger.info(f"Using font: {font.getname()}")
|
||||
return font
|
||||
|
||||
def shuffle_fonts(self):
|
||||
l = lzip(self.fonts, self.fonts_lower)
|
||||
rnd.shuffle(l)
|
||||
self.fonts, self.fonts_lower = lzip(*l)
|
||||
|
||||
def pick_random_mono_space_font_available_on_system(self) -> ImageFont:
|
||||
return self.pick_random_font_available_on_system(includes=["mono"], excludes=["oblique"])
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def load_font(self, font: str):
|
||||
logger.trace(f"Loading font: {font}")
|
||||
try:
|
||||
return ImageFont.truetype(font, size=11)
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def font_is_renderable(self, font):
|
||||
text_size = self.draw.textsize("Test String", font=font)
|
||||
return text_size[0] > 0 and text_size[1]
|
||||
|
||||
|
||||
def get_fonts(path: Path = None) -> List[str]:
|
||||
path = path or Path("/usr/share/fonts")
|
||||
fonts = list(path.rglob("*.ttf"))
|
||||
fonts = [font.name for font in fonts]
|
||||
return fonts
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def get_font_picker(**kwargs):
|
||||
return RandomFontPicker(**kwargs, return_default_font=True)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user