Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion desktop/src/render/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl RenderState {
return;
};
let size = glam::UVec2::new(viewport_texture.width(), viewport_texture.height());
let result = futures::executor::block_on(self.executor.render_vello_scene_to_target_texture(&scene, size, &Default::default(), None, &mut self.overlays_texture));
let result = futures::executor::block_on(self.executor.render_vello_scene_to_target_texture(&scene, size, &Default::default(), &mut self.overlays_texture));
if let Err(e) = result {
tracing::error!("Error rendering overlays: {:?}", e);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::messages::prelude::*;
pub enum ExportDialogMessage {
FileType { file_type: FileType },
ScaleFactor { factor: f64 },
TransparentBackground { transparent: bool },
ExportBounds { bounds: ExportBounds },

Submit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub struct ExportDialogMessageHandler {
pub file_type: FileType,
pub scale_factor: f64,
pub bounds: ExportBounds,
pub transparent_background: bool,
pub artboards: HashMap<LayerNodeIdentifier, String>,
pub has_selection: bool,
}
Expand All @@ -25,7 +24,6 @@ impl Default for ExportDialogMessageHandler {
file_type: Default::default(),
scale_factor: 1.,
bounds: Default::default(),
transparent_background: false,
artboards: Default::default(),
has_selection: false,
}
Expand All @@ -40,20 +38,25 @@ impl MessageHandler<ExportDialogMessage, ExportDialogMessageContext<'_>> for Exp
match message {
ExportDialogMessage::FileType { file_type } => self.file_type = file_type,
ExportDialogMessage::ScaleFactor { factor } => self.scale_factor = factor,
ExportDialogMessage::TransparentBackground { transparent } => self.transparent_background = transparent,
ExportDialogMessage::ExportBounds { bounds } => self.bounds = bounds,

ExportDialogMessage::Submit => {
let artboard_name = match self.bounds {
// Fall back to "All Artwork" if "Selection" was chosen but nothing is currently selected
let bounds = if !self.has_selection && self.bounds == ExportBounds::Selection {
ExportBounds::AllArtwork
} else {
self.bounds
};

let artboard_name = match bounds {
ExportBounds::Artboard(layer) => self.artboards.get(&layer).cloned(),
_ => None,
};
responses.add_front(PortfolioMessage::SubmitDocumentExport {
name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(),
file_type: self.file_type,
scale_factor: self.scale_factor,
bounds: self.bounds,
transparent_background: self.file_type != FileType::Jpg && self.transparent_background,
bounds,
artboard_name,
artboard_count: self.artboards.len(),
})
Expand Down Expand Up @@ -127,6 +130,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
let artboards = self.artboards.iter().map(|(&layer, name)| (ExportBounds::Artboard(layer), name.to_string(), false)).collect();
let choices = [standard_bounds, artboards];

// Fall back to "All Artwork" if "Selection" was chosen but nothing is currently selected
let current_bounds = if !self.has_selection && self.bounds == ExportBounds::Selection {
ExportBounds::AllArtwork
} else {
Expand Down Expand Up @@ -159,22 +163,6 @@ impl LayoutHolder for ExportDialogMessageHandler {
DropdownInput::new(entries).selected_index(Some(index as u32)).widget_instance(),
];

let checkbox_id = CheckboxId::new();
let transparent_background = vec![
TextLabel::new("Transparency").table_align(true).min_width(100).for_checkbox(checkbox_id).widget_instance(),
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
CheckboxInput::new(self.transparent_background)
.disabled(self.file_type == FileType::Jpg)
.on_update(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground { transparent: value.checked }.into())
.for_label(checkbox_id)
.widget_instance(),
];

Layout(vec![
LayoutGroup::row(export_type),
LayoutGroup::row(resolution),
LayoutGroup::row(export_area),
LayoutGroup::row(transparent_background),
])
Layout(vec![LayoutGroup::row(export_type), LayoutGroup::row(resolution), LayoutGroup::row(export_area)])
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
use glam::{IVec2, UVec2};
use graph_craft::document::NodeId;
use graphene_std::Color;

/// A dialog to allow users to set some initial options about a new document.
#[derive(Debug, Clone, Default, ExtractField)]
Expand All @@ -22,25 +24,39 @@ impl MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHa
NewDocumentDialogMessage::Submit => {
responses.add(PortfolioMessage::NewDocumentWithName { name: self.name.clone() });

let create_artboard = !self.infinite && self.dimensions.x > 0 && self.dimensions.y > 0;
if create_artboard {
if self.infinite {
// Infinite canvas: add a locked white background layer
let node_id = NodeId::new();
responses.add(GraphOperationMessage::NewColorFillLayer {
node_id,
color: Color::WHITE,
parent: LayerNodeIdentifier::ROOT_PARENT,
insert_index: 0,
});
responses.add(NodeGraphMessage::SetDisplayNameImpl {
node_id,
alias: "Background".to_string(),
});
responses.add(NodeGraphMessage::SetLocked { node_id, locked: true });
} else if self.dimensions.x > 0 && self.dimensions.y > 0 {
// Finite canvas: create an artboard with the specified dimensions
responses.add(GraphOperationMessage::NewArtboard {
id: NodeId::new(),
artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()),
});
responses.add(NavigationMessage::CanvasPan { delta: self.dimensions.as_dvec2() });
responses.add(NodeGraphMessage::RunDocumentGraph);
}

responses.add(ViewportMessage::RepropagateUpdate);
responses.add(NodeGraphMessage::RunDocumentGraph);
responses.add(ViewportMessage::RepropagateUpdate);

responses.add(DeferMessage::AfterNavigationReady {
messages: vec![
DocumentMessage::ZoomCanvasToFitAll.into(),
DocumentMessage::DeselectAllLayers.into(),
PortfolioMessage::AutoSaveActiveDocument.into(),
],
});
}
responses.add(DeferMessage::AfterNavigationReady {
messages: vec![
DocumentMessage::ZoomCanvasToFitAll.into(),
DocumentMessage::DeselectAllLayers.into(),
PortfolioMessage::AutoSaveActiveDocument.into(),
],
});

responses.add(DocumentMessage::MarkAsSaved);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1400,8 +1400,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
let node_layer_id = LayerNodeIdentifier::new_unchecked(node_id);
let new_artboard_node = document_node_definitions::resolve_network_node_type("Artboard")
.expect("Failed to create artboard node")
// Enable clipping by default (input index 5) so imported content is masked to the artboard bounds
.node_template_input_override([None, None, None, None, None, Some(NodeInput::value(TaggedValue::Bool(true), false))]);
.default_node_template();
responses.add(NodeGraphMessage::InsertNode {
node_id,
node_template: Box::new(new_artboard_node),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
use crate::messages::prelude::*;
use glam::{DAffine2, IVec2};
use graph_craft::document::NodeId;
use graphene_std::Artboard;
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::raster::BlendMode;
use graphene_std::raster_types::{CPU, Raster};
Expand All @@ -14,6 +13,7 @@ use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::PointId;
use graphene_std::vector::VectorModificationType;
use graphene_std::vector::style::{Fill, Stroke};
use graphene_std::{Artboard, Color};

#[impl_message(Message, DocumentMessage, GraphOperation)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -97,6 +97,12 @@ pub enum GraphOperationMessage {
parent: LayerNodeIdentifier,
insert_index: usize,
},
NewColorFillLayer {
node_id: NodeId,
color: Color,
parent: LayerNodeIdentifier,
insert_index: usize,
},
NewVectorLayer {
id: NodeId,
subpaths: Vec<Subpath<PointId>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index });
responses.add(NodeGraphMessage::RunDocumentGraph);
}
GraphOperationMessage::NewColorFillLayer { node_id, color, parent, insert_index } => {
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
let layer = modify_inputs.create_layer(node_id);
modify_inputs.insert_color_value(color, layer);
network_interface.move_layer_to_stack(layer, parent, insert_index, &[]);
responses.add(NodeGraphMessage::RunDocumentGraph);
}
GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => {
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
let layer = modify_inputs.create_layer(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use glam::{DAffine2, IVec2};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graph_craft::{ProtoNodeIdentifier, concrete};
use graphene_std::Artboard;
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::raster::BlendMode;
use graphene_std::raster_types::{CPU, Raster};
Expand All @@ -17,7 +16,7 @@ use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::Vector;
use graphene_std::vector::style::{Fill, Stroke};
use graphene_std::vector::{PointId, VectorModificationType};
use graphene_std::{Graphic, NodeInputDecleration};
use graphene_std::{Artboard, Color, Graphic, NodeInputDecleration};

#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub enum TransformIn {
Expand Down Expand Up @@ -289,6 +288,19 @@ impl<'a> ModifyInputsContext<'a> {
self.network_interface.move_node_to_chain_start(&fill_id, layer, &[], self.import);
}

pub fn insert_color_value(&mut self, color: Color, layer: LayerNodeIdentifier) {
let color_value = resolve_proto_node_type(graphene_std::math_nodes::color_value::IDENTIFIER)
.expect("Color Value node does not exist")
.node_template_input_override([
Some(NodeInput::value(TaggedValue::None, false)),
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(color)), false)),
]);

let color_value_id = NodeId::new();
self.network_interface.insert_node(color_value_id, color_value, &[]);
self.network_interface.move_node_to_chain_start(&color_value_id, layer, &[], self.import);
}

pub fn insert_image_data(&mut self, image_frame: Table<Raster<CPU>>, layer: LayerNodeIdentifier) {
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
let image = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false),
NodeInput::value(TaggedValue::Color(Table::new_from_element(Color::WHITE)), false),
NodeInput::value(TaggedValue::Bool(false), false),
NodeInput::value(TaggedValue::Bool(true), false),
],
..Default::default()
},
Expand Down
1 change: 0 additions & 1 deletion editor/src/messages/portfolio/portfolio_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ pub enum PortfolioMessage {
file_type: FileType,
scale_factor: f64,
bounds: ExportBounds,
transparent_background: bool,
artboard_name: Option<String>,
artboard_count: usize,
},
Expand Down
2 changes: 0 additions & 2 deletions editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,7 +1382,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
file_type,
scale_factor,
bounds,
transparent_background,
artboard_name,
artboard_count,
} => {
Expand All @@ -1392,7 +1391,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
file_type,
scale_factor,
bounds,
transparent_background,
artboard_name,
artboard_count,
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion editor/src/messages/tool/tool_messages/artboard_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl Fsm for ArtboardToolFsmState {
location: start.min(end).round().as_ivec2(),
dimensions: (start.round() - end.round()).abs().as_ivec2(),
background: graphene_std::Color::WHITE,
clip: false,
clip: true,
},
})
}
Expand Down
19 changes: 12 additions & 7 deletions editor/src/node_graph_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ impl NodeGraphExecutor {
pointer,
export_format: graphene_std::application_io::ExportFormat::Raster,
render_mode: document.render_mode,
hide_artboards: false,
for_export: false,
for_eyedropper: false,
};
Expand Down Expand Up @@ -218,7 +217,6 @@ impl NodeGraphExecutor {
pointer,
export_format: graphene_std::application_io::ExportFormat::Raster,
render_mode,
hide_artboards: false,
for_export: false,
for_eyedropper: true,
};
Expand All @@ -241,10 +239,10 @@ impl NodeGraphExecutor {
graphene_std::application_io::ExportFormat::Raster
};

