Tone Curve (RGB)
Tone Curves for ComfyUI, Photoshop-Style
- image
- image_toned
JHPixelProToneCurve is a Photoshop-style tone curve for ComfyUI. Eight control points, baked into a 1024-step Catmull-Rom LUT, applied straight to your tensor. If you've graded in Lightroom or Photoshop, you already know the moves - the S-curve for contrast, lifted shadows for a film look - and this node gives you those exact moves without leaving the graph.
The smart part is that it ships with hand-tuned presets, so you don't have to plot points to get a good result:
s_curve_mild/s_curve_strong- the classic contrast bump. Mild is the safe default for portraits.lift_shadows- matte/film-stock vibe.crush_blacks- dramatic, cinematic.linear- identity, for an A/B baseline.
channel switches between rgb_master (global contrast) and r / g / b (color balance / white balance). The killer use case: lift the shadows on the blue channel for a teal-and-orange grade - a two-widget operation that takes a whole chain in other tools. And strength (0.0–1.0) blends the graded result with the original, so you can work at 0.6 instead of always committing to the full curve.
custom mode takes an 8-point JSON, [[x1,y1],...,[x8,y8]]. Two hard rules, or it raises:
- Endpoints MUST be (0,0) and (1,1) - this guarantees blacks stay black and whites stay white.
- x values must be strictly increasing (monotone).
Inputs: image, preset, channel, points_json, strength. Output: image_toned.
Install is the shared pack install:
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/ComfyUI-JH-PixelPro.git
cd ComfyUI-JH-PixelPro
pip install -r requirements.txt
Restart and it's under ComfyUI-JH-PixelPro/color, or use ComfyUI Manager → search "ComfyUI-JH-PixelPro".
Troubleshooting: the JSON validation errors are the #1 newbie wall. Copy the default points string, edit the middle six points, keep (0,0)/(1,1) and monotone x, and you're fine. Importing a Photoshop .acv? Those can have anywhere from 2 to 16 points; this node wants exactly 8, so re-sample your curve to 8 evenly spaced control points before pasting. Performance note: on CPU at 2K, rgb_master costs ~225 ms because the LUT apply is memory-bandwidth-bound; single-channel runs are ~96 ms, and it's far faster on GPU or at 1K. For a 2K pro retouch chain, run it on the GPU.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| preset | COMBO | linear | Tone curve preset. s_curve_mild / s_curve_strong add contrast; lift_shadows opens up dark regions; crush_blacks deepens shadows for dramatic look; linear = identity. Choose 'custom' to paste your own 8-point JSON below. |
| channel | COMBO | rgb_master | rgb_master = apply the curve equally to R, G, B (global contrast). r / g / b = apply only to that channel (color balance / white-balance correction). |
| points_json | STRING | [[0.0, 0.0], [0.15, 0.10], [0.30, 0.25], [0.45, 0.43], [0.55, 0.57], [0.70, 0.75], [0.85, 0.90], [1.0, 1.0]] | Custom 8 control points [[x1,y1],...,[x8,y8]] in [0,1]^2. Endpoints MUST be (0,0) and (1,1). x must be strictly increasing (monotone). Used only when preset = custom; ignored otherwise. |
| strength | FLOAT | 1.000–1 | Blend factor. 0 = identity (bypass), 1 = full curve. Use 0.5–0.8 for subtle grading. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image_toned | IMAGE | — |