ultrapro-tagger / modules /art_tools.py
Hydragee's picture
Upload folder using huggingface_hub
772b344 verified
# modules/art_tools.py
import os
import math
import numpy as np
from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageOps
import gradio as gr
import io
# --- ADOPTABLE GRID MAKER ---
def hex_to_rgb(hex_color):
"""Hex color kodunu (ör: #FF0000) (255, 0, 0) tuple'ına çevirir."""
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) + (255,) # Alpha ekle
def create_grid_collage(files, columns, add_labels, label_type, start_number, bg_color_hex, title_text, banner_color_hex, title_color_hex):
"""
Adoptable Style Grid Collage Maker
"""
if not files:
return None, "⚠️ Lütfen resim dosyalarını seçin."
try:
images = []
for file_obj in files:
try:
img = Image.open(file_obj.name).convert("RGBA")
images.append(img)
except:
continue
if not images:
return None, "⚠️ Geçerli resim bulunamadı."
count = len(images)
cols = int(columns)
rows = math.ceil(count / cols)
# 1. Boyut Standardizasyonu (İlk resme göre)
base_w, base_h = images[0].size
resized_images = []
for img in images:
if img.size != (base_w, base_h):
resized_images.append(img.resize((base_w, base_h), Image.Resampling.LANCZOS))
else:
resized_images.append(img)
# Tasarım Parametreleri
padding = 40 # Resimler arası boşluk biraz arttı
frame_width = 15 # Çerçeve kalınlığı arttı
# Renkler
bg_color = hex_to_rgb(bg_color_hex)
banner_color = hex_to_rgb(banner_color_hex)
title_color = hex_to_rgb(title_color_hex)
frame_color = title_color # Çerçeve rengi başlık rengiyle aynı olsun
# Canvas Boyutu (Önce hesapla)
grid_w = (cols * base_w) + ((cols + 1) * padding)
# Header Yüksekliği: Grid genişliğine orantılı olsun (Genişlik arttıkça yükseklik de artsın ki text büyüyebilsin)
# Min 250px, yoksa genişliğin %15'i
header_height = max(250, int(grid_w * 0.15))
grid_h = header_height + (rows * base_h) + ((rows + 1) * padding)
grid_img = Image.new("RGBA", (grid_w, grid_h), bg_color)
draw = ImageDraw.Draw(grid_img)
# --- HEADER (BANNER) ÇİZİMİ ---
draw.rectangle([(0, 0), (grid_w, header_height)], fill=banner_color)
draw.rectangle([(0, header_height-15), (grid_w, header_height)], fill=frame_color)
# Başlangıç Font Boyutu (Çok daha büyük başlıyoruz - Grid genişliğine orantılı)
font_title_size = int(grid_w * 0.1) # Genişliğin %10'u ile başla
# --- BAŞLIK FONTU BÜYÜKLÜĞÜNÜ AYARLA (Agresif Scaling) ---
target_width = grid_w * 0.95 # Banner genişliğinin %95'ini doldurmalı
max_height_text = header_height * 0.8 # Yüksekliğin %80'ini geçmesin (Hava kalsın)
try:
font_path = "timesbd.ttf"
font_title = ImageFont.truetype(font_path, font_title_size)
except:
font_path = None
font_title = ImageFont.load_default()
if font_path:
# İterasyonla en uygun boyutu bul
for _ in range(50): # Sonsuz döngüden kaçınmak için limitli
bbox_title = draw.textbbox((0, 0), title_text, font=font_title)
w_total = (bbox_title[2] - bbox_title[0])
h_max = bbox_title[3] - bbox_title[1]
# Çok büyükse küçült
if w_total > target_width or h_max > max_height_text:
font_title_size -= 5
if font_title_size < 20: break
font_title = ImageFont.truetype(font_path, font_title_size)
# Çok küçükse büyüt (Eğer dikeyde ve yatayda yer varsa)
elif w_total < target_width * 0.9 and h_max < max_height_text * 0.9:
font_title_size += 5
font_title = ImageFont.truetype(font_path, font_title_size)
else:
break # Tamamdır
# Son Ölçümler & Çizim
bbox_title = draw.textbbox((0, 0), title_text, font=font_title)
w_title = bbox_title[2] - bbox_title[0]
h_title = bbox_title[3] - bbox_title[1]
start_x_text = (grid_w - w_title) // 2
bg_center_y = header_height // 2
# Başlık çiz
draw.text((start_x_text, bg_center_y - h_title//2), title_text, font=font_title, fill=title_color, stroke_width=int(font_title_size*0.02), stroke_fill="black")
# --- RESİMLERİ YERLEŞTİR ---
# Numara Fontunu Resim Boyutuna Göre Ayarla (Çok Büyük)
try:
num_font_size = int(base_w * 0.25) # Resim genişliğinin %25'i kadar (Kocaman)
font_num = ImageFont.truetype("impact.ttf", num_font_size)
except:
font_num = ImageFont.load_default()
current_num = int(start_number)
for i, img in enumerate(resized_images):
r = i // cols
c = i % cols
x = padding + (c * (base_w + padding))
y = header_height + padding + (r * (base_h + padding))
# Kalın Çerçeve
draw.rectangle(
[(x - frame_width, y - frame_width),
(x + base_w + frame_width, y + base_h + frame_width)],
fill=None, outline=frame_color, width=frame_width
)
# Resim
grid_img.paste(img, (x, y), mask=img)
# --- OVERLAY NUMARA (DEVASA) ---
if add_labels:
if str(label_type).startswith("Sadece"):
num_str = f"{current_num}"
else:
num_str = f"#{current_num}"
current_num += 1
bbox_num = draw.textbbox((0, 0), num_str, font=font_num)
w_num = bbox_num[2] - bbox_num[0]
h_num = bbox_num[3] - bbox_num[1]
# Ortala ve Biraz daha yukarı al (Resmin altından %10 yukarıda)
num_x = x + (base_w - w_num) // 2
num_y = y + base_h - h_num - int(base_h * 0.05) - 20
# Çok Kalın Outline
outline_width = int(num_font_size * 0.08) # Font boyutuna göre outline kalınlığı
draw.text((num_x, num_y), num_str, font=font_num, fill="white", stroke_width=outline_width, stroke_fill="black")
return grid_img, "✅ Adoptable Grid oluşturuldu!"
except Exception as e:
import traceback
traceback.print_exc()
return None, f"❌ Hata: {str(e)}"