import streamlit as st from PIL import Image, UnidentifiedImageError import io import zipfile import logging # Configuración inicial de la página y logging st.set_page_config( page_title="Image Converter", page_icon="🖼️", layout="wide" ) logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") def convert_image(image_file, output_format): """ Verifica la integridad del archivo y lo convierte al formato de salida deseado. Parámetros: - image_file: objeto BytesIO del archivo de imagen. - output_format: cadena con el formato de salida deseado ('png' o 'jpg'). Retorna: - Los bytes de la imagen convertida o None si no se puede/conviene convertir. """ image_name = getattr(image_file, 'name', 'Imagen sin nombre') # Regresamos el puntero al inicio para asegurarnos de leer bien la imagen image_file.seek(0) try: # Intentamos abrir y verificar la integridad de la imagen image = Image.open(image_file) image.verify() # Lanza excepción si el archivo está dañado logging.info(f"{image_name} verificado correctamente.") # Volvemos a posicionar el puntero y abrimos de nuevo para manipular image_file.seek(0) image = Image.open(image_file) except (UnidentifiedImageError, Exception) as e: st.error(f"El archivo {image_name} está dañado o es inválido: {e}") logging.error(f"Error al verificar {image_name}: {e}") return None # Detectamos el formato real de la imagen usando PIL # Nota: PIL suele identificar JPG como 'JPEG' original_format = image.format.lower() if image.format else None if original_format in ["jpeg", "jpg"]: original_format = "jpg" elif original_format == "png": original_format = "png" elif original_format == "webp": original_format = "webp" # Puedes agregar más formatos si lo deseas # Si el formato original y el de salida son el mismo, advertimos y no convertimos if original_format == output_format.lower(): st.warning(f"No se puede convertir '{image_name}' al mismo formato: '{output_format}'.") return None # Para JPG es necesario que la imagen esté en modo RGB if output_format.lower() == "jpg" and image.mode != "RGB": image = image.convert("RGB") output_io = io.BytesIO() try: # Ajustamos la forma en que PIL reconoce los formatos if output_format.lower() == "jpg": pil_format = "JPEG" else: pil_format = output_format.upper() image.save(output_io, format=pil_format) logging.info(f"{image_name} convertido a {output_format}.") return output_io.getvalue() except Exception as e: st.error(f"Error al convertir {image_name}: {e}") logging.error(f"Error al guardar {image_name}: {e}") return None def main(): st.title("Conversor de Formatos de Imagen") st.markdown("Convierte tus imágenes al formato deseado y verifica la integridad de cada archivo.") # Selección del formato de salida output_format = st.selectbox( "Formato de salida", ["png", "jpg"], help="Selecciona el formato al que deseas convertir la imagen" ) # Carga de imágenes uploaded_files = st.file_uploader( "Sube tus imágenes (Formatos soportados: PNG, JPG, JPEG, WEBP)", type=['png', 'jpg', 'jpeg', 'webp'], accept_multiple_files=True ) if uploaded_files: st.header("Vista Previa Original") cols = st.columns(3) original_images = [] for idx, file in enumerate(uploaded_files): file_bytes = file.getvalue() original_images.append((file.name, file_bytes)) with cols[idx % 3]: st.image(file_bytes, caption=file.name, use_column_width=True) if st.button("✨ Convertir Imágenes"): converted_images = [] for name, file_bytes in original_images: st.write(f"Procesando: {name}") img_io = io.BytesIO(file_bytes) output_bytes = convert_image(img_io, output_format) # Solo agregamos a 'converted_images' si hubo conversión exitosa if output_bytes: converted_images.append((name, output_bytes)) if converted_images: st.header("Imágenes Convertidas") cols = st.columns(3) for idx, (name, img_bytes) in enumerate(converted_images): with cols[idx % 3]: st.image(img_bytes, caption=f"{name} convertido a {output_format}", use_column_width=True) # Empaquetar las imágenes convertidas en un ZIP zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w') as zip_file: for name, img_bytes in converted_images: # Ajusta el nombre del archivo con la extensión deseada base_name = name.rsplit('.', 1)[0] zip_file.writestr(f"{base_name}.{output_format}", img_bytes) st.download_button( label="📥 Descargar todas las imágenes convertidas", data=zip_buffer.getvalue(), file_name="imagenes_convertidas.zip", mime="application/zip" ) if __name__ == "__main__": main()