Files
comic-manager/processors/image_normalizer.py
T

116 lines
3.7 KiB
Python

# 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)
def _detected_formats(work_dir: str) -> set[str]:
"""Devuelve el conjunto de extensiones de imagen presentes en work_dir (normalizando .jpeg → .jpg)."""
formats = set()
for fname in os.listdir(work_dir):
ext = os.path.splitext(fname)[1].lower()
if ext == ".jpeg":
ext = ".jpg"
if ext in IMAGE_EXTENSIONS:
formats.add(ext)
return formats
def preview_uniformize_images(work_dir: str, target_ext: str) -> list[tuple[str, str]]:
"""Como preview_normalize_images pero devuelve [] si las imágenes ya son uniformes."""
if len(_detected_formats(work_dir)) <= 1:
return []
return preview_normalize_images(work_dir, target_ext)
def uniformize_images(work_dir: str, target_ext: str = ".jpg") -> StepResult:
"""Como normalize_images pero solo actúa si hay formatos mixtos."""
if len(_detected_formats(work_dir)) <= 1:
return StepResult(step="normalize_images", changed=False)
return normalize_images(work_dir, target_ext)