Add alpha to Extract Channel node and remove Extract Alpha node (#1731)

* add `TaggedValue::RedGreenBlueAlpha`

* add alpha to `ExtractChannelNode`

* remove `ExtractAlphaNode` from `Split Channels`

* remove `ExtractAlphaNode`
This commit is contained in:
Karthik Prakash 2024-04-18 04:14:14 +05:30 committed by GitHub
parent 438c45eb80
commit 3019cc7253
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 33 deletions

View file

@ -14,7 +14,7 @@ use graph_craft::imaginate_input::ImaginateSamplingMethod;
use graph_craft::ProtoNodeIdentifier;
use graphene_core::raster::brush_cache::BrushCache;
use graphene_core::raster::{
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute,
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
SelectiveColorChoice,
};
use graphene_core::text::Font;
@ -867,20 +867,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractChannelNode<_>"),
inputs: vec![
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("From", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false),
DocumentInputType::value("From", TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false),
],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::extract_channel_properties,
..Default::default()
},
DocumentNodeDefinition {
name: "Extract Alpha",
category: "Image Adjustments",
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractAlphaNode<>"),
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
..Default::default()
},
DocumentNodeDefinition {
name: "Extract Opaque",
category: "Image Adjustments",
@ -912,26 +904,26 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
name: "RedNode".to_string(),
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Red), false)],
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "GreenNode".to_string(),
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Green), false)],
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "BlueNode".to_string(),
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Blue), false)],
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "AlphaNode".to_string(),
inputs: vec![NodeInput::node(NodeId(0), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractAlphaNode<>")),
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<>")),
..Default::default()
},
]

View file

@ -10,7 +10,8 @@ use graph_craft::document::{DocumentNode, NodeId, NodeInput};
use graph_craft::imaginate_input::{ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus};
use graphene_core::memo::IORecord;
use graphene_core::raster::{
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice,
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
SelectiveColorChoice,
};
use graphene_core::text::Font;
use graphene_core::vector::style::{FillType, GradientType, LineCap, LineJoin};
@ -400,6 +401,33 @@ fn color_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, na
LayoutGroup::Row { widgets }.with_tooltip("Color Channel")
}
fn rgba_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
if let &NodeInput::Value {
tagged_value: TaggedValue::RedGreenBlueAlpha(mode),
exposed: false,
} = &document_node.inputs[index]
{
let calculation_modes = [RedGreenBlueAlpha::Red, RedGreenBlueAlpha::Green, RedGreenBlueAlpha::Blue, RedGreenBlueAlpha::Alpha];
let mut entries = Vec::with_capacity(calculation_modes.len());
for method in calculation_modes {
entries.push(
MenuListEntry::new(format!("{method:?}"))
.label(method.to_string())
.on_update(update_value(move |_| TaggedValue::RedGreenBlueAlpha(method), node_id, index))
.on_commit(commit_value),
);
}
let entries = vec![entries];
widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
DropdownInput::new(entries).selected_index(Some(mode as u32)).widget_holder(),
]);
}
LayoutGroup::Row { widgets }.with_tooltip("Color Channel")
}
// TODO Generalize this instead of using a separate function per dropdown menu enum
fn noise_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
@ -971,7 +999,7 @@ pub fn insert_channel_properties(document_node: &DocumentNode, node_id: NodeId,
}
pub fn extract_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_channel = color_channel(document_node, node_id, 1, "From", true);
let color_channel = rgba_channel(document_node, node_id, 1, "From", true);
vec![color_channel]
}

View file

@ -256,22 +256,14 @@ pub struct ExtractChannelNode<TargetChannel> {
}
#[node_macro::node_fn(ExtractChannelNode)]
fn extract_channel_node(color: Color, channel: RedGreenBlue) -> Color {
fn extract_channel_node(color: Color, channel: RedGreenBlueAlpha) -> Color {
let extracted_value = match channel {
RedGreenBlue::Red => color.r(),
RedGreenBlue::Green => color.g(),
RedGreenBlue::Blue => color.b(),
RedGreenBlueAlpha::Red => color.r(),
RedGreenBlueAlpha::Green => color.g(),
RedGreenBlueAlpha::Blue => color.b(),
RedGreenBlueAlpha::Alpha => color.a(),
};
color.map_rgb(|_| extracted_value)
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ExtractAlphaNode;
#[node_macro::node_fn(ExtractAlphaNode)]
fn extract_alpha_node(color: Color) -> Color {
let alpha = color.a();
Color::from_rgbaf32(alpha, alpha, alpha, 1.).unwrap()
color.map_rgba(|_| extracted_value)
}
#[derive(Debug, Clone, Copy, Default)]
@ -606,6 +598,27 @@ impl core::fmt::Display for RedGreenBlue {
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "std", derive(specta::Type))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]
pub enum RedGreenBlueAlpha {
Red,
Green,
Blue,
Alpha,
}
impl core::fmt::Display for RedGreenBlueAlpha {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
RedGreenBlueAlpha::Red => write!(f, "Red"),
RedGreenBlueAlpha::Green => write!(f, "Green"),
RedGreenBlueAlpha::Blue => write!(f, "Blue"),
RedGreenBlueAlpha::Alpha => write!(f, "Alpha"),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "std", derive(specta::Type))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]

