(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(); })();