mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 15:38:12 +08:00
Add checkbox for a transparent BG when exporting image (#1344)
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user