Spaces:
Running
Running
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() | |