Skip to content

range type#13322

Merged
guill merged 3 commits intomasterfrom
range-type
Apr 24, 2026
Merged

range type#13322
guill merged 3 commits intomasterfrom
range-type

Conversation

@jtydhr88
Copy link
Copy Markdown
Contributor

@jtydhr88 jtydhr88 commented Apr 7, 2026

FE change (but not required) Comfy-Org/ComfyUI_frontend#10936

Summary

  • Add RANGE ComfyType for image levels/range adjustments, modeling the input side of GIMP's Levels operation
  • Add RangeInput helper class with from_raw() deserialization and to_lut() for LUT generation
  • Support three display modes for the frontend widget: plain, gradient, and histogram overlay

Design

The RANGE type represents an input levels adjustment with three parameters: min, max, and an optional midpoint.

This follows the same mathematical model as
https://gitlab.gnome.org/GNOME/gimp/-/blob/master/app/operations/gimpoperationlevels.c
(gimp_operation_levels_map), which applies a three-step mapping:

  1. Normalize: value = (input - low_input) / (high_input - low_input)
  2. Gamma: value = pow(value, 1.0 / gamma)
  3. Clamp: value = clamp(value, 0.0, 1.0)

midpoint instead of gamma

GIMP stores gamma directly but needs a logarithmic UI mapping (log10(1/gamma)) to make the slider feel linear. here it uses midpoint instead — a value in [0, 1] representing where the midtone sits within the input range. The conversion is gamma = -log2(midpoint), so midpoint=0.5 means gamma=1.0 (linear, no correction). This is more intuitive for a frontend slider widget since the handle position directly corresponds to the midpoint value, with no additional log transform needed.

Input side only

GIMP's Levels has both input mapping (black point, white point, gamma) and output mapping (output black, output white). In ComfyUI's node-based architecture, output remapping can be achieved by chaining another node downstream. Keeping the RANGE type focused on the input side (min, max, midpoint) keeps the type minimal and composable.

widget sceenshot

image image image

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f6bd798-d05c-482a-bde7-cc06a9a2357b

📥 Commits

Reviewing files that changed from the base of the PR and between d1aadc2 and 8822627.

📒 Files selected for processing (4)
  • comfy_api/input/__init__.py
  • comfy_api/latest/_input/__init__.py
  • comfy_api/latest/_input/range_types.py
  • comfy_api/latest/_io.py
✅ Files skipped from review due to trivial changes (1)
  • comfy_api/input/init.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • comfy_api/latest/_input/init.py
  • comfy_api/latest/_io.py
  • comfy_api/latest/_input/range_types.py

📝 Walkthrough

Walkthrough

