// import { w2ui,w2toolbar,w2field,query,w2alert, w2utils,w2confirm} from "https://rawgit.com/vitmalina/w2ui/master/dist/w2ui.es6.min.js"
// import { w2ui,w2toolbar,w2field,query,w2alert, w2utils,w2confirm} from "https://cdn.jsdelivr.net/gh/vitmalina/w2ui@master/dist/w2ui.es6.min.js"
// https://stackoverflow.com/questions/36280818/how-to-convert-file-to-base64-in-javascript
function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
add_image(reader.result);
// console.log(reader.result);
};
reader.onerror = function (error) {
console.log("Error: ", error);
};
}
function getText(file) {
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function () {
window.postMessage(["load",reader.result],"*")
// console.log(reader.result);
};
reader.onerror = function (error) {
console.log("Error: ", error);
};
}
document.querySelector("#upload_file").addEventListener("change", (event)=>{
console.log(event);
let file = document.querySelector("#upload_file").files[0];
getBase64(file);
})
document.querySelector("#upload_state").addEventListener("change", (event)=>{
console.log(event);
let file = document.querySelector("#upload_state").files[0];
getText(file);
})
open_setting = function() {
if (!w2ui.foo) {
new w2form({
name: "foo",
style: "border: 0px; background-color: transparent;",
fields: [{
field: "canvas_width",
type: "int",
required: true,
html: {
label: "Canvas Width"
}
},
{
field: "canvas_height",
type: "int",
required: true,
html: {
label: "Canvas Height"
}
},
],
record: {
canvas_width: 1200,
canvas_height: 600,
},
actions: {
Save() {
this.validate();
let record = this.getCleanRecord();
window.postMessage(["resize",record.canvas_width,record.canvas_height],"*");
w2popup.close();
},
custom: {
text: "Cancel",
style: "text-transform: uppercase",
onClick(event) {
w2popup.close();
}
}
}
});
}
w2popup.open({
title: "Form in a Popup",
body: "
",
style: "padding: 15px 0px 0px 0px",
width: 500,
height: 280,
showMax: true,
async onToggle(event) {
await event.complete
w2ui.foo.resize();
}
})
.then((event) => {
w2ui.foo.render("#form")
});
}
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"];
var upload_button_lst=['clear', 'load', 'save', "upload", 'export', 'outpaint', 'resize_selection', 'help', "setting"];
var resize_button_lst=['clear', 'load', 'save', "upload", 'export', "selection", "canvas", "eraser", 'outpaint', 'resize_selection',"zoom_in", "zoom_out", 'help', "setting"];
var outpaint_button_lst=['clear', 'load', 'save', "canvas", "eraser", "upload", 'export', 'resize_selection', "zoom_in", "zoom_out",'help', "setting"];
var outpaint_result_lst=["accept", "cancel", "retry", "prev", "current", "next"];
var outpaint_result_func_lst=["accept", "retry", "prev", "current", "next"];
function check_button(id,text="",checked=true,tooltip="")
{
return { type: "check", id: id, text: text, icon: checked?"fa-solid fa-square-check":"fa-regular fa-square", checked: checked, tooltip: tooltip };
}
var toolbar=new w2toolbar({
box: "#toolbar",
name: "toolbar",
tooltip: "top",
items: [
{ type: "button", id: "clear", text: "Reset", tooltip: "Reset Canvas", icon: "fa-solid fa-rectangle-xmark" },
{ type: "break" },
{ type: "button", id: "load", tooltip: "Load Canvas", icon: "fa-solid fa-file-import" },
{ type: "button", id: "save", tooltip: "Save Canvas", icon: "fa-solid fa-file-export" },
{ type: "button", id: "export", tooltip: "Export Image", icon: "fa-solid fa-floppy-disk" },
{ type: "break" },
{ type: "button", id: "upload", text: "Upload Image", icon: "fa-solid fa-upload" },
{ type: "break" },
{ type: "radio", id: "selection", group: "1", tooltip: "Selection", icon: "fa-solid fa-arrows-up-down-left-right", checked: true },
{ type: "radio", id: "canvas", group: "1", tooltip: "Canvas", icon: "fa-solid fa-image" },
{ type: "radio", id: "eraser", group: "1", tooltip: "Eraser", icon: "fa-solid fa-eraser" },
{ type: "break" },
{ type: "button", id: "outpaint", text: "Outpaint", tooltip: "Run Outpainting", icon: "fa-solid fa-brush" },
{ type: "break" },
{ type: "button", id: "accept", text: "Accept", tooltip: "Accept current result", icon: "fa-solid fa-check", hidden: true, disable:true,},
{ type: "button", id: "cancel", text: "Cancel", tooltip: "Cancel current outpainting/error", icon: "fa-solid fa-ban", hidden: true},
{ type: "button", id: "retry", text: "Retry", tooltip: "Retry", icon: "fa-solid fa-rotate", hidden: true, disable:true,},
{ type: "button", id: "prev", tooltip: "Prev Result", icon: "fa-solid fa-caret-left", hidden: true, disable:true,},
{ type: "html", id: "current", hidden: true, disable:true,
async onRefresh(event) {
await event.complete
let fragment = query.html(`
${this.sel_value ?? "1/1"}
`)
query(this.box).find("#tb_toolbar_item_current").append(fragment)
}
},
{ type: "button", id: "next", tooltip: "Next Result", icon: "fa-solid fa-caret-right", hidden: true,disable:true,},
{ type: "button", id: "add_image", text: "Add Image", icon: "fa-solid fa-file-circle-plus", hidden: true,disable:true,},
{ type: "button", id: "delete_image", text: "Delete Image", icon: "fa-solid fa-trash-can", hidden: true,disable:true,},
{ type: "button", id: "confirm", text: "Confirm", icon: "fa-solid fa-check", hidden: true,disable:true,},
{ type: "button", id: "cancel_overlay", text: "Cancel", icon: "fa-solid fa-ban", hidden: true,disable:true,},
{ type: "break" },
{ type: "spacer" },
{ type: "break" },
{ type: "button", id: "eraser_size_btn", tooltip: "Eraser Size", text:"Size", icon: "fa-solid fa-eraser", hidden: true, count: 32},
{ type: "html", id: "eraser_size", hidden: true,
async onRefresh(event) {
await event.complete
// let fragment = query.html(`
//
// `)
let fragment = query.html(`
`)
fragment.filter("input").on("change", event => {
this.eraser_size = event.target.value;
window.overlay.freeDrawingBrush.width=this.eraser_size;
this.setCount("eraser_size_btn", event.target.value);
window.postMessage(["eraser_size", event.target.value],"*")
this.refresh();
})
query(this.box).find("#tb_toolbar_item_eraser_size").append(fragment)
}
},
// { type: "button", id: "resize_eraser", tooltip: "Resize Eraser", icon: "fa-solid fa-sliders" },
{ type: "button", id: "resize_selection", text: "Resize Selection", tooltip: "Resize Selection", icon: "fa-solid fa-expand" },
{ type: "break" },
{ type: "html", id: "scale",
async onRefresh(event) {
await event.complete
let fragment = query.html(`
${this.scale_value ?? "100%"}
`)
query(this.box).find("#tb_toolbar_item_scale").append(fragment)
}
},
{ type: "button", id: "zoom_in", tooltip: "Zoom In", icon: "fa-solid fa-magnifying-glass-plus" },
{ type: "button", id: "zoom_out", tooltip: "Zoom Out", icon: "fa-solid fa-magnifying-glass-minus" },
{ type: "break" },
{ type: "button", id: "help", tooltip: "Help", icon: "fa-solid fa-circle-info" },
{ type: "new-line"},
{ type: "button", id: "setting", text: "Canvas Setting", tooltip: "Resize Canvas Here", icon: "fa-solid fa-sliders" },
{ type: "break" },
check_button("enable_img2img","Enable Img2Img",false),
// check_button("use_correction","Photometric Correction",false),
check_button("resize_check","Resize Small Input",true),
check_button("enable_safety","Enable Safety Checker",true),
check_button("square_selection","Square Selection Only",false),
{type: "break"},
check_button("use_seed","Use Seed:",false),
{ type: "html", id: "seed_val",
async onRefresh(event) {
await event.complete
let fragment = query.html(`
`)
fragment.filter("input").on("change", event => {
this.config_obj.seed_val = event.target.value;
parent.config_obj=this.config_obj;
this.refresh();
})
query(this.box).find("#tb_toolbar_item_seed_val").append(fragment)
}
},
{ type: "button", id: "random_seed", tooltip: "Set a random seed", icon: "fa-solid fa-dice" },
],
onClick(event) {
switch(event.target){
case "setting":
open_setting();
break;
case "upload":
this.upload_mode=true
document.querySelector("#overlay_container").style.pointerEvents="auto";
this.click("canvas");
this.click("selection");
this.show("confirm","cancel_overlay","add_image","delete_image");
this.enable("confirm","cancel_overlay","add_image","delete_image");
this.disable(...upload_button_lst);
query("#upload_file").click();
if(this.upload_tip)
{
this.upload_tip=false;
w2utils.notify("Note that only visible images will be added to canvas",{timeout:10000,where:query("#container")})
}
break;
case "resize_selection":
this.resize_mode=true;
this.disable(...resize_button_lst);
this.enable("confirm","cancel_overlay");
this.show("confirm","cancel_overlay");
window.postMessage(["resize_selection",""],"*");
document.querySelector("#overlay_container").style.pointerEvents="auto";
break;
case "confirm":
if(this.upload_mode)
{
export_image();
}
else
{
let sel_box=this.selection_box;
window.postMessage(["resize_selection",sel_box.x,sel_box.y,sel_box.width,sel_box.height],"*");
}
case "cancel_overlay":
end_overlay();
this.hide("confirm","cancel_overlay","add_image","delete_image");
if(this.upload_mode){
this.enable(...upload_button_lst);
}
else
{
this.enable(...resize_button_lst);
window.postMessage(["resize_selection","",""],"*");
if(event.target=="cancel_overlay")
{
this.selection_box=this.selection_box_bak;
}
}
if(this.selection_box)
{
this.setCount("resize_selection",`${Math.floor(this.selection_box.width/8)*8}x${Math.floor(this.selection_box.height/8)*8}`);
}
this.disable("confirm","cancel_overlay","add_image","delete_image");
this.upload_mode=false;
this.resize_mode=false;
this.click("selection");
break;
case "add_image":
query("#upload_file").click();
break;
case "delete_image":
let active_obj = window.overlay.getActiveObject();
if(active_obj)
{
window.overlay.remove(active_obj);
window.overlay.renderAll();
}
else
{
w2utils.notify("You need to select an image first",{error:true,timeout:2000,where:query("#container")})
}
break;
case "load":
query("#upload_state").click();
this.selection_box=null;
this.setCount("resize_selection","");
break;
case "next":
case "prev":
window.postMessage(["outpaint", "", event.target], "*");
break;
case "outpaint":
this.click("selection");
this.disable(...outpaint_button_lst);
this.show(...outpaint_result_lst);
if(this.outpaint_tip)
{
this.outpaint_tip=false;
w2utils.notify("The canvas stays locked until you accept/cancel current outpainting",{timeout:10000,where:query("#container")})
}
document.querySelector("#container").style.pointerEvents="none";
case "retry":
this.disable(...outpaint_result_func_lst);
window.postMessage(["transfer",""],"*")
break;
case "accept":
case "cancel":
this.hide(...outpaint_result_lst);
this.disable(...outpaint_result_func_lst);
this.enable(...outpaint_button_lst);
document.querySelector("#container").style.pointerEvents="auto";
window.postMessage(["click", event.target],"*");
let app=parent.document.querySelector("gradio-app");
app=app.shadowRoot??app;
app.querySelector("#cancel").click();
break;
case "eraser":
case "selection":
case "canvas":
if(event.target=="eraser")
{
this.show("eraser_size","eraser_size_btn");
window.overlay.freeDrawingBrush.width=this.eraser_size;
window.overlay.isDrawingMode = true;
}
else
{
this.hide("eraser_size","eraser_size_btn");
window.overlay.isDrawingMode = false;
}
if(this.upload_mode)
{
if(event.target=="canvas")
{
window.postMessage(["mode", event.target],"*")
document.querySelector("#overlay_container").style.pointerEvents="none";
document.querySelector("#overlay_container").style.opacity = 0.5;
}
else
{
document.querySelector("#overlay_container").style.pointerEvents="auto";
document.querySelector("#overlay_container").style.opacity = 1.0;
}
}
else
{
window.postMessage(["mode", event.target],"*")
}
break;
case "help":
w2popup.open({
title: "Document",
body: "Usage: https://github.com/lkwq007/stablediffusion-infinity/blob/master/docs/usage.md"
})
break;
case "clear":
w2confirm("Reset canvas?").yes(() => {
window.postMessage(["click", event.target],"*");
}).no(() => {})
break;
case "random_seed":
this.config_obj.seed_val=Math.floor(Math.random() * 3000000000);
parent.config_obj=this.config_obj;
this.refresh();
break;
case "enable_img2img":
case "use_correction":
case "resize_check":
case "enable_safety":
case "use_seed":
case "square_selection":
let target=this.get(event.target);
target.icon=target.checked?"fa-regular fa-square":"fa-solid fa-square-check";
this.config_obj[event.target]=!target.checked;
parent.config_obj=this.config_obj;
this.refresh();
break;
case "save":
case "export":
ask_filename(event.target);
break;
default:
// clear, save, export, outpaint, retry
// break, save, export, accept, retry, outpaint
window.postMessage(["click", event.target],"*")
}
console.log("Target: "+ event.target, event)
}
})
window.w2ui=w2ui;
w2ui.toolbar.config_obj={
resize_check: true,
enable_safety: true,
use_correction: false,
enable_img2img: false,
use_seed: false,
seed_val: 0,
square_selection: false,
};
w2ui.toolbar.outpaint_tip=true;
w2ui.toolbar.upload_tip=true;
window.update_count=function(cur,total){
w2ui.toolbar.sel_value=`${cur}/${total}`;
w2ui.toolbar.refresh();
}
window.update_eraser=function(val,max_val){
w2ui.toolbar.eraser_size=`${val}`;
w2ui.toolbar.eraser_max=`${max_val}`;
w2ui.toolbar.setCount("eraser_size_btn", `${val}`);
w2ui.toolbar.refresh();
}
window.update_scale=function(val){
w2ui.toolbar.scale_value=`${val}`;
w2ui.toolbar.refresh();
}
window.enable_result_lst=function(){
w2ui.toolbar.enable(...outpaint_result_lst);
}
function onObjectScaled(e)
{
let object = e.target;
if(object.isType("rect"))
{
let width=object.getScaledWidth();
let height=object.getScaledHeight();
object.scale(1);
width=Math.max(Math.min(width,window.overlay.width-object.left),256);
height=Math.max(Math.min(height,window.overlay.height-object.top),256);
let l=Math.max(Math.min(object.left,window.overlay.width-width-object.strokeWidth),0);
let t=Math.max(Math.min(object.top,window.overlay.height-height-object.strokeWidth),0);
if(window.w2ui.toolbar.config_obj.square_selection)
{
let max_val = Math.min(Math.max(width,height),window.overlay.width,window.overlay.height);
width=max_val;
height=max_val;
}
object.set({ width: width, height: height, left:l,top:t})
window.w2ui.toolbar.selection_box={width: width, height: height, x:object.left, y:object.top};
window.w2ui.toolbar.setCount("resize_selection",`${Math.floor(width/8)*8}x${Math.floor(height/8)*8}`);
window.w2ui.toolbar.refresh();
}
}
function onObjectMoved(e)
{
let object = e.target;
if(object.isType("rect"))
{
let l=Math.max(Math.min(object.left,window.overlay.width-object.width-object.strokeWidth),0);
let t=Math.max(Math.min(object.top,window.overlay.height-object.height-object.strokeWidth),0);
object.set({left:l,top:t});
window.w2ui.toolbar.selection_box={width: object.width, height: object.height, x:object.left, y:object.top};
}
}
window.setup_overlay=function(width,height)
{
if(window.overlay)
{
window.overlay.setDimensions({width:width,height:height});
let app=parent.document.querySelector("gradio-app");
app=app.shadowRoot??app;
app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
document.querySelector("#container").style.height= height+"px";
document.querySelector("#container").style.width = width+"px";
}
else
{
canvas=new fabric.Canvas("overlay_canvas");
canvas.setDimensions({width:width,height:height});
let app=parent.document.querySelector("gradio-app");
app=app.shadowRoot??app;
app.querySelector("#sdinfframe").style.height=80+Number(height)+"px";
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
canvas.on("object:scaling", onObjectScaled);
canvas.on("object:moving", onObjectMoved);
window.overlay=canvas;
}
document.querySelector("#overlay_container").style.pointerEvents="none";
}
window.update_overlay=function(width,height)
{
window.overlay.setDimensions({width:width,height:height},{backstoreOnly:true});
// document.querySelector("#overlay_container").style.pointerEvents="none";
}
window.adjust_selection=function(x,y,width,height)
{
var rect = new fabric.Rect({
left: x,
top: y,
fill: "rgba(0,0,0,0)",
strokeWidth: 3,
stroke: "rgba(0,0,0,0.7)",
cornerColor: "red",
cornerStrokeColor: "red",
borderColor: "rgba(255, 0, 0, 1.0)",
width: width,
height: height,
lockRotation: true,
});
rect.setControlsVisibility({ mtr: false });
window.overlay.add(rect);
window.overlay.setActiveObject(window.overlay.item(0));
window.w2ui.toolbar.selection_box={width: width, height: height, x:x, y:y};
window.w2ui.toolbar.selection_box_bak={width: width, height: height, x:x, y:y};
}
function add_image(url)
{
fabric.Image.fromURL(url,function(img){
window.overlay.add(img);
window.overlay.setActiveObject(img);
},{left:100,top:100});
}
function export_image()
{
data=window.overlay.toDataURL();
document.querySelector("#upload_content").value=data;
window.postMessage(["upload",""],"*");
end_overlay();
}
function end_overlay()
{
window.overlay.clear();
document.querySelector("#overlay_container").style.opacity = 1.0;
document.querySelector("#overlay_container").style.pointerEvents="none";
}
function ask_filename(target)
{
w2prompt({
label: "Enter filename",
value: `outpaint_${((new Date(Date.now() -(new Date()).getTimezoneOffset() * 60000))).toISOString().replace("T","_").replace(/[^0-9_]/g, "").substring(0,15)}`,
})
.change((event) => {
console.log("change", event.detail.originalEvent.target.value);
})
.ok((event) => {
console.log("value=", event.detail.value);
window.postMessage(["click",target,event.detail.value],"*");
})
.cancel((event) => {
console.log("cancel");
});
}
document.querySelector("#container").addEventListener("wheel",(e)=>{e.preventDefault()})
window.setup_shortcut=function(json)
{
var config=JSON.parse(json);
var key_map={};
Object.keys(config.shortcut).forEach(k=>{
key_map[config.shortcut[k]]=k;
})
document.addEventListener("keydown",(e)=>{
if(e.target.tagName!="INPUT")
{
let key=e.key;
if(e.ctrlKey)
{
key="Ctrl+"+e.key;
if(key in key_map)
{
e.preventDefault();
}
}
if(key in key_map)
{
w2ui.toolbar.click(key_map[key]);
}
}
})
}