[WIP] random font selection

This commit is contained in:
Matthias Bisping 2023-01-17 14:58:54 +01:00
parent 0f6cbec1d5
commit 4c10d521e2

View File

@ -1,13 +1,16 @@
import io
import itertools
import os
import random
import string
import textwrap
from functools import lru_cache
from pathlib import Path
from typing import Tuple, Union, Iterable, List
import albumentations as A
import cv2 as cv
import loguru
import numpy as np
import pandas as pd
import pytest
@ -92,6 +95,9 @@ from funcy import (
rcompose,
lsplit,
lfilter,
lzip,
keep,
lkeep,
)
from cv_analysis.locations import TEST_PAGE_TEXTURES_DIR
@ -178,8 +184,8 @@ def dpi(request):
@pytest.fixture(
params=[
# "brown",
"sepia",
# "gray",
# "sepia",
"gray",
# "white",
# "light_red",
# "light_blue",
@ -202,8 +208,8 @@ def texture_name(request):
@pytest.fixture(
params=[
# 30,
70,
30,
# 70,
# 150,
]
)
@ -362,7 +368,7 @@ class ContentRectangle(Rectangle):
class ContentGenerator:
def __init__(self):
self.constrain_layouts = False
self.constrain_layouts = True
def __call__(self, boxes: List[Rectangle]) -> Image:
random.shuffle(boxes)
@ -375,7 +381,7 @@ class ContentGenerator:
text_boxes = merge_related_rectangles(text_boxes)
text_boxes = lmap(generate_random_text_block, text_boxes)
plots = lmap(generate_random_plot, every_nth(2, char_boxes))
plots = lmap(generate_random_table, every_nth(2, char_boxes))
tables = lmap(generate_random_table, every_nth(2, char_boxes[1:]))
boxes = text_boxes + plots + tables
@ -479,6 +485,74 @@ def dump_plt_to_image(rectangle):
return image
class RandomFontPicker:
def __init__(self, font_dir=None):
self.fonts = get_fonts(font_dir)
self.fonts_lower = [font.lower() for font in self.fonts]
self.test_image = Image.new("RGB", (200, 200), (255, 255, 255))
self.draw = ImageDraw.Draw(self.test_image)
def pick_random_font_available_on_system(self, includes=None, excludes=None) -> ImageFont: # FIXME: Slow!
self.shuffle_fonts()
includes_pattern = (lambda f: includes.lower() in f) if includes else (lambda f: True)
excludes_pattern = (lambda f: excludes.lower() not in f) if excludes else (lambda f: True)
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)
loguru.logger.debug(f"Using font: {font}")
return font
def shuffle_fonts(self):
l = lzip(self.fonts, self.fonts_lower)
random.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):
loguru.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(font_dir=None):
return RandomFontPicker(font_dir=font_dir)
def pick_random_mono_space_font_available_on_system():
font_picker = get_font_picker()
return font_picker.pick_random_mono_space_font_available_on_system()
def pick_random_font_available_on_system():
font_picker = get_font_picker()
return font_picker.pick_random_font_available_on_system(includes="mono")
class RandomPlot(RandomContentRectangle):
def __init__(self, x1, y1, x2, y2, seed=None):
super().__init__(x1, y1, x2, y2, seed=seed)
@ -600,7 +674,7 @@ def write_lines_to_image(lines: List[str], rectangle: Rectangle, font=None) -> I
def write_line(line, line_number):
draw.text((0, line_number * text_size), line, font=font, fill=(0, 0, 0, 200))
font = font or ImageFont.load_default()
font = font or pick_random_mono_space_font_available_on_system()
image = Image.new("RGBA", (rectangle.width, rectangle.height), (0, 255, 255, 0))
draw = ImageDraw.Draw(image)
@ -616,7 +690,7 @@ class RandomTextBlock(ContentRectangle):
def __init__(self, x1, y1, x2, y2):
super().__init__(x1, y1, x2, y2)
self.blank_line_percentage = random.uniform(0, 0.5)
self.font = ImageFont.load_default()
self.font = pick_random_font_available_on_system()
def __call__(self, *args, **kwargs):
pass
@ -688,7 +762,7 @@ class PagePartitioner:
self.top_margin_percentage = 0.1
self.bottom_margin_percentage = 0.1
self.margin_percentage = 0.005
self.margin_percentage = 0.007
self.max_depth = 3
self.initial_recursion_probability = 1
self.recursion_probability_decay = 0.1