Film Emulation
Portra, Velvia, and Tri-X as a node instead of a prompt trick
- image
- image
- film_info
If you've spent time on the photoreal side of ComfyUI, you already know the trick: naming a real film stock in your prompt - "Kodak Portra 400," "Ilford HP5" - does more for realism than a wall of quality tags ever will, because modern text encoders actually understand what those stocks look like. FilmEmulation takes that same idea and moves it out of the prompt and into a dedicated post-process node, with actual per-stock color science instead of hoping the model interprets the words right.
What it is and why you'd reach for it
This node exists for the case where you want a specific, named film look applied deterministically - not "hope the model read Portra 400 correctly," but pick it from a dropdown and get consistent, tunable results every time. It's grading with a very specific target: the characteristic color response, contrast curve, and grain of real film stocks, which is a different job from the main Color Corrector's general-purpose "make it look good" AI analysis.
How it works
You pick a film_stock and the node applies that stock's characteristic response - including highlight rolloff, which is the real, physical thing film does that digital sensors don't: film compresses highlights gradually instead of clipping them hard, which is a big part of why film-emulated images read as less harsh than a straight digital render. On top of the base stock look, it layers grain, exposure compensation (simulated over/under-exposure response, in stops), and push/pull processing simulation, which affects contrast and grain the way actually pushing or pulling film in the darkroom would.
The inputs and outputs that matter
image and film_stock are required, alongside a set of tunable knobs with sensible defaults. The stock list covers real, recognizable film: color negative (Kodak Portra 400/800, Kodak Gold 200, Fuji Pro 400H), color reversal/slide (Fuji Velvia 50/100 - famously high-saturation stocks), a cinema stock (Kodak Vision3 500T, tuned for tungsten/low light), and two black-and-white stocks (Kodak Tri-X 400, Ilford HP5 Plus) that will fully desaturate your image - that's the stock, not a bug. strength (default 1.0) blends between your original and the full emulated look, so if 100% Portra is too much, dial it back rather than fighting it with other sliders. grain_intensity (default 0.3) adds film grain - keep this low or off on anime/illustration content, where grain reads as noise rather than texture. exposure_compensation and push_pull (both -2 to +2) simulate shooting over/underexposed or developing pushed/pulled, and highlight_rolloff (default 0.8) controls how gradually highlights compress instead of clipping.
Outputs: image (the film-emulated result) and film_info - a string output describing the stock and settings applied, useful for keeping track of which look you used across a batch of comparisons.
How to install it
Via ComfyUI Manager: search "Easy Color Correction" and install - this node comes bundled with the pack, no separate download. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/regiellis/ComfyUI-EasyColorCorrector.git
cd ComfyUI-EasyColorCorrector
pip install -r requirements.txt
then restart ComfyUI.
Common issues & troubleshooting
The look is too strong / too obviously "filtered." Drop strength below 1.0 before you start second-guessing which stock to pick - most of the "this looks fake" complaints about film-emulation filters in general come from applying the full effect at full strength rather than blending it in.
Grain looks like noise, not texture. This is a real trade-off with grain_intensity - push it too high on a clean, high-resolution generated image and it can read as sensor noise rather than film grain. Start around the 0.2-0.3 default and adjust from there.
You picked a B&W stock and the image is now black and white. That's Tri-X or HP5 doing exactly what film stock does - those are monochrome films. If you wanted color with just the grain/contrast character, pick a color stock instead.
Pairing with prompt-level film language. If your prompt already names a film stock (a real, working technique - see the photorealism playbook), this node and your prompt are doing overlapping jobs. That's not necessarily bad - you can use the prompt for the base look the model generates and this node for a controlled, repeatable final pass - but be aware you're stacking two "film" signals, not adding a completely independent one.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| film_stock | COMBO | Kodak Portra 400 | 9 options: Kodak Portra 400, Kodak Portra 800, Fuji Velvia 50, Fuji Velvia 100, Kodak Vision3 500T, Kodak Gold 200, +3 |
| strength | FLOAT | 1.000–1 | Blend strength between original and film emulation |
| grain_intensity | FLOAT | 0.300–1 | Film grain intensity (0.0 = no grain, 1.0 = maximum grain) |
| exposure_compensation | FLOAT | 0.0-2–2 | Exposure compensation in stops (simulates over/under exposure response) |
| push_pull | FLOAT | 0.0-2–2 | Push/pull processing simulation (affects contrast and grain) |
| highlight_rolloff | FLOAT | 0.800–1 | Film highlight rolloff characteristics |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| film_info | STRING | — |