c79f33265e
Arregla los dos defectos reportados del pipeline comfyui_pixelart_real_oneshot:
el sujeto salía diminuto respecto al frame y siempre traía fondo (sin opción de
transparencia).
Causa raíz: comfyui_pixelize_image hacía convert("RGB") y descartaba el alpha;
comfyui_build_pixelart_workflow no inyectaba rembg (a diferencia de sus hermanos
item_icon/enemy_creature); y no había ningún paso de auto-crop al contenido.
Orden correcto del pipeline ahora:
generar (rembg) -> autocrop al bbox + cuadrar -> downscale (alpha aparte por
PixelOE) -> cuantización alpha-aware -> PNG RGBA transparente.
Piezas:
- comfyui_pixelize_image (1.1.0): keep_alpha/alpha_threshold. Con RGBA cuantiza
solo el RGB (fondo transparente relleno con la moda del sujeto, fuera de la
paleta) y preserva/binariza el alpha aparte. RGB sin alpha intacto.
- crop_to_content (NUEVA, pura PIL): bbox del contenido (alpha o diff-fondo) ->
recorta -> margen -> cuadra centrando. No-throw; imagen vacía -> copia intacta.
- comfyui_build_pixelart_workflow (1.1.0): transparent=True + rembg_model.
Inyecta nodo Image Rembg tras VAEDecode (patrón de item_icon).
- comfyui_pixelart_real_oneshot (1.1.0): transparent + autocrop + crop_pad_ratio
+ rembg_model. Recombina el alpha aparte tras PixelOE (trabaja en RGB). Campos
nuevos: has_alpha, autocrop_applied.
Verificado en GPU (knight 64px): RGBA con 4 esquinas alpha==0, contenido cubre
88% del frame (antes 48%), 16 colores, 64x64. 32 tests offline en verde.
Report: reports/0218-2026-06-28-pixelart-sprite-fix.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.9 KiB
6.9 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | params | output | tested | tests | test_file_path | file_path | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| comfyui_pixelize_image | function | py | ml | 1.1.0 | impure | def comfyui_pixelize_image(src_path: str, dst_path: str, *, downscale: int = 8, colors: int = 16, palette=None, dither: bool = False, upscale_back: bool = True, keep_alpha: bool = True, alpha_threshold: int = 128) -> dict | Post-proceso pixel-perfect (Fase 2 pixelart): imagen -> downscale nearest-neighbor por factor (colapsa cada bloque borroso a un pixel duro) -> cuantizacion a N colores (MEDIANCUT) o a una paleta fija embebida (game-boy / pico-8 / nes / lista de hex) -> opcional re-upscale nearest conservando los pixeles duros. Alpha-aware: si la entrada es RGBA y keep_alpha, cuantiza SOLO el RGB (el fondo transparente no entra en la paleta) y preserva/binariza el alpha por separado -> PNG RGBA con transparencia real. Convierte el 'pixelart borroso de IA' en pixelart de verdad. Nucleo PIL puro, CPU-only: sin GPU, sin red. Devuelve {ok, out_path, size, n_colors_final, has_alpha, error}. Impura solo por la lectura/escritura de disco. |
|
false | error_py_core |
|
dict con ok (bool), out_path (str), size ([w,h] de la imagen final), n_colors_final (int, colores RGB distintos; en la zona opaca si es RGBA), has_alpha (bool, True si la salida es RGBA), error (str, vacio si OK). | true |
|
python/functions/ml/comfyui_pixelize_image_test.py | python/functions/ml/comfyui_pixelize_image.py |
Ejemplo
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_pixelize_image import comfyui_pixelize_image
# Crudo SDXL+SDXL_pixel-art 1024x1024 -> pixelart 16 colores, grid de 128
res = comfyui_pixelize_image(
os.path.expanduser("~/ComfyUI/output/pixelart_00001_.png"),
"/tmp/hero_pixel.png",
downscale=8, colors=16,
)
# {'ok': True, 'out_path': '/tmp/hero_pixel.png', 'size': [1024, 1024], 'n_colors_final': 16, 'error': ''}
# Forzar la paleta retro Game Boy (4 colores) y dejar la imagen pequena (sin upscale)
comfyui_pixelize_image("/tmp/hero_pixel.png", "/tmp/hero_gb.png",
palette="game-boy", upscale_back=False)
# Sprite RGBA (tras rembg): preserva la transparencia, cuantiza solo el sujeto
res = comfyui_pixelize_image("/tmp/knight_rgba.png", "/tmp/knight_px.png",
downscale=1, colors=16, keep_alpha=True)
# {'ok': True, 'has_alpha': True, 'n_colors_final': 16, ...} -> fondo transparente intacto
Cuando usarla
Fase 2 del pipeline pixelart: tras generar el crudo (SDXL + LoRA SDXL_pixel-art),
para colapsar el grid borroso a pixeles duros y limitar la paleta. Si la imagen
viene de rembg con fondo recortado (RGBA), keep_alpha=True mantiene la
transparencia y deja el fondo fuera de la paleta. Tambien sirve para "pixelizar"
cualquier imagen (sprite, render, foto) a estetica retro sin tocar la GPU. Para
llevar el resultado a Godot con filtro Nearest:
comfyui_export_asset_to_godot(out, "pixelart", proj).
Gotchas
- nearest, no lanczos: el downscale usa NEAREST a proposito; interpolar suave re-difumina el grid. No lo cambies por "calidad".
palettefija (game-boy/pico-8/nes o lista de hex) ignoracolors. La paleta se rellena internamente repitiendo su ultimo color para quequantizeno introduzca un negro extra por entradas vacias (bug arreglado en v1.0.0).downscaleconupscale_back=Falsedeja la imagen dew//downscale x h//downscale: util para spritesheets compactos; conTruevuelve al tamano original con bordes duros (preview).- Todo error es dict
ok=False(no excepcion):src_pathinexistente,downscale<1, paleta desconocida ->errorexplica. No crashea ni borra nada. n_colors_finalcuenta colores RGB distintos reales del PNG escrito; con salida RGBA cuenta solo la zona opaca (el transparente no es un color del pixel-art); con paleta fija puede ser menor que el tamano de la paleta si la imagen no usa todos.- alpha-aware (v1.1.0): con entrada RGBA y
keep_alpha=True(default), el fondo transparente se rellena internamente con la moda del sujeto antes de cuantizar, asi NO gasta una entrada de la paleta; el alpha se downscalea nearest aparte y se binariza poralpha_threshold(0/255 = bordes duros pixel-art). Entrada sin alpha -> comportamiento RGB identico al de antes (retrocompatible). - Si la entrada RGBA esta toda transparente (rembg sin sujeto), no crashea:
devuelve
ok=True,has_alpha=True,n_colors_final=0y el PNG sigue transparente. - CPU-only: no toca la GPU ni el servidor ComfyUI; corre en cualquier interprete con Pillow (numpy acelera el relleno alpha; sin numpy degrada limpio).
Capability growth log
- v1.1.0 (2026-06-28) — alpha-aware:
keep_alpha/alpha_threshold. Si la entrada es RGBA, cuantiza solo el RGB (fondo transparente fuera de la paleta) y preserva el alpha binarizado -> PNG RGBA con transparencia real. Cierra el bug del pipeline pixelart que perdia el fondo transparente por elconvert("RGB")(issue sprite-fix).