# processors/image_normalizer.py import os from core.constants import IMAGE_EXTENSIONS from core.result import StepResult def preview_normalize_images(work_dir: str, target_ext: str) -> list[tuple[str, str]]: """Devuelve lista de (nombre_actual, nombre_final) sin convertir nada.""" target_ext = target_ext.lower() if not target_ext.startswith("."): target_ext = "." + target_ext result = [] for root, _, files in os.walk(work_dir): for f in files: ext = os.path.splitext(f)[1].lower() normalized_ext = ".jpg" if ext == ".jpeg" else ext if ext not in IMAGE_EXTENSIONS: continue if normalized_ext == target_ext: continue stem = os.path.splitext(f)[0] result.append((f, stem + target_ext)) return result def normalize_images(work_dir: str, target_ext: str = ".jpg") -> StepResult: """ Convierte todas las imágenes al formato indicado por target_ext. Requiere Pillow. Si no está instalado, devuelve un StepResult con error. """ try: from PIL import Image except ImportError: return StepResult( step="normalize_images", changed=False, errors=["Pillow no instalado. Ejecuta: pip install Pillow"], ) target_ext = target_ext.lower() if not target_ext.startswith("."): target_ext = "." + target_ext # Mapa de extensión a formato PIL FORMAT_MAP = { ".jpg": "JPEG", ".jpeg": "JPEG", ".png": "PNG", ".webp": "WEBP", } pil_format = FORMAT_MAP.get(target_ext) if pil_format is None: return StepResult( step="normalize_images", changed=False, errors=[f"Formato de imagen no soportado: {target_ext}"], ) changed = False details = [] for root, _, files in os.walk(work_dir): for f in files: ext = os.path.splitext(f)[1].lower() normalized_ext = ".jpg" if ext == ".jpeg" else ext if ext not in IMAGE_EXTENSIONS: continue if normalized_ext == target_ext: continue src = os.path.join(root, f) stem = os.path.splitext(f)[0] dst = os.path.join(root, stem + target_ext) with Image.open(src) as img: # Convertir modos incompatibles con JPEG if pil_format == "JPEG" and img.mode in ("RGBA", "P", "LA"): img = img.convert("RGB") img.save(dst, format=pil_format) os.remove(src) details.append(f"{f} → {stem + target_ext}") changed = True return StepResult(step="normalize_images", changed=changed, details=details)