File size: 5,167 Bytes
0e2c31f
a4b6d66
 
 
 
 
3eb4bfd
a4b6d66
 
 
 
 
65fb503
 
a4b6d66
3eb4bfd
a4b6d66
b0f4df1
65fb503
a4b6d66
 
 
3eb4bfd
a4b6d66
af3a707
3eb4bfd
 
 
 
 
 
 
 
 
 
af3a707
3eb4bfd
 
 
 
 
 
 
0e2c31f
3eb4bfd
0e2c31f
 
 
 
 
 
3eb4bfd
 
 
 
 
af3a707
3eb4bfd
0e2c31f
 
3eb4bfd
0e2c31f
3eb4bfd
0e2c31f
3eb4bfd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4b6d66
 
 
 
3eb4bfd
a4b6d66
 
 
 
 
 
65fb503
 
a4b6d66
65fb503
3eb4bfd
 
 
 
b0f4df1
 
3eb4bfd
 
 
 
 
 
 
 
 
 
 
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

import cv2
import numpy as np
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from PIL import Image, ImageDraw, ImageFont
import tempfile

PAGE_WIDTH = 8.67 * inch
PAGE_HEIGHT = 11.5 * inch
MARGIN = 0.5 * inch

def verificar_contraste(imagem_array):
    gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
    contrast = gray.std()
    return "⚠️ Baixo contraste detectado!" if contrast < 30 else "✅ Contraste adequado."

def detectar_pontos(imagem_array, idade, distancia_maxima=50):
    gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    if not contours:
        return [], None
    main_contour = max(contours, key=cv2.contourArea)
    epsilon = 1.0
    simplified = cv2.approxPolyDP(main_contour, epsilon, closed=False)
    max_pontos = min(30 + (idade - 4) * 10, 100)
    step = max(1, len(simplified) // max_pontos)
    pontos = [tuple(pt[0]) for pt in simplified[::step]]
    if len(pontos) > 2:
        ordenados = [pontos[0]]
        restantes = pontos[1:]
        while restantes:
            ultimo = ordenados[-1]
            prox = min(restantes, key=lambda p: np.hypot(p[0]-ultimo[0], p[1]-ultimo[1]))
            if np.hypot(prox[0] - ultimo[0], prox[1] - ultimo[1]) > distancia_maxima:
                break
            ordenados.append(prox)
            restantes.remove(prox)
        pontos = ordenados
    return pontos, thresh

def normalizar_para_preview(pontos, largura=600, altura=800, margem=50, posicao="Centro da página"):
    if not pontos:
        return [], 0
    x_coords, y_coords = zip(*pontos)
    min_x, max_x = min(x_coords), max(x_coords)
    min_y, max_y = min(y_coords), max(y_coords)
    escala_x = (largura - 2 * margem) / (max_x - min_x + 1e-5)
    escala_y = (altura - 2 * margem) / (max_y - min_y + 1e-5)
    escala = min(escala_x, escala_y)
    altura_desenho = (max_y - min_y) * escala
    if posicao == "Topo da página":
        offset_y = margem
    elif posicao == "Base da página":
        offset_y = altura - margem - altura_desenho
    else:
        offset_y = (altura - altura_desenho) // 2
    pontos_normalizados = [(
        int((x - min_x) * escala + margem),
        int((y - min_y) * escala + offset_y)
    ) for x, y in pontos]
    return pontos_normalizados, escala

def gerar_preview_com_pontos(pontos, posicao):
    largura, altura = 600, 800
    margem = 50
    img = np.ones((altura, largura, 3), dtype=np.uint8) * 255
    pontos_norm, _ = normalizar_para_preview(pontos, largura, altura, margem, posicao)
    for i, (x, y) in enumerate(pontos_norm):
        cv2.circle(img, (x, y), 4, (0, 0, 0), -1)
        cv2.putText(img, str(i+1), (x + 6, y - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 1)
    path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
    cv2.imwrite(path, img)
    return path, img, pontos_norm

def gerar_overlay(original, pontos_norm):
    overlay = original.copy()
    h, w = overlay.shape[:2]
    resize = cv2.resize(overlay, (w, h))
    transparente = cv2.addWeighted(resize, 0.5, np.ones_like(resize) * 255, 0.5, 0)
    for i, (x, y) in enumerate(pontos_norm):
        if x < w and y < h:
            cv2.circle(transparente, (x, y), 4, (0, 0, 0), -1)
            cv2.putText(transparente, str(i+1), (x + 6, y - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 1)
    path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
    cv2.imwrite(path, transparente)
    return path

def gerar_pdf(pontos_norm):
    pdf_path = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf").name
    c = canvas.Canvas(pdf_path, pagesize=(PAGE_WIDTH, PAGE_HEIGHT))
    for i, (x, y) in enumerate(pontos_norm):
        c.circle(x, PAGE_HEIGHT - y, 2, fill=1)
        c.setFont("Helvetica", 8)
        c.drawString(x + 3, PAGE_HEIGHT - y + 3, str(i + 1))
    c.save()
    return pdf_path

def gerar_preview_kdp():
    img = Image.new("RGB", (1500, 1000), color=(250, 240, 210))
    draw = ImageDraw.Draw(img)
    font = ImageFont.load_default()
    draw.rectangle([50, 50, 1450, 950], outline="black", width=4)
    draw.text((600, 100), "Dot-to-Dot Book", fill="black", font=font)
    draw.text((580, 160), "For Kids Ages 4 to 12", fill="black", font=font)
    draw.ellipse((1100, 700, 1300, 900), outline="gray", width=3)
    draw.text((1120, 780), "Your Art Here", fill="gray", font=font)
    path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
    img.save(path)
    return path

def processar_e_mostrar(imagem_array, _, idade, posicao):
    pontos, _ = detectar_pontos(imagem_array, idade)
    preview_path, preview_img, pontos_norm = gerar_preview_com_pontos(pontos, posicao)
    overlay_path = gerar_overlay(cv2.resize(imagem_array, (600, 800)), pontos_norm)
    pdf_path = gerar_pdf(pontos_norm)
    png_path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
    cv2.imwrite(png_path, preview_img)
    return {
        "preview": preview_path,
        "overlay": overlay_path,
        "pdf": pdf_path,
        "png": png_path
    }