Adds range input support: a new RangeInput class (with min_val, max_val, optional midpoint, from_raw, to_lut, __repr__) in comfy_api/latest/_input/range_types.py, and re-exports it via comfy_api/latest/_input/__init__.py and comfy_api/input/__init__.py. Introduces a Range ComfyType IO in comfy_api/latest/_io.py with a nested Range.Input widget type (configurable display, gradient stops, midpoint options, min/max bounds and default {"min":0.0,"max":1.0}), and updates relevant __all__ exports.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title "range type" directly describes the main change—adding a new RANGE ComfyType for input-side levels/range adjustments.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the RANGE type design, mathematical model, parameter choices, and frontend widget display modes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@comfy_api/latest/_input/range_types.py`:
- Around line 43-44: The to_lut() docstring states it returns float32 but the
implementation builds/returns a float64 NumPy array; update either the docstring
to float64 or (preferred) cast the final LUT to np.float32 before returning in
to_lut(), and apply the same fix to the other LUT-producing code paths noted
(the blocks referenced around lines 49-53 and line 66) so all LUT-returning
functions consistently produce float32; look for the to_lut() function and any
similarly named LUT builders in this module and add an explicit
.astype(np.float32) (or update their docstrings) to resolve the mismatch.
- Around line 34-39: The from_raw parsing in RangeInput currently calls
float(data["midpoint"]) when "midpoint" exists which crashes on payloads like
{"midpoint": None}; update the dict branch in RangeInput.from_raw to check that
data.get("midpoint") is not None before converting to float and otherwise set
midpoint to None (e.g., use a conditional: midpoint = float(value) if value is
not None else None), ensuring other fields (min_val/max_val) remain converted as
before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 58e52ad1-06bc-4395-bf35-65151ad95f40

📥 Commits

Reviewing files that changed from the base of the PR and between b615af1 and 7eab016.

📒 Files selected for processing (4)
  • comfy_api/input/__init__.py
  • comfy_api/latest/_input/__init__.py
  • comfy_api/latest/_input/range_types.py
  • comfy_api/latest/_io.py

Comment thread comfy_api/latest/_input/range_types.py
Comment thread comfy_api/latest/_input/range_types.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
comfy_api/latest/_io.py (1)

1269-1304: LGTM! Clean implementation following established patterns.

The Range ComfyTypeIO class correctly follows the existing patterns in this file (similar to Curve, BoundingBox). The super().__init__ call properly maps all parameters, the default value {"min": 0.0, "max": 1.0} aligns with RangeInput.from_raw() expectations, and as_dict() correctly serializes the UI configuration fields.

One minor type hint improvement:

📝 Optional: More specific type hint for gradient_stops
-                     gradient_stops: list=None,
+                     gradient_stops: list[dict]=None,

This matches the pattern used in Float.Input (line 300).

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@comfy_api/latest/_io.py` around lines 1269 - 1304, Update the type hint for
the Range.Input.gradient_stops attribute to be more specific (matching
Float.Input's pattern) by changing its annotation from plain list to an optional
list of dicts (e.g., gradient_stops: list[dict] | None or Optional[List[dict]]),
and ensure any imports (typing.Optional or List) are added if needed; locate and
edit the attribute declaration inside the Range.Input __init__ and the as_dict
usage remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@comfy_api/latest/_io.py`:
- Around line 1269-1304: Update the type hint for the Range.Input.gradient_stops
attribute to be more specific (matching Float.Input's pattern) by changing its
annotation from plain list to an optional list of dicts (e.g., gradient_stops:
list[dict] | None or Optional[List[dict]]), and ensure any imports
(typing.Optional or List) are added if needed; locate and edit the attribute
declaration inside the Range.Input __init__ and the as_dict usage remains
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fca090c0-a28a-43b4-b1dd-3591dba54a25

📥 Commits

Reviewing files that changed from the base of the PR and between 7eab016 and d1aadc2.

📒 Files selected for processing (4)
  • comfy_api/input/__init__.py
  • comfy_api/latest/_input/__init__.py
  • comfy_api/latest/_input/range_types.py
  • comfy_api/latest/_io.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • comfy_api/input/init.py
  • comfy_api/latest/_input/init.py
  • comfy_api/latest/_input/range_types.py

christian-byrne pushed a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 10, 2026
BE change Comfy-Org/ComfyUI#13322

## Summary
Add RANGE widget for image levels adjustment       
- Add RangeEditor widget with three display modes: plain, gradient, and
histogram
- Support optional midpoint (gamma) control for non-linear midtone
adjustment
- Integrate histogram display from upstream node outputs

## Screenshots (if applicable)
<img width="1450" height="715" alt="image"
src="https://github.com/user-attachments/assets/864976af-9eb7-4dd0-9ce1-2f5d7f003117"
/>
<img width="1431" height="701" alt="image"
src="https://github.com/user-attachments/assets/7ee2af65-f87a-407b-8bf2-6ec59a1dff59"
/>
<img width="705" height="822" alt="image"
src="https://github.com/user-attachments/assets/7bcb8f17-795f-498a-9f8a-076ed6c05a98"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10936-Range-editor-33b6d73d365081089e8be040b40f6c8a)
by [Unito](https://www.unito.io)
@guill guill merged commit 2e05037 into master Apr 24, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants