import gradio as gr from PIL import Image import os import tempfile import pyheif import ntpath import shutil def open_heic_image(image_path): heif_file = pyheif.read(image_path) img = Image.frombytes( heif_file.mode, heif_file.size, heif_file.data, "raw", heif_file.mode, heif_file.stride, ) return img def optimize_single_image(image_path, png_optimize, jpeg_quality, jpeg_resolution, webp_quality): original_filename = ntpath.basename(image_path) base_name, ext = os.path.splitext(original_filename) if image_path.lower().endswith(".heic"): img = open_heic_image(image_path) else: img = Image.open(image_path) if img.mode not in ['RGB', 'L']: img = img.convert('RGB') original_size = os.path.getsize(image_path) / 1024 # tamaño en KB output_dir = tempfile.mkdtemp() # Crear un directorio temporal para las imágenes optimizadas optimized_images = [] if png_optimize: lossless_output_path = os.path.join(output_dir, f"{base_name}-lossless.png") img.save(lossless_output_path, format="PNG", optimize=True) optimized_images.append(lossless_output_path) lossy_output_path = os.path.join(output_dir, f"{base_name}-lossy.jpg") img.save(lossy_output_path, format="JPEG", quality=jpeg_quality, optimize=True) optimized_images.append(lossy_output_path) reduced_output_path = os.path.join(output_dir, f"{base_name}-reduced_resolution.jpg") new_resolution = (img.width * jpeg_resolution // 100, img.height * jpeg_resolution // 100) reduced_img = img.resize(new_resolution, Image.LANCZOS) reduced_img.save(reduced_output_path, format="JPEG", quality=jpeg_quality, optimize=True) optimized_images.append(reduced_output_path) webp_lossy_output_path = os.path.join(output_dir, f"{base_name}-lossy.webp") img.save(webp_lossy_output_path, format="WEBP", quality=webp_quality, optimize=True) optimized_images.append(webp_lossy_output_path) return optimized_images def optimize_zip_images(zip_file, png_optimize, jpeg_quality, jpeg_resolution, webp_quality): with tempfile.TemporaryDirectory() as tmp_dir: shutil.unpack_archive(zip_file.name, tmp_dir) output_dir = tempfile.mkdtemp() optimized_files = [] for root, _, files in os.walk(tmp_dir): for file in files: file_path = os.path.join(root, file) optimized_images = optimize_single_image(file_path, png_optimize, jpeg_quality, jpeg_resolution, webp_quality) for optimized_image in optimized_images: output_path = os.path.join(output_dir, ntpath.basename(optimized_image)) shutil.move(optimized_image, output_path) optimized_files.append(output_path) zip_output_path = os.path.join(output_dir, "optimized_images.zip") shutil.make_archive(zip_output_path.replace(".zip", ""), 'zip', output_dir) return zip_output_path, optimized_files with gr.Blocks() as demo: gr.Markdown(""" # Optimización de Imágenes para la Web Esta aplicación te permite optimizar imágenes individuales o múltiples imágenes a través de un archivo ZIP. - **Pestaña "Optimización Tradicional"**: Sube una imagen individual para optimización y descarga. - **Pestaña "Optimización por Lote"**: Elige los parámetros de optimización, sube un archivo ZIP con múltiples imágenes y descarga todas las imágenes optimizadas. """) with gr.Tab("Optimización Tradicional"): image_input = gr.File(label="Sube tu imagen", file_types=['image', '.heic']) optimize_button = gr.Button("Optimizar") with gr.Row(): with gr.Column(): optimized_output1 = gr.Image(label="Optimización sin pérdida") png_optimize = gr.Checkbox(label="Optimizar PNG", value=True) download_button1 = gr.File(label="Descargar", visible=True) optimized_size1 = gr.Text(value="", interactive=False, show_label=False) with gr.Column(): optimized_output2 = gr.Image(label="Optimización con pérdida (JPEG)") jpeg_quality = gr.Slider(label="Calidad JPEG", minimum=10, maximum=100, value=50, step=1) download_button2 = gr.File(label="Descargar", visible=True) optimized_size2 = gr.Text(value="", interactive=False, show_label=False) with gr.Column(): optimized_output3 = gr.Image(label="Reducción de resolución (JPEG)") jpeg_resolution = gr.Slider(label="Resolución JPEG (%)", minimum=10, maximum=100, value=50, step=1) download_button3 = gr.File(label="Descargar", visible=True) optimized_size3 = gr.Text(value="", interactive=False, show_label=False) with gr.Column(): optimized_output4 = gr.Image(label="Optimización WebP con pérdida") webp_quality = gr.Slider(label="Calidad WebP", minimum=10, maximum=100, value=50, step=1) download_button4 = gr.File(label="Descargar", visible=True) optimized_size4 = gr.Text(value="", interactive=False, show_label=False) optimize_button.click( fn=optimize_single_image, inputs=[image_input, png_optimize, jpeg_quality, jpeg_resolution, webp_quality], outputs=[ optimized_output1, optimized_size1, download_button1, optimized_output2, optimized_size2, download_button2, optimized_output3, optimized_size3, download_button3, optimized_output4, optimized_size4, download_button4 ] ) with gr.Tab("Optimización por Lote"): with gr.Row(): png_optimize_batch = gr.Checkbox(label="Optimizar PNG", value=True) jpeg_quality_batch = gr.Slider(label="Calidad JPEG", minimum=10, maximum=100, value=50, step=1) jpeg_resolution_batch = gr.Slider(label="Resolución JPEG (%)", minimum=10, maximum=100, value=50, step=1) webp_quality_batch = gr.Slider(label="Calidad WebP", minimum=10, maximum=100, value=50, step=1) zip_input = gr.File(label="Sube tu archivo ZIP con imágenes", file_types=['.zip']) optimize_batch_button = gr.Button("Optimizar Imágenes en ZIP") batch_output_zip = gr.File(label="Descargar ZIP de imágenes optimizadas", visible=True) batch_gallery = gr.Gallery(label="Imágenes optimizadas (individuales)") def update_gallery(zip_file, png_optimize, jpeg_quality, jpeg_resolution, webp_quality): zip_output_path, optimized_files = optimize_zip_images(zip_file, png_optimize, jpeg_quality, jpeg_resolution, webp_quality) return zip_output_path, optimized_files optimize_batch_button.click( fn=update_gallery, inputs=[zip_input, png_optimize_batch, jpeg_quality_batch, jpeg_resolution_batch, webp_quality_batch], outputs=[batch_output_zip, batch_gallery] ) demo.launch()