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

¡Oferta!

PRECIO

El precio original era: $ 230.000,00.El 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

¡Oferta!

PRECIO

El precio original era: $ 230.000,00.El 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

¡Oferta!

PRECIO

El precio original era: $ 321.954,00.El 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:
  1. Ve a python.org/downloads
  2. Descarga la última versión de Python (botón amarillo «Download Python»)
  3. Ejecuta el instalador descargado
  4. MUY IMPORTANTE: Marca la casilla «Add Python to PATH» en la primera pantalla
  5. Haz clic en «Install Now»
  6. Espera a que termine la instalación y cierra el instalador
En Mac:
  1. Ve a python.org/downloads
  2. Descarga la última versión para macOS
  3. Abre el archivo .pkg descargado
  4. Sigue las instrucciones del instalador
  5. Completa la instalación
Paso 2: Crear la carpeta del proyecto
  1. Crea una carpeta en tu escritorio o donde prefieras, por ejemplo: img_optim
  2. 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
  1. Abre PowerShell (Windows) o Terminal (Mac)
  2. Escribe el siguiente comando y presiona Enter:
En Windows:
py -m pip install Pillow
En Mac:
python3 -m pip install Pillow
  1. 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
  1. Descarga el archivo con el código del programa (te lo proporcionarán)
  2. Guárdalo o copia el código que te den
Paso 5: Crear el archivo del programa
  1. Abre el Bloc de notas (Windows) o TextEdit (Mac)
  2. Pega el código que descargaste
  3. Ve a «Archivo» → «Guardar como…»
  4. Navega hasta la carpeta img_optim que creaste en el Paso 2
  5. En «Nombre del archivo» escribe exactamente: image_optimizer_gui.py
  6. En Windows: Cambia «Tipo» a «Todos los archivos (.
  7. Haz clic en «Guardar»
Paso 6: Ejecutar el programa
En Windows:
  1. Abre PowerShell
  2. 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)

  1. Ejecuta el programa con el comando:
py image_optimizer_gui.py
En Mac:
  1. Abre Terminal
  2. Navega hasta la carpeta:
cd /Users/TuNombre/Desktop/img_optim
  1. Ejecuta el programa:
python3 image_optimizer_gui.py
Paso 7: Usar el programa
  1. Se abrirá una ventana con la interfaz del optimizador
  2. Selecciona las imágenes que quieres optimizar
  3. Elige la calidad de compresión
  4. Haz clic en «Optimizar» y espera a que termine
  5. ¡Listo! Tus imágenes optimizadas en formato WebP estarán guardadas

Código de Python

Image optimizer gui · PY

#!/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

COMPLETAMENTE GRATIS