| | async function _import() { |
| | if (!globalThis.posex || !globalThis.posex.import) { |
| | return await import('posex'); |
| | } else { |
| | return await globalThis.posex.imports.posex(); |
| | } |
| | } |
| | const { init, init_3d } = await _import(); |
| |
|
| | (async function () { |
| | let _r = 0; |
| | function to_gradio(v) { |
| | |
| | return [v.toString(), (_r++).toString()]; |
| | } |
| |
|
| | function js2py(type, gradio_field, value) { |
| | |
| | |
| | |
| | |
| | return new Promise(resolve => { |
| | const callback_name = `posex-${type}-${gradio_field}`; |
| |
|
| | |
| | globalThis[callback_name] = () => { |
| |
|
| | delete globalThis[callback_name]; |
| |
|
| | |
| | const callback_after = callback_name + '_after'; |
| | globalThis[callback_after] = () => { |
| | delete globalThis[callback_after]; |
| | resolve(); |
| | }; |
| |
|
| | return to_gradio(value); |
| | }; |
| |
|
| | |
| | gradioApp().querySelector(`#${callback_name}_set`).click(); |
| | }); |
| | } |
| |
|
| | function py2js(type, pyname, ...args) { |
| | |
| | |
| | |
| | |
| |
|
| | |
| | return (args.length == 0 ? Promise.resolve() : js2py(type, pyname + '_args', JSON.stringify(args))) |
| | .then(() => { |
| | return new Promise(resolve => { |
| | const callback_name = `posex-${type}-${pyname}`; |
| | |
| | globalThis[callback_name] = value => { |
| | delete globalThis[callback_name]; |
| | resolve(value); |
| | } |
| | |
| | gradioApp().querySelector(`#${callback_name}_get`).click(); |
| | }); |
| | }); |
| | } |
| |
|
| | function reload_poses(json, ui) { |
| | const df = document.createDocumentFragment(); |
| | for (let data of json) { |
| | const fig = document.createElement('figure') |
| | const img = document.createElement('img'); |
| | const cap = document.createElement('figcaption'); |
| | const clo = document.createElement('div'); |
| | const cloimg = document.createElement('img'); |
| | const clo2 = document.createElement('span'); |
| | fig.dataset.poseName = data.name; |
| | cap.textContent = data.name; |
| | clo.classList.add('close'); |
| | cloimg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAAAG3RFWHRTb2Z0d2FyZQBDZWxzeXMgU3R1ZGlvIFRvb2zBp+F8AAAAxElEQVQ4y82T0REBQRBEX0dAJk4GJwKXgZMBESADIiADJwKXATI4GRBB+1lqKa62+DFV+7E7U6+6e2plm19K/wWQ1AE2QBcobZ9fehVwCb3rWwWShmHwaLsfvW+BAihs71otSJoBc2BuexFBl7anSRlI2gN5OBXQxIpSAB2gCXlcgCzOJGkLkg5ABhyB/B5cqoI1UAb5BbCxPU4CSBqFdda2B1GoE9urVoCkHlCH68N3ZOfzGkNw9dvBZ3Bu+/SHf+GbugG9/4ThhKqF8gAAAABJRU5ErkJggg=='; |
| | clo2.classList.add('close2'); |
| | clo2.textContent = 'delete'; |
| | clo.append(cloimg, clo2); |
| |
|
| | img.src = 'data:image/png;base64,' + data.image; |
| | img.title = data.name; |
| | fig.append(clo, img, cap); |
| |
|
| | df.appendChild(fig); |
| | } |
| |
|
| | ui.saved_poses.innerHTML = ''; |
| | ui.saved_poses.appendChild(df); |
| | } |
| |
|
| | function init_ui(type, api) { |
| | const $ = x => document.createElement(x); |
| |
|
| | const all_reset = $('button'); |
| | all_reset.innerHTML = '🔄 All Reset'; |
| | all_reset.classList.add('posex_all_reset', 'posex_box'); |
| |
|
| | const reset_camera = $('button'); |
| | reset_camera.innerHTML = '🎥 Reset Camera'; |
| | reset_camera.classList.add('posex_reset_camera', 'posex_box'); |
| |
|
| | const reset_pose = $('button'); |
| | reset_pose.innerHTML = '🧍 Reset Pose'; |
| | reset_pose.classList.add('posex_reset_pose', 'posex_box'); |
| |
|
| | const reset_cont = $('div'); |
| | reset_cont.classList.add('posex_reset_cont'); |
| | reset_cont.append(reset_camera, reset_pose); |
| |
|
| | const canvas = $('canvas'); |
| | canvas.width = 512; |
| | canvas.height = 512; |
| |
|
| | const camera_marker = $('div'); camera_marker.textContent = '- Camera'; |
| | const fixed_roll_label = $('label'); |
| | const fixed_roll = $('input'); fixed_roll.type = 'checkbox'; fixed_roll.classList.add('posex_fixed_roll', 'posex_camera'); fixed_roll.checked = true; |
| | fixed_roll_label.append(fixed_roll, document.createTextNode('Fixed Roll')); |
| | const body_marker = $('div'); body_marker.textContent = '- Body'; |
| | const add_body = $('button'); add_body.classList.add('posex_add_body', 'posex_body'); add_body.innerHTML = '➕ Add'; |
| | const remove_body = $('button'); remove_body.classList.add('posex_remove_body', 'posex_body'); remove_body.innerHTML = '➖ Remove'; |
| | const canvas_marker = $('div'); canvas_marker.textContent = '- Canvas Size'; |
| | const canvas_width = $('input'); canvas_width.type = 'number'; canvas_width.value = 512; canvas_width.min = 64; canvas_width.classList.add('posex_canvas_width', 'posex_canvas_size'); |
| | const canvas_height = $('input'); canvas_height.type = 'number'; canvas_height.value = 512; canvas_height.min = 64; canvas_height.classList.add('posex_canvas_height', 'posex_canvas_size'); |
| | const bg_marker = $('div'); bg_marker.textContent = '- Background'; |
| | const set_bg = $('label'); set_bg.classList.add('posex_bg'); |
| | const bg_button = $('button'); bg_button.innerHTML = '🖼 Set'; bg_button.onclick = () => bg_input.click(); |
| | const bg_input = $('input'); bg_input.type = 'file'; bg_input.style.display = 'none'; |
| | set_bg.append(bg_button, bg_input); |
| | const reset_bg = $('button'); reset_bg.classList.add('posex_bg'); reset_bg.innerHTML = '❌ Del'; |
| | const bg_cont = $('div'); bg_cont.classList.add('posex_bg_cont'); |
| | bg_cont.append(set_bg, reset_bg); |
| | const joint_marker = $('div'); joint_marker.textContent = '- Joints and Limbs'; |
| | const limb_width_label = $('label'); |
| | const limb_width = $('input'); limb_width.type = 'range'; limb_width.min = 1; limb_width.max = 16; limb_width.value = 4; limb_width.classList.add('posex_joints', 'posex_limb_width'); |
| | limb_width_label.append(limb_width, document.createTextNode('Limb Width')); |
| | const elliptic_limbs_label = $('label'); |
| | const elliptic_limbs = $('input'); elliptic_limbs.type = 'checkbox'; elliptic_limbs.classList.add('posex_joints', 'posex_elliptic_limbs'); elliptic_limbs.checked = true; |
| | elliptic_limbs_label.append(elliptic_limbs, document.createTextNode('Elliptic Limbs')); |
| | const other_marker = $('div'); other_marker.textContent = '- Others'; |
| | const low_fps_label = $('label'); |
| | const low_fps = $('input'); low_fps.type = 'checkbox'; low_fps.classList.add('posex_low_fps', 'posex_others'); low_fps.checked = false; |
| | low_fps_label.append(low_fps, document.createTextNode('Low fps')); |
| |
|
| | const setting_cont = $('div'); |
| | setting_cont.classList.add('posex_setting_cont'); |
| | setting_cont.append( |
| | camera_marker, |
| | fixed_roll_label, |
| | body_marker, |
| | add_body, |
| | remove_body, |
| | canvas_marker, |
| | canvas_width, |
| | canvas_height, |
| | bg_marker, |
| | bg_cont, |
| | joint_marker, |
| | limb_width_label, |
| | elliptic_limbs_label, |
| | other_marker, |
| | low_fps_label, |
| | ); |
| |
|
| | const canvas_cont = $('div'); |
| | canvas_cont.classList.add('posex_canvas_cont'); |
| | canvas_cont.append( |
| | canvas, |
| | setting_cont, |
| | ); |
| |
|
| | const notation = $('p'); |
| | notation.classList.add('posex_notation'); |
| |
|
| | const indicator1 = $('div'); |
| | indicator1.classList.add('posex_indicator1'); |
| |
|
| | const indicator2 = $('div'); |
| | indicator2.classList.add('posex_indicator2'); |
| |
|
| | const copy = $('button'); copy.classList.add('posex_copy', 'posex_misc', 'posex_box'); copy.innerHTML = '📋 Copy to clipboard'; |
| | const save = $('button'); save.classList.add('posex_save', 'posex_misc', 'posex_box'); save.innerHTML = '💾 Download image'; |
| |
|
| | const misc_cont = $('div'); |
| | misc_cont.classList.add('posex_misc_cont'); |
| | misc_cont.append( |
| | copy, |
| | save |
| | ); |
| |
|
| | const save_pose = $('button'); |
| | save_pose.classList.add('posex_save_pose', 'posex_box'); |
| | save_pose.innerHTML = '💾🧍 Save Pose'; |
| |
|
| | const save_pose_callback = async obj => { |
| | await py2js(type, 'savepose', obj); |
| | const json = await py2js(type, 'allposes') |
| | reload_poses(JSON.parse(json), ui); |
| | return { result: '', ok: true }; |
| | }; |
| |
|
| | const saved_poses = $('div'); |
| | saved_poses.classList.add('posex_saved_poses'); |
| |
|
| | saved_poses.addEventListener('click', async e => { |
| | const get_name = ele => { |
| | while (ele && ele !== document) { |
| | if (ele.dataset && ele.dataset.poseName !== undefined) |
| | return ele.dataset.poseName; |
| | ele = ele.parentNode; |
| | } |
| | return ''; |
| | }; |
| |
|
| | let target = e.target; |
| | if (target.tagName === 'IMG') target = target.parentNode; |
| | if (target.classList.contains('close2')) target = target.parentNode; |
| | if (target.tagName === 'FIGURE') { |
| | const name = get_name(target); |
| | if (name.length != 0) { |
| | const json = await py2js(type, 'loadpose', name); |
| | ui.loadPose(JSON.parse(json)); |
| | } |
| | } else if (target.classList.contains('close')) { |
| | const name = get_name(target); |
| | if (name.length != 0) { |
| | await py2js(type, 'delpose', name); |
| | const json = await py2js(type, 'allposes') |
| | reload_poses(JSON.parse(json), ui); |
| | } |
| | } |
| | }, false); |
| |
|
| | const ui = { |
| | canvas, |
| | notation, |
| | indicator1, |
| | indicator2, |
| | all_reset, |
| | reset_camera, |
| | reset_pose, |
| | fixed_roll, |
| | add_body, |
| | remove_body, |
| | canvas_width, |
| | canvas_height, |
| | bg: bg_input, |
| | reset_bg, |
| | limb_width, |
| | elliptic_limbs, |
| | low_fps, |
| | save, |
| | copy, |
| | save_pose, |
| | save_pose_callback, |
| | saved_poses, |
| | }; |
| |
|
| | const df = document.createDocumentFragment(); |
| | df.append( |
| | all_reset, |
| | reset_cont, |
| | canvas_cont, |
| | indicator2, |
| | indicator1, |
| | notation, |
| | misc_cont, |
| | save_pose, |
| | saved_poses, |
| | ); |
| |
|
| | return { ui, df }; |
| | }; |
| |
|
| | async function init_canvas( |
| | type, |
| | enabled, |
| | generate_button, |
| | container, |
| | api |
| | ) { |
| | container.classList.add('posex_cont'); |
| | container.innerHTML = ''; |
| | const { ui, df } = init_ui(type, api); |
| | container.appendChild(df); |
| |
|
| | ui.container = container; |
| | ui.notify = function (str, type) { if (type === 'error') console.error(str); }; |
| |
|
| | if (!posex[`${type}_click`]) { |
| | |
| | let force = false; |
| | gradioApp().addEventListener('click', async e => { |
| | if (e.target !== generate_button) return; |
| |
|
| | if (!enabled.checked) return; |
| |
|
| | if (force) { |
| | force = false; |
| | return; |
| | } |
| |
|
| | |
| | e.preventDefault(); |
| | e.stopPropagation(); |
| |
|
| | const data_url = await ui.getDataURL(); |
| | await js2py(type, 'base64', data_url); |
| | force = true; |
| | generate_button.click(); |
| | }, true); |
| | posex[`${type}_click`] = true; |
| | } |
| |
|
| | { |
| | |
| | const json = await py2js(type, 'allposes') |
| | reload_poses(JSON.parse(json), ui); |
| | } |
| |
|
| | init(ui); |
| |
|
| | const animate = init_3d(ui); |
| |
|
| | animate(); |
| |
|
| | onUiTabChange(() => { |
| | const tabname = get_uiCurrentTabContent().id; |
| | if (type === 't2i') { |
| | if (0 <= tabname.indexOf('txt2img')) { |
| | ui.play(); |
| | } else { |
| | ui.stop(); |
| | } |
| | } else if (type === 'i2i') { |
| | if (0 <= tabname.indexOf('img2img')) { |
| | ui.play(); |
| | } else { |
| | ui.stop(); |
| | } |
| | } else { |
| | ui.stop(); |
| | } |
| | }); |
| | } |
| |
|
| | async function init_t2i() { |
| | const app = gradioApp(); |
| | await init_canvas( |
| | 't2i', |
| | app.querySelector('#posex-t2i-enabled input[type=checkbox]'), |
| | app.querySelector('#txt2img_generate'), |
| | Array.from(app.querySelectorAll('#posex-t2i-html')).at(-1), |
| | { |
| | load_all_poses: app.querySelector('#posex-t2i-api-all_pose'), |
| | delete_pose: app.querySelector('#posex-t2i-api-delete_pose'), |
| | } |
| | ); |
| | } |
| |
|
| | async function init_i2i() { |
| | const app = gradioApp(); |
| | await init_canvas( |
| | 'i2i', |
| | app.querySelector('#posex-i2i-enabled input[type=checkbox]'), |
| | app.querySelector('#img2img_generate'), |
| | Array.from(app.querySelectorAll('#posex-i2i-html')).at(-1), |
| | { |
| | load_all_poses: app.querySelector('#posex-i2i-api-all_pose'), |
| | delete_pose: app.querySelector('#posex-i2i-api-delete_pose'), |
| | } |
| | ); |
| | } |
| |
|
| | if (!globalThis.posex) globalThis.posex = {}; |
| | const posex = globalThis.posex; |
| | posex.init_t2i = init_t2i; |
| | posex.init_i2i = init_i2i; |
| |
|
| | posex.script_loaded = true; |
| | document.dispatchEvent(new CustomEvent('posexscriptloaded')); |
| |
|
| | })(); |
| |
|