Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |
| ) |