From 437ffbc9a2bedafb13323231adccd97654b158b9 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 17 Apr 2024 02:20:58 -0700 Subject: [PATCH 1/6] Add RasterizeVector node --- node-graph/gstd/src/http.rs | 26 +++++++++ node-graph/gstd/src/wasm_application_io.rs | 68 +++++++++++++++++++--- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/node-graph/gstd/src/http.rs b/node-graph/gstd/src/http.rs index 9bdfbb0905..78edf14080 100644 --- a/node-graph/gstd/src/http.rs +++ b/node-graph/gstd/src/http.rs @@ -1,3 +1,5 @@ +use graphene_core::raster::{ImageFrame, SRGBA8}; + use crate::Node; pub struct GetNode; @@ -15,3 +17,27 @@ pub struct PostNode { async fn post_node(url: String, body: String) -> reqwest::Response { reqwest::Client::new().post(url).body(body).send().await.unwrap() } + +async fn image_to_image(image: ImageFrame, prompt: String) -> ImageFrame { + let png_bytes = image.image.to_png(); + let base64 = base64::encode(png_bytes); + // post to cloudflare image to image endpoint using reqwest + + image +} + +#[cfg(test)] +mod test { + use super::*; + use graphene_core::{raster::Image, Color}; + #[test] + fn test_cloudflare() { + let test_image = ImageFrame { + image: Image::new(100, 100, SRGBA8::from(Color::RED)), + ..Default::default() + }; + let result = futures::executor::block_on(image_to_image(test_image, "make green".into())); + dbg!(result); + panic!("show result"); + } +} diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 21d8ac4367..57b4951ee5 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -1,10 +1,6 @@ -pub use graph_craft::document::value::RenderOutput; -pub use graph_craft::wasm_application_io::*; -#[cfg(target_arch = "wasm32")] -use graphene_core::application_io::SurfaceHandle; -use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig}; -#[cfg(target_arch = "wasm32")] -use graphene_core::raster::bbox::Bbox; +use base64::Engine; +use dyn_any::StaticType; +use graphene_core::application_io::{ApplicationError, ApplicationIo, ExportFormat, RenderConfig, ResourceFuture, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; use graphene_core::raster::Image; use graphene_core::raster::ImageFrame; use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender}; @@ -190,8 +186,66 @@ async fn rasterize<_T: GraphicElementRendered + graphene_core::transform::Transf .draw_image_with_html_image_element_and_dw_and_dh(&image_data, 0., 0., resolution.x as f64, resolution.y as f64) .unwrap(); +pub struct RasterizeVectorNode { + footprint: Footprint, + surface_handle: Surface, +} + +#[node_macro::node_fn(RasterizeVectorNode)] +async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footprint, surface_handle: Arc>) -> ImageFrame { + let mut render = SvgRender::new(); + + let resolution = footprint.resolution; + // TODO: reenable once we switch to full node graph + let min = footprint.transform.inverse().transform_point2((0., 0.).into()); + let max = footprint.transform.inverse().transform_point2(resolution.as_dvec2()); + let render_params = RenderParams { + // TODO: Use correct bounds + culling_bounds: Some([min, max]), + ..Default::default() + }; + + data.render_svg(&mut render, &render_params); + render.format_svg(min, max); + let svg_string = render.svg.to_svg_string(); + + let canvas = &surface_handle.surface; + canvas.set_width(resolution.x); + canvas.set_height(resolution.y); + + let array = svg_string.as_bytes(); + let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::().unwrap(); + + let preamble = "data:image/svg+xml;base64,"; + let mut base64_string = String::with_capacity(preamble.len() + array.len() * 4); + base64_string.push_str(preamble); + base64::engine::general_purpose::STANDARD.encode_string(array, &mut base64_string); + + let image_data = web_sys::HtmlImageElement::new().unwrap(); + image_data.set_src(base64_string.as_str()); + wasm_bindgen_futures::JsFuture::from(image_data.decode()).await.unwrap(); + context.draw_image_with_html_image_element(&image_data, 0., 0.).unwrap(); + let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap(); + let image = Image::from_raw_buffer(resolution.x, resolution.y, rasterized.data().0); + ImageFrame { + image, + transform: glam::DAffine2::from_scale(resolution.as_dvec2()), + ..Default::default() + } +} + +// Render with the data node taking in Footprint. +impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future, Data: 'input, Surface: 'input, SurfaceFuture: 'input> Node<'input, WasmEditorApi<'a>> + for RenderNode +where + Data: Node<'input, Footprint, Output = F>, + Surface: Node<'input, (), Output = SurfaceFuture>, + SurfaceFuture: core::future::Future>>, +{ + type Output = core::pin::Pin + 'input>>; + let image = Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32); ImageFrame { image, From 9fa501600d7778408aefa003f158a5cebd52fc76 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 19 May 2024 23:48:09 +0200 Subject: [PATCH 2/6] Add document node definition for RasterizeVectorNode --- node-graph/gstd/src/http.rs | 26 ------------------- node-graph/gstd/src/wasm_application_io.rs | 4 +-- .../interpreted-executor/src/node_registry.rs | 24 +++++++---------- 3 files changed, 11 insertions(+), 43 deletions(-) diff --git a/node-graph/gstd/src/http.rs b/node-graph/gstd/src/http.rs index 78edf14080..9bdfbb0905 100644 --- a/node-graph/gstd/src/http.rs +++ b/node-graph/gstd/src/http.rs @@ -1,5 +1,3 @@ -use graphene_core::raster::{ImageFrame, SRGBA8}; - use crate::Node; pub struct GetNode; @@ -17,27 +15,3 @@ pub struct PostNode { async fn post_node(url: String, body: String) -> reqwest::Response { reqwest::Client::new().post(url).body(body).send().await.unwrap() } - -async fn image_to_image(image: ImageFrame, prompt: String) -> ImageFrame { - let png_bytes = image.image.to_png(); - let base64 = base64::encode(png_bytes); - // post to cloudflare image to image endpoint using reqwest - - image -} - -#[cfg(test)] -mod test { - use super::*; - use graphene_core::{raster::Image, Color}; - #[test] - fn test_cloudflare() { - let test_image = ImageFrame { - image: Image::new(100, 100, SRGBA8::from(Color::RED)), - ..Default::default() - }; - let result = futures::executor::block_on(image_to_image(test_image, "make green".into())); - dbg!(result); - panic!("show result"); - } -} diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 57b4951ee5..13c1d9f246 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -192,7 +192,7 @@ pub struct RasterizeVectorNode { } #[node_macro::node_fn(RasterizeVectorNode)] -async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footprint, surface_handle: Arc>) -> ImageFrame { +async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footprint, surface_handle: Arc>) -> ImageFrame { let mut render = SvgRender::new(); let resolution = footprint.resolution; @@ -228,7 +228,7 @@ async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footp let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap(); - let image = Image::from_raw_buffer(resolution.x, resolution.y, rasterized.data().0); + let image = Image::from_image_data(&rasterized.data().0, resolution.x, resolution.y); ImageFrame { image, transform: glam::DAffine2::from_scale(resolution.as_dvec2()), diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index c964f287f9..f1dd9abafe 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -651,21 +651,15 @@ fn node_registry() -> HashMap, input: Color, params: [QuantizationChannels]), register_node!(graphene_core::quantization::DeQuantizeNode<_>, input: PackedPixel, params: [QuantizationChannels]), register_node!(graphene_core::ops::CloneNode<_>, input: &QuantizationChannels, params: []), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, () => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, () => Option]), - #[cfg(target_arch = "wasm32")] - async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), - #[cfg(target_arch = "wasm32")] - async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ImageFrame, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => VectorData, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Artboard, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ArtboardGroup, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Option, () => Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Vec, () => Arc]), + async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), // async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame, fn_params: [Footprint => ImageFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), From 8ac87b7e7528dcca7e3e0fd01e93899fa9e31f00 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Wed, 17 Apr 2024 15:09:53 +0200 Subject: [PATCH 3/6] Add api calling infrastructure --- node-graph/gcore/src/raster/image.rs | 26 ++++++- node-graph/gstd/Cargo.toml | 7 +- node-graph/gstd/src/http.rs | 110 +++++++++++++++++++++++++++ shell.nix | 33 +++----- 4 files changed, 145 insertions(+), 31 deletions(-) diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 0aeb4845d8..3a51fff561 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -127,6 +127,15 @@ impl Image

{ } } + pub fn from_raw_buffer(width: u32, height: u32, data: Vec) -> Self { + Self { + width, + height, + data: bytemuck::cast_vec(data), + base64_string: None, + } + } + pub fn as_slice(&self) -> ImageSlice

{ ImageSlice { width: self.width, @@ -147,13 +156,15 @@ impl Image { base64_string: None, } } - +} +impl Image { pub fn to_png(&self) -> Vec { use ::image::ImageEncoder; - let (data, width, height) = self.to_flat_u8(); let mut png = Vec::new(); let encoder = ::image::codecs::png::PngEncoder::new(&mut png); - encoder.write_image(&data, width, height, ::image::ExtendedColorType::Rgba8).expect("failed to encode image as png"); + encoder + .write_image(bytemuck::cast_slice(self.data.as_slice()), self.width, self.height, ::image::ColorType::Rgba8) + .expect("failed to encode image as png"); png } } @@ -214,6 +225,15 @@ where (result, *width, *height) } + + pub fn to_png(&self) -> Vec { + use ::image::ImageEncoder; + let (data, width, height) = self.to_flat_u8(); + let mut png = Vec::new(); + let encoder = ::image::codecs::png::PngEncoder::new(&mut png); + encoder.write_image(&data, width, height, ::image::ColorType::Rgba8).expect("failed to encode image as png"); + png + } } impl IntoIterator for Image

