File size: 3,746 Bytes
2c1aa80
f0e0cbc
2c1aa80
f0e0cbc
f31f808
 
 
 
2c1aa80
7010bd4
f31f808
 
 
 
 
67e60b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7533dc6
 
 
 
 
 
 
 
 
 
2c1aa80
78699c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5a1f9f8
 
 
f31f808
5a1f9f8
2c1aa80
 
 
 
78699c5
5a1f9f8
78699c5
 
5a1f9f8
 
7010bd4
5a1f9f8
 
7010bd4
 
78699c5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from shapely.geometry import Polygon, MultiPoint
import os

FONT_PATH = os.path.join(os.path.dirname(__file__), "..", "NotoSansSC-Regular.ttf")
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import textwrap

def shrink_polygon(polygon, shrink_ratio=0.9):
    cx = sum(x for x, _ in polygon) / len(polygon)
    cy = sum(y for _, y in polygon) / len(polygon)
    shrunk = [((x - cx) * shrink_ratio + cx, (y - cy) * shrink_ratio + cy) for x, y in polygon]
    return [(int(x), int(y)) for x, y in shrunk]

import numpy as np
import cv2
from PIL import Image, ImageDraw

def inpaint_polygon(img: Image.Image, polygon, mode="auto", fallback_color=(255, 255, 255)):
    np_img = np.array(img.convert("RGB"))
    mask = np.zeros((np_img.shape[0], np_img.shape[1]), dtype=np.uint8)
    pts = np.array(polygon, np.int32).reshape((-1, 1, 2))
    cv2.fillPoly(mask, [pts], 255)

    if mode == "fill":
        img_copy = img.copy()
        draw = ImageDraw.Draw(img_copy)
        draw.polygon(polygon, fill=fallback_color)
        return img_copy

    # try:
    #     inpainted = cv2.inpaint(np_img, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA)
    #     return Image.fromarray(inpainted)
    # except Exception as e:
    #     print("⚠️ Inpaint failed, falling back to solid fill:", e)
    
    img_copy = img.copy()
    draw = ImageDraw.Draw(img_copy)
    draw.polygon(polygon, fill=fallback_color)
    return img_copy

def merge_polygons_to_convex_hull(polygons):
    points = [pt for poly in polygons for pt in poly]
    hull = MultiPoint(points).convex_hull
    return list(hull.exterior.coords)

def render_translated_chunk(img: Image.Image, translations, font_path="NotoSansSC-Regular.ttf", font_scale=1.0):
    from PIL import ImageDraw
    img_copy = img.copy()

    for entry in translations:
        polygon = entry.get("polygon") or entry.get("polygons")
        text = entry.get("translated", "")

        if polygon and text:
            img_copy = draw_translated_text_convex(img_copy, polygon, text, font_path, font_scale)

    return img_copy

def draw_translated_text_convex(img, polygon_coords, text, font_path="NotoSansSC-Regular.ttf", font_scale=1.0):
    from PIL import ImageDraw
    font_polygon = polygon_coords
    render_polygon = shrink_polygon(polygon_coords, shrink_ratio=0.9)
    img = inpaint_polygon(img, render_polygon, mode="auto", fallback_color=(255, 255, 255))
    debug_color = (180, 255, 180)
    draw = ImageDraw.Draw(img)
    draw.line(render_polygon + [render_polygon[0]], fill=debug_color, width=1)
    draw_wrapped_text(img, render_polygon, text, font_path, polygon_for_size=font_polygon, font_scale=font_scale)
    return img

def draw_wrapped_text(img, polygon, text, font_path, polygon_for_size=None, font_scale=1.0):
    from PIL import ImageDraw, ImageFont
    import textwrap
    polygon_for_size = polygon_for_size or polygon
    draw = ImageDraw.Draw(img)
    xs, ys = zip(*polygon_for_size)
    x_min, x_max = min(xs), max(xs)
    y_min, y_max = min(ys), max(ys)
    box_width = x_max - x_min
    box_height = y_max - y_min
    avg_char_width = 0.4
    estimated_size = int(min(box_height / 1.2, box_width / (len(text) * avg_char_width)))
    estimated_size = max(6, estimated_size)
    font_size = int(estimated_size * font_scale)
    font = ImageFont.truetype(font_path, font_size)
    max_chars = max(1, int(box_width / (font.getbbox("A")[2] + 1)))
    wrapped = textwrap.fill(text, width=max_chars)
    bbox = draw.textbbox((0, 0), wrapped, font=font)
    text_w, text_h = bbox[2] - bbox[0], bbox[3] - bbox[1]
    x = x_min + (box_width - text_w) / 2
    y = y_min + (box_height - text_h) / 2
    draw.text((x, y), wrapped, font=font, fill="black", align="center")