stanley commited on
Commit
6baf100
·
1 Parent(s): e27bb44

updated toolbar, gradio elements, ui

Browse files
Files changed (4) hide show
  1. app.py +20 -16
  2. index.html +59 -2
  3. js/setup.js +5 -1
  4. js/toolbar.js +662 -569
app.py CHANGED
@@ -969,26 +969,30 @@ margin-bottom: 0rem;
969
  #markdown {
970
  min-height: 0rem;
971
  }
 
 
 
 
972
  """,
973
  theme=gr.themes.Soft()
974
  )
975
  model_path_input_val = ""
976
  with blocks as demo:
977
- # title
978
- title = gr.Markdown(
979
- """
980
- stanley capstone
981
- """,
982
- elem_id="markdown",
983
- )
984
- # github logo
985
- github_logo = gr.HTML(
986
- """
987
- <a href="https://github.com/stanleywalker1/capstone-studio-2">
988
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" fill="white"/></svg>
989
- </a>
990
- """
991
- )
992
  # frame
993
  frame = gr.HTML(test(2), visible=RUN_IN_SPACE)
994
  # setup
@@ -1008,7 +1012,7 @@ with blocks as demo:
1008
  sd_prompt = gr.Textbox(
1009
  label="Prompt", placeholder="input your prompt here!", lines=2
1010
  )
1011
- with gr.Accordion("developer tools", open=True):
1012
  with gr.Row(elem_id="setup_row"):
1013
  with gr.Column(scale=4, min_width=350):
1014
  token = gr.Textbox(
 
969
  #markdown {
970
  min-height: 0rem;
971
  }
972
+ .contain {
973
+ display: flex;
974
+ align-items: center;
975
+ }
976
  """,
977
  theme=gr.themes.Soft()
978
  )
979
  model_path_input_val = ""
980
  with blocks as demo:
981
+ # # title
982
+ # title = gr.Markdown(
983
+ # """
984
+ # stanley capstone
985
+ # """,
986
+ # elem_id="markdown",
987
+ # )
988
+ # # github logo
989
+ # github_logo = gr.HTML(
990
+ # """
991
+ # <a href="https://github.com/stanleywalker1/capstone-studio-2">
992
+ # <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" fill="white"/></svg>
993
+ # </a>
994
+ # """
995
+ # )
996
  # frame
997
  frame = gr.HTML(test(2), visible=RUN_IN_SPACE)
998
  # setup
 
1012
  sd_prompt = gr.Textbox(
1013
  label="Prompt", placeholder="input your prompt here!", lines=2
1014
  )
1015
+ with gr.Accordion("developer tools", open=False):
1016
  with gr.Row(elem_id="setup_row"):
1017
  with gr.Column(scale=4, min_width=350):
