ComfyUI Node

Pixelate

Turn AI slop into actual pixel art in one node

By flycarl·Created 2 years ago·Updated 2 years ago· 8
Pixelate
  • image
  • palette_image
  • IMAGE
downscale_factor4
scale_mode
rescale_to_originalfalse
color_mode
colors16
quantization_method
dithering
palette_size32

Pixel art is the one style diffusion is genuinely bad at. Models don't understand "chunky" - they give you soft blobs that read as pixel art from across the room and fall apart the second you zoom in. The fix has always been post-processing: downscale hard, shrink the color palette, then upscale back up. That's exactly the recipe sd-webui-pixelart gave A1111 users for years, and ComfyUI-Pixelate is the same trick as a single native ComfyUI node. No model, no API key, no VRAM pressure - it's pure image math running on CPU.

What it actually does

Feed it an image and it runs a four-stage pipeline. First it downscales by an integer factor (OpenCV interpolation, nearest through lanczos). If you flip rescale_to_original, it scales back up to the original dimensions with nearest-neighbor, which is what gives you those hard blocky edges instead of mush. Next it optionally converts to grayscale or binary. Then it builds a color palette and snaps every pixel to the nearest palette color. Optionally it adds Floyd–Steinberg dithering - the classic error-diffusion trick that fakes extra tones by scattering colored dots, the thing that makes 16-color images look like they have 40.

The inputs that matter

There are ten knobs but you'll realistically touch these:

  • image - anything: a generated image, a screenshot, a low-res render you want to gamesify.
  • downscale_factor (1–32, default 4) - the block size. 4 gives you that classic chunky SNES feel.
  • colors (2–256, default 16) - target palette size. 16 is the retro sweet spot.
  • rescale_to_original - leave it off if you want small pixel output, on if your downstream nodes expect the original resolution.
  • dithering - none for clean flat colors, floyd-steinberg for that dithered Game Boy look.
  • quantization_method - set to auto until you have a reason not to.

Two optional inputs, palette_image and palette_size, let you extract a palette from a reference image instead of the input - handy if you want to force your output into, say, the actual Game Boy palette.

The single output is an IMAGE with the same batch/alpha shape it went in with. Wire it straight to Save Image, or run it through a VAE encode and feed it back into img2img for a "stylize my render as pixel art" workflow.

Installing it

It's a one-node pack with no requirements.txt, so install is painless:

cd ComfyUI/custom_nodes
git clone https://github.com/flycarl/ComfyUI-Pixelate

Restart ComfyUI and search for "Pixelate" in the node menu. Or just use ComfyUI Manager and search "ComfyUI-Pixelate". That's the whole install - it leans on OpenCV, Pillow, numpy and torch, all of which ship with ComfyUI. No weights to download.

Where people get burned

A few things the README glosses over that the source code tells you plainly:

  • It only processes the first image in a batch. The node reads image[0] and drops the rest. Fine for a single generated image, a trap if you feed it a batch grid or video frames - you'll silently get one frame back.
  • scale_mode: auto isn't smart. It just maps to OpenCV's INTER_AREA, which is honestly the right default for downscaling anyway. "Auto" is marketing, not magic.
  • The GPU k-means is fiction. Stock OpenCV has no CUDA build, so that path always throws and falls back to CPU k-means on a random 10,000-pixel sample. Worse, k-means is capped at 32 colors no matter what you put in colors. If you want the full palette, pick libimagequant or auto (which routes big images there).
  • Floyd–Steinberg is slow. It's pure-Python, pixel-by-pixel, and it runs after any rescale - so dithering a 1024² image with rescale_to_original on will make you wait. Keep downscale_factor high or skip dithering on big images.
  • Wire palette_image and colors is ignored - the reference image owns the palette, and palette_size decides how many colors it extracts.
  • Output dimensions change unless rescale_to_original is on, so make sure whatever you plug it into accepts arbitrary sizes.

Realistic take: it's a small, occasionally rough port, not a polished piece of infrastructure - there's a single commit stream and it doesn't get much community chatter. But for "I want this render to look like a sprite," it does the job in one node and costs you nothing to try.

Categoryimage/Pixel Art

Inputs (10)

NameTypeDefaultDescription
imageIMAGE
downscale_factorINT41–32
scale_modeCOMBO6 options: auto, nearest, area, linear, cubic, lanczos
rescale_to_originalBOOLEANfalse
color_modeCOMBO3 options: rgb, grayscale, bw
colorsINT162–256
quantization_methodCOMBO7 options: auto, kmeans, mediancut, maxcoverage, fastoctree, libimagequant, +1
ditheringCOMBO2 options: none, floyd-steinberg
palette_imageoptIMAGE
palette_sizeoptINT322–256

Outputs (1)

NameTypeDescription
IMAGEIMAGE