@@ -190,14 +190,20 @@ impl NodeGraphExecutor {
190190 let size = bounds[ 1 ] - bounds[ 0 ] ;
191191 let transform = DAffine2 :: from_translation ( bounds[ 0 ] ) . inverse ( ) ;
192192
193+ let export_format = if export_config. file_type == FileType :: Svg || cfg ! ( not( feature = "gpu" ) ) {
194+ graphene_std:: application_io:: ExportFormat :: Svg
195+ } else {
196+ graphene_std:: application_io:: ExportFormat :: Texture
197+ } ;
198+
193199 let render_config = RenderConfig {
194200 viewport : Footprint {
195201 transform : DAffine2 :: from_scale ( DVec2 :: splat ( export_config. scale_factor ) ) * transform,
196202 resolution : ( size * export_config. scale_factor ) . as_uvec2 ( ) ,
197203 ..Default :: default ( )
198204 } ,
199205 time : Default :: default ( ) ,
200- export_format : graphene_std :: application_io :: ExportFormat :: Svg ,
206+ export_format,
201207 render_mode : document. render_mode ,
202208 hide_artboards : export_config. transparent_background ,
203209 for_export : true ,
@@ -219,28 +225,81 @@ impl NodeGraphExecutor {
219225 }
220226
221227 fn export ( & self , node_graph_output : TaggedValue , export_config : ExportConfig , responses : & mut VecDeque < Message > ) -> Result < ( ) , String > {
222- let TaggedValue :: RenderOutput ( RenderOutput {
223- data : RenderOutputType :: Svg { svg, .. } ,
228+ let ExportConfig {
229+ file_type,
230+ name,
231+ size,
232+ scale_factor,
233+ #[ cfg( feature = "gpu" ) ]
234+ transparent_background,
224235 ..
225- } ) = node_graph_output
226- else {
227- return Err ( "Incorrect render type for exporting (expected RenderOutput::Svg)" . to_string ( ) ) ;
236+ } = export_config;
237+
238+ let file_extension = match file_type {
239+ FileType :: Svg => "svg" ,
240+ FileType :: Png => "png" ,
241+ FileType :: Jpg => "jpg" ,
228242 } ;
243+ let name = format ! ( "{name}.{file_extension}" ) ;
244+
245+ match node_graph_output {
246+ TaggedValue :: RenderOutput ( RenderOutput {
247+ data : RenderOutputType :: Svg { svg, .. } ,
248+ ..
249+ } ) => {
250+ if file_type == FileType :: Svg {
251+ responses. add ( FrontendMessage :: TriggerSaveFile { name, content : svg. into_bytes ( ) } ) ;
252+ } else {
253+ let mime = file_type. to_mime ( ) . to_string ( ) ;
254+ let size = ( size * scale_factor) . into ( ) ;
255+ responses. add ( FrontendMessage :: TriggerExportImage { svg, name, mime, size } ) ;
256+ }
257+ }
258+ #[ cfg( feature = "gpu" ) ]
259+ TaggedValue :: RenderOutput ( RenderOutput {
260+ data : RenderOutputType :: Buffer { data, width, height } ,
261+ ..
262+ } ) if file_type != FileType :: Svg => {
263+ use image:: buffer:: ConvertBuffer ;
264+ use image:: { ImageFormat , RgbImage , RgbaImage } ;
265+
266+ let Some ( image) = RgbaImage :: from_raw ( width, height, data) else {
267+ return Err ( format ! ( "Failed to create image buffer for export" ) ) ;
268+ } ;
229269
230- let ExportConfig {
231- file_type, name, size, scale_factor, ..
232- } = export_config;
270+ let mut encoded = Vec :: new ( ) ;
271+ let mut cursor = std:: io:: Cursor :: new ( & mut encoded) ;
233272
234- let file_suffix = & format ! ( ".{file_type:?}" ) . to_lowercase ( ) ;
235- let name = name + file_suffix;
273+ match file_type {
274+ FileType :: Png => {
275+ let result = if transparent_background {
276+ image. write_to ( & mut cursor, ImageFormat :: Png )
277+ } else {
278+ let image: RgbImage = image. convert ( ) ;
279+ image. write_to ( & mut cursor, ImageFormat :: Png )
280+ } ;
281+ if let Err ( err) = result {
282+ return Err ( format ! ( "Failed to encode PNG: {err}" ) ) ;
283+ }
284+ }
285+ FileType :: Jpg => {
286+ let image: RgbImage = image. convert ( ) ;
287+ let result = image. write_to ( & mut cursor, ImageFormat :: Jpeg ) ;
288+ if let Err ( err) = result {
289+ return Err ( format ! ( "Failed to encode JPG: {err}" ) ) ;
290+ }
291+ }
292+ FileType :: Svg => {
293+ return Err ( format ! ( "SVG cannot be exported from an image buffer" ) ) ;
294+ }
295+ }
236296
237- if file_type == FileType :: Svg {
238- responses. add ( FrontendMessage :: TriggerSaveFile { name, content : svg. into_bytes ( ) } ) ;
239- } else {
240- let mime = file_type. to_mime ( ) . to_string ( ) ;
241- let size = ( size * scale_factor) . into ( ) ;
242- responses. add ( FrontendMessage :: TriggerExportImage { svg, name, mime, size } ) ;
243- }
297+ responses. add ( FrontendMessage :: TriggerSaveFile { name, content : encoded } ) ;
298+ }
299+ _ => {
300+ return Err ( format ! ( "Incorrect render type for exporting to an SVG ({file_type:?}, {node_graph_output})" ) ) ;
301+ }
302+ } ;
244303
245304 Ok ( ( ) )
246305 }
0 commit comments