48 lines
1.8 KiB
Python
48 lines
1.8 KiB
Python
import numpy as np
|
|
from PIL import Image, ImageDraw, ImageFilter, ImageFont
|
|
|
|
from . import config
|
|
from .fonts import get_cached_font
|
|
|
|
|
|
def render_layout_occupancy(layout, mask_shape, font_path):
|
|
h, w = mask_shape
|
|
canvas = Image.new("L", (w, h), 0)
|
|
draw = ImageDraw.Draw(canvas)
|
|
for word, size, (y, x), orient, _color in layout:
|
|
font = get_cached_font(font_path, size)
|
|
if orient:
|
|
font = ImageFont.TransposedFont(font, orientation=orient)
|
|
draw.text((x, y), word, font=font, fill=255)
|
|
return (np.array(canvas) > 0).astype(np.uint8)
|
|
|
|
|
|
def compute_fill_ratio_fast(layout, mask, font_path):
|
|
if not layout:
|
|
return 0.0, None
|
|
occ = render_layout_occupancy(layout, mask.shape, font_path)
|
|
free_area = np.sum(mask == 0)
|
|
if free_area == 0:
|
|
return 0.0, occ
|
|
filled_area = np.sum((mask == 0) & (occ == 1))
|
|
return filled_area / free_area, occ
|
|
|
|
|
|
def apply_dot_matrix(base_img, mask_hd):
|
|
text_mask = base_img.convert("L").point(lambda x: 0 if x < 200 else 255)
|
|
filter_size = max(3, (config.DOT_SAFETY_BUFFER // 2) * 2 + 1)
|
|
safe_zone_mask = text_mask.filter(ImageFilter.MinFilter(size=filter_size))
|
|
safe_zone_array = np.array(safe_zone_mask)
|
|
unfilled_zone = (mask_hd == 0) & (safe_zone_array > 200)
|
|
draw = ImageDraw.Draw(base_img)
|
|
h, w = mask_hd.shape
|
|
dot_color = "white" if config.FILL_ON == "WHITE" else "black"
|
|
for y in range(0, h, config.DOT_SPACING):
|
|
for x in range(0, w, config.DOT_SPACING):
|
|
if unfilled_zone[y, x]:
|
|
if config.DOT_RADIUS > 0:
|
|
draw.ellipse([x - config.DOT_RADIUS, y - config.DOT_RADIUS, x + config.DOT_RADIUS, y + config.DOT_RADIUS], fill=dot_color)
|
|
else:
|
|
draw.point((x, y), fill=dot_color)
|
|
return base_img
|