// Calculate the bounding box of the region to be exported
// Calculate the bounding box of the region to be exported (artboard bounds always contribute)
let bounds = match export_config.bounds {
ExportBounds::AllArtwork => document.network_interface.document_bounds_document_space(!export_config.transparent_background),
ExportBounds::Selection => document.network_interface.selected_bounds_document_space(!export_config.transparent_background, &[]),
ExportBounds::AllArtwork => document.network_interface.document_bounds_document_space(true),
ExportBounds::Selection => document.network_interface.selected_bounds_document_space(true, &[]),
ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id),
}
.ok_or_else(|| "No bounding box".to_string())?;
Expand All @@ -266,7 +264,6 @@ impl NodeGraphExecutor {
pointer: DVec2::ZERO,
export_format,
render_mode: document.render_mode,
hide_artboards: export_config.transparent_background,
for_export: true,
for_eyedropper: false,
};
Expand Down Expand Up @@ -481,7 +478,7 @@ impl NodeGraphExecutor {
use image::buffer::ConvertBuffer;
use image::{ImageFormat, RgbImage, RgbaImage};

let Some(image) = RgbaImage::from_raw(width, height, data) else {
let Some(mut image) = RgbaImage::from_raw(width, height, data) else {
return Err("Failed to create image buffer for export".to_string());
};

Expand All @@ -496,6 +493,14 @@ impl NodeGraphExecutor {
}
}
FileType::Jpg => {
// Composite onto a white background since JPG doesn't support transparency
for pixel in image.pixels_mut() {
let [r, g, b, a] = pixel.0;
let alpha = a as f32 / 255.;
let blend = |channel: u8| (channel as f32 * alpha + 255. * (1. - alpha)).round() as u8;
*pixel = image::Rgba([blend(r), blend(g), blend(b), 255]);
}

let image: RgbImage = image.convert();
let result = image.write_to(&mut cursor, ImageFormat::Jpeg);
if let Err(err) = result {
Expand Down
1 change: 0 additions & 1 deletion editor/src/node_graph_executor/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ pub struct ExportConfig {
pub file_type: FileType,
pub scale_factor: f64,
pub bounds: ExportBounds,
pub transparent_background: bool,
pub size: UVec2,
pub artboard_name: Option<String>,
pub artboard_count: usize,
Expand Down
1 change: 0 additions & 1 deletion node-graph/libraries/application-io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ pub struct RenderConfig {
#[serde(alias = "view_mode")]
pub render_mode: RenderMode,
pub export_format: ExportFormat,
pub hide_artboards: bool,
pub for_export: bool,
pub for_eyedropper: bool,
}
Expand Down
2 changes: 1 addition & 1 deletion node-graph/libraries/graphic-types/src/artboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Artboard {
location: location.min(location + dimensions),
dimensions: dimensions.abs(),
background: Color::WHITE,
clip: false,
clip: true,
}
}
}
Expand Down
Loading
Loading