Introduce Split/Combine Channels nodes (#1153)

* Add Channel Extrataction Node

* Add hacky BlendModes for Inserting Color Channels

* Fix Channel Exporter

* Add Monochrome Option and Multi Output Node

* Fix Input Mapping

* Fix Formatting

* Split Alpha Extraction to seperate node

* Remove unnecessary functionality

* Add Alpha Channel as an output to the extract channel node

* Fix compilation

* Add unpolished 'Combine Channels' Node

* Fix Rebasing Issues

* Add a bit of polish

* Fix Rebase Issues

* Switch from 'ColorChannel' to 'RedGreenBlue'
I initially added an enum to hold color channels called 'ColorChannel', but while implementing the nodes, there somebody allready added a similar enum so I switched to that type

* Add correct names

* Add Improvement

- Some Performance Improvements
- Some Formatting Improvements

* Add some improvements
Most of this stuff was done by TrueDoctor in my Luchbreak :D

* Implement IO Improvements
- Converted primary output from split node to a dummy output
- Removed primary Input from split node

* Fix Formatting

* Fix Combine RGB Node (hopefully final :D )

* Swap around Inputs and Outputs
Move from ARGB -> RGBA

* Improve naming

* More naming fixes

* Fix Replace -> Into

* Rename Replacment -> Insertion

* Add blank assist area

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
isiko
2023-05-25 12:15:00 +02:00
committed by Keavon Chambers
parent 41f7ce0bb3
commit 8d778e4848
7 changed files with 331 additions and 5 deletions

View File

@@ -371,6 +371,35 @@ fn static_nodes() -> Vec<DocumentNodeType> {
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::mask_properties,
},
DocumentNodeType {
name: "Insert Channel",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::InsertChannelNode<_, _, _, _>"),
inputs: vec![
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Insertion", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Replace", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false),
],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::insert_channel_properties,
},
DocumentNodeType {
name: "Combine Channels",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::CombineChannelsNode"),
inputs: vec![
DocumentInputType::value("None", TaggedValue::None, false),
DocumentInputType::value("Red", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Green", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Blue", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Alpha", TaggedValue::ImageFrame(ImageFrame::empty()), true),
],
outputs: vec![DocumentOutputType {
name: "Image",
data_type: FrontendGraphDataType::Raster,
}],
properties: node_properties::no_properties,
},
DocumentNodeType {
name: "Blend",
category: "Image Adjustments",
@@ -483,6 +512,86 @@ fn static_nodes() -> Vec<DocumentNodeType> {
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::luminance_properties,
},
DocumentNodeType {
name: "Extract Channel",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_core::raster::ExtractChannelNode<_>"),
inputs: vec![
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("From", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false),
],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::extract_channel_properties,
},
DocumentNodeType {
name: "Extract Alpha",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_core::raster::ExtractAlphaNode<>"),
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::no_properties,
},
DocumentNodeType {
name: "Split Channels",
category: "Image Adjustments",
identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0],
outputs: vec![NodeOutput::new(4, 0), NodeOutput::new(1, 0), NodeOutput::new(2, 0), NodeOutput::new(3, 0), NodeOutput::new(4, 0)],
nodes: [
DocumentNode {
name: "Identity".to_string(),
inputs: vec![NodeInput::Network(concrete!(ImageFrame<Color>))],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")),
..Default::default()
},
DocumentNode {
name: "RedNode".to_string(),
inputs: vec![NodeInput::node(0, 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Red), false)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "GreenNode".to_string(),
inputs: vec![NodeInput::node(0, 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Green), false)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "BlueNode".to_string(),
inputs: vec![NodeInput::node(0, 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Blue), false)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")),
..Default::default()
},
DocumentNode {
name: "AlphaNode".to_string(),
inputs: vec![NodeInput::node(0, 0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::ExtractAlphaNode<>")),
..Default::default()
},
DocumentNode {
name: "EmptyOutput".to_string(),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), false)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")),
..Default::default()
},
]
.into_iter()
.enumerate()
.map(|(id, node)| (id as NodeId, node))
.collect(),
..Default::default()
}),
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
outputs: vec![
DocumentOutputType::new("Empty", FrontendGraphDataType::Raster),
DocumentOutputType::new("Red", FrontendGraphDataType::Raster),
DocumentOutputType::new("Green", FrontendGraphDataType::Raster),
DocumentOutputType::new("Blue", FrontendGraphDataType::Raster),
DocumentOutputType::new("Alpha", FrontendGraphDataType::Raster),
],
properties: node_properties::no_properties,
},
DocumentNodeType {
name: "Gaussian Blur",
category: "Image Filters",

View File

@@ -231,6 +231,26 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na
widgets
}
//TODO Use generalized Version of this as soon as it's available
fn color_channel(document_node: &DocumentNode, node_id: u64, 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::RedGreenBlue(mode),
exposed: false,
} = &document_node.inputs[index]
{
let calculation_modes = [RedGreenBlue::Red, RedGreenBlue::Green, RedGreenBlue::Blue];
let mut entries = Vec::with_capacity(calculation_modes.len());
for method in calculation_modes {
entries.push(DropdownEntryData::new(method.to_string()).on_update(update_value(move |_| TaggedValue::RedGreenBlue(method), node_id, index)));
}
let entries = vec![entries];
widgets.extend_from_slice(&[WidgetHolder::unrelated_separator(), DropdownInput::new(entries).selected_index(Some(mode as u32)).widget_holder()]);
}
LayoutGroup::Row { widgets }.with_tooltip("Color Channel")
}
//TODO Use generalized Version of this as soon as it's available
fn blend_mode(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
@@ -251,7 +271,7 @@ fn blend_mode(document_node: &DocumentNode, node_id: u64, index: usize, name: &s
LayoutGroup::Row { widgets }.with_tooltip("Formula used for blending")
}
// TODO: Generalize this for all dropdowns ( also see blend_mode )
// TODO: Generalize this for all dropdowns ( also see blend_mode and channel_extration )
fn luminance_calculation(document_node: &DocumentNode, node_id: u64, 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 {
@@ -590,6 +610,18 @@ pub fn luminance_properties(document_node: &DocumentNode, node_id: NodeId, _cont
vec![luminance_calc]
}
pub fn insert_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_channel = color_channel(document_node, node_id, 2, "Into", true);
vec![color_channel]
}
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);
vec![color_channel]
}
pub fn adjust_hsl_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let hue_shift = number_widget(document_node, node_id, 1, "Hue Shift", NumberInput::default().min(-180.).max(180.).unit("°"), true);
let saturation_shift = number_widget(document_node, node_id, 2, "Saturation Shift", NumberInput::default().min(-100.).max(100.).unit("%"), true);