@@ -17,12 +17,16 @@ use editor::messages::prelude::*;
17
17
use editor:: messages:: tool:: tool_messages:: tool_prelude:: WidgetId ;
18
18
use graph_craft:: document:: NodeId ;
19
19
use graphene_std:: raster:: color:: Color ;
20
+ use graphene_std:: raster:: { Image , TransformImage } ;
21
+ use js_sys:: { Object , Reflect } ;
20
22
use serde:: Serialize ;
21
23
use serde_wasm_bindgen:: { self , from_value} ;
22
24
use std:: cell:: RefCell ;
23
25
use std:: sync:: atomic:: Ordering ;
24
26
use std:: time:: Duration ;
27
+ use wasm_bindgen:: JsCast ;
25
28
use wasm_bindgen:: prelude:: * ;
29
+ use web_sys:: { CanvasRenderingContext2d , HtmlCanvasElement , ImageData , window} ;
26
30
27
31
/// Set the random seed used by the editor by calling this from JS upon initialization.
28
32
/// This is necessary because WASM doesn't have a random number generator.
@@ -37,6 +41,73 @@ pub fn wasm_memory() -> JsValue {
37
41
wasm_bindgen:: memory ( )
38
42
}
39
43
44
+ fn render_image_data_to_canvases ( image_data : & [ ( u64 , Image < Color > , TransformImage ) ] ) {
45
+ let window = match window ( ) {
46
+ Some ( window) => window,
47
+ None => {
48
+ error ! ( "Cannot render canvas: window object not found" ) ;
49
+ return ;
50
+ }
51
+ } ;
52
+ let document = window. document ( ) . expect ( "window should have a document" ) ;
53
+ let window_obj = Object :: from ( window) ;
54
+ let image_canvases_key = JsValue :: from_str ( "imageCanvases" ) ;
55
+
56
+ let canvases_obj = match Reflect :: get ( & window_obj, & image_canvases_key) {
57
+ Ok ( obj) if !obj. is_undefined ( ) && !obj. is_null ( ) => obj,
58
+ _ => {
59
+ let new_obj = Object :: new ( ) ;
60
+ if Reflect :: set ( & window_obj, & image_canvases_key, & new_obj) . is_err ( ) {
61
+ error ! ( "Failed to create and set imageCanvases object on window" ) ;
62
+ return ;
63
+ }
64
+ new_obj. into ( )
65
+ }
66
+ } ;
67
+ let canvases_obj = Object :: from ( canvases_obj) ;
68
+
69
+ for ( placeholder_id, image, _) in image_data. iter ( ) {
70
+ if image. width == 0 || image. height == 0 {
71
+ continue ;
72
+ }
73
+
74
+ let canvas: HtmlCanvasElement = document
75
+ . create_element ( "canvas" )
76
+ . expect ( "Failed to create canvas element" )
77
+ . dyn_into :: < HtmlCanvasElement > ( )
78
+ . expect ( "Failed to cast element to HtmlCanvasElement" ) ;
79
+
80
+ canvas. set_width ( 1 ) ;
81
+ canvas. set_height ( 1 ) ;
82
+ let context: CanvasRenderingContext2d = canvas
83
+ . get_context ( "2d" )
84
+ . expect ( "Failed to get 2d context" )
85
+ . expect ( "2d context was not found" )
86
+ . dyn_into :: < CanvasRenderingContext2d > ( )
87
+ . expect ( "Failed to cast context to CanvasRenderingContext2d" ) ;
88
+ let u8_data: Vec < u8 > = image. data . iter ( ) . flat_map ( |color| color. to_rgba8_srgb ( ) ) . collect ( ) ;
89
+ let clamped_u8_data = wasm_bindgen:: Clamped ( & u8_data[ ..] ) ;
90
+ match ImageData :: new_with_u8_clamped_array_and_sh ( clamped_u8_data, image. width , image. height ) {
91
+ Ok ( image_data_obj) => {
92
+ if context. put_image_data ( & image_data_obj, 0.0 , 0.0 ) . is_err ( ) {
93
+ error ! ( "Failed to put image data on canvas for id: {}" , placeholder_id) ;
94
+ }
95
+ }
96
+ Err ( e) => {
97
+ error ! ( "Failed to create ImageData for id: {}: {:?}" , placeholder_id, e) ;
98
+ }
99
+ }
100
+
101
+ let canvas_name = format ! ( "canvas{}" , placeholder_id) ;
102
+ let js_key = JsValue :: from_str ( & canvas_name) ;
103
+ let js_value = JsValue :: from ( canvas) ;
104
+
105
+ if Reflect :: set ( & canvases_obj, & js_key, & js_value) . is_err ( ) {
106
+ error ! ( "Failed to set canvas '{}' on imageCanvases object" , canvas_name) ;
107
+ }
108
+ }
109
+ }
110
+
40
111
// ============================================================================
41
112
42
113
/// This struct is, via wasm-bindgen, used by JS to interact with the editor backend. It does this by calling functions, which are `impl`ed
@@ -88,6 +159,11 @@ impl EditorHandle {
88
159
89
160
// Sends a FrontendMessage to JavaScript
90
161
fn send_frontend_message_to_js ( & self , mut message : FrontendMessage ) {
162
+ if let FrontendMessage :: UpdateImageData { ref image_data } = message {
163
+ render_image_data_to_canvases ( image_data. as_slice ( ) ) ;
164
+ return ;
165
+ }
166
+
91
167
if let FrontendMessage :: UpdateDocumentLayerStructure { data_buffer } = message {
92
168
message = FrontendMessage :: UpdateDocumentLayerStructureJs { data_buffer : data_buffer. into ( ) } ;
93
169
}
0 commit comments