Aquí Mantenemos nuestra comunidad emprendedora con café y tu ayuda
«Con tu donación ayudas a crear más recursos gratuitos para emprendedores»
Quieres llevar el control de tu negocio?
Dashboard de ventas y gastos + bonus
PRECIO
El precio original era: $ 230.000,00.$ 91.954,00El precio actual es: $ 91.954,00.
Los precios está en Pesos Colombnianos (COP) si estás en Colombia. Si estas en otro país, los precios son en Dólares (USD). En el momento del pago, pagas en tu moneda local.
Dashboard para negocios
PRECIO
El precio original era: $ 230.000,00.$ 114.954,00El precio actual es: $ 114.954,00.
Los precios está en Pesos Colombnianos (COP) si estás en Colombia. Si estas en otro país, los precios son en Dólares (USD). En el momento del pago, pagas en tu moneda local.
Control de inventario en Excel
PRECIO
El precio original era: $ 321.954,00.$ 59.754,00El precio actual es: $ 59.754,00.
Los precios está en Pesos Colombnianos (COP) si estás en Colombia. Si estas en otro país, los precios son en Dólares (USD). En el momento del pago, pagas en tu moneda local.
Código de Python para convertir imágenes a .webp
Paso 1: Instalar Python
En Windows:
- Ve a python.org/downloads
- Descarga la última versión de Python (botón amarillo «Download Python»)
- Ejecuta el instalador descargado
- MUY IMPORTANTE: Marca la casilla «Add Python to PATH» en la primera pantalla
- Haz clic en «Install Now»
- Espera a que termine la instalación y cierra el instalador
En Mac:
- Ve a python.org/downloads
- Descarga la última versión para macOS
- Abre el archivo
.pkgdescargado - Sigue las instrucciones del instalador
- Completa la instalación
Paso 2: Crear la carpeta del proyecto
- Crea una carpeta en tu escritorio o donde prefieras, por ejemplo:
img_optim - Anota la ruta completa de esta carpeta, la necesitarás después
Ejemplo de rutas:
- Windows:
C:\Users\TuNombre\Desktop\img_optim - Mac:
/Users/TuNombre/Desktop/img_optim
Paso 3: Instalar la librería Pillow
- Abre PowerShell (Windows) o Terminal (Mac)
- Escribe el siguiente comando y presiona Enter:
En Windows:
py -m pip install PillowEn Mac:
python3 -m pip install Pillow- Espera a que se complete la instalación. Verás varias líneas de texto y al final debería decir «Successfully installed Pillow…»
Paso 4: Descargar el código del programa
- Descarga el archivo con el código del programa (te lo proporcionarán)
- Guárdalo o copia el código que te den
Paso 5: Crear el archivo del programa
- Abre el Bloc de notas (Windows) o TextEdit (Mac)
- Pega el código que descargaste
- Ve a «Archivo» → «Guardar como…»
- Navega hasta la carpeta
img_optimque creaste en el Paso 2 - En «Nombre del archivo» escribe exactamente:
image_optimizer_gui.py - En Windows: Cambia «Tipo» a «Todos los archivos (.)»
- Haz clic en «Guardar»
Paso 6: Ejecutar el programa
En Windows:
- Abre PowerShell
- Navega hasta la carpeta donde guardaste el archivo usando el comando
cd:
cd C:\Users\TuNombre\Desktop\img_optim(Reemplaza la ruta con la tuya)
- Ejecuta el programa con el comando:
py image_optimizer_gui.pyEn Mac:
- Abre Terminal
- Navega hasta la carpeta:
cd /Users/TuNombre/Desktop/img_optim- Ejecuta el programa:
python3 image_optimizer_gui.pyPaso 7: Usar el programa
- Se abrirá una ventana con la interfaz del optimizador
- Selecciona las imágenes que quieres optimizar
- Elige la calidad de compresión
- Haz clic en «Optimizar» y espera a que termine
- ¡Listo! Tus imágenes optimizadas en formato WebP estarán guardadas
Código de Python
#!/usr/bin/env python3
«»»
Optimizador de Imágenes para Web – Con Interfaz Gráfica
=======================================================
Convierte imágenes a WebP, redimensiona manteniendo aspect ratio y comprime.
Conserva transparencias en imágenes PNG/GIF.
«»»
import os
import threading
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from pathlib import Path
from PIL import Image
# Extensiones de imagen soportadas
SUPPORTED_EXTENSIONS = {‘.jpg’, ‘.jpeg’, ‘.png’, ‘.gif’, ‘.bmp’, ‘.tiff’, ‘.tif’, ‘.webp’}
class ImageOptimizerApp:
def __init__(self, root):
self.root = root
self.root.title(«Optimizador de Imágenes para Web»)
self.root.geometry(«600×700»)
self.root.resizable(True, True)
# Variables
self.input_folder = tk.StringVar()
self.output_folder = tk.StringVar()
self.resize_mode = tk.StringVar(value=»width»)
self.size_value = tk.StringVar(value=»1200″)
self.quality = tk.StringVar(value=»85″)
self.recursive = tk.BooleanVar(value=False)
self.processing = False
self.create_widgets()
self.center_window()
def center_window(self):
«»»Centra la ventana en la pantalla.»»»
self.root.update_idletasks()
width = self.root.winfo_width()
height = self.root.winfo_height()
x = (self.root.winfo_screenwidth() // 2) – (width // 2)
y = (self.root.winfo_screenheight() // 2) – (height // 2)
self.root.geometry(f'{width}x{height}+{x}+{y}’)
def create_widgets(self):
«»»Crea todos los widgets de la interfaz.»»»
main_frame = ttk.Frame(self.root, padding=»20″)
main_frame.pack(fill=tk.BOTH, expand=True)
# Título
title_label = ttk.Label(main_frame, text=»🖼️ Optimizador de Imágenes»,
font=(‘Helvetica’, 16, ‘bold’))
title_label.pack(pady=(0, 20))
# Frame carpeta de entrada
input_frame = ttk.LabelFrame(main_frame, text=»Carpeta de origen», padding=»10″)
input_frame.pack(fill=tk.X, pady=(0, 10))
input_entry = ttk.Entry(input_frame, textvariable=self.input_folder, width=50)
input_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
input_btn = ttk.Button(input_frame, text=»Examinar…»,
command=self.select_input_folder)
input_btn.pack(side=tk.RIGHT)
# Frame carpeta de salida
output_frame = ttk.LabelFrame(main_frame, text=»Carpeta de destino», padding=»10″)
output_frame.pack(fill=tk.X, pady=(0, 10))
output_entry = ttk.Entry(output_frame, textvariable=self.output_folder, width=50)
output_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
output_btn = ttk.Button(output_frame, text=»Examinar…»,
command=self.select_output_folder)
output_btn.pack(side=tk.RIGHT)
# Frame opciones de redimensionado
resize_frame = ttk.LabelFrame(main_frame, text=»Redimensionar», padding=»10″)
resize_frame.pack(fill=tk.X, pady=(0, 10))
# Radio buttons para modo
mode_frame = ttk.Frame(resize_frame)
mode_frame.pack(fill=tk.X, pady=(0, 10))
ttk.Radiobutton(mode_frame, text=»Ajustar por ancho»,
variable=self.resize_mode, value=»width»).pack(side=tk.LEFT, padx=(0, 20))
ttk.Radiobutton(mode_frame, text=»Ajustar por alto»,
variable=self.resize_mode, value=»height»).pack(side=tk.LEFT, padx=(0, 20))
ttk.Radiobutton(mode_frame, text=»No redimensionar»,
variable=self.resize_mode, value=»none»).pack(side=tk.LEFT)
# Valor de tamaño
size_frame = ttk.Frame(resize_frame)
size_frame.pack(fill=tk.X)
ttk.Label(size_frame, text=»Tamaño en píxeles:»).pack(side=tk.LEFT, padx=(0, 10))
size_entry = ttk.Entry(size_frame, textvariable=self.size_value, width=10)
size_entry.pack(side=tk.LEFT)
ttk.Label(size_frame, text=»px»).pack(side=tk.LEFT, padx=(5, 0))
# Frame calidad
quality_frame = ttk.LabelFrame(main_frame, text=»Calidad WebP», padding=»10″)
quality_frame.pack(fill=tk.X, pady=(0, 10))
quality_inner = ttk.Frame(quality_frame)
quality_inner.pack(fill=tk.X)
ttk.Label(quality_inner, text=»Calidad (1-100):»).pack(side=tk.LEFT, padx=(0, 10))
self.quality_label = ttk.Label(quality_inner, text=»85%», width=5)
self.quality_scale = ttk.Scale(quality_inner, from_=1, to=100,
orient=tk.HORIZONTAL, length=300,
command=self.update_quality_label)
self.quality_scale.set(85)
self.quality_scale.pack(side=tk.LEFT, padx=(0, 10))
self.quality_label.pack(side=tk.LEFT)
# Opciones adicionales
options_frame = ttk.LabelFrame(main_frame, text=»Opciones», padding=»10″)
options_frame.pack(fill=tk.X, pady=(0, 10))
ttk.Checkbutton(options_frame, text=»Procesar subcarpetas recursivamente»,
variable=self.recursive).pack(anchor=tk.W)
# Barra de progreso
progress_frame = ttk.Frame(main_frame)
progress_frame.pack(fill=tk.X, pady=(10, 10))
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var,
maximum=100, length=400)
self.progress_bar.pack(fill=tk.X)
self.status_label = ttk.Label(progress_frame, text=»», foreground=»gray»)
self.status_label.pack(pady=(5, 0))
# Botón procesar
self.process_btn = ttk.Button(main_frame, text=»🚀 Optimizar Imágenes»,
command=self.start_processing,
style=’Accent.TButton’)
self.process_btn.pack(pady=(10, 0))
# Configurar estilo del botón
style = ttk.Style()
style.configure(‘Accent.TButton’, font=(‘Helvetica’, 11, ‘bold’))
def update_quality_label(self, value):
«»»Actualiza la etiqueta de calidad.»»»
self.quality_label.config(text=f»{int(float(value))}%»)
self.quality.set(str(int(float(value))))
def select_input_folder(self):
«»»Abre diálogo para seleccionar carpeta de entrada.»»»
folder = filedialog.askdirectory(title=»Seleccionar carpeta con imágenes»)
if folder:
self.input_folder.set(folder)
# Auto-completar carpeta de salida si está vacía
if not self.output_folder.get():
self.output_folder.set(os.path.join(folder, «optimized»))
def select_output_folder(self):
«»»Abre diálogo para seleccionar carpeta de salida.»»»
folder = filedialog.askdirectory(title=»Seleccionar carpeta de destino»)
if folder:
self.output_folder.set(folder)
def validate_inputs(self) -> bool:
«»»Valida las entradas del usuario.»»»
if not self.input_folder.get():
messagebox.showerror(«Error», «Selecciona una carpeta de origen»)
return False
if not os.path.isdir(self.input_folder.get()):
messagebox.showerror(«Error», «La carpeta de origen no existe»)
return False
if not self.output_folder.get():
messagebox.showerror(«Error», «Selecciona una carpeta de destino»)
return False
if self.resize_mode.get() != «none»:
try:
size = int(self.size_value.get())
if size < 1: raise ValueError() except ValueError: messagebox.showerror(«Error», «El tamaño debe ser un número entero positivo») return False return True def start_processing(self): «»»Inicia el procesamiento en un hilo separado.»»» if self.processing: return if not self.validate_inputs(): return self.processing = True self.process_btn.config(state=tk.DISABLED) self.progress_var.set(0) # Ejecutar en hilo separado para no bloquear la GUI thread = threading.Thread(target=self.process_images) thread.daemon = True thread.start() def process_images(self): «»»Procesa todas las imágenes.»»» input_path = Path(self.input_folder.get()) output_path = Path(self.output_folder.get()) # Crear carpeta de salida output_path.mkdir(parents=True, exist_ok=True) # Buscar imágenes if self.recursive.get(): files = list(input_path.rglob(‘*’)) else: files = list(input_path.glob(‘*’)) image_files = [f for f in files if f.is_file() and f.suffix.lower() in SUPPORTED_EXTENSIONS] if not image_files: self.root.after(0, lambda: messagebox.showwarning( «Aviso», «No se encontraron imágenes en la carpeta seleccionada»)) self.finish_processing() return total = len(image_files) successful = 0 failed = 0 total_original = 0 total_optimized = 0 quality = int(self.quality.get()) # Determinar tamaño objetivo width = None height = None if self.resize_mode.get() == «width»: width = int(self.size_value.get()) elif self.resize_mode.get() == «height»: height = int(self.size_value.get()) for i, input_file in enumerate(image_files): try: # Actualizar estado self.root.after(0, lambda f=input_file.name, idx=i, t=total: self.update_status(f»Procesando: {f} ({idx+1}/{t})»)) # Nombre de salida output_name = input_file.stem + ‘.webp’ if self.recursive.get(): relative_path = input_file.parent.relative_to(input_path) output_dir = output_path / relative_path output_dir.mkdir(parents=True, exist_ok=True) output_file = output_dir / output_name else: output_file = output_path / output_name # Obtener tamaño original original_size = input_file.stat().st_size total_original += original_size # Procesar imagen with Image.open(input_file) as img: # Conservar transparencia si existe has_transparency = img.mode in (‘RGBA’, ‘LA’) or \ (img.mode == ‘P’ and ‘transparency’ in img.info) if has_transparency: # Convertir a RGBA para conservar transparencia img = img.convert(‘RGBA’) elif img.mode != ‘RGB’: img = img.convert(‘RGB’) # Calcular nuevas dimensiones new_width, new_height = self.get_new_dimensions( img.width, img.height, width, height ) # Redimensionar si es necesario if new_width != img.width or new_height != img.height: img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) # Guardar como WebP (WebP soporta transparencia) img.save(output_file, ‘WEBP’, quality=quality, method=6) total_optimized += output_file.stat().st_size successful += 1 except Exception as e: failed += 1 print(f»Error procesando {input_file}: {e}») # Actualizar progreso progress = ((i + 1) / total) * 100 self.root.after(0, lambda p=progress: self.progress_var.set(p)) # Mostrar resultados saved = total_original – total_optimized saved_percent = (saved / total_original * 100) if total_original > 0 else 0
result_msg = f»»»✅ Proceso completado
Imágenes procesadas: {successful}
Errores: {failed}
Tamaño original: {self.format_size(total_original)}
Tamaño optimizado: {self.format_size(total_optimized)}
Espacio ahorrado: {self.format_size(saved)} ({saved_percent:.1f}%)
Guardado en: {output_path}»»»
self.root.after(0, lambda: messagebox.showinfo(«Completado», result_msg))
self.finish_processing()
def get_new_dimensions(self, original_width: int, original_height: int,
target_width: int = None, target_height: int = None) -> tuple:
«»»Calcula nuevas dimensiones manteniendo aspect ratio.»»»
if target_width:
ratio = target_width / original_width
return target_width, int(original_height * ratio)
elif target_height:
ratio = target_height / original_height
return int(original_width * ratio), target_height
return original_width, original_height
def format_size(self, bytes_size: int) -> str:
«»»Formatea bytes a KB o MB.»»»
if bytes_size < 1024:
return f»{bytes_size} B»
elif bytes_size < 1024 * 1024:
return f»{bytes_size / 1024:.1f} KB»
else:
return f»{bytes_size / (1024 * 1024):.2f} MB»
def update_status(self, text: str):
«»»Actualiza el texto de estado.»»»
self.status_label.config(text=text)
def finish_processing(self):
«»»Finaliza el procesamiento.»»»
self.processing = False
self.root.after(0, lambda: self.process_btn.config(state=tk.NORMAL))
self.root.after(0, lambda: self.update_status(«Listo»))
def main():
root = tk.Tk()
app = ImageOptimizerApp(root)
root.mainloop()
if __name__ == ‘__main__’:
main()
Newsletter
CONTENIDO PARA EMPRENDEDORES
Hemos creado una suscripción para emprendedores donde recibirán contenido de negocios durante un año