{ diff --git a/node-graph/gstd/Cargo.toml b/node-graph/gstd/Cargo.toml index 9a2090c0ec..efc83ec3fd 100644 --- a/node-graph/gstd/Cargo.toml +++ b/node-graph/gstd/Cargo.toml @@ -85,9 +85,6 @@ web-sys = { workspace = true, optional = true, features = [ "HtmlImageElement", "ImageBitmapRenderingContext", ] } -autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = [ - "fitting", -] } -# Optional dependencies -image-compare = { version = "0.4.1", optional = true } +[dev-dependencies] +tokio = { workspace = true, features = ["macros", "rt"] } diff --git a/node-graph/gstd/src/http.rs b/node-graph/gstd/src/http.rs index 9bdfbb0905..ce6bf6ca4a 100644 --- a/node-graph/gstd/src/http.rs +++ b/node-graph/gstd/src/http.rs @@ -1,4 +1,5 @@ use crate::Node; +use graphene_core::raster::{ImageFrame, SRGBA8}; pub struct GetNode; @@ -15,3 +16,112 @@ pub struct PostNode { async fn post_node(url: String, body: String) -> reqwest::Response { reqwest::Client::new().post(url).body(body).send().await.unwrap() } + +#[cfg(feature = "serde")] +async fn image_to_image(image: ImageFrame, prompt: String) -> reqwest::Result> { + let png_bytes = image.image.to_png(); + // let base64 = base64::encode(png_bytes); + // post to cloudflare image to image endpoint using reqwest + let payload = PayloadBuilder::new().guidance(7.5).image(png_bytes.to_vec()).num_steps(20).prompt(prompt).strength(1).build(); + + let client = Client::new(); + let account_id = "023e105f4ecef8ad9ca31a8372d0c353"; + let response = client + .post(format!("https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/bytedance/stable-diffusion-xl-lightning")) + .json(&payload) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer 123") + .send() + .await?; + + let text = response.text().await?; + println!("{}", text); + + Ok(image) +} +use reqwest::Client; +use serde::Serialize; + +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Default)] +struct PayloadBuilder { + guidance: Option, + image: Option>, + mask: Option>, + num_steps: Option, + prompt: Option, + strength: Option, +} + +impl PayloadBuilder { + fn new() -> Self { + Self::default() + } + + fn guidance(mut self, value: f64) -> Self { + self.guidance = Some(value); + self + } + + fn image(mut self, value: Vec) -> Self { + self.image = Some(value); + self + } + + fn mask(mut self, value: Vec) -> Self { + self.mask = Some(value); + self + } + + fn num_steps(mut self, value: u32) -> Self { + self.num_steps = Some(value); + self + } + + fn prompt(mut self, value: String) -> Self { + self.prompt = Some(value); + self + } + + fn strength(mut self, value: u32) -> Self { + self.strength = Some(value); + self + } + + fn build(self) -> Payload { + Payload { + guidance: self.guidance.unwrap_or_default(), + image: self.image.unwrap_or_default(), + mask: self.mask.unwrap_or_default(), + num_steps: self.num_steps.unwrap_or_default(), + prompt: self.prompt.unwrap_or_default(), + strength: self.strength.unwrap_or_default(), + } + } +} + +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +struct Payload { + guidance: f64, + image: Vec, + mask: Vec, + num_steps: u32, + prompt: String, + strength: u32, +} + +#[cfg(test)] +mod test { + use super::*; + use graphene_core::{raster::Image, Color}; + #[tokio::test] + async fn test_cloudflare() { + let test_image = ImageFrame { + image: Image::new(100, 100, SRGBA8::from(Color::RED)), + ..Default::default() + }; + let result = image_to_image(test_image, "make green".into()).await; + dbg!(result); + panic!("show result"); + } +} diff --git a/shell.nix b/shell.nix index 5feb1012db..e1d675b01b 100644 --- a/shell.nix +++ b/shell.nix @@ -35,47 +35,34 @@ let # wasm-pack needs this extensions = [ "rust-src" "rust-analyzer" "clippy"]; }; -in - # Make a shell with the dependencies we need - pkgs.mkShell { - packages = with pkgs; [ + + packages = with pkgs; [ rustc-wasm nodejs cargo cargo-watch - cargo-nextest - cargo-expand wasm-pack - binaryen - wasm-bindgen-cli - vulkan-loader - libxkbcommon - llvm - gcc-unwrapped.lib - llvmPackages.libcxxStdenv - pkg-config - # used for profiling - gnuplot - samply - cargo-flamegraph - # For Tauri openssl glib gtk3 libsoup webkitgtk - # For Raw-rs tests - libraw + pkg-config - # Use Mold as a linker + # Use Mold as a Linke mold - ]; + ]; +in + # Make a shell with the dependencies we need + pkgs.mkShell { + packages = packages; # Hacky way to run Cargo through Mold LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.openssl pkgs.vulkan-loader pkgs.libxkbcommon pkgs.llvmPackages.libcxxStdenv pkgs.gcc-unwrapped.lib pkgs.llvm pkgs.libraw]; shellHook = '' + export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath packages}:$LD_LIBRARY_PATH alias cargo='mold --run cargo' ''; } From 5063ac0565e1b7795435e7507ae6445ce9be18d4 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 17 Apr 2024 12:35:43 -0700 Subject: [PATCH 4/6] Additional changes from pair programming session --- .../gcore/src/graphic_element/renderer.rs | 35 ++++++++++++++++--- node-graph/gcore/src/raster/image.rs | 1 + .../interpreted-executor/src/node_registry.rs | 14 ++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 481be53ade..e0c2a19597 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -268,15 +268,40 @@ pub fn to_transform(transform: DAffine2) -> usvg::Transform { usvg::Transform::from_row(cols[0] as f32, cols[1] as f32, cols[2] as f32, cols[3] as f32, cols[4] as f32, cols[5] as f32) } +// TODO: Consider renaming this to better express what it does pub trait GraphicElementRendered { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams); + fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]>; + fn add_click_targets(&self, click_targets: &mut Vec); - #[cfg(feature = "vello")] - fn to_vello_scene(&self, transform: DAffine2, context: &mut RenderContext) -> Scene { - let mut scene = vello::Scene::new(); - self.render_to_vello(&mut scene, transform, context); - scene + + fn to_usvg_node(&self) -> usvg::Node { + let mut render = SvgRender::new(); + let render_params = RenderParams::new(crate::vector::style::ViewMode::Normal, ImageRenderMode::Base64, None, false, false, false); + self.render_svg(&mut render, &render_params); + render.format_svg(DVec2::ZERO, DVec2::ONE); + let svg = render.svg.to_svg_string(); + + let opt = usvg::Options::default(); + + let tree = usvg::Tree::from_str(&svg, &opt).expect("Failed to parse SVG"); + usvg::Node::Group(Box::new(tree.root.clone())) + } + + fn to_usvg_tree(&self, resolution: glam::UVec2, viewbox: [DVec2; 2]) -> usvg::Tree { + let root = match self.to_usvg_node() { + usvg::Node::Group(root_node) => *root_node, + _ => usvg::Group::default(), + }; + usvg::Tree { + size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(), + view_box: usvg::ViewBox { + rect: usvg::NonZeroRect::from_ltrb(viewbox[0].x as f32, viewbox[0].y as f32, viewbox[1].x as f32, viewbox[1].y as f32).unwrap(), + aspect: usvg::AspectRatio::default(), + }, + root, + } } #[cfg(feature = "vello")] fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2, _render_condext: &mut RenderContext) {} diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 3a51fff561..57e37ac70e 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -157,6 +157,7 @@ impl Image { } } } + impl Image { pub fn to_png(&self) -> Vec { use ::image::ImageEncoder; diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index f1dd9abafe..bf742831a2 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -658,8 +658,18 @@ fn node_registry() -> HashMap, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ArtboardGroup, () => Arc]), async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Option, () => Arc]), async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Vec, () => Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [ImageFrame, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [VectorData, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [GraphicGroup, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Artboard, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [bool, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f32, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f64, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [String, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Option, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Vec, Arc]), + async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), // async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame, fn_params: [Footprint => ImageFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), From 14f8a28b2b0766031e0ff2128e3495df4d4a0a45 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Thu, 18 Apr 2024 02:43:42 -0700 Subject: [PATCH 5/6] Fix api interaction --- node-graph/gstd/src/http.rs | 109 ---------------------- node-graph/gstd/src/imaginate_v2.rs | 138 ++++++++++++++++++++++++++++ node-graph/gstd/src/lib.rs | 3 + 3 files changed, 141 insertions(+), 109 deletions(-) create mode 100644 node-graph/gstd/src/imaginate_v2.rs diff --git a/node-graph/gstd/src/http.rs b/node-graph/gstd/src/http.rs index ce6bf6ca4a..1833dcaa53 100644 --- a/node-graph/gstd/src/http.rs +++ b/node-graph/gstd/src/http.rs @@ -16,112 +16,3 @@ pub struct PostNode { async fn post_node(url: String, body: String) -> reqwest::Response { reqwest::Client::new().post(url).body(body).send().await.unwrap() } - -#[cfg(feature = "serde")] -async fn image_to_image(image: ImageFrame, prompt: String) -> reqwest::Result> { - let png_bytes = image.image.to_png(); - // let base64 = base64::encode(png_bytes); - // post to cloudflare image to image endpoint using reqwest - let payload = PayloadBuilder::new().guidance(7.5).image(png_bytes.to_vec()).num_steps(20).prompt(prompt).strength(1).build(); - - let client = Client::new(); - let account_id = "023e105f4ecef8ad9ca31a8372d0c353"; - let response = client - .post(format!("https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/bytedance/stable-diffusion-xl-lightning")) - .json(&payload) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer 123") - .send() - .await?; - - let text = response.text().await?; - println!("{}", text); - - Ok(image) -} -use reqwest::Client; -use serde::Serialize; - -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -#[derive(Default)] -struct PayloadBuilder { - guidance: Option, - image: Option>, - mask: Option>, - num_steps: Option, - prompt: Option, - strength: Option, -} - -impl PayloadBuilder { - fn new() -> Self { - Self::default() - } - - fn guidance(mut self, value: f64) -> Self { - self.guidance = Some(value); - self - } - - fn image(mut self, value: Vec) -> Self { - self.image = Some(value); - self - } - - fn mask(mut self, value: Vec) -> Self { - self.mask = Some(value); - self - } - - fn num_steps(mut self, value: u32) -> Self { - self.num_steps = Some(value); - self - } - - fn prompt(mut self, value: String) -> Self { - self.prompt = Some(value); - self - } - - fn strength(mut self, value: u32) -> Self { - self.strength = Some(value); - self - } - - fn build(self) -> Payload { - Payload { - guidance: self.guidance.unwrap_or_default(), - image: self.image.unwrap_or_default(), - mask: self.mask.unwrap_or_default(), - num_steps: self.num_steps.unwrap_or_default(), - prompt: self.prompt.unwrap_or_default(), - strength: self.strength.unwrap_or_default(), - } - } -} - -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -struct Payload { - guidance: f64, - image: Vec, - mask: Vec, - num_steps: u32, - prompt: String, - strength: u32, -} - -#[cfg(test)] -mod test { - use super::*; - use graphene_core::{raster::Image, Color}; - #[tokio::test] - async fn test_cloudflare() { - let test_image = ImageFrame { - image: Image::new(100, 100, SRGBA8::from(Color::RED)), - ..Default::default() - }; - let result = image_to_image(test_image, "make green".into()).await; - dbg!(result); - panic!("show result"); - } -} diff --git a/node-graph/gstd/src/imaginate_v2.rs b/node-graph/gstd/src/imaginate_v2.rs new file mode 100644 index 0000000000..fb8de8b6de --- /dev/null +++ b/node-graph/gstd/src/imaginate_v2.rs @@ -0,0 +1,138 @@ +use graphene_core::raster::{Image, ImageFrame, Pixel, SRGBA8}; + +use crate::Node; + +async fn image_to_image(image_frame: ImageFrame, prompt: String) -> reqwest::Result> { + let png_bytes = image_frame.image.to_png(); + //let base64 = base64::encode(png_bytes); + // post to cloudflare image to image endpoint using reqwest + let payload = PayloadBuilder::new() + .guidance(7.5) + .image(png_bytes.to_vec()) + //.mask(png_bytes.to_vec()) + .num_steps(20) + .prompt(prompt) + .strength(1); + + let client = Client::new(); + let account_id = "xxx"; + let api_key = "123"; + let request = client + //.post(format!("https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/bytedance/stable-diffusion-xl-base-1.0")) + //.post(format!("https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/stabilityai/stable-diffusion-xl-base-1.0")) + /*.post(format!( + "https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/runwayml/stable-diffusion-v1-5-inpainting" + ))*/ + .post(format!("https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/runwayml/stable-diffusion-v1-5-img2img")) + .json(&payload) + .header("Authorization", format!("Bearer {api_key}")); + //println!("{}", serde_json::to_string(&payload).unwrap()); + let response = dbg!(request).send().await?; + + #[derive(Debug, serde::Deserialize)] + struct Response { + result: String, + success: bool, + }; + + match response.error_for_status_ref() { + Ok(_) => (), + Err(_) => panic!("{}", response.text().await?), + } + //let text: Response = response.json().await?; + /*let text = response.text().await?; + let text = Response { + result: serde_json::Value::String(text), + success: false, + }; + dbg!(&text);*/ + + let bytes = response.bytes().await?; + //let bytes = &[]; + + let image = image::load_from_memory_with_format(&bytes[..], image::ImageFormat::Png).unwrap(); + let width = image.width(); + let height = image.height(); + let image = image.to_rgba8(); + let data = image.as_raw(); + let color_data = bytemuck::cast_slice(data).to_owned(); + let image = Image { + width, + height, + data: color_data, + base64_string: None, + }; + + let image_frame = ImageFrame { image, ..image_frame }; + Ok(image_frame) +} +use reqwest::Client; +use serde::Serialize; + +#[derive(Default, Serialize)] +struct PayloadBuilder { + #[serde(skip_serializing_if = "Option::is_none")] + guidance: Option, + #[serde(skip_serializing_if = "Option::is_none")] + image: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + mask: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + num_steps: Option, + #[serde(skip_serializing_if = "Option::is_none")] + prompt: Option, + #[serde(skip_serializing_if = "Option::is_none")] + strength: Option, +} + +impl PayloadBuilder { + fn new() -> Self { + Self::default() + } + + fn guidance(mut self, value: f64) -> Self { + self.guidance = Some(value); + self + } + + fn image(mut self, value: Vec) -> Self { + self.image = Some(value); + self + } + + fn mask(mut self, value: Vec) -> Self { + self.mask = Some(value); + self + } + + fn num_steps(mut self, value: u32) -> Self { + self.num_steps = Some(value); + self + } + + fn prompt(mut self, value: String) -> Self { + self.prompt = Some(value); + self + } + + fn strength(mut self, value: u32) -> Self { + self.strength = Some(value); + self + } +} + +#[cfg(test)] +mod test { + use super::*; + use graphene_core::{raster::Image, Color}; + #[tokio::test] + async fn test_cloudflare() { + let test_image = ImageFrame { + image: Image::new(1024, 1024, SRGBA8::from(Color::RED)), + ..Default::default() + }; + let result = image_to_image(test_image, "make green".into()).await; + dbg!(result.unwrap()); + panic!("show result"); + } +} diff --git a/node-graph/gstd/src/lib.rs b/node-graph/gstd/src/lib.rs index 129bb5b571..3903ee2619 100644 --- a/node-graph/gstd/src/lib.rs +++ b/node-graph/gstd/src/lib.rs @@ -11,6 +11,9 @@ pub mod vector; pub mod http; +#[cfg(feature = "serde")] +pub mod imaginate_v2; + pub mod any; #[cfg(feature = "gpu")] From 501d968899d1bb6f5a99883fb332db1dda61c625 Mon Sep 17 00:00:00 2001 From: "dennis@kobert.dev" Date: Sat, 17 Aug 2024 15:56:22 +0200 Subject: [PATCH 6/6] Rebase onto master --- .../gcore/src/graphic_element/renderer.rs | 35 ++-------- node-graph/gstd/Cargo.toml | 7 +- node-graph/gstd/src/wasm_application_io.rs | 68 ++----------------- .../interpreted-executor/src/node_registry.rs | 34 ++++------ shell.nix | 29 +++++--- 5 files changed, 53 insertions(+), 120 deletions(-) diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index e0c2a19597..481be53ade 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -268,40 +268,15 @@ pub fn to_transform(transform: DAffine2) -> usvg::Transform { usvg::Transform::from_row(cols[0] as f32, cols[1] as f32, cols[2] as f32, cols[3] as f32, cols[4] as f32, cols[5] as f32) } -// TODO: Consider renaming this to better express what it does pub trait GraphicElementRendered { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams); - fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]>; - fn add_click_targets(&self, click_targets: &mut Vec); - - fn to_usvg_node(&self) -> usvg::Node { - let mut render = SvgRender::new(); - let render_params = RenderParams::new(crate::vector::style::ViewMode::Normal, ImageRenderMode::Base64, None, false, false, false); - self.render_svg(&mut render, &render_params); - render.format_svg(DVec2::ZERO, DVec2::ONE); - let svg = render.svg.to_svg_string(); - - let opt = usvg::Options::default(); - - let tree = usvg::Tree::from_str(&svg, &opt).expect("Failed to parse SVG"); - usvg::Node::Group(Box::new(tree.root.clone())) - } - - fn to_usvg_tree(&self, resolution: glam::UVec2, viewbox: [DVec2; 2]) -> usvg::Tree { - let root = match self.to_usvg_node() { - usvg::Node::Group(root_node) => *root_node, - _ => usvg::Group::default(), - }; - usvg::Tree { - size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(), - view_box: usvg::ViewBox { - rect: usvg::NonZeroRect::from_ltrb(viewbox[0].x as f32, viewbox[0].y as f32, viewbox[1].x as f32, viewbox[1].y as f32).unwrap(), - aspect: usvg::AspectRatio::default(), - }, - root, - } + #[cfg(feature = "vello")] + fn to_vello_scene(&self, transform: DAffine2, context: &mut RenderContext) -> Scene { + let mut scene = vello::Scene::new(); + self.render_to_vello(&mut scene, transform, context); + scene } #[cfg(feature = "vello")] fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2, _render_condext: &mut RenderContext) {} diff --git a/node-graph/gstd/Cargo.toml b/node-graph/gstd/Cargo.toml index efc83ec3fd..9a2090c0ec 100644 --- a/node-graph/gstd/Cargo.toml +++ b/node-graph/gstd/Cargo.toml @@ -85,6 +85,9 @@ web-sys = { workspace = true, optional = true, features = [ "HtmlImageElement", "ImageBitmapRenderingContext", ] } +autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = [ + "fitting", +] } -[dev-dependencies] -tokio = { workspace = true, features = ["macros", "rt"] } +# Optional dependencies +image-compare = { version = "0.4.1", optional = true } diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 13c1d9f246..21d8ac4367 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -1,6 +1,10 @@ -use base64::Engine; -use dyn_any::StaticType; -use graphene_core::application_io::{ApplicationError, ApplicationIo, ExportFormat, RenderConfig, ResourceFuture, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; +pub use graph_craft::document::value::RenderOutput; +pub use graph_craft::wasm_application_io::*; +#[cfg(target_arch = "wasm32")] +use graphene_core::application_io::SurfaceHandle; +use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig}; +#[cfg(target_arch = "wasm32")] +use graphene_core::raster::bbox::Bbox; use graphene_core::raster::Image; use graphene_core::raster::ImageFrame; use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender}; @@ -186,66 +190,8 @@ async fn rasterize<_T: GraphicElementRendered + graphene_core::transform::Transf .draw_image_with_html_image_element_and_dw_and_dh(&image_data, 0., 0., resolution.x as f64, resolution.y as f64) .unwrap(); -pub struct RasterizeVectorNode { - footprint: Footprint, - surface_handle: Surface, -} - -#[node_macro::node_fn(RasterizeVectorNode)] -async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footprint, surface_handle: Arc>) -> ImageFrame { - let mut render = SvgRender::new(); - - let resolution = footprint.resolution; - // TODO: reenable once we switch to full node graph - let min = footprint.transform.inverse().transform_point2((0., 0.).into()); - let max = footprint.transform.inverse().transform_point2(resolution.as_dvec2()); - let render_params = RenderParams { - // TODO: Use correct bounds - culling_bounds: Some([min, max]), - ..Default::default() - }; - - data.render_svg(&mut render, &render_params); - render.format_svg(min, max); - let svg_string = render.svg.to_svg_string(); - - let canvas = &surface_handle.surface; - canvas.set_width(resolution.x); - canvas.set_height(resolution.y); - - let array = svg_string.as_bytes(); - let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::().unwrap(); - - let preamble = "data:image/svg+xml;base64,"; - let mut base64_string = String::with_capacity(preamble.len() + array.len() * 4); - base64_string.push_str(preamble); - base64::engine::general_purpose::STANDARD.encode_string(array, &mut base64_string); - - let image_data = web_sys::HtmlImageElement::new().unwrap(); - image_data.set_src(base64_string.as_str()); - wasm_bindgen_futures::JsFuture::from(image_data.decode()).await.unwrap(); - context.draw_image_with_html_image_element(&image_data, 0., 0.).unwrap(); - let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap(); - let image = Image::from_image_data(&rasterized.data().0, resolution.x, resolution.y); - ImageFrame { - image, - transform: glam::DAffine2::from_scale(resolution.as_dvec2()), - ..Default::default() - } -} - -// Render with the data node taking in Footprint. -impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future, Data: 'input, Surface: 'input, SurfaceFuture: 'input> Node<'input, WasmEditorApi<'a>> - for RenderNode -where - Data: Node<'input, Footprint, Output = F>, - Surface: Node<'input, (), Output = SurfaceFuture>, - SurfaceFuture: core::future::Future>>, -{ - type Output = core::pin::Pin + 'input>>; - let image = Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32); ImageFrame { image, diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index bf742831a2..c964f287f9 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -651,25 +651,21 @@ fn node_registry() -> HashMap, input: Color, params: [QuantizationChannels]), register_node!(graphene_core::quantization::DeQuantizeNode<_>, input: PackedPixel, params: [QuantizationChannels]), register_node!(graphene_core::ops::CloneNode<_>, input: &QuantizationChannels, params: []), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ImageFrame, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => VectorData, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Artboard, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ArtboardGroup, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Option, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Vec, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [ImageFrame, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [VectorData, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [GraphicGroup, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Artboard, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [bool, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f32, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f64, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [String, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Option, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Vec, Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, () => Option]), + #[cfg(target_arch = "wasm32")] + async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), + #[cfg(target_arch = "wasm32")] + async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), // async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame, fn_params: [Footprint => ImageFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), diff --git a/shell.nix b/shell.nix index e1d675b01b..1ca9e01b87 100644 --- a/shell.nix +++ b/shell.nix @@ -41,28 +41,41 @@ let nodejs cargo cargo-watch + cargo-nextest + cargo-expand wasm-pack + binaryen + wasm-bindgen-cli + vulkan-loader + libxkbcommon + llvm + gcc-unwrapped.lib + llvmPackages.libcxxStdenv + pkg-config + # used for profiling + gnuplot + samply + cargo-flamegraph + # For Tauri openssl glib gtk3 libsoup webkitgtk - pkg-config + # For Raw-rs tests + libraw - # Use Mold as a Linke + # Use Mold as a linker mold - ]; + ]; in # Make a shell with the dependencies we need - pkgs.mkShell { - packages = packages; - + pkgs.mkShell { + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages; # Hacky way to run Cargo through Mold - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.openssl pkgs.vulkan-loader pkgs.libxkbcommon pkgs.llvmPackages.libcxxStdenv pkgs.gcc-unwrapped.lib pkgs.llvm pkgs.libraw]; shellHook = '' - export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath packages}:$LD_LIBRARY_PATH alias cargo='mold --run cargo' ''; }