Vintage Effect
Make AI photos look shot, not rendered — vintage grain, JPG rot, and all
- images
- IMAGE
Your Flux/SDXL output looks wrong in a way you can't name. Skin is too even. Colors are too punchy. Edges are too crisp. It's too perfect - nobody's camera takes a picture like that, so your brain quietly files it under "rendered." The Vintage Effect node is the fix: one image-in/image-out node that bakes in exactly the imperfections real photos have - film grain, faded color, darkened corners, and yes, actual JPG compression artifacts.
This is the same advice the photorealism crowd keeps landing on, packaged as a single node: grain and noise in post make images read as captured rather than generated, and AI images are chronically oversaturated and over-contrasty, so pulling saturation down and adding a color cast helps more than any "ultra realistic" prompt token. Vintage Effect bundles all of it so you don't have to assemble grain, vignette, and grading from three separate packs.
How it works
Under the hood it converts your batch to PIL, then runs a fixed pipeline: color grade → saturation → grain → blur → vignette → JPG re-encode. The standout trick is the last step. It saves each image to a JPEG in memory and reopens it, once per passes value. Re-encoding lossy files over and over is what produces that soft, blocky, "uploaded to Facebook in 2009" degradation that noise alone can't fake. Nothing else in the pack calls an API or needs a key - it's pure CPU numpy/Pillow, torch in and torch out.
The inputs that matter
Only one input is required in the strict sense (images), but you'll touch these:
- quality (default 70) - JPG quality, 0–100. Lower means more artifacts. Note 0 is silently clamped to 1 in the code, so "0" isn't full destruction; the real range is 1–100.
- passes (default 1) - how many times it re-encodes. More passes = more degradation. This is the "generation loss" dial.
- grain_strength (default 5, 0 disables) - film grain. Values read high: the code divides your number by 2, so 100 is aggressively noisy. Start around 5–15.
- color_grade (default Faded) with color_grade_strength (default 50) - None/Warm/Cool/Faded/Sepia. Faded drops contrast to 0.75 and lifts brightness; Sepia is a classic matrix. Strength blends the grade back toward the original, so 50 is a gentle wash.
- saturation (default 70) - 100 is original, below that you go toward gray. The default already pulls you down 30%, which lines up with the "AI is oversaturated, desaturate in post" playbook.
- vignette_strength (default 0) and the blur trio (
blur_type+blur_strength) - both off by default. Vignette is a quadratic darkening toward the corners; blur offers Gaussian, Box, motion/radial/lens/soft-focus, all good for the dreamy-lens look.
The single output is an IMAGE, so it drops straight into your VAE decode → Save Image chain, or upstream of an upscaler if you want to bake the look before sharpening.
Installing
Install via ComfyUI Manager (search "Vintage Effect"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/brucew4yn3rp/ComfyUI_VintageEffect
Then restart ComfyUI. It pulls in torch, Pillow, numpy, and scipy - scipy is only actually imported when you use the motion-blur types, so you'll likely already have everything in your venv. No model files, no downloads, no keys.
Where people get burned
The node quantizes everything through uint8 PIL and drops alpha on RGBA images (JPEG has no transparency), so don't feed it images you need transparency from. And because it's all CPU numpy, a big batch at low quality with multiple passes is slow - it's a finishing step, run it once on the image you actually keep, not on every preview. If you need a live preview, keep grain low; at high settings each frame's noise is random, so the grain shimmers between previews.
It's a niche node with a small footprint, but for one specific job - convincing film-look finishing on a photo-real workflow - it does in one node what usually takes three.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | The images to apply vintage effect to. | |
| quality | INT | 700–100 | JPG compression quality. Lower = more artifacts (0-100) |
| passes | INT | 11–10 | Number of compression passes. More passes = more degradation |
| grain_strength | INT | 50–100 | Amount of film grain. Set to 0 to disable (0-100) |
| vignette_strength | INT | 00–100 | Vignette darkness around edges. Set to 0 to disable (0-100) |
| color_grade | COMBO | Faded | Color grading preset |
| color_grade_strength | INT | 500–100 | Strength of color grade effect. 0 = disabled, 100 = full effect (0-100) |
| saturation | INT | 700–200 | Color saturation (0 = grayscale, 100 = original, 200 = max boost) |
| blur_type | COMBO | None | Type of blur to apply |
| blur_strength | INT | 00–100 | Strength of blur effect. Set to 0 to disable (0-100) |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |