@@ -190,14 +190,20 @@ impl NodeGraphExecutor {
190
190
let size = bounds[ 1 ] - bounds[ 0 ] ;
191
191
let transform = DAffine2 :: from_translation ( bounds[ 0 ] ) . inverse ( ) ;
192
192
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
+
193
199
let render_config = RenderConfig {
194
200
viewport : Footprint {
195
201
transform : DAffine2 :: from_scale ( DVec2 :: splat ( export_config. scale_factor ) ) * transform,
196
202
resolution : ( size * export_config. scale_factor ) . as_uvec2 ( ) ,
197
203
..Default :: default ( )
198
204
} ,
199
205
time : Default :: default ( ) ,
200
- export_format : graphene_std :: application_io :: ExportFormat :: Svg ,
206
+ export_format,
201
207
render_mode : document. render_mode ,
202
208
hide_artboards : export_config. transparent_background ,
203
209
for_export : true ,
@@ -219,28 +225,81 @@ impl NodeGraphExecutor {
219
225
}
220
226
221
227
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,
224
235
..
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" ,
228
242
} ;
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
+ } ;
229
269
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) ;
233
272
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
+ }
236
296
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
+ } ;
244
303
245
304
Ok ( ( ) )
246
305
}
0 commit comments