mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add 'Gradient Map' adjustment node
This commit is contained in:
@@ -5,6 +5,7 @@ use super::curve::{Curve, CurveManipulatorGroup, ValueMapperNode};
|
||||
#[cfg(feature = "alloc")]
|
||||
use super::ImageFrame;
|
||||
use super::{Channel, Color, Node, RGBMut};
|
||||
use crate::vector::style::GradientStops;
|
||||
use crate::vector::VectorData;
|
||||
use crate::GraphicGroup;
|
||||
|
||||
@@ -554,6 +555,21 @@ pub fn blend_colors(foreground: Color, background: Color, blend_mode: BlendMode,
|
||||
background.alpha_blend(target_color.to_associated_alpha(opacity))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GradientMapNode<Gradient, Reverse> {
|
||||
gradient: Gradient,
|
||||
reverse: Reverse,
|
||||
// TODO: Add support for dithering to break up gradient color banding
|
||||
// TODO: Add support for controlling the gradient interpolation method (instead of always `luminance_srgb()`)
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(GradientMapNode)]
|
||||
fn gradient_map_node(color: Color, gradient: GradientStops, reverse: bool) -> Color {
|
||||
let intensity = color.luminance_srgb();
|
||||
let intensity = if reverse { 1. - intensity } else { intensity };
|
||||
gradient.evalute(intensity as f64)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct VibranceNode<Vibrance> {
|
||||
vibrance: Vibrance,
|
||||
|
||||
@@ -36,6 +36,32 @@ impl Default for GradientStops {
|
||||
}
|
||||
}
|
||||
|
||||
impl GradientStops {
|
||||
pub fn evalute(&self, t: f64) -> Color {
|
||||
if self.0.is_empty() {
|
||||
return Color::BLACK;
|
||||
}
|
||||
|
||||
if t <= self.0[0].0 {
|
||||
return self.0[0].1;
|
||||
}
|
||||
if t >= self.0[self.0.len() - 1].0 {
|
||||
return self.0[self.0.len() - 1].1;
|
||||
}
|
||||
|
||||
for i in 0..self.0.len() - 1 {
|
||||
let (t1, c1) = self.0[i];
|
||||
let (t2, c2) = self.0[i + 1];
|
||||
if t >= t1 && t <= t2 {
|
||||
let normalized_t = (t - t1) / (t2 - t1);
|
||||
return c1.lerp(&c2, normalized_t as f32);
|
||||
}
|
||||
}
|
||||
|
||||
Color::BLACK
|
||||
}
|
||||
}
|
||||
|
||||
/// A gradient fill.
|
||||
///
|
||||
/// Contains the start and end points, along with the colors at varying points along the length.
|
||||
|
||||
@@ -19,6 +19,7 @@ use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||
use graphene_std::application_io::{RenderConfig, TextureFrame};
|
||||
use graphene_std::raster::*;
|
||||
use graphene_std::vector::style::GradientStops;
|
||||
use graphene_std::wasm_application_io::*;
|
||||
use graphene_std::GraphicElement;
|
||||
#[cfg(feature = "gpu")]
|
||||
@@ -484,6 +485,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]),
|
||||
raster_node!(graphene_core::raster::InvertRGBNode, params: []),
|
||||
raster_node!(graphene_core::raster::ThresholdNode<_, _, _>, params: [f64, f64, LuminanceCalculation]),
|
||||
raster_node!(graphene_core::raster::GradientMapNode<_, _>, params: [GradientStops, bool]),
|
||||
raster_node!(graphene_core::raster::VibranceNode<_>, params: [f64]),
|
||||
raster_node!(
|
||||
graphene_core::raster::ChannelMixerNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>,
|
||||
|
||||
Reference in New Issue
Block a user