""" App 1: Image Loader & Exporter Micro-app para importar e exportar imagens em múltiplos formatos """ import gradio as gr from PIL import Image, ImageOps import tempfile import os from pathlib import Path from typing import Optional, Tuple import mimetypes class ImageLoaderExporter: """Micro-app dedicado apenas a carregar e exportar imagens""" def __init__(self): # Formatos suportados para importação self.supported_input_formats = [ '.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp', '.ico', '.psd' ] # Formatos suportados para exportação self.supported_output_formats = { 'PNG': 'png', 'JPEG': 'jpeg', 'BMP': 'bmp', 'TIFF': 'tiff', 'WEBP': 'webp', 'GIF': 'gif' } def load_image(self, file_path: str) -> Tuple[Optional[Image.Image], str]: """ Carrega uma imagem do sistema de arquivos Args: file_path: Caminho do arquivo de imagem Returns: Tuple[imagem, mensagem_status] """ try: # Verificar se é um arquivo de imagem if not os.path.exists(file_path): return None, "❌ Arquivo não encontrado" # Verificar extensão ext = Path(file_path).suffix.lower() if ext not in self.supported_input_formats: return None, f"❌ Formato não suportado: {ext}" # Carregar imagem img = Image.open(file_path) # Converter para RGB se necessário (exceto para PNG com alpha) if img.mode not in ['RGB', 'RGBA', 'L']: img = img.convert('RGB') # Informações da imagem info = self._get_image_info(img, file_path) return img, f"✅ Imagem carregada com sucesso!\n{info}" except Exception as e: return None, f"❌ Erro ao carregar imagem: {str(e)}" def export_image(self, image: Image.Image, format: str, quality: int = 95, optimize: bool = True) -> Optional[str]: """ Exporta imagem para arquivo temporário Args: image: Imagem PIL para exportar format: Formato de exportação quality: Qualidade (1-100) optimize: Otimizar tamanho do arquivo Returns: Caminho do arquivo temporário ou None """ try: # Criar arquivo temporário format_lower = format.lower() suffix = f".{format_lower}" # Configurações específicas por formato save_args = {'format': format} if format_lower == 'jpeg': save_args.update({ 'quality': quality, 'optimize': optimize, 'progressive': True }) elif format_lower == 'png': save_args.update({ 'optimize': optimize, 'compress_level': 9 - int((quality / 100) * 8) }) elif format_lower == 'webp': save_args.update({ 'quality': quality, 'method': 6 if quality > 80 else 4 }) # Criar arquivo temporário with tempfile.NamedTemporaryFile( delete=False, suffix=suffix, prefix='export_' ) as tmp_file: image.save(tmp_file.name, **save_args) return tmp_file.name except Exception as e: print(f"Erro na exportação: {str(e)}") return None def _get_image_info(self, image: Image.Image, file_path: str) -> str: """Extrai informações da imagem""" file_size = os.path.getsize(file_path) info_lines = [ f"📏 Dimensões: {image.width} x {image.height} px", f"🎨 Modo: {image.mode}", f"📊 Tamanho do arquivo: {self._format_file_size(file_size)}", f"🔤 Formato: {image.format or 'Desconhecido'}" ] # Informações adicionais se disponíveis if hasattr(image, 'info'): if 'dpi' in image.info: info_lines.append(f"📐 DPI: {image.info['dpi']}") return "\n".join(info_lines) def _format_file_size(self, size_bytes: int) -> str: """Formata tamanho do arquivo para leitura humana""" for unit in ['B', 'KB', 'MB', 'GB']: if size_bytes < 1024.0: return f"{size_bytes:.1f} {unit}" size_bytes /= 1024.0 return f"{size_bytes:.1f} TB" def get_format_options(self) -> dict: """Retorna opções de formato para a interface""" return list(self.supported_output_formats.keys()) # Criar instância do app app_processor = ImageLoaderExporter() # Interface Gradio def create_interface(): """Cria interface do app""" with gr.Blocks( title="🖼️ Image Loader & Exporter", theme=gr.themes.Soft() ) as app: gr.Markdown("# 🖼️ Image Loader & Exporter") gr.Markdown("### App 1 do Photoshop AI Ecosystem") gr.Markdown("Importe e exporte imagens em múltiplos formatos") with gr.Row(): with gr.Column(scale=1): # Upload de imagem gr.Markdown("### 📤 Importar Imagem") file_input = gr.File( label="Selecione uma imagem", file_types=["image"] ) load_btn = gr.Button( "📥 Carregar Imagem", variant="primary", size="lg" ) status_output = gr.Textbox( label="Status", lines=4, interactive=False ) with gr.Column(scale=2): # Visualização gr.Markdown("### 👁️ Visualização") image_preview = gr.Image( label="Pré-visualização", type="pil", interactive=False ) with gr.Row(): with gr.Column(): gr.Markdown("### ⚙️ Configurações de Exportação") format_select = gr.Dropdown( label="Formato de Exportação", choices=app_processor.get_format_options(), value="PNG" ) quality_slider = gr.Slider( label="Qualidade (JPEG/WEBP)", minimum=1, maximum=100, value=95, step=1, visible=True ) optimize_check = gr.Checkbox( label="Otimizar tamanho", value=True ) with gr.Column(): gr.Markdown("### 📥 Exportar") export_btn = gr.Button( "💾 Exportar Imagem", variant="secondary", size="lg" ) download_output = gr.File( label="Download", interactive=False ) # Funções de controle de visibilidade def update_quality_visibility(format_choice): """Mostra/oculta controle de qualidade baseado no formato""" return gr.update(visible=format_choice in ['JPEG', 'WEBP']) # Event handlers load_btn.click( fn=app_processor.load_image, inputs=[file_input], outputs=[image_preview, status_output] ) format_select.change( fn=update_quality_visibility, inputs=[format_select], outputs=[quality_slider] ) export_btn.click( fn=app_processor.export_image, inputs=[image_preview, format_select, quality_slider, optimize_check], outputs=[download_output] ) # Exemplos with gr.Accordion("📚 Exemplos de Uso", open=False): gr.Markdown(""" ### Como usar este app: 1. **Importar Imagem:** - Clique em "Selecione uma imagem" ou arraste uma imagem - Clique em "Carregar Imagem" 2. **Visualizar:** - A imagem aparecerá na área de pré-visualização - Informações técnicas serão exibidas 3. **Exportar:** - Selecione o formato desejado - Ajuste a qualidade se necessário - Clique em "Exportar Imagem" - Faça download do arquivo ### Formatos suportados: - **Importação:** JPG, PNG, BMP, GIF, TIFF, WEBP, ICO, PSD - **Exportação:** PNG, JPEG, BMP, TIFF, WEBP, GIF ### Dica: Use PNG para imagens com transparência, JPEG para fotos. """) # Footer gr.Markdown("---") gr.Markdown("**📌 App 1 - Photoshop AI Ecosystem** | Apenas uma função: Carregar/Exportar") return app # Ponto de entrada do app if __name__ == "__main__": # Para desenvolvimento local interface = create_interface() interface.launch( server_name="0.0.0.0", server_port=7860, share=False, debug=True )