(function () {
if (!globalThis.LLuL) globalThis.LLuL = {};
const LLuL = globalThis.LLuL;
function id(type, s) {
return `llul-${type}-${s}`;
}
function isDark() {
return gradioApp().querySelector('.dark') !== null;
}
const M = 2;
function setSize(canvas, width, height) {
width = Math.floor(+width / M);
height = Math.floor(+height / M);
if (canvas.width != width) canvas.width = width;
if (canvas.height != height) canvas.height = height;
}
function updateXY(canvas) {
let x = +canvas.dataset.x,
y = +canvas.dataset.y,
m = +canvas.dataset.m,
mm = Math.pow(2, m),
w = +canvas.width * M,
h = +canvas.height * M;
if (x < 0) x = 0;
if (w < x + w / mm) x = Math.floor(w - w / mm);
if (y < 0) y = 0;
if (h < y + h / mm) y = Math.floor(h - h / mm);
canvas.dataset.x = x;
canvas.dataset.y = y;
canvas.dataset.m = m;
canvas.parentNode.querySelector('.llul-pos-x').value = x;
canvas.parentNode.querySelector('.llul-pos-y').value = y;
}
let last_image = new Image();
let hide_image = true;
async function draw(canvas) {
const
x = +canvas.dataset.x,
y = +canvas.dataset.y,
m = +canvas.dataset.m,
mm = Math.pow(2, m),
w = +canvas.width,
h = +canvas.height,
bg = canvas.dataset.bg;
const ctx = canvas.getContext('2d');
if (bg) {
if (last_image?.src === bg) {
// do nothing
} else {
await (new Promise(resolve => {
last_image.onload = () => resolve();
last_image.src = bg;
}));
}
hide_image = false;
} else {
last_image.src = '';
hide_image = true;
}
if (last_image.src && !hide_image) {
ctx.drawImage(last_image, 0, 0, +last_image.width, +last_image.height, 0, 0, +canvas.width, +canvas.height);
} else {
const bgcolor = isDark() ? 'black' : 'white';
ctx.fillStyle = bgcolor;
ctx.fillRect(0, 0, +canvas.width, +canvas.height);
}
ctx.fillStyle = 'gray';
ctx.fillRect(x / M, y / M, Math.floor(w / mm), Math.floor(h / mm));
}
async function update_gradio(type, canvas) {
await LLuL.js2py(type, 'x', +canvas.dataset.x);
await LLuL.js2py(type, 'y', +canvas.dataset.y);
}
function init(type) {
const $$ = (x,n) => Array.from(gradioApp().querySelectorAll(x)).at(n);
const $ = x => $$(x, -1);
if (!$('#' + id(type, 'accordion'))) return false;
const cont = $('#' + id(type, 'container'));
const x = $('#' + id(type, 'x'));
const y = $('#' + id(type, 'y'));
const m = $(`#${id(type, 'm')} input[type=number]`);
const ms = $(`#${id(type, 'm')} input[type=range]`);
if (!cont || !x || !y || !m || !ms) return false;
if (cont.querySelector('canvas')) return true; // already called
const width = $$(`#${type}_width input[type=number]`, 0);
const height = $$(`#${type}_height input[type=number]`, 0);
const width2 = $$(`#${type}_width input[type=range]`, 0);
const height2 = $$(`#${type}_height input[type=range]`, 0);
const pos_x = Math.floor(+width.value / 4);
const pos_y = Math.floor(+height.value / 4);
const pos_cont = document.createElement('div');
pos_cont.innerHTML = `
`;
const canvas = document.createElement('canvas');
canvas.style.border = '1px solid gray';
canvas.dataset.x = pos_x;
canvas.dataset.y = pos_y;
canvas.dataset.m = m.value;
const bg_cont = document.createElement('div');
bg_cont.classList.add('llul-bg-setting');
bg_cont.innerHTML = `
Load BG
Erase BG
`;
for (let ele of [width, height, width2, height2, m, ms]) {
ele.addEventListener('input', e => {
canvas.dataset.m = +m.value;
setSize(canvas, width.value, height.value);
updateXY(canvas);
draw(canvas);
});
}
//
// Event Listeners
//
// canvas
let dragging = false;
let last_x, last_y;
canvas.addEventListener('pointerdown', e => {
e.preventDefault();
dragging = true;
last_x = e.offsetX;
last_y = e.offsetY;
});
canvas.addEventListener('pointerup', async e => {
e.preventDefault();
dragging = false;
await update_gradio(type, canvas);
});
canvas.addEventListener('pointermove', e => {
if (!dragging) return;
const dx = e.offsetX - last_x, dy = e.offsetY - last_y;
const x = +canvas.dataset.x, y = +canvas.dataset.y;
canvas.dataset.x = x + dx * M;
canvas.dataset.y = y + dy * M;
last_x = e.offsetX;
last_y = e.offsetY;
updateXY(canvas);
draw(canvas);
});
// bg_cont
function set_bg(url) {
canvas.dataset.bg = url;
draw(canvas);
}
bg_cont.querySelector('input[type=file]').addEventListener('change', e => {
const ele = e.target;
const files = ele.files;
if (files.length != 0) {
const file = files[0];
const r = new FileReader();
r.onload = () => set_bg(r.result);
r.readAsDataURL(file);
}
ele.value = '';
}, false);
bg_cont.addEventListener('click', e => {
const ele = e.target;
if (ele.textContent == 'Load BG') {
bg_cont.querySelector('input[type=file]').click();
} else if (ele.textContent == 'Erase BG') {
set_bg('');
}
});
// pos_cont
//pos_cont.addEventListener('input', e => {
// const ele = e.target;
// let x = +canvas.dataset.x;
// let y = +canvas.dataset.y;
// if (ele.classList.contains(`llul-pos-x`)) {
// x = +ele.value;
// } else if (ele.classList.contains(`llul-pos-y`)) {
// y = +ele.value;
// } else {
// return;
// }
// canvas.dataset.x = x;
// canvas.dataset.y = y;
// updateXY(canvas);
// draw(canvas);
// update_gradio(type, canvas);
//});
cont.appendChild(pos_cont);
cont.appendChild(canvas);
cont.appendChild(bg_cont);
setSize(canvas, width.value, height.value);
updateXY(canvas);
draw(canvas);
return true;
}
function init2(type, init_fn) {
const repeat_until = (fn, resolve) => {
const v = fn();
if (v) {
resolve(v);
} else {
setTimeout(() => repeat_until(fn, resolve), 500);
}
};
return new Promise(resolve => repeat_until(() => init_fn(type), resolve));
}
function init_LLuL() {
if (!LLuL.txt2img) {
LLuL.txt2img = init2('txt2img', init);
if (LLuL.txt2img) {
LLuL.txt2img.then(() => console.log('[LLuL] txt2img initialized'));
}
}
if (!LLuL.img2img) {
LLuL.img2img = init2('img2img', init);
if (LLuL.img2img) {
LLuL.img2img.then(() => console.log('[LLuL] img2img initialized'));
}
}
return LLuL.txt2img && LLuL.img2img;
}
function apply() {
const ok = init_LLuL();
if (!ok) {
setTimeout(apply, 500);
}
}
apply();
})();