Spaces:
Sleeping
Sleeping
| """ | |
| 🌈 HDR Creator Pro - Ultimate Version | |
| Cria imagens HDR com assinaturas visuais extremas e comparação lado a lado. | |
| Autor: Daniel251 | |
| Versão: 1.2.0 | |
| Data: 2026 | |
| """ | |
| import gradio as gr | |
| from PIL import Image, ImageEnhance, ImageFilter, ImageOps | |
| import numpy as np | |
| import cv2 | |
| import tempfile | |
| import time | |
| import os | |
| import warnings | |
| import traceback | |
| warnings.filterwarnings("ignore") | |
| # ========== CONFIGURAÇÃO ========== | |
| MAX_IMAGE_SIZE = 1200 | |
| HDR_MODES = { | |
| "standard_hdr": "🌈 HDR Padrão (Equilibrado)", | |
| "natural_hdr": "🌿 HDR Natural (Fiel à Realidade)", | |
| "dramatic_hdr": "🎭 HDR Dramático (Alto Contraste/Cinema)", | |
| "artistic_hdr": "🎨 HDR Artístico (Efeito Orton/Sonho)", | |
| "vibrant_hdr": "💥 HDR Vibrante (Explosão de Cores)", | |
| "monochrome_hdr": "⚫ HDR Noir (P&B Profundo)", | |
| "infrared_hdr": "🔴 HDR Surreal (Infravermelho Falso)", | |
| "cyberpunk_hdr": "🌆 HDR Cyberpunk (Neon/Noite)", | |
| "vintage_hdr": "🎞️ HDR Vintage (Filme Antigo)", | |
| "single_image": "📷 HDR de Uma Imagem" | |
| } | |
| # ========== FUNÇÕES DE LOG ========== | |
| def log_event(level, message, context="SYSTEM"): | |
| timestamp = time.strftime("%Y-%m-%d %H:%M:%S") | |
| print(f"[{timestamp}] [{level}] [{context}] {message}") | |
| # ========== PROCESSAMENTO CORE ========== | |
| def validate_and_resize(image_path): | |
| try: | |
| img = Image.open(image_path).convert('RGB') | |
| if max(img.size) > MAX_IMAGE_SIZE: | |
| ratio = MAX_IMAGE_SIZE / max(img.size) | |
| new_size = (int(img.width * ratio), int(img.height * ratio)) | |
| img = img.resize(new_size, Image.Resampling.LANCZOS) | |
| return img | |
| except Exception as e: | |
| log_event("ERROR", f"Erro ao carregar imagem: {str(e)}") | |
| return None | |
| def align_images_cv2(images): | |
| if len(images) < 2: return images | |
| log_event("INFO", "Alinhando múltiplas exposições...", "ALIGN") | |
| img_arrays = [np.array(img) for img in images] | |
| ref_gray = cv2.cvtColor(img_arrays[0], cv2.COLOR_RGB2GRAY) | |
| aligned = [images[0]] | |
| for i in range(1, len(img_arrays)): | |
| try: | |
| warp_matrix = np.eye(2, 3, dtype=np.float32) | |
| _, warp_matrix = cv2.findTransformECC( | |
| ref_gray, | |
| cv2.cvtColor(img_arrays[i], cv2.COLOR_RGB2GRAY), | |
| warp_matrix, | |
| cv2.MOTION_AFFINE | |
| ) | |
| w_img = cv2.warpAffine( | |
| img_arrays[i], | |
| warp_matrix, | |
| (img_arrays[0].shape[1], img_arrays[0].shape[0]), | |
| flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP | |
| ) | |
| aligned.append(Image.fromarray(w_img.astype(np.uint8))) | |
| except: | |
| aligned.append(images[i]) | |
| return aligned | |
| # ========== TONEMAPPING AVANÇADO (ESTILO PHOTOSHOP) ========== | |
| def apply_tonemap(hdr_array, mode, strength): | |
| """Aplica tonemapping avançado baseado no modo selecionado""" | |
| # Normalizar para 0-1 | |
| hdr_norm = hdr_array.astype(float) / 255.0 | |
| if mode == "standard_hdr": | |
| # Curva S suave - padrão Photoshop | |
| gamma = 1.0 / (0.7 + strength * 0.3) | |
| result = np.power(hdr_norm, gamma) | |
| # Pequeno aumento de contraste | |
| result = (result - 0.5) * 1.1 + 0.5 | |
| elif mode == "natural_hdr": | |
| # Preserva tons médios, comprime altas luzes | |
| gamma = 1.0 / (0.9 + strength * 0.1) | |
| result = np.power(hdr_norm, gamma) | |
| # Curva mais linear | |
| mask = result > 0.5 | |
| result[mask] = 0.5 + (result[mask] - 0.5) * 0.8 | |
| elif mode == "dramatic_hdr": | |
| # Curva agressiva - tons escuros mais escuros, claros preservados | |
| gamma = 1.0 / (0.5 + strength * 0.5) | |
| result = np.power(hdr_norm, gamma) | |
| # Aumento significativo de contraste | |
| result = (result - 0.5) * 1.8 + 0.5 | |
| elif mode == "artistic_hdr": | |
| # Comprime dinâmica para criar efeito dreamy | |
| gamma = 1.0 / (0.8 + strength * 0.2) | |
| result = np.power(hdr_norm, gamma) | |
| # Achatamento de contraste | |
| result = (result - 0.5) * 0.7 + 0.5 | |
| elif mode == "vibrant_hdr": | |
| # Curva que aumenta saturação nos tons médios | |
| gamma = 1.0 / (0.6 + strength * 0.4) | |
| result = np.power(hdr_norm, gamma) | |
| # Leve aumento de contraste | |
| result = (result - 0.5) * 1.2 + 0.5 | |
| else: | |
| # Padrão para outros modos | |
| gamma = 1.0 / (0.8 + strength * 0.2) | |
| result = np.power(hdr_norm, gamma) | |
| return np.clip(result * 255, 0, 255).astype(np.uint8) | |
| def apply_base_hdr(images, strength, mode): | |
| """Processa HDR base com alinhamento e tonemapping específico""" | |
| if len(images) == 1: | |
| # Para imagem única, simula múltiplas exposições | |
| img_array = np.array(images[0]).astype(float) | |
| # Gera 3 exposições virtuais | |
| under = np.clip(img_array * 0.3, 0, 255) | |
| normal = img_array | |
| over = np.clip(img_array * 2.0, 0, 255) | |
| # Combinação ponderada | |
| hdr = under * 0.3 + normal * 0.4 + over * 0.3 | |
| else: | |
| # Para múltiplas imagens | |
| aligned = align_images_cv2(images) | |
| arrs = [np.array(img).astype(float) for img in aligned] | |
| # Combinação baseada no modo | |
| if mode in ["dramatic_hdr", "monochrome_hdr"]: | |
| hdr = np.max(arrs, axis=0) # Preserva detalhes nas sombras | |
| elif mode == "natural_hdr": | |
| hdr = np.median(arrs, axis=0) # Reduz ruído | |
| else: | |
| # Média ponderada com ênfase nas exposições médias | |
| weights = [0.3, 0.4, 0.3] if len(arrs) == 3 else [1.0/len(arrs)] * len(arrs) | |
| hdr = np.sum([arr * w for arr, w in zip(arrs, weights[:len(arrs)])], axis=0) | |
| # Aplica tonemapping específico | |
| return apply_tonemap(hdr, mode, strength) | |
| # ========== ASSINATURAS VISUAIS ESPECÍFICAS ========== | |
| def create_standard(images, s): | |
| """HDR Padrão - Equilibrado como Photoshop""" | |
| base = apply_base_hdr(images, s, "standard_hdr") | |
| img = Image.fromarray(base) | |
| # Ajustes finais | |
| img = ImageEnhance.Contrast(img).enhance(1.15) | |
| img = ImageEnhance.Color(img).enhance(1.05) | |
| img = ImageEnhance.Sharpness(img).enhance(1.1) | |
| return img, "HDR Padrão: Equilíbrio tonal perfeito, detalhes naturais preservados." | |
| def create_natural(images, s): | |
| """HDR Natural - Minimalista e realista""" | |
| base = apply_base_hdr(images, s * 0.7, "natural_hdr") # Menor intensidade | |
| img = Image.fromarray(base) | |
| # Ajustes sutis | |
| img = ImageEnhance.Color(img).enhance(0.9) | |
| img = ImageEnhance.Contrast(img).enhance(1.05) | |
| img = ImageEnhance.Sharpness(img).enhance(1.05) | |
| # Redução de ruído (suave) | |
| img = img.filter(ImageFilter.MedianFilter(size=1)) | |
| return img, "HDR Natural: Cores orgânicas, dinâmica preservada, sem artificialidade." | |
| def create_dramatic(images, s): | |
| """HDR Dramático - Alto contraste, estilo cinematográfico""" | |
| base = apply_base_hdr(images, s * 1.3, "dramatic_hdr") | |
| img = Image.fromarray(base) | |
| # Ajustes agressivos | |
| img = ImageEnhance.Contrast(img).enhance(1.8 + s * 0.5) | |
| img = ImageEnhance.Color(img).enhance(0.85) # Dessaturação leve para drama | |
| img = ImageEnhance.Sharpness(img).enhance(1.3) | |
| # Máscara de nitidez para realçar bordas | |
| img = img.filter(ImageFilter.UnsharpMask(radius=2, percent=180, threshold=3)) | |
| # Aumento seletivo de brilho nas altas luzes | |
| enhancer = ImageEnhance.Brightness(img) | |
| img = enhancer.enhance(1.05) | |
| return img, "HDR Dramático: Contraste cinematográfico, sombras profundas, texturas realçadas." | |
| def create_artistic(images, s): | |
| """HDR Artístico - Efeito Orton/Sonho""" | |
| base = apply_base_hdr(images, s * 0.8, "artistic_hdr") | |
| img = Image.fromarray(base) | |
| # Efeito Orton: sobreposição de blur | |
| blur_amount = int(5 + s * 10) | |
| blurred = img.filter(ImageFilter.GaussianBlur(radius=blur_amount)) | |
| # Mistura para efeito dreamy | |
| blend_amount = 0.3 + s * 0.3 | |
| img = Image.blend(img, blurred, blend_amount) | |
| # Ajustes de cor | |
| img = ImageEnhance.Brightness(img).enhance(1.1) | |
| img = ImageEnhance.Color(img).enhance(1.25) | |
| img = ImageEnhance.Contrast(img).enhance(0.9) # Contraste reduzido | |
| return img, "HDR Artístico: Efeito Orton etéreo, atmosfera onírica, cores suavizadas." | |
| def create_vibrant(images, s): | |
| """HDR Vibrante - Cores saturadas e vivas""" | |
| base = apply_base_hdr(images, s, "vibrant_hdr") | |
| img = Image.fromarray(base) | |
| # Aumento agressivo de saturação | |
| img = ImageEnhance.Color(img).enhance(2.0 + s * 1.0) | |
| # Contraste moderado | |
| img = ImageEnhance.Contrast(img).enhance(1.25) | |
| # Brilho ajustado | |
| img = ImageEnhance.Brightness(img).enhance(1.05) | |
| # Nitidez para realçar detalhes | |
| img = ImageEnhance.Sharpness(img).enhance(1.2) | |
| return img, "HDR Vibrante: Saturação máxima, cores intensas, energia visual explosiva." | |
| def create_monochrome(images, s): | |
| """HDR Noir - P&B profundo com textura""" | |
| base = apply_base_hdr(images, s * 1.2, "monochrome_hdr") | |
| img = Image.fromarray(base) | |
| # Conversão para P&B com canal de luminância | |
| img_gray = ImageOps.grayscale(img).convert("RGB") | |
| # Contraste extremo | |
| img = ImageEnhance.Contrast(img_gray).enhance(2.0 + s * 0.5) | |
| # Brilho ajustado | |
| img = ImageEnhance.Brightness(img).enhance(0.9) | |
| # Textura adicionada | |
| arr = np.array(img).astype(float) | |
| noise = np.random.normal(0, 8 * s, arr.shape) | |
| arr = np.clip(arr + noise, 0, 255).astype(np.uint8) | |
| img = Image.fromarray(arr) | |
| return img, "HDR Noir: Preto e branco profundo, contraste dramático, textura cinematográfica." | |
| def create_infrared(images, s): | |
| """HDR Surreal - Efeito infravermelho falso""" | |
| img, _ = create_standard(images, s * 0.7) | |
| # Separa canais | |
| r, g, b = img.split() | |
| # Efeito infravermelho: troca de canais | |
| # Canal vermelho recebe verde (folhagens ficam claras) | |
| new_r = g.point(lambda x: min(x * 1.5, 255)) | |
| # Canal azul escurecido | |
| new_b = b.point(lambda x: x * 0.7) | |
| # Canal verde com vermelho | |
| new_g = r.point(lambda x: x * 0.8) | |
| img = Image.merge("RGB", (new_r, new_g, new_b)) | |
| # Ajustes finais | |
| img = ImageEnhance.Contrast(img).enhance(1.3) | |
| img = ImageEnhance.Color(img).enhance(1.2) | |
| return img, "HDR Surreal: Espectro infravermelho simulado, folhagens brancas, céu escuro." | |
| def create_cyberpunk(images, s): | |
| """HDR Cyberpunk - Estética neon futurista""" | |
| img, _ = create_standard(images, s) | |
| # Separa canais para ajustes individuais | |
| r, g, b = img.split() | |
| # Realça azuis e vermelhos (neon) | |
| new_r = ImageEnhance.Brightness(r).enhance(1.6 + s * 0.5) | |
| new_b = ImageEnhance.Brightness(b).enhance(1.8 + s * 0.7) | |
| new_g = ImageEnhance.Brightness(g).enhance(0.8) # Verdes reduzidos | |
| img = Image.merge("RGB", (new_r, new_g, new_b)) | |
| # Ajustes gerais | |
| img = ImageEnhance.Brightness(img).enhance(0.85) # Escurece | |
| img = ImageEnhance.Contrast(img).enhance(1.4) | |
| img = ImageEnhance.Color(img).enhance(1.5) | |
| # Adiciona leve vinheta | |
| width, height = img.size | |
| arr = np.array(img).astype(float) | |
| # Cria máscara de vinheta | |
| x = np.linspace(-1, 1, width) | |
| y = np.linspace(-1, 1, height) | |
| X, Y = np.meshgrid(x, y) | |
| vignette = 1 - np.sqrt(X**2 + Y**2) * 0.3 | |
| vignette = vignette[:, :, np.newaxis] | |
| arr = arr * vignette | |
| img = Image.fromarray(np.clip(arr, 0, 255).astype(np.uint8)) | |
| return img, "HDR Cyberpunk: Estética Neon-Noir futurista, cores sintéticas, atmosfera noturna." | |
| def create_vintage(images, s): | |
| """HDR Vintage - Filme antigo com grão""" | |
| img, _ = create_standard(images, s * 0.6) | |
| # Dessaturação e tom sépia | |
| img = ImageEnhance.Color(img).enhance(0.65) | |
| # Aplica sépia | |
| sepia_base = ImageOps.colorize( | |
| ImageOps.grayscale(img), | |
| "#3d2b1f", # Sombra | |
| "#fff5e6", # Destaque | |
| "#8b6b42" # Meio-tom | |
| ) | |
| img = Image.blend(img, sepia_base, 0.7) | |
| # Adiciona grão de filme | |
| arr = np.array(img).astype(float) | |
| grain = np.random.normal(0, 12 * s, arr.shape) | |
| arr = np.clip(arr + grain, 0, 255) | |
| # Adiciona leve vinheta | |
| height, width = arr.shape[0], arr.shape[1] | |
| x = np.linspace(-1, 1, width) | |
| y = np.linspace(-1, 1, height) | |
| X, Y = np.meshgrid(x, y) | |
| vignette = 1 - np.sqrt(X**2 + Y**2) * 0.4 | |
| vignette = vignette[:, :, np.newaxis] | |
| arr = arr * vignette | |
| img = Image.fromarray(np.clip(arr, 0, 255).astype(np.uint8)) | |
| # Contraste suave | |
| img = ImageEnhance.Contrast(img).enhance(1.1) | |
| return img, "HDR Vintage: Visual de filme analógico desgastado, grão natural, tons sépia." | |
| def create_single(image, s): | |
| """HDR de imagem única - Recuperação de detalhes""" | |
| # Converte para array | |
| img_arr = np.array(image).astype(float) | |
| # Cria múltiplas exposições virtuais | |
| exp1 = np.clip(img_arr * 0.25, 0, 255) # Subexposta | |
| exp2 = img_arr # Normal | |
| exp3 = np.clip(img_arr * 2.2, 0, 255) # Superexposta | |
| # Mapeamento de tons local (similar ao Photoshop) | |
| # Combina detalhes das sombras (exp1), tons médios (exp2) e altas luzes (exp3) | |
| # Máscara para sombras | |
| luminance = 0.299 * exp2[:,:,0] + 0.587 * exp2[:,:,1] + 0.114 * exp2[:,:,2] | |
| shadow_mask = np.clip((0.5 - luminance) * 2, 0, 1)[:,:,np.newaxis] | |
| # Máscara para altas luzes | |
| highlight_mask = np.clip((luminance - 0.7) * 3, 0, 1)[:,:,np.newaxis] | |
| # Máscara para tons médios | |
| midtone_mask = 1 - shadow_mask - highlight_mask | |
| midtone_mask = np.clip(midtone_mask, 0, 1) | |
| # Combinação ponderada | |
| hdr = exp1 * shadow_mask + exp2 * midtone_mask + exp3 * highlight_mask | |
| # Ajuste de contraste local | |
| result = np.clip(hdr, 0, 255).astype(np.uint8) | |
| img = Image.fromarray(result) | |
| # Ajustes finais | |
| img = ImageEnhance.Contrast(img).enhance(1.3 + s * 0.3) | |
| img = ImageEnhance.Sharpness(img).enhance(1.2) | |
| img = ImageEnhance.Color(img).enhance(1.1) | |
| return img, "HDR Simulado: Detalhes recuperados de uma única foto, dinâmica expandida." | |
| # ========== INTERFACE GRADIO ========== | |
| def create_interface(): | |
| custom_css = """ | |
| .gradio-container { max-width: 1400px !important; margin: 0 auto !important; background-color: #0f172a; color: #f8fafc; } | |
| .header { text-align: center; padding: 30px; background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%); border-bottom: 2px solid #334155; margin-bottom: 20px; } | |
| .header h1 { font-size: 3em; margin: 0; background: linear-gradient(to right, #38bdf8, #818cf8); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } | |
| .header p { color: #94a3b8; font-size: 1.2em; margin-top: 10px; } | |
| .status-box { padding: 15px; border-radius: 8px; text-align: center; margin: 15px 0; font-weight: bold; font-size: 1.1em; } | |
| .status-success { background: #065f46; color: #34d399; border: 1px solid #059669; } | |
| .status-info { background: #1e3a8a; color: #93c5fd; border: 1px solid #2563eb; } | |
| .status-warning { background: #7c2d12; color: #fdba74; border: 1px solid #ea580c; } | |
| .status-error { background: #7f1d1d; color: #fca5a5; border: 1px solid #dc2626; } | |
| .image-container { border: 2px solid #334155; border-radius: 12px; overflow: hidden; background: #1e293b; padding: 10px; } | |
| .image-label { font-weight: bold; color: #cbd5e1; margin-bottom: 5px; text-align: center; } | |
| button#component-4 { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important; } | |
| button#component-4:hover { background: linear-gradient(135deg, #4338ca 0%, #6d28d9 100%) !important; } | |
| .slider-container { padding: 15px; background: #1e293b; border-radius: 8px; margin: 10px 0; } | |
| .output-image { max-width: 100% !important; height: auto !important; } | |
| """ | |
| with gr.Blocks(css=custom_css, title="HDR Creator Pro Ultra") as demo: | |
| gr.HTML(""" | |
| <div class='header'> | |
| <h1>🌈 HDR Creator Pro Ultra</h1> | |
| <p>Motor de Renderização HDR com Assinaturas Visuais de Alta Precisão | Versão 1.2.0</p> | |
| <p style="font-size: 0.9em; color: #64748b;"> | |
| Para HDR verdadeiro: Carregue 2+ imagens com diferentes exposições<br> | |
| Para HDR de imagem única: Carregue 1 imagem e selecione "Single Image" | |
| </p> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| with gr.Group(): | |
| gr.Markdown("### 📤 Entrada de Dados") | |
| image_input = gr.File( | |
| label="Upload de Imagens", | |
| file_count="multiple", | |
| type="filepath", | |
| file_types=["image"], | |
| elem_id="file-upload" | |
| ) | |
| hdr_select = gr.Dropdown( | |
| choices=list(HDR_MODES.values()), | |
| value=HDR_MODES["standard_hdr"], | |
| label="Estilo HDR", | |
| info="Selecione o estilo de processamento" | |
| ) | |
| gr.Markdown("### ⚙️ Configurações") | |
| with gr.Row(): | |
| strength_slider = gr.Slider( | |
| 0.1, 2.0, 1.0, step=0.1, | |
| label="Intensidade do Efeito", | |
| info="Controla a força do processamento HDR" | |
| ) | |
| apply_button = gr.Button( | |
| "🚀 RENDERIZAR HDR", | |
| variant="primary", | |
| size="lg", | |
| scale=1 | |
| ) | |
| with gr.Group(): | |
| gr.Markdown("### 📊 Status do Processamento") | |
| status_output = gr.HTML( | |
| "<div class='status-box status-info'>Pronto para processar. Carregue imagens e clique em Renderizar.</div>" | |
| ) | |
| gr.Markdown("### 📥 Exportação") | |
| download_file = gr.File( | |
| label="Baixar Imagem HDR Final", | |
| file_types=[".png"] | |
| ) | |
| with gr.Column(scale=2): | |
| gr.Markdown("### 🔍 Comparação em Tempo Real") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("**Original (Primeira Imagem)**") | |
| original_preview = gr.Image( | |
| label="Original", | |
| type="pil", | |
| interactive=False, | |
| height=450, | |
| elem_classes="output-image" | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("**Resultado HDR Final**") | |
| hdr_preview = gr.Image( | |
| label="HDR Result", | |
| type="pil", | |
| interactive=False, | |
| height=450, | |
| elem_classes="output-image" | |
| ) | |
| gr.Markdown("### ℹ️ Guia Rápido") | |
| with gr.Accordion("Clique para expandir", open=False): | |
| gr.Markdown(""" | |
| **Modos HDR:** | |
| - **Padrão**: Equilíbrio perfeito entre contraste e cores | |
| - **Natural**: Minimalista, preserva aparência original | |
| - **Dramático**: Contraste cinematográfico agressivo | |
| - **Artístico**: Efeito Orton etéreo e dreamy | |
| - **Vibrante**: Cores saturadas e vivas | |
| - **Noir**: P&B profundo com textura | |
| - **Surreal**: Efeito infravermelho | |
| - **Cyberpunk**: Estética neon futurista | |
| - **Vintage**: Filme antigo com grão | |
| - **Single Image**: HDR de uma única foto | |
| **Dicas:** | |
| - Use 3+ imagens com diferentes exposições para melhor qualidade | |
| - Ajuste a intensidade conforme necessário (comece com 1.0) | |
| - Para paisagens: HDR Natural ou Artístico | |
| - Para arquitetura: HDR Dramático | |
| - Para retratos: HDR Padrão com intensidade baixa | |
| """) | |
| def process(files, label, s): | |
| if not files: | |
| return ( | |
| None, | |
| None, | |
| "<div class='status-box status-error'>❌ Erro: Nenhuma imagem selecionada.</div>", | |
| None | |
| ) | |
| try: | |
| # Identifica o modo selecionado | |
| key = next((k for k, v in HDR_MODES.items() if v == label), "standard_hdr") | |
| log_event("INFO", f"Iniciando processamento: {key} com {len(files)} imagens") | |
| # Carrega e valida imagens | |
| imgs = [] | |
| for f in files: | |
| img = validate_and_resize(f.name) | |
| if img is not None: | |
| imgs.append(img) | |
| else: | |
| log_event("WARNING", f"Falha ao carregar imagem: {f.name}") | |
| if not imgs: | |
| return ( | |
| None, | |
| None, | |
| "<div class='status-box status-error'>❌ Erro: Falha ao carregar todas as imagens.</div>", | |
| None | |
| ) | |
| orig = imgs[0] | |
| # Mapeamento das funções de processamento | |
| funcs = { | |
| "standard_hdr": create_standard, | |
| "natural_hdr": create_natural, | |
| "dramatic_hdr": create_dramatic, | |
| "artistic_hdr": create_artistic, | |
| "vibrant_hdr": create_vibrant, | |
| "monochrome_hdr": create_monochrome, | |
| "infrared_hdr": create_infrared, | |
| "cyberpunk_hdr": create_cyberpunk, | |
| "vintage_hdr": create_vintage, | |
| "single_image": lambda imgs, s: create_single(imgs[0], s) | |
| } | |
| # Verifica se deve usar single image automaticamente | |
| if len(imgs) == 1 and key != "single_image": | |
| log_event("INFO", "Apenas 1 imagem detectada, usando Single Image automaticamente") | |
| res, msg = create_single(imgs[0], s) | |
| msg = "⚠️ Modo Single-Image Automático (apenas 1 foto detectada). " + msg | |
| status_class = "status-warning" | |
| else: | |
| # Processa com a função específica | |
| if key == "single_image" and len(imgs) > 1: | |
| log_event("INFO", f"Usando apenas a primeira imagem de {len(imgs)} para Single Image") | |
| res, msg = funcs[key]([imgs[0]], s) | |
| else: | |
| res, msg = funcs[key](imgs, s) | |
| status_class = "status-success" | |
| # Salva resultado | |
| temp_path = tempfile.NamedTemporaryFile( | |
| delete=False, | |
| suffix=".png", | |
| prefix="hdr_output_" | |
| ).name | |
| res.save(temp_path, "PNG", quality=100, optimize=True) | |
| log_event("SUCCESS", f"Processamento {key} concluído com sucesso") | |
| return ( | |
| orig, | |
| res, | |
| f'<div class="status-box {status_class}">✅ {msg}</div>', | |
| temp_path | |
| ) | |
| except Exception as e: | |
| error_msg = str(e) | |
| log_event("ERROR", f"Erro no processamento: {error_msg}\n{traceback.format_exc()}") | |
| return ( | |
| None, | |
| None, | |
| f'<div class="status-box status-error">❌ Erro: {error_msg}</div>', | |
| None | |
| ) | |
| # Conecta o botão ao processamento | |
| apply_button.click( | |
| process, | |
| inputs=[image_input, hdr_select, strength_slider], | |
| outputs=[original_preview, hdr_preview, status_output, download_file] | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| log_event("INFO", "Iniciando HDR Creator Pro Ultra v1.2.0") | |
| demo = create_interface() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) |