@@ -17,12 +17,16 @@ use editor::messages::prelude::*;
1717use editor:: messages:: tool:: tool_messages:: tool_prelude:: WidgetId ;
1818use graph_craft:: document:: NodeId ;
1919use graphene_std:: raster:: color:: Color ;
20+ use graphene_std:: raster:: { Image , TransformImage } ;
21+ use js_sys:: { Object , Reflect } ;
2022use serde:: Serialize ;
2123use serde_wasm_bindgen:: { self , from_value} ;
2224use std:: cell:: RefCell ;
2325use std:: sync:: atomic:: Ordering ;
2426use std:: time:: Duration ;
27+ use wasm_bindgen:: JsCast ;
2528use wasm_bindgen:: prelude:: * ;
29+ use web_sys:: { CanvasRenderingContext2d , HtmlCanvasElement , ImageData , window} ;
2630
2731/// Set the random seed used by the editor by calling this from JS upon initialization.
2832/// This is necessary because WASM doesn't have a random number generator.
@@ -37,6 +41,73 @@ pub fn wasm_memory() -> JsValue {
3741 wasm_bindgen:: memory ( )
3842}
3943
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+
40111// ============================================================================
41112
42113/// 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 {
88159
89160 // Sends a FrontendMessage to JavaScript
90161 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+
91167 if let FrontendMessage :: UpdateDocumentLayerStructure { data_buffer } = message {
92168 message = FrontendMessage :: UpdateDocumentLayerStructureJs { data_buffer : data_buffer. into ( ) } ;
93169 }
0 commit comments