streamlit-design-toolkit / pages /4_Image_Converter.py
Wkatir
feat: adding a description and validation
422421f
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()