From be04d17ede462b89b3c68199055508039188fa39 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 12 Sep 2026 17:01:15 -0700 Subject: [PATCH] Move Gradient Map into adjustments.rs and position it by the classic 0.3/0.59/0.11 luma --- .../messages/portfolio/document_migration.rs | 2 +- node-graph/nodes/raster/src/adjustments.rs | 39 +++++++++++++++++++ node-graph/nodes/raster/src/gradient_map.rs | 36 ----------------- node-graph/nodes/raster/src/lib.rs | 2 - 4 files changed, 40 insertions(+), 39 deletions(-) delete mode 100644 node-graph/nodes/raster/src/gradient_map.rs diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index 1fe2976c121..dfb2ed6125b 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -539,7 +539,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ aliases: &["graphene_raster_nodes::adjustments::GammaCorrectionNode", "graphene_core::raster::adjustments::GammaCorrectionNode"], }, NodeReplacement { - node: graphene_std::raster_nodes::gradient_map::gradient_map::IDENTIFIER, + node: graphene_std::raster_nodes::adjustments::gradient_map::IDENTIFIER, aliases: &[ "graphene_raster_nodes::gradient_map::GradientMapNode", "graphene_raster_nodes::adjustments::GradientMapNode", diff --git a/node-graph/nodes/raster/src/adjustments.rs b/node-graph/nodes/raster/src/adjustments.rs index d7833c5ca4d..3c760a0d967 100644 --- a/node-graph/nodes/raster/src/adjustments.rs +++ b/node-graph/nodes/raster/src/adjustments.rs @@ -613,6 +613,45 @@ fn threshold>( image } +// Aims for interoperable compatibility with: +// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27grdm%27%20%3D%20Gradient%20Map +// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Gradient%20settings%20(Photoshop%206.0) +// +// TODO: Full PSD interop needs a compatibility variant of `GradientInterpolation` with its own midpoint semantics, position warp, +// TODO: and smoothing (a `gradient_smoothness` attribute), plus noise gradients, which we don't yet support. +// TODO: Its axes differ from ours: its midpoint is always a knee in the position warp and its smoothness blends the curve over +// TODO: that fixed warp, while each variant here picks warp and curve together, so neither end of the blend is Linear or Smooth. +// TODO: Per channel in the gradient space (measured on gamma RGB): +// TODO: - Position t maps to a parameter p by a piecewise-linear knee through (stop position, index) and (midpoint, index - 0.5). +// TODO: - Linear lerps the interval's stop colors by the fraction of p. Smooth is a cubic Hermite over the stop index with tangent +// TODO: `(c[i + 1] - c[i - 1]) / 2`, the end stops repeated past the ends, so two stops give `0.5 p + 1.5 p^2 - p^3`. +// TODO: - The ramp is `(1 - s) * linear + s * smooth` for smoothness s, clamped per interval to its two stop colors. +#[cfg(feature = "std")] +#[node_macro::node(category("Raster: Adjustment"))] +async fn gradient_map + Send>( + _: impl Ctx, + #[implementations(Raster, Color, Gradient)] image: Item, + #[default(Color::BLACK, Color::WHITE)] gradient: Item, + reverse: Item, +) -> Item { + let mut image = image; + let settings = vector_types::GradientSettings::from(&gradient); + let evaluator = gradient.into_element().evaluator(settings); + let reverse = reverse.into_element(); + + image.element_mut().adjust(|color| { + // The classic 0.3/0.59/0.11 luma of the gamma-encoded channels picks the position along the gradient + let [r, g, b, alpha] = color.to_gamma_srgb_channels(); + let intensity = 0.3 * r + 0.59 * g + 0.11 * b; + let intensity = if reverse { 1. - intensity } else { intensity }; + + // The source alpha is kept and the gradient's own alpha stops are ignored + evaluator.evaluate(intensity as f64).with_alpha(alpha) + }); + + image +} + // Aims for interoperable compatibility with: // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27-,vibA%27%20%3D%20Vibrance,-%27hue%20%27%20%3D%20Old // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Vibrance%20(Photoshop%20CS3) diff --git a/node-graph/nodes/raster/src/gradient_map.rs b/node-graph/nodes/raster/src/gradient_map.rs deleted file mode 100644 index 51ed59ad822..00000000000 --- a/node-graph/nodes/raster/src/gradient_map.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Not immediately shader compatible due to needing [`Gradient`] as a param, which needs [`Vec`] - -use crate::adjust::Adjust; -use core_types::list::Item; -use core_types::{Color, Ctx}; -use raster_types::{CPU, Raster}; -use vector_types::Gradient; - -// Aims for interoperable compatibility with: -// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27grdm%27%20%3D%20Gradient%20Map -// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Gradient%20settings%20(Photoshop%206.0) -#[node_macro::node(category("Raster: Adjustment"))] -async fn gradient_map + Send>( - _: impl Ctx, - #[implementations( - Raster, - Color, - Gradient, - )] - image: Item, - #[default(Color::BLACK, Color::WHITE)] gradient: Item, - reverse: Item, -) -> Item { - let mut image = image; - let settings = vector_types::GradientSettings::from(&gradient); - let evaluator = gradient.into_element().evaluator(settings); - let reverse = reverse.into_element(); - - image.element_mut().adjust(|color| { - let intensity = color.luminance_rec_709(); - let intensity = if reverse { 1. - intensity } else { intensity }; - evaluator.evaluate(intensity as f64) - }); - - image -} diff --git a/node-graph/nodes/raster/src/lib.rs b/node-graph/nodes/raster/src/lib.rs index c3a7699c8cf..cd982d4890b 100644 --- a/node-graph/nodes/raster/src/lib.rs +++ b/node-graph/nodes/raster/src/lib.rs @@ -15,8 +15,6 @@ pub mod dehaze; #[cfg(feature = "std")] pub mod filter; #[cfg(feature = "std")] -pub mod gradient_map; -#[cfg(feature = "std")] pub mod image_color_palette; #[cfg(feature = "std")] pub mod std_nodes;