mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 03:18:06 +08:00
Implement animation export
This commit is contained in:
@@ -31,6 +31,15 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
|
||||
SaveFileDialogContext::File { content } => {
|
||||
dispatcher.respond(DesktopFrontendMessage::WriteFile { path, content });
|
||||
}
|
||||
SaveFileDialogContext::MultipleFiles { files } => {
|
||||
// Treat the chosen path as the folder name; strip any extension the user typed (e.g. "MyAnim.png" → "MyAnim").
|
||||
// The `WriteFile` handler creates parent directories if they don't exist, so the folder is materialized on first write.
|
||||
let folder = path.with_extension("");
|
||||
for (filename, content) in files {
|
||||
let file_path = folder.join(&filename);
|
||||
dispatcher.respond(DesktopFrontendMessage::WriteFile { path: file_path, content });
|
||||
}
|
||||
}
|
||||
},
|
||||
DesktopWrapperMessage::OpenFile { path, content } => {
|
||||
let message = PortfolioMessage::OpenFile { path, content };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use graphite_editor::messages::frontend::utility_types::ExportAnimationFrame;
|
||||
#[cfg(target_os = "macos")]
|
||||
use graphite_editor::messages::layout::utility_types::layout_widget::LayoutTarget;
|
||||
use graphite_editor::messages::prelude::FrontendMessage;
|
||||
@@ -59,6 +60,52 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
|
||||
context: SaveFileDialogContext::File { content },
|
||||
});
|
||||
}
|
||||
FrontendMessage::TriggerExportAnimation {
|
||||
name,
|
||||
extension,
|
||||
mime,
|
||||
size,
|
||||
folder,
|
||||
frames,
|
||||
} => {
|
||||
// Materialize each frame to bytes; SVG strings are encoded as UTF-8.
|
||||
// Raster-needs-canvas-rasterize frames can't be encoded here without a Rust SVG rasterizer,
|
||||
// so fall through to the frontend zip path in that case.
|
||||
let mut needs_frontend_rasterization = false;
|
||||
let mut materialized = Vec::with_capacity(frames.len());
|
||||
for (index, frame) in frames.iter().enumerate() {
|
||||
let filename = format!("{name}_{:04}.{extension}", index + 1);
|
||||
let bytes = match frame {
|
||||
ExportAnimationFrame::Svg(svg) if extension == "svg" => svg.as_bytes().to_vec(),
|
||||
ExportAnimationFrame::Bytes(bytes) => bytes.to_vec(),
|
||||
ExportAnimationFrame::Svg(_) => {
|
||||
needs_frontend_rasterization = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
materialized.push((filename, bytes));
|
||||
}
|
||||
|
||||
if needs_frontend_rasterization {
|
||||
return Some(FrontendMessage::TriggerExportAnimation {
|
||||
name,
|
||||
extension,
|
||||
mime,
|
||||
size,
|
||||
folder,
|
||||
frames,
|
||||
});
|
||||
}
|
||||
|
||||
// The dialog name is the folder the frames go into (analogous to the .zip on web).
|
||||
dispatcher.respond(DesktopFrontendMessage::SaveFileDialog {
|
||||
title: "Save Animation Frames Folder As".to_string(),
|
||||
default_filename: name.clone(),
|
||||
default_folder: folder,
|
||||
filters: Vec::new(),
|
||||
context: SaveFileDialogContext::MultipleFiles { files: materialized },
|
||||
});
|
||||
}
|
||||
FrontendMessage::TriggerVisitLink { url } => {
|
||||
dispatcher.respond(DesktopFrontendMessage::OpenUrl(url));
|
||||
}
|
||||
|
||||
@@ -111,8 +111,19 @@ pub enum OpenFileDialogContext {
|
||||
}
|
||||
|
||||
pub enum SaveFileDialogContext {
|
||||
Document { document_id: DocumentId, content: Vec<u8> },
|
||||
File { content: Vec<u8> },
|
||||
Document {
|
||||
document_id: DocumentId,
|
||||
content: Vec<u8>,
|
||||
},
|
||||
File {
|
||||
content: Vec<u8>,
|
||||
},
|
||||
/// Multiple files written into a folder whose path is the user-chosen path with any extension stripped
|
||||
/// (e.g. picking `MyAnim.png` yields a `MyAnim/` folder). Each `(filename, content)` entry is written
|
||||
/// inside that folder, which is created if it doesn't exist.
|
||||
MultipleFiles {
|
||||
files: Vec<(String, Vec<u8>)>,
|
||||
},
|
||||
}
|
||||
|
||||
pub enum MenuItem {
|
||||
|
||||
Reference in New Issue
Block a user