Add the Mask node (#1080)
* Add MaskImageNode Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
parent
ea02a2d53a
commit
9c4164291c
|
|
@ -286,7 +286,18 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
properties: |_document_node, _node_id, _context| node_properties::string_properties("Creates an embedded image with the given transform"),
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Blend Node",
|
||||
name: "Mask",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::MaskImageNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
DocumentInputType::value("Stencil", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: node_properties::mask_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Blend",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeImplementation::proto("graphene_core::raster::BlendNode<_, _, _, _>"),
|
||||
inputs: vec![
|
||||
|
|
|
|||
|
|
@ -477,6 +477,12 @@ pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context:
|
|||
vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }]
|
||||
}
|
||||
|
||||
pub fn mask_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let mask = color_widget(document_node, node_id, 1, "Stencil", ColorInput::default(), true);
|
||||
|
||||
vec![mask]
|
||||
}
|
||||
|
||||
pub fn luminance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let luminance_calc = luminance_calculation(document_node, node_id, 1, "Luminance Calc", true);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ fn main() {
|
|||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Inc Node".into(),
|
||||
name: "Inc".into(),
|
||||
inputs: vec![NodeInput::Network(concrete!(u32))],
|
||||
implementation: DocumentNodeImplementation::Network(add_network()),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
|
|
|
|||
|
|
@ -442,7 +442,7 @@ mod image {
|
|||
&mut self.image.data[y * (self.image.width as usize) + x]
|
||||
}
|
||||
|
||||
/// Clamps the provided point to (0, 0) (ImageSize) and returns the closest pixel
|
||||
/// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel
|
||||
pub fn sample(&self, position: DVec2) -> Color {
|
||||
let x = position.x.clamp(0., self.image.width as f64 - 1.) as usize;
|
||||
let y = position.y.clamp(0., self.image.height as f64 - 1.) as usize;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ fn map_gpu_single_image(input: Image, node: String) -> Image {
|
|||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Image filter Node".into(),
|
||||
name: "Image Filter".into(),
|
||||
inputs: vec![NodeInput::Network(concrete!(Color))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(identifier),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
|
|
|
|||
|
|
@ -194,6 +194,40 @@ fn compute_transformed_bounding_box(transform: DAffine2) -> Bbox {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MaskImageNode<Mask> {
|
||||
mask: Mask,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(MaskImageNode)]
|
||||
fn mask_image(mut image: ImageFrame, mask: ImageFrame) -> ImageFrame {
|
||||
let image_size = DVec2::new(image.image.width as f64, image.image.height as f64);
|
||||
let mask_size = DVec2::new(mask.image.width as f64, mask.image.height as f64);
|
||||
|
||||
if mask_size == DVec2::ZERO {
|
||||
return image;
|
||||
}
|
||||
|
||||
// Transforms a point from the background image to the forground image
|
||||
let bg_to_fg = DAffine2::from_scale(mask_size) * mask.transform.inverse() * image.transform * DAffine2::from_scale(1. / image_size);
|
||||
|
||||
for y in 0..image.image.height {
|
||||
for x in 0..image.image.width {
|
||||
let image_point = DVec2::new(x as f64, y as f64);
|
||||
let mut mask_point = bg_to_fg.transform_point2(image_point);
|
||||
mask_point = mask_point.clamp(DVec2::ZERO, mask_size);
|
||||
|
||||
let image_pixel = image.get_mut(x as usize, y as usize);
|
||||
let mask_pixel = mask.sample(mask_point);
|
||||
let alpha = image_pixel.a() * mask_pixel.r();
|
||||
|
||||
*image_pixel = Color::from_rgbaf32(image_pixel.r(), image_pixel.g(), image_pixel.b(), alpha).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
image
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BlendImageNode<Background, MapFn> {
|
||||
background: Background,
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
|
||||
register_node!(graphene_core::ops::SomeNode, input: ImageFrame, params: []),
|
||||
register_node!(graphene_std::raster::DownscaleNode, input: ImageFrame, params: []),
|
||||
register_node!(graphene_std::raster::MaskImageNode<_>, input: ImageFrame, params: [ImageFrame]),
|
||||
#[cfg(feature = "gpu")]
|
||||
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image, params: [String]),
|
||||
vec![(
|
||||
|
|
|
|||
Loading…
Reference in New Issue