[WIP] random font selection
This commit is contained in:
parent
0f6cbec1d5
commit
4c10d521e2
92
test/fixtures/page_generation/page.py
vendored
92
test/fixtures/page_generation/page.py
vendored
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user