Downscale Images to document resolution (#1077)

* Add DownscaleNode

* Add lambda (call argument) input type + fix caching

* Add comment explaining Lambda input

* Automatically insert cache node after downscale node

* Implement sparse hashing of images
This commit is contained in:
Dennis Kobert
2023-03-15 12:49:56 +01:00
committed by GitHub
parent a14af91031
commit d8de17b96f
13 changed files with 209 additions and 224 deletions

View File

@@ -612,6 +612,9 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
let center_in_viewport = DAffine2::from_translation(viewport_location - ipp.viewport_bounds.top_left);
let center_in_viewport_layerspace = to_parent_folder.inverse() * center_in_viewport;
// Scale the image to fit into a 512x512 box
let image_size = image_size / DVec2::splat((image_size.max_element() / 512.).max(1.));
// Make layer the size of the image
let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.);

View File

@@ -107,7 +107,35 @@ fn static_nodes() -> Vec<DocumentNodeType> {
DocumentNodeType {
name: "Image",
category: "Ignore",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0],
outputs: vec![NodeOutput::new(2, 0)],
nodes: [
DocumentNode {
name: "Downscale".to_string(),
inputs: vec![NodeInput::Network(concrete!(ImageFrame))],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::raster::DownscaleNode")),
metadata: Default::default(),
},
DocumentNode {
name: "Cache".to_string(),
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
metadata: Default::default(),
},
DocumentNode {
name: "Clone".to_string(),
inputs: vec![NodeInput::node(1, 0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
metadata: Default::default(),
},
]
.into_iter()
.enumerate()
.map(|(id, node)| (id as NodeId, node))
.collect(),
..Default::default()
}),
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), false)],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
@@ -422,7 +450,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
0,
DocumentNode {
name: "CacheNode".to_string(),
inputs: vec![NodeInput::Network(concrete!(Image))],
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(concrete!(ImageFrame))],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
metadata: Default::default(),
},

View File

@@ -81,6 +81,7 @@ impl NodeGraphExecutor {
inner_network.outputs[0] = NodeOutput::new(*node_id, *output_index);
break 'outer;
}
NodeInput::ShortCircut(_) => (),
}
}
@@ -92,7 +93,7 @@ impl NodeGraphExecutor {
use image::{ImageBuffer, Rgba};
use std::io::Cursor;
let (result_bytes, width, height) = image.as_flat_u8();
let (result_bytes, width, height) = image.into_flat_u8();
let mut output: ImageBuffer<Rgba<u8>, _> = image::ImageBuffer::from_raw(width, height, result_bytes).ok_or_else(|| "Invalid image size".to_string())?;
if let Some(size) = resize {