diff --git a/document-legacy/src/document_metadata.rs b/document-legacy/src/document_metadata.rs index 4d7ab7c5..9e1830cb 100644 --- a/document-legacy/src/document_metadata.rs +++ b/document-legacy/src/document_metadata.rs @@ -319,8 +319,19 @@ impl DocumentMetadata { } /// Calculates the document bounds in document space - pub fn document_bounds_document_space(&self) -> Option<[DVec2; 2]> { - self.all_layers().filter_map(|layer| self.bounding_box_document(layer)).reduce(Quad::combine_bounds) + pub fn document_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> { + self.all_layers() + .filter(|&layer| include_artboards || self.is_artboard(layer)) + .filter_map(|layer| self.bounding_box_document(layer)) + .reduce(Quad::combine_bounds) + } + + /// Calculates the selected layer bounds in document space + pub fn selected_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> { + self.selected_layers() + .filter(|&layer| include_artboards || self.is_artboard(layer)) + .filter_map(|layer| self.bounding_box_document(layer)) + .reduce(Quad::combine_bounds) } pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> graphene_core::vector::Subpath { diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs index 07ecf458..5a130cad 100644 --- a/editor/src/messages/dialog/dialog_message_handler.rs +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -93,7 +93,7 @@ impl MessageHandler> for DialogMessageHandler { self.export_dialog = ExportDialogMessageHandler { scale_factor: 1., artboards, - has_selection: document.selected_layers().next().is_some(), + has_selection: document.metadata().selected_layers().next().is_some(), ..Default::default() }; self.export_dialog.send_dialog_to_frontend(responses); diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs index 48093659..4d965e7d 100644 --- a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs @@ -23,7 +23,7 @@ impl MessageHandler for ExportDia ExportDialogMessage::TransparentBackground(transparent_background) => self.transparent_background = transparent_background, ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area, - ExportDialogMessage::Submit => responses.add_front(DocumentMessage::ExportDocument { + ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::SubmitDocumentExport { file_name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(), file_type: self.file_type, scale_factor: self.scale_factor, diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index 6d4c2287..1f9537fb 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -1,4 +1,3 @@ -use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::utility_types::layer_panel::LayerMetadata; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; @@ -74,13 +73,6 @@ pub enum DocumentMessage { layer_path: Vec, }, DuplicateSelectedLayers, - ExportDocument { - file_name: String, - file_type: FileType, - scale_factor: f64, - bounds: ExportBounds, - transparent_background: bool, - }, FlipSelectedLayers { flip_axis: FlipAxis, }, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 92c15ebb..d8558264 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1,9 +1,7 @@ use super::utility_types::error::EditorError; -use super::utility_types::misc::{DocumentRenderMode, SnappingOptions, SnappingState}; +use super::utility_types::misc::{SnappingOptions, SnappingState}; use crate::application::generate_uuid; use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR}; -use crate::messages::frontend::utility_types::ExportBounds; -use crate::messages::frontend::utility_types::FileType; use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; @@ -354,43 +352,6 @@ impl MessageHandler> for DocumentMessageHand responses.add(DocumentOperation::DuplicateLayer { path: path.to_vec() }); } } - ExportDocument { - file_name, - file_type, - scale_factor, - bounds, - transparent_background, - } => { - let old_artwork_transform = self.remove_document_transform(); - - // Calculate the bounding box of the region to be exported - let bounds = match bounds { - ExportBounds::AllArtwork => self.all_layer_bounds(&render_data), - ExportBounds::Selection => self.document_legacy.selected_visible_layers_bounding_box_viewport(), - ExportBounds::Artboard(id) => self.metadata().bounding_box_document(id), - } - .unwrap_or_default(); - let size = bounds[1] - bounds[0]; - let transform = (DAffine2::from_translation(bounds[0]) * DAffine2::from_scale(size)).inverse(); - - let document = self.render_document(size, transform, transparent_background, persistent_data, DocumentRenderMode::Root); - - self.restore_document_transform(old_artwork_transform); - - let file_suffix = &format!(".{file_type:?}").to_lowercase(); - let name = match file_name.ends_with(FILE_SAVE_SUFFIX) { - true => file_name.replace(FILE_SAVE_SUFFIX, file_suffix), - false => file_name + file_suffix, - }; - - if file_type == FileType::Svg { - responses.add(FrontendMessage::TriggerDownloadTextFile { document, name }); - } else { - let mime = file_type.to_mime().to_string(); - let size = (size * scale_factor).into(); - responses.add(FrontendMessage::TriggerDownloadImage { svg: document, name, mime, size }); - } - } FlipSelectedLayers { flip_axis } => { self.backup(responses); let scale = match flip_axis { @@ -878,7 +839,7 @@ impl MessageHandler> for DocumentMessageHand responses.add_front(NavigationMessage::SetCanvasZoom { zoom_factor: 2. }); } ZoomCanvasToFitAll => { - if let Some(bounds) = self.metadata().document_bounds_document_space() { + if let Some(bounds) = self.metadata().document_bounds_document_space(true) { responses.add(NavigationMessage::FitViewportToBounds { bounds, padding_scale_factor: Some(VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR), @@ -902,7 +863,6 @@ impl DocumentMessageHandler { SelectAllLayers, DeselectAllLayers, RenderDocument, - ExportDocument, SaveDocument, SetSnapping, DebugPrintDocument, @@ -940,49 +900,6 @@ impl DocumentMessageHandler { &self.document_legacy.metadata } - /// Remove the artwork and artboard pan/tilt/zoom to render it without the user's viewport navigation, and save it to be restored at the end - pub(crate) fn remove_document_transform(&mut self) -> DAffine2 { - let old_artwork_transform = self.metadata().document_to_viewport; - self.document_legacy.metadata.document_to_viewport = DAffine2::IDENTITY; - DocumentLegacy::mark_children_as_dirty(&mut self.document_legacy.root); - - old_artwork_transform - } - - /// Transform the artwork and artboard back to their original scales - pub(crate) fn restore_document_transform(&mut self, old_artwork_transform: DAffine2) { - self.document_legacy.metadata.document_to_viewport = old_artwork_transform; - DocumentLegacy::mark_children_as_dirty(&mut self.document_legacy.root); - } - - pub fn render_document(&mut self, size: DVec2, transform: DAffine2, transparent_background: bool, persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String { - // Render the document SVG code - - let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None); - - let (artwork, outside) = match render_mode { - DocumentRenderMode::Root => (self.document_legacy.render_root(&render_data), None), - DocumentRenderMode::OnlyBelowLayerInFolder(below_layer_path) => (self.document_legacy.render_layers_below(below_layer_path, &render_data).unwrap(), None), - DocumentRenderMode::LayerCutout(layer_path, background) => (self.document_legacy.render_layer(layer_path, &render_data).unwrap(), Some(background)), - }; - let canvas_background_color = outside.map_or_else(|| "222222".to_string(), |col| col.rgba_hex()); - let canvas_background = match transparent_background { - false => format!(r##""##), - true => "".into(), - }; - let matrix = transform - .to_cols_array() - .iter() - .enumerate() - .fold(String::new(), |acc, (i, entry)| acc + &(entry.to_string() + if i == 5 { "" } else { "," })); - let svg = format!( - r#"{}{canvas_background}{artwork}"#, - size.x, size.y, "\n", - ); - - svg - } - pub fn serialize_document(&self) -> String { let val = serde_json::to_string(self); // We fully expect the serialization to succeed diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 402df949..501a75d5 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -1,6 +1,6 @@ +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; use crate::messages::prelude::*; - use document_legacy::document_metadata::LayerNodeIdentifier; use document_legacy::LayerId; use graph_craft::document::NodeId; @@ -110,6 +110,13 @@ pub enum PortfolioMessage { blob_url: String, resolution: (f64, f64), }, + SubmitDocumentExport { + file_name: String, + file_type: FileType, + scale_factor: f64, + bounds: ExportBounds, + transparent_background: bool, + }, SubmitGraphRender { document_id: u64, layer_path: Vec, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index b70fc3a3..35aafebc 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -9,7 +9,7 @@ use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, use crate::messages::portfolio::document::DocumentInputs; use crate::messages::prelude::*; use crate::messages::tool::utility_types::{HintData, HintGroup}; -use crate::node_graph_executor::NodeGraphExecutor; +use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; use document_legacy::layers::style::RenderData; use graph_craft::document::NodeId; @@ -511,6 +511,31 @@ impl MessageHandler { + let document = self.active_document_id.and_then(|id| self.documents.get_mut(&id)).expect("Tried to render no existent Document"); + let export_config = ExportConfig { + file_name, + file_type, + scale_factor, + bounds, + transparent_background, + ..Default::default() + }; + let result = self.executor.submit_document_export(document, export_config); + + if let Err(description) = result { + responses.add(DialogMessage::DisplayDialogError { + title: "Unable to export document".to_string(), + description, + }); + } + } PortfolioMessage::SubmitGraphRender { document_id, layer_path } => { let result = self.executor.submit_node_graph_evaluation( self.documents.get_mut(&document_id).expect("Tried to render no existent Document"), diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 70a0176e..d0fd843b 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -1,13 +1,13 @@ +use crate::consts::FILE_SAVE_SUFFIX; use crate::messages::frontend::utility_types::FrontendImageData; +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::portfolio::document::node_graph::wrap_network_in_scope; use crate::messages::portfolio::document::utility_types::misc::{LayerMetadata, LayerPanelEntry}; use crate::messages::prelude::*; - use document_legacy::document::Document as DocumentLegacy; use document_legacy::document_metadata::LayerNodeIdentifier; use document_legacy::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant}; use document_legacy::{LayerId, Operation}; - use graph_craft::document::value::TaggedValue; use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork}; use graph_craft::graphene_compiler::Compiler; @@ -69,6 +69,16 @@ enum NodeRuntimeMessage { ImaginatePreferencesUpdate(ImaginatePreferences), } +#[derive(Default, Debug, Clone)] +pub struct ExportConfig { + pub file_name: String, + pub file_type: FileType, + pub scale_factor: f64, + pub bounds: ExportBounds, + pub transparent_background: bool, + pub size: DVec2, +} + pub(crate) struct GenerationRequest { generation_id: u64, graph: NodeNetwork, @@ -269,7 +279,7 @@ impl NodeRuntime { let graphic_element = &io_data.output; use graphene_core::renderer::*; let bounds = graphic_element.bounding_box(DAffine2::IDENTITY); - let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::BlobUrl, bounds, true); + let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::BlobUrl, bounds, true, false, false); let mut render = SvgRender::new(); graphic_element.render_svg(&mut render, &render_params); let [min, max] = bounds.unwrap_or_default(); @@ -370,6 +380,7 @@ pub struct NodeGraphExecutor { #[derive(Debug, Clone)] struct ExecutionContext { layer_path: Vec, + export_config: Option, } impl Default for NodeGraphExecutor { @@ -502,16 +513,85 @@ impl NodeGraphExecutor { #[cfg(not(any(feature = "resvg", feature = "vello")))] export_format: graphene_core::application_io::ExportFormat::Svg, view_mode: document.view_mode, + hide_artboards: false, + for_export: false, }; // Execute the node graph let generation_id = self.queue_execution(network, layer_path.clone(), render_config); - self.futures.insert(generation_id, ExecutionContext { layer_path }); + self.futures.insert(generation_id, ExecutionContext { layer_path, export_config: None }); Ok(()) } + /// Evaluates a node graph for export + pub fn submit_document_export(&mut self, document: &mut DocumentMessageHandler, mut export_config: ExportConfig) -> Result<(), String> { + let network = document.network().clone(); + + // Calculate the bounding box of the region to be exported + let bounds = match export_config.bounds { + ExportBounds::AllArtwork => document.metadata().document_bounds_document_space(!export_config.transparent_background), + ExportBounds::Selection => document.metadata().selected_bounds_document_space(!export_config.transparent_background), + ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id), + } + .ok_or_else(|| "No bounding box".to_string())?; + let size = bounds[1] - bounds[0]; + let transform = DAffine2::from_translation(bounds[0]).inverse(); + + let render_config = RenderConfig { + viewport: Footprint { + transform, + resolution: (size * export_config.scale_factor).as_uvec2(), + ..Default::default() + }, + export_format: graphene_core::application_io::ExportFormat::Svg, + view_mode: document.view_mode, + hide_artboards: export_config.transparent_background, + for_export: true, + }; + export_config.size = size; + + // Execute the node graph + let generation_id = self.queue_execution(network, Vec::new(), render_config); + let execution_context = ExecutionContext { + layer_path: Vec::new(), + export_config: Some(export_config), + }; + self.futures.insert(generation_id, execution_context); + + Ok(()) + } + + fn export(&self, node_graph_output: TaggedValue, export_config: ExportConfig, responses: &mut VecDeque) -> Result<(), String> { + let TaggedValue::RenderOutput(graphene_std::wasm_application_io::RenderOutput::Svg(svg)) = node_graph_output else { + return Err("Incorrect render type for exportign (expected RenderOutput::Svg)".to_string()); + }; + + let ExportConfig { + file_type, + file_name, + size, + scale_factor, + .. + } = export_config; + + let file_suffix = &format!(".{file_type:?}").to_lowercase(); + let name = match file_name.ends_with(FILE_SAVE_SUFFIX) { + true => file_name.replace(FILE_SAVE_SUFFIX, file_suffix), + false => file_name + file_suffix, + }; + + if file_type == FileType::Svg { + responses.add(FrontendMessage::TriggerDownloadTextFile { document: svg, name }); + } else { + let mime = file_type.to_mime().to_string(); + let size = (size * scale_factor).into(); + responses.add(FrontendMessage::TriggerDownloadImage { svg, name, mime, size }); + } + Ok(()) + } + pub fn poll_node_graph_evaluation(&mut self, document: &mut DocumentLegacy, responses: &mut VecDeque) -> Result<(), String> { let results = self.receiver.try_iter().collect::>(); for response in results { @@ -525,6 +605,13 @@ impl NodeGraphExecutor { new_upstream_transforms, transform, }) => { + let node_graph_output = result.map_err(|e| format!("Node graph evaluation failed: {e:?}"))?; + let execution_context = self.futures.remove(&generation_id).ok_or_else(|| "Invalid generation ID".to_string())?; + + if let Some(export_config) = execution_context.export_config { + return self.export(node_graph_output, export_config, responses); + } + for (&node_id, svg) in &new_thumbnails { if !document.document_network.nodes.contains_key(&node_id) { warn!("Missing node"); @@ -555,8 +642,6 @@ impl NodeGraphExecutor { self.thumbnails = new_thumbnails; document.metadata.update_transforms(new_upstream_transforms); document.metadata.update_click_targets(new_click_targets); - let node_graph_output = result.map_err(|e| format!("Node graph evaluation failed: {e:?}"))?; - let execution_context = self.futures.remove(&generation_id).ok_or_else(|| "Invalid generation ID".to_string())?; responses.extend(updates); self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?; responses.add(DocumentMessage::LayerChanged { @@ -581,13 +666,13 @@ impl NodeGraphExecutor { // Setup rendering let mut render = SvgRender::new(); - let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::BlobUrl, None, false); + let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::BlobUrl, None, false, false, false); // Render SVG render_object.render_svg(&mut render, &render_params); // Concatenate the defs and the SVG into one string - render.wrap_with_transform(transform); + render.wrap_with_transform(transform, None); let svg = render.svg.to_string(); // Send to frontend diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index 0accc1b6..b409f91b 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -153,6 +153,8 @@ pub struct RenderConfig { pub viewport: Footprint, pub export_format: ExportFormat, pub view_mode: ViewMode, + pub hide_artboards: bool, + pub for_export: bool, } pub struct EditorApi<'a, Io> { diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 1bca385f..b0b6f0c1 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -90,10 +90,17 @@ impl SvgRender { } /// Wraps the SVG with ``, which allows for rotation - pub fn wrap_with_transform(&mut self, transform: DAffine2) { + pub fn wrap_with_transform(&mut self, transform: DAffine2, size: Option) { let defs = &self.svg_defs; + let view_box = size + .map(|size| format!("viewbox=\"0 0 {} {}\" width=\"{}\" height=\"{}\"", size.x, size.y, size.x, size.y)) + .unwrap_or_default(); - let svg_header = format!(r#"{defs}"#, format_transform_matrix(transform)); + let svg_header = format!( + r#"{defs}"#, + view_box, + format_transform_matrix(transform) + ); self.svg.insert(0, svg_header.into()); self.svg.push(""); } @@ -154,15 +161,21 @@ pub struct RenderParams { pub image_render_mode: ImageRenderMode, pub culling_bounds: Option<[DVec2; 2]>, pub thumbnail: bool, + /// Don't render the rectangle for an artboard to allow exporting with a transparent background. + pub hide_artboards: bool, + /// Are we exporting? Causes the text above an artboard to be hidden. + pub for_export: bool, } impl RenderParams { - pub fn new(view_mode: crate::vector::style::ViewMode, image_render_mode: ImageRenderMode, culling_bounds: Option<[DVec2; 2]>, thumbnail: bool) -> Self { + pub fn new(view_mode: crate::vector::style::ViewMode, image_render_mode: ImageRenderMode, culling_bounds: Option<[DVec2; 2]>, thumbnail: bool, hide_artboards: bool, for_export: bool) -> Self { Self { view_mode, image_render_mode, culling_bounds, thumbnail, + hide_artboards, + for_export, } } } @@ -192,7 +205,7 @@ pub trait GraphicElementRendered { 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::BlobUrl, None, false); + let render_params = RenderParams::new(crate::vector::style::ViewMode::Normal, ImageRenderMode::BlobUrl, None, false, false, false); self.render_svg(&mut render, &render_params); render.format_svg(DVec2::ZERO, DVec2::ONE); let svg = render.svg.to_string(); @@ -335,31 +348,34 @@ impl GraphicElementRendered for VectorData { impl GraphicElementRendered for Artboard { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { - // Background - render.leaf_tag("rect", |attributes| { - attributes.push("class", "artboard-bg"); - attributes.push("fill", format!("#{}", self.background.rgba_hex())); - attributes.push("x", self.location.x.min(self.location.x + self.dimensions.x).to_string()); - attributes.push("y", self.location.y.min(self.location.y + self.dimensions.y).to_string()); - attributes.push("width", self.dimensions.x.abs().to_string()); - attributes.push("height", self.dimensions.y.abs().to_string()); - }); - - // Label - render.parent_tag( - "text", - |attributes| { - attributes.push("class", "artboard-label"); - attributes.push("fill", "white"); - attributes.push("x", (self.location.x.min(self.location.x + self.dimensions.x)).to_string()); - attributes.push("y", (self.location.y.min(self.location.y + self.dimensions.y) - 4).to_string()); - attributes.push("font-size", "14px"); - }, - |render| { - // TODO: Use the artboard's layer name - render.svg.push("Artboard"); - }, - ); + if !render_params.hide_artboards { + // Background + render.leaf_tag("rect", |attributes| { + attributes.push("class", "artboard-bg"); + attributes.push("fill", format!("#{}", self.background.rgba_hex())); + attributes.push("x", self.location.x.min(self.location.x + self.dimensions.x).to_string()); + attributes.push("y", self.location.y.min(self.location.y + self.dimensions.y).to_string()); + attributes.push("width", self.dimensions.x.abs().to_string()); + attributes.push("height", self.dimensions.y.abs().to_string()); + }); + } + if !render_params.hide_artboards && !render_params.for_export { + // Label + render.parent_tag( + "text", + |attributes| { + attributes.push("class", "artboard-label"); + attributes.push("fill", "white"); + attributes.push("x", (self.location.x.min(self.location.x + self.dimensions.x)).to_string()); + attributes.push("y", (self.location.y.min(self.location.y + self.dimensions.y) - 4).to_string()); + attributes.push("font-size", "14px"); + }, + |render| { + // TODO: Use the artboard's layer name + render.svg.push("Artboard"); + }, + ); + } // Contents group (includes the artwork but not the background) render.parent_tag( diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index d0145c60..82941427 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -2,9 +2,9 @@ use std::cell::RefCell; use core::future::Future; use dyn_any::StaticType; -use graphene_core::application_io::{ApplicationError, ApplicationIo, ExportFormat, ResourceFuture, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; +use graphene_core::application_io::{ApplicationError, ApplicationIo, ExportFormat, RenderConfig, ResourceFuture, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; use graphene_core::raster::Image; -use graphene_core::renderer::{GraphicElementRendered, RenderParams, SvgRender}; +use graphene_core::renderer::{GraphicElementRendered, ImageRenderMode, RenderParams, SvgRender}; use graphene_core::transform::Footprint; use graphene_core::Color; use graphene_core::{ @@ -292,7 +292,7 @@ pub struct RenderNode { fn render_svg(data: impl GraphicElementRendered, mut render: SvgRender, render_params: RenderParams, footprint: Footprint) -> RenderOutput { data.render_svg(&mut render, &render_params); - render.wrap_with_transform(footprint.transform); + render.wrap_with_transform(footprint.transform, Some(footprint.resolution.as_dvec2())); RenderOutput::Svg(render.svg.to_string()) } @@ -363,7 +363,9 @@ where fn eval(&'input self, editor: WasmEditorApi<'a>) -> Self::Output { Box::pin(async move { let footprint = editor.render_config.viewport; - let render_params = RenderParams::new(editor.render_config.view_mode, graphene_core::renderer::ImageRenderMode::Base64, None, false); + + let RenderConfig { hide_artboards, for_export, .. } = editor.render_config; + let render_params = RenderParams::new(editor.render_config.view_mode, ImageRenderMode::Base64, None, false, hide_artboards, for_export); let output_format = editor.render_config.export_format; match output_format { @@ -388,10 +390,10 @@ where #[inline] fn eval(&'input self, editor: WasmEditorApi<'a>) -> Self::Output { Box::pin(async move { - use graphene_core::renderer::ImageRenderMode; - let footprint = editor.render_config.viewport; - let render_params = RenderParams::new(editor.render_config.view_mode, ImageRenderMode::Base64, None, false); + + let RenderConfig { hide_artboards, for_export, .. } = editor.render_config; + let render_params = RenderParams::new(editor.render_config.view_mode, ImageRenderMode::Base64, None, false, hide_artboards, for_export); let output_format = editor.render_config.export_format; match output_format {