View file

@ -46,6 +46,7 @@ pub enum TaggedValue {
VecF64(Vec<f64>),
VecDVec2(Vec<DVec2>),
RedGreenBlue(graphene_core::raster::RedGreenBlue),
RedGreenBlueAlpha(graphene_core::raster::RedGreenBlueAlpha),
NoiseType(graphene_core::raster::NoiseType),
FractalType(graphene_core::raster::FractalType),
CellularDistanceFunction(graphene_core::raster::CellularDistanceFunction),
@ -114,6 +115,7 @@ impl Hash for TaggedValue {
Self::VecF64(x) => x.iter().for_each(|val| val.to_bits().hash(state)),
Self::VecDVec2(x) => x.iter().for_each(|val| val.to_array().iter().for_each(|x| x.to_bits().hash(state))),
Self::RedGreenBlue(x) => x.hash(state),
Self::RedGreenBlueAlpha(x) => x.hash(state),
Self::NoiseType(x) => x.hash(state),
Self::FractalType(x) => x.hash(state),
Self::CellularDistanceFunction(x) => x.hash(state),
@ -189,6 +191,7 @@ impl<'a> TaggedValue {
TaggedValue::VecF64(x) => Box::new(x),
TaggedValue::VecDVec2(x) => Box::new(x),
TaggedValue::RedGreenBlue(x) => Box::new(x),
TaggedValue::RedGreenBlueAlpha(x) => Box::new(x),
TaggedValue::NoiseType(x) => Box::new(x),
TaggedValue::FractalType(x) => Box::new(x),
TaggedValue::CellularDistanceFunction(x) => Box::new(x),
@ -266,6 +269,7 @@ impl<'a> TaggedValue {
TaggedValue::VecF64(_) => concrete!(Vec<f64>),
TaggedValue::VecDVec2(_) => concrete!(Vec<DVec2>),
TaggedValue::RedGreenBlue(_) => concrete!(graphene_core::raster::RedGreenBlue),
TaggedValue::RedGreenBlueAlpha(_) => concrete!(graphene_core::raster::RedGreenBlueAlpha),
TaggedValue::NoiseType(_) => concrete!(graphene_core::raster::NoiseType),
TaggedValue::FractalType(_) => concrete!(graphene_core::raster::FractalType),
TaggedValue::CellularDistanceFunction(_) => concrete!(graphene_core::raster::CellularDistanceFunction),
@ -330,6 +334,7 @@ impl<'a> TaggedValue {
x if x == TypeId::of::<Vec<f64>>() => Ok(TaggedValue::VecF64(*downcast(input).unwrap())),
x if x == TypeId::of::<Vec<DVec2>>() => Ok(TaggedValue::VecDVec2(*downcast(input).unwrap())),
x if x == TypeId::of::<graphene_core::raster::RedGreenBlue>() => Ok(TaggedValue::RedGreenBlue(*downcast(input).unwrap())),
x if x == TypeId::of::<graphene_core::raster::RedGreenBlueAlpha>() => Ok(TaggedValue::RedGreenBlueAlpha(*downcast(input).unwrap())),
x if x == TypeId::of::<graphene_core::raster::NoiseType>() => Ok(TaggedValue::NoiseType(*downcast(input).unwrap())),
x if x == TypeId::of::<graphene_core::raster::FractalType>() => Ok(TaggedValue::FractalType(*downcast(input).unwrap())),
x if x == TypeId::of::<graphene_core::raster::CellularDistanceFunction>() => Ok(TaggedValue::CellularDistanceFunction(*downcast(input).unwrap())),

View file

@ -451,8 +451,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_std::brush::BrushNode<_, _, _>, input: ImageFrame<Color>, output: ImageFrame<Color>, params: [ImageFrame<Color>, Vec<BrushStroke>, BrushCache]),
// Filters
raster_node!(graphene_core::raster::LuminanceNode<_>, params: [LuminanceCalculation]),
raster_node!(graphene_core::raster::ExtractChannelNode<_>, params: [RedGreenBlue]),
raster_node!(graphene_core::raster::ExtractAlphaNode<>, params: []),
raster_node!(graphene_core::raster::ExtractChannelNode<_>, params: [RedGreenBlueAlpha]),
raster_node!(graphene_core::raster::ExtractOpaqueNode<>, params: []),
raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]),
register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),