Revamp the syntax to #[hard(a..b)] and #[soft(a..b)] bounds on node definitions (#4307)

* Revamp the syntax to #[hard(a..b)] and #[soft(a..b)] bounds on node definitions

* Address review feedback: error on empty bounds ranges and remove redundant count clamps

* Fix NaN transform from Repeat Array with a count of 1

* Remove redundant manual clamps already enforced by #[hard(...)] bounds
This commit is contained in:
Keavon Chambers
2026-07-03 18:48:58 -07:00
committed by GitHub
parent 95c1ab81f3
commit f05a644bd9
17 changed files with 341 additions and 197 deletions

View File

@@ -85,8 +85,9 @@ fn gamma_correction<T: Adjust<Color>>(
#[gpu_image]
mut input: T,
#[default(2.2)]
#[range((0.01, 10.))]
#[hard_min(0.0001)]
#[range]
#[hard(0.0001..)]
#[soft(0.01..10)]
gamma: f32,
inverse: bool,
) -> T {
@@ -344,22 +345,28 @@ fn black_and_white<T: Adjust<Color>>(
mut image: T,
#[default(Color::BLACK)] tint: Color,
#[default(40.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
reds: PercentageF32,
#[default(60.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
yellows: PercentageF32,
#[default(40.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
greens: PercentageF32,
#[default(60.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
cyans: PercentageF32,
#[default(20.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
blues: PercentageF32,
#[default(80.)]
#[range((-200., 300.))]
#[range]
#[soft(-200..300)]
magentas: PercentageF32,
) -> T {
image.adjust(|color| {
@@ -997,12 +1004,11 @@ fn posterize<T: Adjust<Color>>(
#[gpu_image]
mut input: T,
#[default(4)]
#[hard_min(2)]
#[hard(2..)]
levels: u32,
) -> T {
let levels = levels as f32;
input.adjust(|color| {
// `hard_min(2)` constrains the widget but doesn't bind the data-flow input (a saved doc or upstream node could still feed 0 or 1, producing inf/NaN below).
let levels = (levels as f32).max(2.);
let number_of_areas = levels.recip();
let size_of_areas = (levels - 1.).recip();
color.map_gamma_rgb(|c| (c / number_of_areas).floor() * size_of_areas)
@@ -1029,8 +1035,9 @@ fn exposure<T: Adjust<Color>>(
exposure: f32,
offset: f32,
#[default(1.)]
#[range((0.01, 10.))]
#[hard_min(0.0001)]
#[range]
#[hard(0.0001..)]
#[soft(0.01..10)]
gamma_correction: f32,
) -> T {
input.adjust(|color| {

View File

@@ -92,8 +92,9 @@ async fn blur(
/// The image to be blurred.
image_frame: List<Raster<CPU>>,
/// The radius of the blur kernel.
#[range((0., 100.))]
#[hard_min(0.)]
#[range]
#[hard(0..)]
#[soft(..100)]
radius: PixelLength,
/// Use a lower-quality box kernel instead of a circular Gaussian kernel. This is faster but produces boxy artifacts.
box_blur: bool,
@@ -128,8 +129,9 @@ async fn median_filter(
/// The image to be filtered.
image_frame: List<Raster<CPU>>,
/// The radius of the filter kernel. Larger values remove more noise but may blur fine details.
#[range((0., 50.))]
#[hard_min(0.)]
#[range]
#[hard(0..)]
#[soft(..50)]
radius: PixelLength,
) -> List<Raster<CPU>> {
image_frame

View File

@@ -8,7 +8,7 @@ async fn image_color_palette(
_: impl Ctx,
image: List<Raster<CPU>>,
#[default(4)]
#[hard_min(1)]
#[hard(1..)]
count: u32,
) -> List<Color> {
const GRID: f32 = 3.;