1018
  token = gr.Textbox(
index.html CHANGED
@@ -751,10 +751,69 @@ async def draw_canvas() -> None:
751
  # window.parent.postMessage({ type: "displayLatestImageOnCanvas", image: latest_image }, "*")
752
  # else:
753
  # print("No latest image found in Firebase.")
 
754
 
755
 
 
756
  async def draw_canvas_func(event):
757
  alert("draw_canvas gradio called")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
  try:
759
  app=parent.document.querySelector("gradio-app")
760
  if app.shadowRoot:
@@ -783,8 +842,6 @@ async def draw_canvas_func(event):
783
  canvas.draw_buffer()
784
  canvas.draw_selection_box()
785
 
786
- # await canvas.load_image(image_data)
787
-
788
 
789
  # Update the canvas buffer with the new image data and redraw the buffer
790
  h, w, c = canvas.buffer.shape
 
751
  # window.parent.postMessage({ type: "displayLatestImageOnCanvas", image: latest_image }, "*")
752
  # else:
753
  # print("No latest image found in Firebase.")
754
+ from PIL import ImageOps
755
 
756
 
757
+ # new draw_canvas scale method
758
  async def draw_canvas_func(event):
759
  alert("draw_canvas gradio called")
760
+
761
+ database_url = "https://nyucapstone-7c22c-default-rtdb.firebaseio.com"
762
+ image_data, latest_image_name = await fetch_latest_image_url(database_url)
763
+ pil_image = Image.open(io.BytesIO(image_data.to_py()))
764
+
765
+ np_image = np.array(pil_image)
766
+
767
+ # Get the dimensions of the input image
768
+ img_height, img_width, _ = np_image.shape
769
+
770
+ # Set the desired display dimensions
771
+ display_width = 1024
772
+ display_height = 768
773
+
774
+ # Calculate the zoom level based on the input image dimensions and the desired display dimensions
775
+ zoom_level = min(display_width / img_width, display_height / img_height)
776
+
777
+ # Pad the input image to fit the canvas buffer while maintaining the aspect ratio
778
+ padded_image = ImageOps.pad(pil_image, (int(display_width), int(display_height)), Image.ANTIALIAS, color=(0, 0, 0, 0))
779
+ padded_np_image = np.array(padded_image)
780
+
781
+ # Set the canvas dimensions to match the desired display dimensions
782
+ width = display_width
783
+ height = display_height
784
+ selection_size = min(width, height) // 2
785
+
786
+ document.querySelector("#container").style.width = f"{width}px"
787
+ document.querySelector("#container").style.height = f"{height}px"
788
+
789
+ canvas = InfCanvas(int(width), int(height), selection_size=int(selection_size), firebase_image_data=padded_np_image)
790
+
791
+ canvas.setup_mouse()
792
+ canvas.clear_background()
793
+ canvas.draw_buffer()
794
+ canvas.draw_selection_box()
795
+
796
+ # Update the canvas buffer with the padded image data and redraw the buffer
797
+ h, w, c = canvas.buffer.shape
798
+ canvas.sync_to_buffer()
799
+ canvas.buffer_dirty = True
800
+
801
+ # Create a mask using the padded image shape
802
+ mask = padded_np_image[:, :, 3:4].repeat(4, axis=2)
803
+ canvas.buffer[mask > 0] = 0
804
+ canvas.buffer[:height, :width] += padded_np_image
805
+
806
+ canvas.draw_buffer()
807
+
808
+ base_lst[0] = canvas
809
+
810
+ alert("made it to end of draw_canvas gradio")
811
+
812
+
813
+
814
+ # original draw_canvas
815
+ async def test_canvas_func(event):
816
+ alert("draw_canvas gradio called")
817
  try:
818
  app=parent.document.querySelector("gradio-app")
819
  if app.shadowRoot:
 
842
  canvas.draw_buffer()
843
  canvas.draw_selection_box()
844
 
 
 
845
 
846
  # Update the canvas buffer with the new image data and redraw the buffer
847
  h, w, c = canvas.buffer.shape
js/setup.js CHANGED
@@ -3,7 +3,11 @@ function(token_val, width, height, size, model_choice, model_path){
3
  app=app.shadowRoot??app;
4
  app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
5
  // app.querySelector("#setup_row").style.display="none";
6
- app.querySelector("#model_path_input").style.display="none";
 
 
 
 
7
  let frame=app.querySelector("#sdinfframe").contentWindow.document;
8
 
9
  if(frame.querySelector("#setup").value=="0")
 
3
  app=app.shadowRoot??app;
4
  app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
5
  // app.querySelector("#setup_row").style.display="none";
6
+ // app.querySelector("#model_path_input").style.display="none";
7
+ let modelPathInput = app.querySelector("#model_path_input");
8
+ if (modelPathInput) {
9
+ modelPathInput.style.display = "none";
10
+ }
11
  let frame=app.querySelector("#sdinfframe").contentWindow.document;
12
 
13
  if(frame.querySelector("#setup").value=="0")
js/toolbar.js CHANGED
@@ -2,580 +2,673 @@
2
  // import { w2ui,w2toolbar,w2field,query,w2alert, w2utils,w2confirm} from "https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js"
3
 
4
  // https://stackoverflow.com/questions/36280818/how-to-convert-file-to-base64-in-javascript
5
- function getBase64(file) {
6
- var reader = new FileReader();
7
- reader.readAsDataURL(file);
8
- reader.onload = function () {
9
- add_image(reader.result);
10
- // console.log(reader.result);
11
- };
12
- reader.onerror = function (error) {
13
- console.log("Error: ", error);
14
- };
15
- }
16
-
17
- function getText(file) {
18
- var reader = new FileReader();
19
- reader.readAsText(file);
20
- reader.onload = function () {
21
- window.postMessage(["load",reader.result],"*")
22
- // console.log(reader.result);
23
- };
24
- reader.onerror = function (error) {
25
- console.log("Error: ", error);
26
- };
27
- }
28
-
29
- document.querySelector("#upload_file").addEventListener("change", (event)=>{
30
- console.log(event);
31
- let file = document.querySelector("#upload_file").files[0];
32
- getBase64(file);
33
- })
34
 
35
- document.querySelector("#upload_state").addEventListener("change", (event)=>{
36
- console.log(event);
37
- let file = document.querySelector("#upload_state").files[0];
38
- getText(file);
39
- })
40
-
41
- open_setting = function() {
42
- if (!w2ui.foo) {
43
- new w2form({
44
- name: "foo",
45
- style: "border: 0px; background-color: transparent;",
46
- fields: [{
47
- field: "canvas_width",
48
- type: "int",
49
- required: true,
50
- html: {
51
- label: "Canvas Width"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
  },
54
- {
55
- field: "canvas_height",
56
- type: "int",
57
- required: true,
58
- html: {
59
- label: "Canvas Height"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
  },
62
- ],
63
- record: {
64
- canvas_width: 1200,
65
- canvas_height: 600,
66
- },
67
- actions: {
68
- Save() {
69
- this.validate();
70
- let record = this.getCleanRecord();
71
- window.postMessage(["resize",record.canvas_width,record.canvas_height],"*");
72
- w2popup.close();
73
- },
74
- custom: {
75
- text: "Cancel",
76
- style: "text-transform: uppercase",
77
- onClick(event) {
78
- w2popup.close();
79
  }
80
- }
81
- }
82
- });
83
- }
84
- w2popup.open({
85
- title: "Form in a Popup",
86
- body: "<div id='form' style='width: 100%; height: 100%;''></div>",
87
- style: "padding: 15px 0px 0px 0px",
88
- width: 500,
89
- height: 280,
90
- showMax: true,
91
- async onToggle(event) {
92
- await event.complete
93
- w2ui.foo.resize();
94
- }
95
- })
96
- .then((event) => {
97
- w2ui.foo.render("#form")
98
- });
99
- }
100
-
101
- var button_lst=["clear", "load", "save", "export", "upload", "selection", "canvas", "eraser", "outpaint", "accept", "cancel", "retry", "prev", "current", "next", "eraser_size_btn", "eraser_size", "resize_selection", "scale", "zoom_in", "zoom_out", "help"];
102
- var upload_button_lst=['clear', 'load', 'save', "upload", 'export', 'outpaint', 'resize_selection', 'help', "setting"];
103
- var resize_button_lst=['clear', 'load', 'save', "upload", 'export', "selection", "canvas", "eraser", 'outpaint', 'resize_selection',"zoom_in", "zoom_out", 'help', "setting"];
104
- var outpaint_button_lst=['clear', 'load', 'save', "canvas", "eraser", "upload", 'export', 'resize_selection', "zoom_in", "zoom_out",'help', "setting"];
105
- var outpaint_result_lst=["accept", "cancel", "retry", "prev", "current", "next"];
106
- var outpaint_result_func_lst=["accept", "retry", "prev", "current", "next"];
107
-
108
- function check_button(id,text="",checked=true,tooltip="")
109
- {
110
- return { type: "check", id: id, text: text, icon: checked?"fa-solid fa-square-check":"fa-regular fa-square", checked: checked, tooltip: tooltip };
111
- }
112
-
113
- var toolbar=new w2toolbar({
114
- box: "#toolbar",
115
- name: "toolbar",
116
- tooltip: "top",
117
- items: [
118
- { type: "button", id: "clear", text: "Reset", tooltip: "Reset Canvas", icon: "fa-solid fa-rectangle-xmark" },
119
- { type: "break" },
120
- { type: "button", id: "load", tooltip: "Load Canvas", icon: "fa-solid fa-file-import" },
121
- { type: "button", id: "save", tooltip: "Save Canvas", icon: "fa-solid fa-file-export" },
122
- { type: "button", id: "export", tooltip: "Export Image", icon: "fa-solid fa-floppy-disk" },
123
- { type: "break" },
124
- { type: "button", id: "upload", text: "Upload Image", icon: "fa-solid fa-upload" },
125
- { type: "break" },
126
- { type: "radio", id: "selection", group: "1", tooltip: "Selection", icon: "fa-solid fa-arrows-up-down-left-right", checked: true },
127
- { type: "radio", id: "canvas", group: "1", tooltip: "Canvas", icon: "fa-solid fa-image" },
128
- { type: "radio", id: "eraser", group: "1", tooltip: "Eraser", icon: "fa-solid fa-eraser" },
129
- { type: "break" },
130
- { type: "button", id: "outpaint", text: "Outpaint", tooltip: "Run Outpainting", icon: "fa-solid fa-brush" },
131
- { type: "break" },
132
- { type: "button", id: "accept", text: "Accept", tooltip: "Accept current result", icon: "fa-solid fa-check", hidden: true, disable:true,},
133
- { type: "button", id: "cancel", text: "Cancel", tooltip: "Cancel current outpainting/error", icon: "fa-solid fa-ban", hidden: true},
134
- { type: "button", id: "retry", text: "Retry", tooltip: "Retry", icon: "fa-solid fa-rotate", hidden: true, disable:true,},
135
- { type: "button", id: "prev", tooltip: "Prev Result", icon: "fa-solid fa-caret-left", hidden: true, disable:true,},
136
- { type: "html", id: "current", hidden: true, disable:true,
137
- async onRefresh(event) {
138
- await event.complete
139
- let fragment = query.html(`
140
- <div class="w2ui-tb-text">
141
- <div class="w2ui-tb-count">
142
- <span>${this.sel_value ?? "1/1"}</span>
143
- </div> </div>`)
144
- query(this.box).find("#tb_toolbar_item_current").append(fragment)
145
- }
146
- },
147
- { type: "button", id: "next", tooltip: "Next Result", icon: "fa-solid fa-caret-right", hidden: true,disable:true,},
148
- { type: "button", id: "add_image", text: "Add Image", icon: "fa-solid fa-file-circle-plus", hidden: true,disable:true,},
149
- { type: "button", id: "delete_image", text: "Delete Image", icon: "fa-solid fa-trash-can", hidden: true,disable:true,},
150
- { type: "button", id: "confirm", text: "Confirm", icon: "fa-solid fa-check", hidden: true,disable:true,},
151
- { type: "button", id: "cancel_overlay", text: "Cancel", icon: "fa-solid fa-ban", hidden: true,disable:true,},
152
- { type: "break" },
153
- { type: "spacer" },
154
- { type: "break" },
155
- { type: "button", id: "eraser_size_btn", tooltip: "Eraser Size", text:"Size", icon: "fa-solid fa-eraser", hidden: true, count: 32},
156
- { type: "html", id: "eraser_size", hidden: true,
157
- async onRefresh(event) {
158
- await event.complete
159
- // let fragment = query.html(`
160
- // <input type="number" size="${this.eraser_size ? this.eraser_size.length:"2"}" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">
161
- // <input type="range" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">`)
162
- let fragment = query.html(`
163
- <input type="range" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">
164
- `)
165
- fragment.filter("input").on("change", event => {
166
- this.eraser_size = event.target.value;
167
- window.overlay.freeDrawingBrush.width=this.eraser_size;
168
- this.setCount("eraser_size_btn", event.target.value);
169
- window.postMessage(["eraser_size", event.target.value],"*")
170
- this.refresh();
171
- })
172
- query(this.box).find("#tb_toolbar_item_eraser_size").append(fragment)
173
- }
174
- },
175
- // { type: "button", id: "resize_eraser", tooltip: "Resize Eraser", icon: "fa-solid fa-sliders" },
176
- { type: "button", id: "resize_selection", text: "Resize Selection", tooltip: "Resize Selection", icon: "fa-solid fa-expand" },
177
- { type: "break" },
178
- { type: "html", id: "scale",
179
- async onRefresh(event) {
180
- await event.complete
181
- let fragment = query.html(`
182
- <div class="">
183
- <div style="padding: 4px; border: 1px solid silver">
184
- <span>${this.scale_value ?? "100%"}</span>
185
- </div></div>`)
186
- query(this.box).find("#tb_toolbar_item_scale").append(fragment)
187
- }
188
- },
189
- { type: "button", id: "zoom_in", tooltip: "Zoom In", icon: "fa-solid fa-magnifying-glass-plus" },
190
- { type: "button", id: "zoom_out", tooltip: "Zoom Out", icon: "fa-solid fa-magnifying-glass-minus" },
191
- { type: "break" },
192
- { type: "button", id: "help", tooltip: "Help", icon: "fa-solid fa-circle-info" },
193
- { type: "new-line"},
194
- { type: "button", id: "setting", text: "Canvas Setting", tooltip: "Resize Canvas Here", icon: "fa-solid fa-sliders" },
195
- { type: "break" },
196
- check_button("enable_img2img","Enable Img2Img",false),
197
- // check_button("use_correction","Photometric Correction",false),
198
- check_button("resize_check","Resize Small Input",true),
199
- check_button("enable_safety","Enable Safety Checker",true),
200
- check_button("square_selection","Square Selection Only",false),
201
- {type: "break"},
202
- check_button("use_seed","Use Seed:",false),
203
- { type: "html", id: "seed_val",
204
- async onRefresh(event) {
205
- await event.complete
206
- let fragment = query.html(`
207
- <input type="number" style="margin: 0px 3px; padding: 4px; width:100px;" value="${this.config_obj.seed_val ?? "0"}">`)
208
- fragment.filter("input").on("change", event => {
209
- this.config_obj.seed_val = event.target.value;
210
- parent.config_obj=this.config_obj;
211
- this.refresh();
212
- })
213
- query(this.box).find("#tb_toolbar_item_seed_val").append(fragment)
214
- }
215
- },
216
- { type: "button", id: "random_seed", tooltip: "Set a random seed", icon: "fa-solid fa-dice" },
217
- ],
218
- onClick(event) {
219
- switch(event.target){
220
- case "setting":
221
- open_setting();
222
- break;
223
- case "upload":
224
- this.upload_mode=true
225
- document.querySelector("#overlay_container").style.pointerEvents="auto";
226
- this.click("canvas");
227
- this.click("selection");
228
- this.show("confirm","cancel_overlay","add_image","delete_image");
229
- this.enable("confirm","cancel_overlay","add_image","delete_image");
230
- this.disable(...upload_button_lst);
231
- query("#upload_file").click();
232
- if(this.upload_tip)
233
- {
234
- this.upload_tip=false;
235
- w2utils.notify("Note that only visible images will be added to canvas",{timeout:10000,where:query("#container")})
236
- }
237
- break;
238
- case "resize_selection":
239
- this.resize_mode=true;
240
- this.disable(...resize_button_lst);
241
- this.enable("confirm","cancel_overlay");
242
- this.show("confirm","cancel_overlay");
243
- window.postMessage(["resize_selection",""],"*");
244
- document.querySelector("#overlay_container").style.pointerEvents="auto";
245
- break;
246
- case "confirm":
247
- if(this.upload_mode)
248
- {
249
- export_image();
250
- }
251
- else
252
- {
253
- let sel_box=this.selection_box;
254
- window.postMessage(["resize_selection",sel_box.x,sel_box.y,sel_box.width,sel_box.height],"*");
255
- }
256
- case "cancel_overlay":
257
- end_overlay();
258
- this.hide("confirm","cancel_overlay","add_image","delete_image");
259
- if(this.upload_mode){
260
- this.enable(...upload_button_lst);
261
- }
262
- else
263
- {
264
- this.enable(...resize_button_lst);
265
- window.postMessage(["resize_selection","",""],"*");
266
- if(event.target=="cancel_overlay")
267
- {
268
- this.selection_box=this.selection_box_bak;
269
- }
270
- }
271
- if(this.selection_box)
272
- {
273
- this.setCount("resize_selection",`${Math.floor(this.selection_box.width/8)*8}x${Math.floor(this.selection_box.height/8)*8}`);
274
- }
275
- this.disable("confirm","cancel_overlay","add_image","delete_image");
276
- this.upload_mode=false;
277
- this.resize_mode=false;
278
- this.click("selection");
279
- break;
280
- case "add_image":
281
- query("#upload_file").click();
282
- break;
283
- case "delete_image":
284
- let active_obj = window.overlay.getActiveObject();
285
- if(active_obj)
286
- {
287
- window.overlay.remove(active_obj);
288
- window.overlay.renderAll();
289
- }
290
- else
291
- {
292
- w2utils.notify("You need to select an image first",{error:true,timeout:2000,where:query("#container")})
293
- }
294
- break;
295
- case "load":
296
- query("#upload_state").click();
297
- this.selection_box=null;
298
- this.setCount("resize_selection","");
299
- break;
300
- case "next":
301
- case "prev":
302
- window.postMessage(["outpaint", "", event.target], "*");
303
- break;
304
- case "outpaint":
305
- this.click("selection");
306
- this.disable(...outpaint_button_lst);
307
- this.show(...outpaint_result_lst);
308
- if(this.outpaint_tip)
309
- {
310
- this.outpaint_tip=false;
311
- w2utils.notify("The canvas stays locked until you accept/cancel current outpainting",{timeout:10000,where:query("#container")})
312
- }
313
- document.querySelector("#container").style.pointerEvents="none";
314
- case "retry":
315
- this.disable(...outpaint_result_func_lst);
316
- window.postMessage(["transfer",""],"*")
317
- break;
318
- case "accept":
319
- case "cancel":
320
- this.hide(...outpaint_result_lst);
321
- this.disable(...outpaint_result_func_lst);
322
- this.enable(...outpaint_button_lst);
323
- document.querySelector("#container").style.pointerEvents="auto";
324
- window.postMessage(["click", event.target],"*");
325
- let app=parent.document.querySelector("gradio-app");
326
- app=app.shadowRoot??app;
327
- app.querySelector("#cancel").click();
328
- break;
329
- case "eraser":
330
- case "selection":
331
- case "canvas":
332
- if(event.target=="eraser")
333
- {
334
- this.show("eraser_size","eraser_size_btn");
335
- window.overlay.freeDrawingBrush.width=this.eraser_size;
336
- window.overlay.isDrawingMode = true;
337
- }
338
- else
339
- {
340
- this.hide("eraser_size","eraser_size_btn");
341
- window.overlay.isDrawingMode = false;
342
- }
343
- if(this.upload_mode)
344
- {
345
- if(event.target=="canvas")
346
- {
347
- window.postMessage(["mode", event.target],"*")
348
- document.querySelector("#overlay_container").style.pointerEvents="none";
349
- document.querySelector("#overlay_container").style.opacity = 0.5;
350
- }
351
- else
352
- {
353
- document.querySelector("#overlay_container").style.pointerEvents="auto";
354
- document.querySelector("#overlay_container").style.opacity = 1.0;
355
  }
356
- }
357
- else
358
- {
359
- window.postMessage(["mode", event.target],"*")
360
- }
361
- break;
362
- case "help":
363
- w2popup.open({
364
- title: "Document",
365
- body: "Usage: <a href='https://github.com/lkwq007/stablediffusion-infinity/blob/master/docs/usage.md' target='_blank'>https://github.com/lkwq007/stablediffusion-infinity/blob/master/docs/usage.md</a>"
366
- })
367
- break;
368
- case "clear":
369
- w2confirm("Reset canvas?").yes(() => {
370
- window.postMessage(["click", event.target],"*");
371
- }).no(() => {})
372
- break;
373
- case "random_seed":
374
- this.config_obj.seed_val=Math.floor(Math.random() * 3000000000);
375
- parent.config_obj=this.config_obj;
376
- this.refresh();
377
- break;
378
- case "enable_img2img":
379
- case "use_correction":
380
- case "resize_check":
381
- case "enable_safety":
382
- case "use_seed":
383
- case "square_selection":
384
- let target=this.get(event.target);
385
- target.icon=target.checked?"fa-regular fa-square":"fa-solid fa-square-check";
386
- this.config_obj[event.target]=!target.checked;
387
- parent.config_obj=this.config_obj;
388
- this.refresh();
389
- break;
390
- case "save":
391
- case "export":
392
- ask_filename(event.target);
393
- break;
394
- default:
395
- // clear, save, export, outpaint, retry
396
- // break, save, export, accept, retry, outpaint
397
- window.postMessage(["click", event.target],"*")
398
- }
399
- console.log("Target: "+ event.target, event)
400
- }
401
- })
402
- window.w2ui=w2ui;
403
- w2ui.toolbar.config_obj={
404
- resize_check: true,
405
- enable_safety: true,
406
- use_correction: false,
407
- enable_img2img: false,
408
- use_seed: false,
409
- seed_val: 0,
410
- square_selection: false,
411
- };
412
- w2ui.toolbar.outpaint_tip=true;
413
- w2ui.toolbar.upload_tip=true;
414
- window.update_count=function(cur,total){
415
- w2ui.toolbar.sel_value=`${cur}/${total}`;
416
- w2ui.toolbar.refresh();
417
- }
418
- window.update_eraser=function(val,max_val){
419
- w2ui.toolbar.eraser_size=`${val}`;
420
- w2ui.toolbar.eraser_max=`${max_val}`;
421
- w2ui.toolbar.setCount("eraser_size_btn", `${val}`);
422
- w2ui.toolbar.refresh();
423
- }
424
- window.update_scale=function(val){
425
- w2ui.toolbar.scale_value=`${val}`;
426
- w2ui.toolbar.refresh();
427
- }
428
- window.enable_result_lst=function(){
429
- w2ui.toolbar.enable(...outpaint_result_lst);
430
- }
431
- function onObjectScaled(e)
432
- {
433
- let object = e.target;
434
- if(object.isType("rect"))
435
- {
436
- let width=object.getScaledWidth();
437
- let height=object.getScaledHeight();
438
- object.scale(1);
439
- width=Math.max(Math.min(width,window.overlay.width-object.left),256);
440
- height=Math.max(Math.min(height,window.overlay.height-object.top),256);
441
- let l=Math.max(Math.min(object.left,window.overlay.width-width-object.strokeWidth),0);
442
- let t=Math.max(Math.min(object.top,window.overlay.height-height-object.strokeWidth),0);
443
- if(window.w2ui.toolbar.config_obj.square_selection)
444
- {
445
- let max_val = Math.min(Math.max(width,height),window.overlay.width,window.overlay.height);
446
- width=max_val;
447
- height=max_val;
448
- }
449
- object.set({ width: width, height: height, left:l,top:t})
450
- window.w2ui.toolbar.selection_box={width: width, height: height, x:object.left, y:object.top};
451
- window.w2ui.toolbar.setCount("resize_selection",`${Math.floor(width/8)*8}x${Math.floor(height/8)*8}`);
452
- window.w2ui.toolbar.refresh();
453
- }
454
- }
455
- function onObjectMoved(e)
456
- {
457
- let object = e.target;
458
- if(object.isType("rect"))
459
- {
460
- let l=Math.max(Math.min(object.left,window.overlay.width-object.width-object.strokeWidth),0);
461
- let t=Math.max(Math.min(object.top,window.overlay.height-object.height-object.strokeWidth),0);
462
- object.set({left:l,top:t});
463
- window.w2ui.toolbar.selection_box={width: object.width, height: object.height, x:object.left, y:object.top};
464
- }
465
- }
466
- window.setup_overlay=function(width,height)
467
- {
468
- if(window.overlay)
469
- {
470
- window.overlay.setDimensions({width:width,height:height});
471
- let app=parent.document.querySelector("gradio-app");
472
- app=app.shadowRoot??app;
473
- app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
474
- document.querySelector("#container").style.height= height+"px";
475
- document.querySelector("#container").style.width = width+"px";
476
- }
477
- else
478
- {
479
- canvas=new fabric.Canvas("overlay_canvas");
480
- canvas.setDimensions({width:width,height:height});
481
- let app=parent.document.querySelector("gradio-app");
482
- app=app.shadowRoot??app;
483
- app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
484
- canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
485
- canvas.on("object:scaling", onObjectScaled);
486
- canvas.on("object:moving", onObjectMoved);
487
- window.overlay=canvas;
488
- }
489
- document.querySelector("#overlay_container").style.pointerEvents="none";
490
- }
491
- window.update_overlay=function(width,height)
492
- {
493
- window.overlay.setDimensions({width:width,height:height},{backstoreOnly:true});
494
- // document.querySelector("#overlay_container").style.pointerEvents="none";
495
- }
496
- window.adjust_selection=function(x,y,width,height)
497
- {
498
- var rect = new fabric.Rect({
499
- left: x,
500
- top: y,
501
- fill: "rgba(0,0,0,0)",
502
- strokeWidth: 3,
503
- stroke: "rgba(0,0,0,0.7)",
504
- cornerColor: "red",
505
- cornerStrokeColor: "red",
506
- borderColor: "rgba(255, 0, 0, 1.0)",
507
- width: width,
508
- height: height,
509
- lockRotation: true,
510
- });
511
- rect.setControlsVisibility({ mtr: false });
512
- window.overlay.add(rect);
513
- window.overlay.setActiveObject(window.overlay.item(0));
514
- window.w2ui.toolbar.selection_box={width: width, height: height, x:x, y:y};
515
- window.w2ui.toolbar.selection_box_bak={width: width, height: height, x:x, y:y};
516
- }
517
- function add_image(url)
518
- {
519
- fabric.Image.fromURL(url,function(img){
520
- window.overlay.add(img);
521
- window.overlay.setActiveObject(img);
522
- },{left:100,top:100});
523
- }
524
- function export_image()
525
- {
526
- data=window.overlay.toDataURL();
527
- document.querySelector("#upload_content").value=data;
528
- window.postMessage(["upload",""],"*");
529
- end_overlay();
530
- }
531
- function end_overlay()
532
- {
533
- window.overlay.clear();
534
- document.querySelector("#overlay_container").style.opacity = 1.0;
535
- document.querySelector("#overlay_container").style.pointerEvents="none";
536
- }
537
- function ask_filename(target)
538
- {
539
- w2prompt({
540
- label: "Enter filename",
541
- value: `outpaint_${((new Date(Date.now() -(new Date()).getTimezoneOffset() * 60000))).toISOString().replace("T","_").replace(/[^0-9_]/g, "").substring(0,15)}`,
542
- })
543
- .change((event) => {
544
- console.log("change", event.detail.originalEvent.target.value);
545
- })
546
- .ok((event) => {
547
- console.log("value=", event.detail.value);
548
- window.postMessage(["click",target,event.detail.value],"*");
549
- })
550
- .cancel((event) => {
551
- console.log("cancel");
552
- });
553
- }
554
-
555
- document.querySelector("#container").addEventListener("wheel",(e)=>{e.preventDefault()})
556
- window.setup_shortcut=function(json)
557
- {
558
- var config=JSON.parse(json);
559
- var key_map={};
560
- Object.keys(config.shortcut).forEach(k=>{
561
- key_map[config.shortcut[k]]=k;
562
- })
563
- document.addEventListener("keydown",(e)=>{
564
- if(e.target.tagName!="INPUT")
565
- {
566
- let key=e.key;
567
- if(e.ctrlKey)
568
- {
569
- key="Ctrl+"+e.key;
570
- if(key in key_map)
571
- {
572
- e.preventDefault();
573
- }
574
- }
575
- if(key in key_map)
576
- {
577
- w2ui.toolbar.click(key_map[key]);
578
  }
579
- }
580
- })
581
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  // import { w2ui,w2toolbar,w2field,query,w2alert, w2utils,w2confirm} from "https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js"
3
 
4
  // https://stackoverflow.com/questions/36280818/how-to-convert-file-to-base64-in-javascript
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ // stanley checkin
7
+ function getBase64(file) {
8
+ var reader = new FileReader();
9
+ reader.readAsDataURL(file);
10
+ reader.onload = function () {
11
+ add_image(reader.result);
12
+ // console.log(reader.result);
13
+ };
14
+ reader.onerror = function (error) {
15
+ console.log("Error: ", error);
16
+ };
17
+ }
18
+
19
+ function getText(file) {
20
+ var reader = new FileReader();
21
+ reader.readAsText(file);
22
+ reader.onload = function () {
23
+ window.postMessage(["load",reader.result],"*")
24
+ // console.log(reader.result);
25
+ };
26
+ reader.onerror = function (error) {
27
+ console.log("Error: ", error);
28
+ };
29
+ }
30
+
31
+ document.querySelector("#upload_file").addEventListener("change", (event)=>{
32
+ console.log(event);
33
+ let file = document.querySelector("#upload_file").files[0];
34
+ getBase64(file);
35
+ })
36
+
37
+ document.querySelector("#upload_state").addEventListener("change", (event)=>{
38
+ console.log(event);
39
+ let file = document.querySelector("#upload_state").files[0];
40
+ getText(file);
41
+ })
42
+
43
+ open_setting = function() {
44
+ if (!w2ui.foo) {
45
+ new w2form({
46
+ name: "foo",
47
+ style: "border: 0px; background-color: transparent;",
48
+ fields: [{
49
+ field: "canvas_width",
50
+ type: "int",
51
+ required: true,
52
+ html: {
53
+ label: "Canvas Width"
54
+ }
55
+ },
56
+ {
57
+ field: "canvas_height",
58
+ type: "int",
59
+ required: true,
60
+ html: {
61
+ label: "Canvas Height"
62
+ }
63
+ },
64
+ ],
65
+ record: {
66
+ canvas_width: 1200,
67
+ canvas_height: 600,
68
+ },
69
+ actions: {
70
+ Save() {
71
+ this.validate();
72
+ let record = this.getCleanRecord();
73
+ window.postMessage(["resize",record.canvas_width,record.canvas_height],"*");
74
+ w2popup.close();
75
+ },
76
+ custom: {
77
+ text: "Cancel",
78
+ style: "text-transform: uppercase",
79
+ onClick(event) {
80
+ w2popup.close();
81
+ }
82
+ }
83
+ }
84
+ });
85
+ }
86
+ w2popup.open({
87
+ title: "Form in a Popup",
88
+ body: "<div id='form' style='width: 100%; height: 100%;''></div>",
89
+ style: "padding: 15px 0px 0px 0px",
90
+ width: 500,
91
+ height: 280,
92
+ showMax: true,
93
+ async onToggle(event) {
94
+ await event.complete
95
+ w2ui.foo.resize();
96
+ }
97
+ })
98
+ .then((event) => {
99
+ w2ui.foo.render("#form")
100
+ });
101
+ }
102
+
103
+ var button_lst=["clear", "load", "save", "export", "upload", "selection", "canvas", "eraser", "outpaint", "accept", "cancel", "retry", "prev", "current", "next", "eraser_size_btn", "eraser_size", "resize_selection", "scale", "zoom_in", "zoom_out", "help"];
104
+ var upload_button_lst=['clear', 'load', 'save', "upload", 'export', 'outpaint', 'resize_selection', 'help', "setting", "interrogate"];
105
+ var resize_button_lst=['clear', 'load', 'save', "upload", 'export', "selection", "canvas", "eraser", 'outpaint', 'resize_selection',"zoom_in", "zoom_out", 'help', "setting", "interrogate"];
106
+ var outpaint_button_lst=['clear', 'load', 'save', "canvas", "eraser", "upload", 'export', 'resize_selection', "zoom_in", "zoom_out",'help', "setting", "interrogate", "undo", "redo"];
107
+ var outpaint_result_lst=["accept", "cancel", "retry", "prev", "current", "next"];
108
+ var outpaint_result_func_lst=["accept", "retry", "prev", "current", "next"];
109
+
110
+ function check_button(id,text="",checked=true,tooltip="")
111
+ {
112
+ return { type: "check", id: id, text: text, icon: checked?"fa-solid fa-square-check":"fa-regular fa-square", checked: checked, tooltip: tooltip };
113
+ }
114
+
115
+ var toolbar=new w2toolbar({
116
+ box: "#toolbar",
117
+ name: "toolbar",
118
+ tooltip: "top",
119
+ items: [
120
+ {
121
+ type: "menu", id: "developer_options", text: "Developer Options", items: [
122
+ { type: "button", id: "clear", text: "Reset", tooltip: "Reset Canvas", icon: "fa-solid fa-rectangle-xmark" },
123
+ { type: "break" },
124
+ { type: "button", id: "load", tooltip: "Load Canvas", icon: "fa-solid fa-file-import" },
125
+ { type: "button", id: "save", tooltip: "Save Canvas", icon: "fa-solid fa-file-export" },
126
+ { type: "button", id: "export", tooltip: "Export Image", icon: "fa-solid fa-floppy-disk" },
127
+ { type: "break" },
128
+ { type: "button", id: "upload", text: "Upload Image", icon: "fa-solid fa-upload" },
129
+ { type: "break" },
130
+ { type: "radio", id: "selection", group: "1", tooltip: "Selection", icon: "fa-solid fa-arrows-up-down-left-right", checked: true },
131
+ { type: "radio", id: "canvas", group: "1", tooltip: "Canvas", icon: "fa-solid fa-image" },
132
+ { type: "radio", id: "eraser", group: "1", tooltip: "Eraser", icon: "fa-solid fa-eraser" },
133
+ { type: "break" },
134
+ { type: "button", id: "interrogate", text: "Interrogate", tooltip: "Get a prompt with Clip Interrogator ", icon: "fa-solid fa-magnifying-glass" },
135
+ { type: "break" },
136
+ { type: "button", id: "retry", text: "Retry", tooltip: "Retry", icon: "fa-solid fa-rotate", hidden: true, disabled:true,},
137
+ { type: "button", id: "prev", tooltip: "Prev Result", icon: "fa-solid fa-caret-left", hidden: true, disabled:true,},
138
+ { type: "html", id: "current", hidden: true, disabled:true,
139
+ async onRefresh(event) {
140
+ await event.complete
141
+ let fragment = query.html(`
142
+ <div class="w2ui-tb-text">
143
+ <div class="w2ui-tb-count">
144
+ <span>${this.sel_value ?? "1/1"}</span>
145
+ </div> </div>`)
146
+ query(this.box).find("#tb_toolbar_item_current").append(fragment)
147
  }
148
  },
149
+ { type: "button", id: "next", tooltip: "Next Result", icon: "fa-solid fa-caret-right", hidden: true,disabled:true,},
150
+ { type: "button", id: "add_image", text: "Add Image", icon: "fa-solid fa-file-circle-plus", hidden: true,disabled:true,},
151
+ { type: "button", id: "delete_image", text: "Delete Image", icon: "fa-solid fa-trash-can", hidden: true,disabled:true,},
152
+ { type: "button", id: "cancel_overlay", text: "Cancel", icon: "fa-solid fa-ban", hidden: true,disabled:true,},
153
+ { type: "break" },
154
+ { type: "spacer" },
155
+ { type: "break" },
156
+ { type: "button", id: "eraser_size_btn", tooltip: "Eraser Size", text:"Size", icon: "fa-solid fa-eraser", hidden: true, count: 32},
157
+ { type: "html", id: "eraser_size", hidden: true,
158
+ async onRefresh(event) {
159
+ await event.complete
160
+ // let fragment = query.html(`
161
+ // <input type="number" size="${this.eraser_size ? this.eraser_size.length:"2"}" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">
162
+ // <input type="range" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">`)
163
+ let fragment = query.html(`
164
+ <input type="range" style="margin: 0px 3px; padding: 4px;" min="8" max="${this.eraser_max ?? "256"}" value="${this.eraser_size ?? "32"}">
165
+ `)
166
+ fragment.filter("input").on("change", event => {
167
+ this.eraser_size = event.target.value;
168
+ window.overlay.freeDrawingBrush.width=this.eraser_size;
169
+ this.setCount("eraser_size_btn", event.target.value);
170
+ window.postMessage(["eraser_size", event.target.value],"*")
171
+ this.refresh();
172
+ })
173
+ query(this.box).find("#tb_toolbar_item_eraser_size").append(fragment)
174
  }
175
  },
176
+ // { type: "button", id: "resize_eraser", tooltip: "Resize Eraser", icon: "fa-solid fa-sliders" },
177
+ { type: "button", id: "resize_selection", text: "Resize Selection", tooltip: "Resize Selection", icon: "fa-solid fa-expand" },
178
+ { type: "break" },
179
+ { type: "html", id: "scale",
180
+ async onRefresh(event) {
181
+ await event.complete
182
+ let fragment = query.html(`
183
+ <div class="">
184
+ <div style="padding: 4px; border: 1px solid silver">
185
+ <span>${this.scale_value ?? "100%"}</span>
186
+ </div></div>`)
187
+ query(this.box).find("#tb_toolbar_item_scale").append(fragment)
 
 
 
 
 
188
  }
189
+ },
190
+ { type: "break" },
191
+ { type: "button", id: "help", tooltip: "Help", icon: "fa-solid fa-circle-info" },
192
+ { type: "new-line"},
193
+ { type: "button", id: "setting", text: "Canvas Setting", tooltip: "Resize Canvas Here", icon: "fa-solid fa-sliders" },
194
+ { type: "break" },
195
+ check_button("enable_history","Enable History:",false, "Enable Canvas History"),
196
+ { type: "button", id: "undo", tooltip: "Undo last erasing/last outpainting", icon: "fa-solid fa-rotate-left", disabled: true },
197
+ { type: "button", id: "redo", tooltip: "Redo", icon: "fa-solid fa-rotate-right", disabled: true },
198
+ { type: "break" },
199
+ check_button("enable_img2img","Enable Img2Img",false),
200
+ // check_button("use_correction","Photometric Correction",false),
201
+ check_button("resize_check","Resize Small Input",true),
202
+ check_button("enable_safety","Enable Safety Checker",true),
203
+ check_button("square_selection","Square Selection Only",false),
204
+ {type: "break"},
205
+ check_button("use_seed","Use Seed:",false),
206
+ { type: "html", id: "seed_val",
207
+ async onRefresh(event) {
208
+ await event.complete
209
+ let fragment = query.html(`
210
+ <input type="number" style="margin: 0px 3px; padding: 4px; width:100px;" value="${this.config_obj.seed_val ?? "0"}">`)
211
+ fragment.filter("input").on("change", event => {
212
+ this.config_obj.seed_val = event.target.value;
213
+ parent.config_obj=this.config_obj;
214
+ this.refresh();
215
+ })
216
+ query(this.box).find("#tb_toolbar_item_seed_val").append(fragment)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  }
218
+ },
219
+ { type: "button", id: "random_seed", tooltip: "Set a random seed", icon: "fa-solid fa-dice" },
220
+ ]
221
+ },
222
+ { type: "button", id: "zoom_in", tooltip: "Zoom In", icon: "fa-solid fa-magnifying-glass-plus" },
223
+ { type: "button", id: "zoom_out", tooltip: "Zoom Out", icon: "fa-solid fa-magnifying-glass-minus" },
224
+
225
+ { type: 'spacer' },
226
+ { type: "button", id: "outpaint", text: "GROW", icon: "fa-solid fa-wand-magic-sparkles" },
227
+ { type: "button", id: "accept", text: "Accept", tooltip: "Accept current result", icon: "fa-solid fa-check", hidden: true, disabled:true,},
228
+ { type: "button", id: "cancel", text: "Cancel", tooltip: "Cancel current outpainting/error", icon: "fa-solid fa-ban", hidden: true},
229
+ { type: "button", id: "confirm", text: "Confirm", icon: "fa-solid fa-check", hidden: true,disabled:true,},
230
+ ],
231
+ onClick(event) {
232
+ // Add this code block inside the onClick function
233
+ setTimeout(() => {
234
+ const outpaintButton = document.querySelector("#tb_toolbar_item_outpaint .w2ui-toolbar-table");
235
+ if (outpaintButton && !outpaintButton.classList.contains("outpaint-button")) {
236
+ outpaintButton.classList.add("outpaint-button");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  }
238
+ }, 0);
239
+ switch(event.target){
240
+ case "setting":
241
+ open_setting();
242
+ break;
243
+ case "upload":
244
+ this.upload_mode=true
245
+ document.querySelector("#overlay_container").style.pointerEvents="auto";
246
+ this.click("canvas");
247
+ this.click("selection");
248
+ this.show("confirm","cancel_overlay","add_image","delete_image");
249
+ this.enable("confirm","cancel_overlay","add_image","delete_image");
250
+ this.disable(...upload_button_lst);
251
+ this.disable("undo","redo")
252
+ query("#upload_file").click();
253
+ if(this.upload_tip)
254
+ {
255
+ this.upload_tip=false;
256
+ w2utils.notify("Note that only visible images will be added to canvas",{timeout:10000,where:query("#container")})
257
+ }
258
+ break;
259
+ case "resize_selection":
260
+ this.resize_mode=true;
261
+ this.disable(...resize_button_lst);
262
+ this.enable("confirm","cancel_overlay");
263
+ this.show("confirm","cancel_overlay");
264
+ window.postMessage(["resize_selection",""],"*");
265
+ document.querySelector("#overlay_container").style.pointerEvents="auto";
266
+ break;
267
+ case "confirm":
268
+ if(this.upload_mode)
269
+ {
270
+ export_image();
271
+ }
272
+ else
273
+ {
274
+ let sel_box=this.selection_box;
275
+ if(sel_box.width*sel_box.height>512*512)
276
+ {
277
+ w2utils.notify("Note that the outpainting will be much slower when the area of selection is larger than 512x512",{timeout:2000,where:query("#container")})
278
+ }
279
+ window.postMessage(["resize_selection",sel_box.x,sel_box.y,sel_box.width,sel_box.height],"*");
280
+ }
281
+ case "cancel_overlay":
282
+ end_overlay();
283
+ this.hide("confirm","cancel_overlay","add_image","delete_image");
284
+ if(this.upload_mode){
285
+ this.enable(...upload_button_lst);
286
+ }
287
+ else
288
+ {
289
+ this.enable(...resize_button_lst);
290
+ window.postMessage(["resize_selection","",""],"*");
291
+ if(event.target=="cancel_overlay")
292
+ {
293
+ this.selection_box=this.selection_box_bak;
294
+ }
295
+ }
296
+ if(this.selection_box)
297
+ {
298
+ this.setCount("resize_selection",`${Math.floor(this.selection_box.width/8)*8}x${Math.floor(this.selection_box.height/8)*8}`);
299
+ }
300
+ this.disable("confirm","cancel_overlay","add_image","delete_image");
301
+ this.upload_mode=false;
302
+ this.resize_mode=false;
303
+ this.click("selection");
304
+ window.update_undo_redo(window.undo_redo_state.undo, window.undo_redo_state.redo);
305
+ break;
306
+ case "add_image":
307
+ query("#upload_file").click();
308
+ break;
309
+ case "delete_image":
310
+ let active_obj = window.overlay.getActiveObject();
311
+ if(active_obj)
312
+ {
313
+ window.overlay.remove(active_obj);
314
+ window.overlay.renderAll();
315
+ }
316
+ else
317
+ {
318
+ w2utils.notify("You need to select an image first",{error:true,timeout:2000,where:query("#container")})
319
+ }
320
+ break;
321
+ case "load":
322
+ query("#upload_state").click();
323
+ this.selection_box=null;
324
+ this.setCount("resize_selection","");
325
+ break;
326
+ case "next":
327
+ case "prev":
328
+ window.postMessage(["outpaint", "", event.target], "*");
329
+ break;
330
+ case "outpaint":
331
+ this.click("selection");
332
+ this.disable(...outpaint_button_lst);
333
+ this.show(...outpaint_result_lst);
334
+ this.disable("undo","redo");
335
+ if(this.outpaint_tip)
336
+ {
337
+ this.outpaint_tip=false;
338
+ w2utils.notify("the ML model is thinking",{timeout:15000,where:query("#container")})
339
+ }
340
+ document.querySelector("#container").style.pointerEvents="none";
341
+ case "retry":
342
+ this.disable(...outpaint_result_func_lst);
343
+ parent.config_obj["interrogate_mode"]=false;
344
+ window.postMessage(["transfer",""],"*")
345
+ break;
346
+ case "interrogate":
347
+ if(this.interrogate_tip)
348
+ {
349
+ this.interrogate_tip=false;
350
+ w2utils.notify("ClipInterrogator v1 will be dynamically loaded when run at the first time, which may take a while",{timeout:10000,where:query("#container")})
351
+ }
352
+ parent.config_obj["interrogate_mode"]=true;
353
+ window.postMessage(["transfer",""],"*")
354
+ break
355
+ case "accept":
356
+ case "cancel":
357
+ this.hide(...outpaint_result_lst);
358
+ this.disable(...outpaint_result_func_lst);
359
+ this.enable(...outpaint_button_lst);
360
+ document.querySelector("#container").style.pointerEvents="auto";
361
+ if(this.config_obj.enable_history)
362
+ {
363
+ window.postMessage(["click", event.target, ""],"*");
364
+ }
365
+ else
366
+ {
367
+ window.postMessage(["click", event.target],"*");
368
+ }
369
+ let app=parent.document.querySelector("gradio-app");
370
+ app=app.shadowRoot??app;
371
+ app.querySelector("#cancel").click();
372
+ window.update_undo_redo(window.undo_redo_state.undo, window.undo_redo_state.redo);
373
+ break;
374
+ case "eraser":
375
+ case "selection":
376
+ case "canvas":
377
+ if(event.target=="eraser")
378
+ {
379
+ this.show("eraser_size","eraser_size_btn");
380
+ window.overlay.freeDrawingBrush.width=this.eraser_size;
381
+ window.overlay.isDrawingMode = true;
382
+ }
383
+ else
384
+ {
385
+ this.hide("eraser_size","eraser_size_btn");
386
+ window.overlay.isDrawingMode = false;
387
+ }
388
+ if(this.upload_mode)
389
+ {
390
+ if(event.target=="canvas")
391
+ {
392
+ window.postMessage(["mode", event.target],"*")
393
+ document.querySelector("#overlay_container").style.pointerEvents="none";
394
+ document.querySelector("#overlay_container").style.opacity = 0.5;
395
+ }
396
+ else
397
+ {
398
+ document.querySelector("#overlay_container").style.pointerEvents="auto";
399
+ document.querySelector("#overlay_container").style.opacity = 1.0;
400
+ }
401
+ }
402
+ else
403
+ {
404
+ window.postMessage(["mode", event.target],"*")
405
+ }
406
+ break;
407
+ case "help":
408
+ w2popup.open({
409
+ title: "Document",
410
+ body: "Usage: <a href='https://stanno.us/' target='_blank'>https://stanno.us/</a>"
411
+ })
412
+ break;
413
+ case "clear":
414
+ w2confirm("Reset canvas?").yes(() => {
415
+ window.postMessage(["click", event.target],"*");
416
+ }).no(() => {})
417
+ break;
418
+ case "random_seed":
419
+ this.config_obj.seed_val=Math.floor(Math.random() * 3000000000);
420
+ parent.config_obj=this.config_obj;
421
+ this.refresh();
422
+ break;
423
+ case "enable_history":
424
+ case "enable_img2img":
425
+ case "use_correction":
426
+ case "resize_check":
427
+ case "enable_safety":
428
+ case "use_seed":
429
+ case "square_selection":
430
+ let target=this.get(event.target);
431
+ if(event.target=="enable_history")
432
+ {
433
+ if(!target.checked)
434
+ {
435
+ w2utils.notify("Enable canvas history might increase resource usage / slow down the canvas ", {error:true,timeout:3000,where:query("#container")})
436
+ window.postMessage(["click","history"],"*");
437
+ }
438
+ else
439
+ {
440
+ window.undo_redo_state.undo=false;
441
+ window.undo_redo_state.redo=false;
442
+ this.disable("undo","redo");
443
+ }
444
+ }
445
+ target.icon=target.checked?"fa-regular fa-square":"fa-solid fa-square-check";
446
+ this.config_obj[event.target]=!target.checked;
447
+ parent.config_obj=this.config_obj;
448
+ this.refresh();
449
+ break;
450
+ case "save":
451
+ case "export":
452
+ ask_filename(event.target);
453
+ break;
454
+ default:
455
+ // clear, save, export, outpaint, retry
456
+ // break, save, export, accept, retry, outpaint
457
+ window.postMessage(["click", event.target],"*")
458
+ }
459
+ console.log("Target: "+ event.target, event)
460
+ }
461
+ })
462
+ window.w2ui=w2ui;
463
+ w2ui.toolbar.config_obj={
464
+ resize_check: true,
465
+ enable_safety: true,
466
+ use_correction: false,
467
+ enable_img2img: false,
468
+ use_seed: false,
469
+ seed_val: 0,
470
+ square_selection: false,
471
+ enable_history: false,
472
+ };
473
+ w2ui.toolbar.outpaint_tip=true;
474
+ w2ui.toolbar.upload_tip=true;
475
+ w2ui.toolbar.interrogate_tip=true;
476
+ window.update_count=function(cur,total){
477
+ w2ui.toolbar.sel_value=`${cur}/${total}`;
478
+ w2ui.toolbar.refresh();
479
+ }
480
+ window.update_eraser=function(val,max_val){
481
+ w2ui.toolbar.eraser_size=`${val}`;
482
+ w2ui.toolbar.eraser_max=`${max_val}`;
483
+ w2ui.toolbar.setCount("eraser_size_btn", `${val}`);
484
+ w2ui.toolbar.refresh();
485
+ }
486
+ window.update_scale=function(val){
487
+ w2ui.toolbar.scale_value=`${val}`;
488
+ w2ui.toolbar.refresh();
489
+ }
490
+ window.enable_result_lst=function(){
491
+ w2ui.toolbar.enable(...outpaint_result_lst);
492
+ }
493
+ function onObjectScaled(e)
494
+ {
495
+ let object = e.target;
496
+ if(object.isType("rect"))
497
+ {
498
+ let width=object.getScaledWidth();
499
+ let height=object.getScaledHeight();
500
+ object.scale(1);
501
+ width=Math.max(Math.min(width,window.overlay.width-object.left),256);
502
+ height=Math.max(Math.min(height,window.overlay.height-object.top),256);
503
+ let l=Math.max(Math.min(object.left,window.overlay.width-width-object.strokeWidth),0);
504
+ let t=Math.max(Math.min(object.top,window.overlay.height-height-object.strokeWidth),0);
505
+ if(window.w2ui.toolbar.config_obj.square_selection)
506
+ {
507
+ let max_val = Math.min(Math.max(width,height),window.overlay.width,window.overlay.height);
508
+ width=max_val;
509
+ height=max_val;
510
+ }
511
+ object.set({ width: width, height: height, left:l,top:t})
512
+ window.w2ui.toolbar.selection_box={width: width, height: height, x:object.left, y:object.top};
513
+ window.w2ui.toolbar.setCount("resize_selection",`${Math.floor(width/8)*8}x${Math.floor(height/8)*8}`);
514
+ window.w2ui.toolbar.refresh();
515
+ }
516
+ }
517
+ function onObjectMoved(e)
518
+ {
519
+ let object = e.target;
520
+ if(object.isType("rect"))
521
+ {
522
+ let l=Math.max(Math.min(object.left,window.overlay.width-object.width-object.strokeWidth),0);
523
+ let t=Math.max(Math.min(object.top,window.overlay.height-object.height-object.strokeWidth),0);
524
+ object.set({left:l,top:t});
525
+ window.w2ui.toolbar.selection_box={width: object.width, height: object.height, x:object.left, y:object.top};
526
+ }
527
+ }
528
+ window.setup_overlay=function(width,height)
529
+ {
530
+ if(window.overlay)
531
+ {
532
+ window.overlay.setDimensions({width:width,height:height});
533
+ let app=parent.document.querySelector("gradio-app");
534
+ app=app.shadowRoot??app;
535
+ app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
536
+ document.querySelector("#container").style.height= height+"px";
537
+ document.querySelector("#container").style.width = width+"px";
538
+ }
539
+ else
540
+ {
541
+ canvas=new fabric.Canvas("overlay_canvas");
542
+ canvas.setDimensions({width:width,height:height});
543
+ let app=parent.document.querySelector("gradio-app");
544
+ app=app.shadowRoot??app;
545
+ app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
546
+ canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
547
+ canvas.on("object:scaling", onObjectScaled);
548
+ canvas.on("object:moving", onObjectMoved);
549
+ window.overlay=canvas;
550
+ }
551
+ document.querySelector("#overlay_container").style.pointerEvents="none";
552
+ }
553
+ window.update_overlay=function(width,height)
554
+ {
555
+ window.overlay.setDimensions({width:width,height:height},{backstoreOnly:true});
556
+ // document.querySelector("#overlay_container").style.pointerEvents="none";
557
+ }
558
+ window.adjust_selection=function(x,y,width,height)
559
+ {
560
+ var rect = new fabric.Rect({
561
+ left: x,
562
+ top: y,
563
+ fill: "rgba(0,0,0,0)",
564
+ strokeWidth: 3,
565
+ stroke: "rgba(0,0,0,0.7)",
566
+ cornerColor: "red",
567
+ cornerStrokeColor: "red",
568
+ borderColor: "rgba(255, 0, 0, 1.0)",
569
+ width: width,
570
+ height: height,
571
+ lockRotation: true,
572
+ });
573
+ rect.setControlsVisibility({ mtr: false });
574
+ window.overlay.add(rect);
575
+ window.overlay.setActiveObject(window.overlay.item(0));
576
+ window.w2ui.toolbar.selection_box={width: width, height: height, x:x, y:y};
577
+ window.w2ui.toolbar.selection_box_bak={width: width, height: height, x:x, y:y};
578
+ }
579
+ function add_image(url)
580
+ {
581
+ fabric.Image.fromURL(url,function(img){
582
+ window.overlay.add(img);
583
+ window.overlay.setActiveObject(img);
584
+ },{left:100,top:100});
585
+ }
586
+ function export_image()
587
+ {
588
+ data=window.overlay.toDataURL();
589
+ document.querySelector("#upload_content").value=data;
590
+ if(window.w2ui.toolbar.config_obj.enable_history)
591
+ {
592
+ window.postMessage(["upload","",""],"*");
593
+ window.w2ui.toolbar.enable("undo");
594
+ window.w2ui.toolbar.disable("redo");
595
+ }
596
+ else
597
+ {
598
+ window.postMessage(["upload",""],"*");
599
+ }
600
+ end_overlay();
601
+ }
602
+ function end_overlay()
603
+ {
604
+ window.overlay.clear();
605
+ document.querySelector("#overlay_container").style.opacity = 1.0;
606
+ document.querySelector("#overlay_container").style.pointerEvents="none";
607
+ }
608
+ function ask_filename(target)
609
+ {
610
+ w2prompt({
611
+ label: "Enter filename",
612
+ value: `outpaint_${((new Date(Date.now() -(new Date()).getTimezoneOffset() * 60000))).toISOString().replace("T","_").replace(/[^0-9_]/g, "").substring(0,15)}`,
613
+ })
614
+ .change((event) => {
615
+ console.log("change", event.detail.originalEvent.target.value);
616
+ })
617
+ .ok((event) => {
618
+ console.log("value=", event.detail.value);
619
+ window.postMessage(["click",target,event.detail.value],"*");
620
+ })
621
+ .cancel((event) => {
622
+ console.log("cancel");
623
+ });
624
+ }
625
+
626
+ document.querySelector("#container").addEventListener("wheel",(e)=>{e.preventDefault()})
627
+ window.setup_shortcut=function(json)
628
+ {
629
+ var config=JSON.parse(json);
630
+ var key_map={};
631
+ Object.keys(config.shortcut).forEach(k=>{
632
+ key_map[config.shortcut[k]]=k;
633
+ })
634
+ document.addEventListener("keydown",(e)=>{
635
+ if(e.target.tagName!="INPUT")
636
+ {
637
+ let key=e.key;
638
+ if(e.ctrlKey)
639
+ {
640
+ key="Ctrl+"+e.key;
641
+ if(key in key_map)
642
+ {
643
+ e.preventDefault();
644
+ }
645
+ }
646
+ if(key in key_map)
647
+ {
648
+ w2ui.toolbar.click(key_map[key]);
649
+ }
650
+ }
651
+ })
652
+ }
653
+ window.undo_redo_state={undo:false,redo:false};
654
+ window.update_undo_redo=function(s0,s1)
655
+ {
656
+ if(s0)
657
+ {
658
+ w2ui.toolbar.enable("undo");
659
+ }
660
+ else
661
+ {
662
+ w2ui.toolbar.disable("undo");
663
+ }
664
+ if(s1)
665
+ {
666
+ w2ui.toolbar.enable("redo");
667
+ }
668
+ else
669
+ {
670
+ w2ui.toolbar.disable("redo");
671
+ }
672
+ window.undo_redo_state.undo=s0;
673
+ window.undo_redo_state.redo=s1;
674
+ }