Add checkbox for a transparent BG when exporting image (#1344)

This commit is contained in:
Keavon Chambers
2023-07-30 10:57:07 -07:00
committed by GitHub
parent 1fc3808b7f
commit f151ba39b5
4 changed files with 41 additions and 9 deletions
@@ -9,6 +9,7 @@ pub enum ExportDialogMessage {
FileName(String), FileName(String),
FileType(FileType), FileType(FileType),
ScaleFactor(f64), ScaleFactor(f64),
TransparentBackground(bool),
ExportBounds(ExportBounds), ExportBounds(ExportBounds),
Submit, Submit,
@@ -2,7 +2,7 @@ use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout}; use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
use crate::messages::layout::utility_types::misc::LayoutTarget; use crate::messages::layout::utility_types::misc::LayoutTarget;
use crate::messages::layout::utility_types::widgets::button_widgets::TextButton; use crate::messages::layout::utility_types::widgets::button_widgets::TextButton;
use crate::messages::layout::utility_types::widgets::input_widgets::{DropdownEntryData, DropdownInput, NumberInput, RadioEntryData, RadioInput, TextInput}; use crate::messages::layout::utility_types::widgets::input_widgets::{CheckboxInput, DropdownEntryData, DropdownInput, NumberInput, RadioEntryData, RadioInput, TextInput};
use crate::messages::layout::utility_types::widgets::label_widgets::{Separator, SeparatorDirection, SeparatorType, TextLabel}; use crate::messages::layout::utility_types::widgets::label_widgets::{Separator, SeparatorDirection, SeparatorType, TextLabel};
use crate::messages::prelude::*; use crate::messages::prelude::*;
@@ -15,6 +15,7 @@ pub struct ExportDialogMessageHandler {
pub file_type: FileType, pub file_type: FileType,
pub scale_factor: f64, pub scale_factor: f64,
pub bounds: ExportBounds, pub bounds: ExportBounds,
pub transparent_background: bool,
pub artboards: HashMap<LayerId, String>, pub artboards: HashMap<LayerId, String>,
pub has_selection: bool, pub has_selection: bool,
} }
@@ -24,7 +25,8 @@ impl MessageHandler<ExportDialogMessage, ()> for ExportDialogMessageHandler {
match message { match message {
ExportDialogMessage::FileName(name) => self.file_name = name, ExportDialogMessage::FileName(name) => self.file_name = name,
ExportDialogMessage::FileType(export_type) => self.file_type = export_type, ExportDialogMessage::FileType(export_type) => self.file_type = export_type,
ExportDialogMessage::ScaleFactor(x) => self.scale_factor = x, ExportDialogMessage::ScaleFactor(factor) => self.scale_factor = factor,
ExportDialogMessage::TransparentBackground(transparent_background) => self.transparent_background = transparent_background,
ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area, ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area,
ExportDialogMessage::Submit => responses.add_front(DocumentMessage::ExportDocument { ExportDialogMessage::Submit => responses.add_front(DocumentMessage::ExportDocument {
@@ -32,6 +34,7 @@ impl MessageHandler<ExportDialogMessage, ()> for ExportDialogMessageHandler {
file_type: self.file_type, file_type: self.file_type,
scale_factor: self.scale_factor, scale_factor: self.scale_factor,
bounds: self.bounds, bounds: self.bounds,
transparent_background: self.file_type != FileType::Jpg && self.transparent_background,
}), }),
} }
@@ -120,6 +123,24 @@ impl PropertyHolder for ExportDialogMessageHandler {
})), })),
]; ];
let transparent_background = vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Transparency".into(),
table_align: true,
..Default::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Unrelated,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::CheckboxInput(CheckboxInput {
checked: self.transparent_background,
disabled: self.file_type == FileType::Jpg,
on_update: WidgetCallback::new(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground(value.checked).into()),
..Default::default()
})),
];
let resolution = vec![ let resolution = vec![
WidgetHolder::new(Widget::TextLabel(TextLabel { WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Scale Factor".into(), value: "Scale Factor".into(),
@@ -174,6 +195,7 @@ impl PropertyHolder for ExportDialogMessageHandler {
LayoutGroup::Row { widgets: export_type }, LayoutGroup::Row { widgets: export_type },
LayoutGroup::Row { widgets: resolution }, LayoutGroup::Row { widgets: resolution },
LayoutGroup::Row { widgets: export_area }, LayoutGroup::Row { widgets: export_area },
LayoutGroup::Row { widgets: transparent_background },
LayoutGroup::Row { widgets: button_widgets }, LayoutGroup::Row { widgets: button_widgets },
])) ]))
} }
@@ -82,6 +82,7 @@ pub enum DocumentMessage {
file_type: FileType, file_type: FileType,
scale_factor: f64, scale_factor: f64,
bounds: ExportBounds, bounds: ExportBounds,
transparent_background: bool,
}, },
FlipSelectedLayers { FlipSelectedLayers {
flip_axis: FlipAxis, flip_axis: FlipAxis,
@@ -370,6 +370,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
file_type, file_type,
scale_factor, scale_factor,
bounds, bounds,
transparent_background,
} => { } => {
let old_transforms = self.remove_document_transform(); let old_transforms = self.remove_document_transform();
@@ -383,7 +384,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
let size = bounds[1] - bounds[0]; let size = bounds[1] - bounds[0];
let transform = (DAffine2::from_translation(bounds[0]) * DAffine2::from_scale(size)).inverse(); let transform = (DAffine2::from_translation(bounds[0]) * DAffine2::from_scale(size)).inverse();
let document = self.render_document(size, transform, persistent_data, DocumentRenderMode::Root); let document = self.render_document(size, transform, transparent_background, persistent_data, DocumentRenderMode::Root);
self.restore_document_transform(old_transforms); self.restore_document_transform(old_transforms);
@@ -1011,7 +1012,8 @@ impl DocumentMessageHandler {
// Calculate the size of the region to be exported and generate an SVG of the artwork below this layer within that region // Calculate the size of the region to be exported and generate an SVG of the artwork below this layer within that region
let transform = self.document_legacy.multiply_transforms(&layer_path).unwrap(); let transform = self.document_legacy.multiply_transforms(&layer_path).unwrap();
let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length()); let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
let svg = self.render_document(size, transform.inverse(), persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path)); // TODO: Test if this would be better to have a transparent background
let svg = self.render_document(size, transform.inverse(), false, persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path));
self.restore_document_transform(old_transforms); self.restore_document_transform(old_transforms);
@@ -1053,7 +1055,7 @@ impl DocumentMessageHandler {
DocumentLegacy::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_document.root); DocumentLegacy::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_document.root);
} }
pub fn render_document(&mut self, size: DVec2, transform: DAffine2, persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String { 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 // Render the document SVG code
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None); let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None);
@@ -1063,20 +1065,26 @@ impl DocumentMessageHandler {
DocumentRenderMode::OnlyBelowLayerInFolder(below_layer_path) => (self.document_legacy.render_layers_below(below_layer_path, &render_data).unwrap(), 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)), DocumentRenderMode::LayerCutout(layer_path, background) => (self.document_legacy.render_layer(layer_path, &render_data).unwrap(), Some(background)),
}; };
let artboards = self.artboard_message_handler.artboards_document.render_root(&render_data); let artboards = match transparent_background {
false => self.artboard_message_handler.artboards_document.render_root(&render_data),
true => "".into(),
};
let outside_artboards_color = outside.map_or_else( let outside_artboards_color = outside.map_or_else(
|| if self.artboard_message_handler.artboard_ids.is_empty() { "ffffff" } else { "222222" }.to_string(), || if self.artboard_message_handler.artboard_ids.is_empty() { "ffffff" } else { "222222" }.to_string(),
|col| col.rgba_hex(), |col| col.rgba_hex(),
); );
let outside_artboards = format!(r##"<rect x="0" y="0" width="100%" height="100%" fill="#{}" />"##, outside_artboards_color); let outside_artboards = match transparent_background {
false => format!(r##"<rect x="0" y="0" width="100%" height="100%" fill="#{}" />"##, outside_artboards_color),
true => "".into(),
};
let matrix = transform let matrix = transform
.to_cols_array() .to_cols_array()
.iter() .iter()
.enumerate() .enumerate()
.fold(String::new(), |acc, (i, entry)| acc + &(entry.to_string() + if i == 5 { "" } else { "," })); .fold(String::new(), |acc, (i, entry)| acc + &(entry.to_string() + if i == 5 { "" } else { "," }));
let svg = format!( let svg = format!(
r#"<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1 1" width="{}" height="{}">{}{}<g transform="matrix({})">{}{}</g></svg>"#, r#"<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1 1" width="{}" height="{}">{}{outside_artboards}<g transform="matrix({matrix})">{artboards}{artwork}</g></svg>"#,
size.x, size.y, "\n", outside_artboards, matrix, artboards, artwork size.x, size.y, "\n",
); );
svg svg