mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-18 18:38:05 +08:00
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:
@@ -12,7 +12,10 @@ license = "Apache-2.0"
|
||||
|
||||
[features]
|
||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "graphene-core/gpu"]
|
||||
quantization = ["graphene-std/quantization", "interpreted-executor/quantization"]
|
||||
quantization = [
|
||||
"graphene-std/quantization",
|
||||
"interpreted-executor/quantization",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
@@ -22,7 +25,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
graphite-proc-macros = { path = "../proc-macros" }
|
||||
bezier-rs = { path = "../libraries/bezier-rs" }
|
||||
glam = { version="0.22", features = ["serde"] }
|
||||
glam = { version = "0.22", features = ["serde"] }
|
||||
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
||||
"serde",
|
||||
] }
|
||||
@@ -32,7 +35,10 @@ once_cell = "1.13.0" # Remove when `core::cell::OnceCell` is stabilized (<https:
|
||||
specta.workspace = true
|
||||
|
||||
# Node graph
|
||||
image = { version = "0.24", default-features = false, features = ["bmp"] }
|
||||
image = { version = "0.24", default-features = false, features = [
|
||||
"bmp",
|
||||
"png",
|
||||
] }
|
||||
graph-craft = { path = "../node-graph/graph-craft" }
|
||||
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
||||
borrow_stack = { path = "../node-graph/borrow_stack" }
|
||||
|
||||
@@ -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.);
|
||||
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user