refactor: Painterro UI code is moved to index.js (#316)

* decouple python from js

* bring the painterro btn back

* refactor painterro code

replicate 7ddbd6533a as close as possible

* improve reliability

* fix big brain import

Co-authored-by: hlky <106811348+hlky@users.noreply.github.com>
This commit is contained in:
Thomas Mello 2022-08-30 16:33:27 +03:00 committed by GitHub
parent fe173407fe
commit bdac53c5a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 41 deletions

View File

@ -18,4 +18,4 @@ input[type=number]:disabled { -moz-appearance: textfield;+ }
#generate, #img2img_mask_btn, #img2img_edit_btn {
align-self: stretch;
}
}

View File

@ -1,9 +1,8 @@
import os
from os import path
def readTextFile(*args):
dir = os.path.dirname(__file__)
entry = os.path.join(dir, *args)
dir = path.dirname(__file__)
entry = path.join(dir, *args)
with open(entry, "r", encoding="utf8") as f:
data = f.read()
return data
@ -31,8 +30,6 @@ def js_move_image(from_id, to_id):
def js_copy_to_clipboard(from_id):
return w(f"copyImageFromGalleryToClipboard('{from_id}')")
def js_painterro_launch():
return w("Painterro.init(SD.x)")
def js_painterro_launch(to_id):
return w(f"Painterro.init('{to_id}')")
def js_painterro_load_image(to_id):
return w(f"Painterro.loadImage('{to_id}')")

View File

@ -92,8 +92,10 @@ def draw_gradio_ui(opt, img2img=lambda x: x, txt2img=lambda x: x, txt2img_defaul
visible=RealESRGAN is not None) # TODO: Feels like I shouldnt slot it in here.
txt2img_ddim_eta = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="DDIM ETA",
value=txt2img_defaults['ddim_eta'], visible=False)
txt2img_variant_amount = gr.Slider(minimum=0.0, maximum=1.0, label='Variation Amount',value=txt2img_defaults['variant_amount'])
txt2img_variant_seed = gr.Textbox(label="Variant Seed (blank to randomize)", lines=1, max_lines=1,value=txt2img_defaults["variant_seed"])
txt2img_variant_amount = gr.Slider(minimum=0.0, maximum=1.0, label='Variation Amount',
value=txt2img_defaults['variant_amount'])
txt2img_variant_seed = gr.Textbox(label="Variant Seed (blank to randomize)", lines=1,
max_lines=1, value=txt2img_defaults["variant_seed"])
txt2img_embeddings = gr.File(label="Embeddings file for textual inversion",
visible=show_embeddings)
@ -139,7 +141,6 @@ def draw_gradio_ui(opt, img2img=lambda x: x, txt2img=lambda x: x, txt2img_defaul
value="Crop", elem_id='edit_mode_select')
img2img_painterro_btn = gr.Button("Advanced Editor")
img2img_copy_from_painterro_btn = gr.Button(value="Get Image from Advanced Editor")
img2img_show_help_btn = gr.Button("Show Hints")
img2img_hide_help_btn = gr.Button("Hide Hints", visible=False)
img2img_help = gr.Markdown(visible=False, value="")
@ -224,7 +225,7 @@ def draw_gradio_ui(opt, img2img=lambda x: x, txt2img=lambda x: x, txt2img_defaul
uifn.change_image_editor_mode,
[img2img_image_editor_mode, img2img_image_editor, img2img_resize, img2img_width, img2img_height],
[img2img_image_editor, img2img_image_mask, img2img_btn_editor, img2img_btn_mask,
img2img_painterro_btn, img2img_copy_from_painterro_btn, img2img_mask, img2img_mask_blur_strength]
img2img_painterro_btn, img2img_mask, img2img_mask_blur_strength]
)
img2img_image_editor.edit(
@ -288,9 +289,7 @@ def draw_gradio_ui(opt, img2img=lambda x: x, txt2img=lambda x: x, txt2img_defaul
img2img_btn_editor.click(*img2img_submit_params())
img2img_prompt.submit(*img2img_submit_params())
img2img_painterro_btn.click(None, [img2img_image_editor], None, _js=js_painterro_launch())
img2img_copy_from_painterro_btn.click(None, None, [img2img_image_editor, img2img_image_mask], _js=js_painterro_load_image("img2img_editor"))
img2img_painterro_btn.click(None, [img2img_image_editor], [img2img_image_editor, img2img_image_mask], _js=js_painterro_launch('img2img_editor'))
if GFPGAN is not None:
gfpgan_defaults = {

View File

@ -1,19 +1,78 @@
window.SD = (() => {
/*
* Painterro is made a field of the SD global object
* To provide convinience when using w() method in css_and_js.py
*/
class PainterroClass {
static init (img) {
Painterro({
hiddenTools: ['arrow'],
saveHandler: function (image, done) {
localStorage.setItem('painterro-image', image.asDataURL());
done(true);
},
}).show(Array.isArray(img) ? img[0] : img);
}
static loadImage (toId) {
window.SD.clearImageInput(window.SD.el.get(`#${toId}`));
static isOpen = false;
static async init (toId) {
const img = SD.x;
const originalImage = Array.isArray(img) ? img[0] : img;
const image = localStorage.getItem('painterro-image')
return [image, image];
if (window.Painterro === undefined) {
try {
await this.load();
} catch (e) {
SDClass.error(e);
return this.fallback(originalImage);
}
}
if (this.isOpen) {
return this.fallback(originalImage);
}
this.isOpen = true;
let resolveResult;
const paintClient = Painterro({
hiddenTools: ['arrow'],
onHide: () => {
resolveResult?.(null);
},
saveHandler: (image, done) => {
const data = image.asDataURL();
// ensures stable performance even
// when the editor is in interactive mode
SD.clearImageInput(SD.el.get(`#${toId}`));
resolveResult(data);
done(true);
paintClient.hide();
},
});
const result = await new Promise((resolve) => {
resolveResult = resolve;
paintClient.show(originalImage);
});
this.isOpen = false;
return result ? this.success(result) : this.fallback(originalImage);
}
static success (result) { return [result, result]; }
static fallback (image) { return [image, image]; }
static load () {
return new Promise((resolve, reject) => {
/* Ensure Painterro window is always on top */
const style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.appendChild(document.createTextNode(`
.ptro-holder-wrapper {
z-index: 100;
}
`));
document.head.appendChild(style);
const script = document.createElement('script');
script.id = '__painterro-script';
script.src = 'https://unpkg.com/painterro@1.2.78/build/painterro.min.js';
script.onload = () => resolve(true);
script.onerror = () => reject(false);
document.head.appendChild(script);
});
}
}
@ -35,7 +94,7 @@ window.SD = (() => {
* The main helper class to incapsulate functions
* that change gradio ui functionality
*/
class SD {
class SDClass {
el = new ElementCache();
x;
Painterro = PainterroClass;
@ -64,9 +123,7 @@ window.SD = (() => {
try {
navigator.clipboard.write([item]);
} catch (e) {
// TODO: graceful error messaing
console.error(e);
alert(e.message);
SDClass.error(e);
}
return this.x;
@ -74,19 +131,19 @@ window.SD = (() => {
clearImageInput (imageEditor) {
imageEditor?.querySelector('.modify-upload button:last-child')?.click();
}
static error (e) {
console.error(e);
if (typeof e === 'string') {
alert(e);
} else if(typeof e === 'object' && Object.hasOwn(e, 'message')) {
alert(e.message);
}
}
#getGallerySelectedIndex (gallery) {
const selected = gallery.querySelector(`.\\!ring-2`);
return selected ? [...selected.parentNode.children].indexOf(selected) : 0;
}
}
// Painterro stuff
const script = document.createElement('script');
script.src = 'https://unpkg.com/painterro@1.2.78/build/painterro.min.js';
document.head.appendChild(script);
const style = document.createElement('style');
style.appendChild(document.createTextNode('.ptro-holder-wrapper { z-index: 9999 !important; }'));
document.head.appendChild(style);
return new SD();
return new SDClass();
})();