reorder
This commit is contained in:
@@ -2004,9 +2004,9 @@
|
|||||||
<div class="sidebar-tabs">
|
<div class="sidebar-tabs">
|
||||||
<button class="sb-tab active" data-tab="info" onclick="switchSidebarTab('info')">Info</button>
|
<button class="sb-tab active" data-tab="info" onclick="switchSidebarTab('info')">Info</button>
|
||||||
<button class="sb-tab" data-tab="generate" onclick="switchSidebarTab('generate')">Generate</button>
|
<button class="sb-tab" data-tab="generate" onclick="switchSidebarTab('generate')">Generate</button>
|
||||||
<button class="sb-tab" data-tab="faceswap" onclick="switchSidebarTab('faceswap')">Faceswap</button>
|
<button class="sb-tab" data-tab="faceswap" onclick="switchSidebarTab('faceswap')">Face</button>
|
||||||
<button class="sb-tab" data-tab="scenery" onclick="switchSidebarTab('scenery')">Scenery</button>
|
<button class="sb-tab" data-tab="scenery" onclick="switchSidebarTab('scenery')">Scene</button>
|
||||||
<button class="sb-tab" data-tab="segment" onclick="switchSidebarTab('segment')">Segment</button>
|
<button class="sb-tab" data-tab="segment" onclick="switchSidebarTab('segment')">SAM</button>
|
||||||
<button class="sb-tab" data-tab="orbit" onclick="switchSidebarTab('orbit')" id="sbTabOrbit">Orbit</button>
|
<button class="sb-tab" data-tab="orbit" onclick="switchSidebarTab('orbit')" id="sbTabOrbit">Orbit</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="sb-panels">
|
<div class="sb-panels">
|
||||||
@@ -2220,6 +2220,18 @@
|
|||||||
|
|
||||||
// --- HYDRATION_START ---
|
// --- HYDRATION_START ---
|
||||||
const PRELOADED_IMAGES = [
|
const PRELOADED_IMAGES = [
|
||||||
|
"20260627_232843_pad_20260626_035101_pad_20260626_034830_jb.nobg.png",
|
||||||
|
"20260627_232502_pad_20260626_035101_pad_20260626_034830_jb.nobg.png",
|
||||||
|
"20260627_232526_pad_20260626_035101_pad_20260626_034830_jb.nobg.png",
|
||||||
|
"20260627_232302_pad_20260627_232133_image.png",
|
||||||
|
"20260627_232238_pad_20260627_232133_image.png",
|
||||||
|
"up_6ed4293c_face.png",
|
||||||
|
"20260627_232209_image.png",
|
||||||
|
"20260627_232151_image.png",
|
||||||
|
"20260627_232133_image.png",
|
||||||
|
"20260627_230405_mr_image.png",
|
||||||
|
"20260627_222806_mr_image.png",
|
||||||
|
"20260627_230301_7_20260627_201343_image.nobg.png",
|
||||||
"20260627_201629_7_20260627_201343_image.nobg.png",
|
"20260627_201629_7_20260627_201343_image.nobg.png",
|
||||||
"20260627_201629_7_20260627_201343_image.png",
|
"20260627_201629_7_20260627_201343_image.png",
|
||||||
"20260627_225051_mr_image.png",
|
"20260627_225051_mr_image.png",
|
||||||
@@ -2234,7 +2246,6 @@
|
|||||||
"20260627_222926_image.png",
|
"20260627_222926_image.png",
|
||||||
"20260627_222915_image.png",
|
"20260627_222915_image.png",
|
||||||
"20260627_222904_image.png",
|
"20260627_222904_image.png",
|
||||||
"20260627_222806_mr_image.png",
|
|
||||||
"20260627_222321_image.png",
|
"20260627_222321_image.png",
|
||||||
"20260627_222310_image.png",
|
"20260627_222310_image.png",
|
||||||
"20260627_222259_image.png",
|
"20260627_222259_image.png",
|
||||||
@@ -6733,6 +6744,7 @@
|
|||||||
let _sbGenJobId = null;
|
let _sbGenJobId = null;
|
||||||
let _sbGenJobPollTimer= null;
|
let _sbGenJobPollTimer= null;
|
||||||
let _followLatestGid = null; // set to gid after generation to auto-jump to newest image
|
let _followLatestGid = null; // set to gid after generation to auto-jump to newest image
|
||||||
|
let _followLatestFilename = null;
|
||||||
let _slideshowActive = false;
|
let _slideshowActive = false;
|
||||||
let _slideshowTimer = null;
|
let _slideshowTimer = null;
|
||||||
let _slideshowInterval= 4000;
|
let _slideshowInterval= 4000;
|
||||||
@@ -6881,6 +6893,27 @@
|
|||||||
return val.toFixed(2);
|
return val.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncPadFields(el) {
|
||||||
|
const id = el.id; // padLeft or sbPadLeft
|
||||||
|
let pairId = null;
|
||||||
|
if (id.endsWith('Left')) pairId = id.replace('Left', 'Right');
|
||||||
|
else if (id.endsWith('Right')) pairId = id.replace('Right', 'Left');
|
||||||
|
else if (id.endsWith('Top')) pairId = id.replace('Top', 'Bottom');
|
||||||
|
else if (id.endsWith('Bottom')) pairId = id.replace('Bottom', 'Top');
|
||||||
|
|
||||||
|
if (pairId) {
|
||||||
|
const pairEl = document.getElementById(pairId);
|
||||||
|
// only sync if the other side is 'empty' (0)
|
||||||
|
if (pairEl && (pairEl.value === '0.00' || pairEl.value === '0' || pairEl.value === '')) {
|
||||||
|
pairEl.value = el.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id.startsWith('sbPad')) {
|
||||||
|
updateSbGenBtn();
|
||||||
|
}
|
||||||
|
updatePadPreview();
|
||||||
|
}
|
||||||
|
|
||||||
function updatePadPreview() {
|
function updatePadPreview() {
|
||||||
const viewer = document.getElementById('studioViewer');
|
const viewer = document.getElementById('studioViewer');
|
||||||
if (!viewer) return;
|
if (!viewer) return;
|
||||||
@@ -8163,7 +8196,7 @@
|
|||||||
bar.id = 'padBar';
|
bar.id = 'padBar';
|
||||||
bar.style.cssText = 'position:absolute;top:0;left:0;right:0;display:flex;gap:8px;padding:8px;background:rgba(0,0,0,0.85);z-index:101;justify-content:flex-end;align-items:center;flex-wrap:wrap;';
|
bar.style.cssText = 'position:absolute;top:0;left:0;right:0;display:flex;gap:8px;padding:8px;background:rgba(0,0,0,0.85);z-index:101;justify-content:flex-end;align-items:center;flex-wrap:wrap;';
|
||||||
const numInput = (id, label) => {
|
const numInput = (id, label) => {
|
||||||
const onInput = `updatePadPreview()`;
|
const onInput = `syncPadFields(this)`;
|
||||||
const onBlur = `this.value = formatPadValue(this.value); updatePadPreview()`;
|
const onBlur = `this.value = formatPadValue(this.value); updatePadPreview()`;
|
||||||
return `<label style="display:flex;align-items:center;gap:3px;font-size:11px;color:#ccc">${label}<input type="text" id="${id}" value="0.00" oninput="${onInput}" onblur="${onBlur}" style="width:52px;background:#111;border:1px solid #333;color:#ccc;border-radius:4px;padding:2px 4px;font-size:11px;text-align:right" placeholder="px or %"></label>`;
|
return `<label style="display:flex;align-items:center;gap:3px;font-size:11px;color:#ccc">${label}<input type="text" id="${id}" value="0.00" oninput="${onInput}" onblur="${onBlur}" style="width:52px;background:#111;border:1px solid #333;color:#ccc;border-radius:4px;padding:2px 4px;font-size:11px;text-align:right" placeholder="px or %"></label>`;
|
||||||
};
|
};
|
||||||
@@ -8174,9 +8207,9 @@
|
|||||||
+ numInput('padBottom','↓')
|
+ numInput('padBottom','↓')
|
||||||
+ numInput('padLeft','←')
|
+ numInput('padLeft','←')
|
||||||
+ `<select id="padFill" style="background:#111;border:1px solid #333;color:#aaa;border-radius:4px;font-size:11px;padding:2px 5px">
|
+ `<select id="padFill" style="background:#111;border:1px solid #333;color:#aaa;border-radius:4px;font-size:11px;padding:2px 5px">
|
||||||
|
<option value="transparent">Transparent</option>
|
||||||
<option value="black">Black</option>
|
<option value="black">Black</option>
|
||||||
<option value="white">White</option>
|
<option value="white">White</option>
|
||||||
<option value="transparent">Transparent</option>
|
|
||||||
</select>`
|
</select>`
|
||||||
+ `<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:#ccc;cursor:pointer" title="Keep original and pad a copy">`
|
+ `<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:#ccc;cursor:pointer" title="Keep original and pad a copy">`
|
||||||
+ `<input type="checkbox" id="padAsCopy" checked style="cursor:pointer">Copy</label>`
|
+ `<input type="checkbox" id="padAsCopy" checked style="cursor:pointer">Copy</label>`
|
||||||
@@ -8204,7 +8237,7 @@
|
|||||||
|
|
||||||
const isZero = (v) => !v || v === '0' || v === '0%' || v === '0px';
|
const isZero = (v) => !v || v === '0' || v === '0%' || v === '0px';
|
||||||
if (isZero(top) && isZero(right) && isZero(bottom) && isZero(left)) { showToast('Enter at least one padding value', 'info'); return; }
|
if (isZero(top) && isZero(right) && isZero(bottom) && isZero(left)) { showToast('Enter at least one padding value', 'info'); return; }
|
||||||
const fill = document.getElementById('padFill')?.value || 'black';
|
const fill = document.getElementById('padFill')?.value || 'transparent';
|
||||||
const asCopy = document.getElementById('padAsCopy')?.checked ?? true;
|
const asCopy = document.getElementById('padAsCopy')?.checked ?? true;
|
||||||
const outpaint = document.getElementById('padOutpaint')?.checked ?? false;
|
const outpaint = document.getElementById('padOutpaint')?.checked ?? false;
|
||||||
const btn = document.getElementById('padConfirmBtn');
|
const btn = document.getElementById('padConfirmBtn');
|
||||||
@@ -8241,6 +8274,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateStudio();
|
updateStudio();
|
||||||
|
_followLatestFilename = newFn;
|
||||||
_followLatestGid = lbCurrentGid;
|
_followLatestGid = lbCurrentGid;
|
||||||
refreshNow(true);
|
refreshNow(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -9184,8 +9218,15 @@
|
|||||||
const visibleIdx = names.map((n, i) => i).filter(i => !fileHidden[names[i]]);
|
const visibleIdx = names.map((n, i) => i).filter(i => !fileHidden[names[i]]);
|
||||||
groupData.set(gid, { urls, names, visibleIdx });
|
groupData.set(gid, { urls, names, visibleIdx });
|
||||||
|
|
||||||
// Auto-follow: if a generation just finished for this group, jump to the last (newest) image
|
// Auto-follow: if a generation just finished for this group, jump to the image
|
||||||
if (_followLatestGid === gid && _isStudioOpen() && lbCurrentGid === gid && names.length > 0) {
|
if (_followLatestFilename && names.includes(_followLatestFilename) && _isStudioOpen() && lbCurrentGid === gid) {
|
||||||
|
lbIdx = names.indexOf(_followLatestFilename);
|
||||||
|
_followLatestFilename = null;
|
||||||
|
_followLatestGid = null;
|
||||||
|
lbUrls = urls;
|
||||||
|
lbNames = names;
|
||||||
|
updateStudio();
|
||||||
|
} else if (_followLatestGid === gid && _isStudioOpen() && lbCurrentGid === gid && names.length > 0) {
|
||||||
_followLatestGid = null;
|
_followLatestGid = null;
|
||||||
lbIdx = names.length - 1;
|
lbIdx = names.length - 1;
|
||||||
lbUrls = urls;
|
lbUrls = urls;
|
||||||
@@ -9777,6 +9818,15 @@
|
|||||||
if ((e.key === 'p' || e.key === 'P') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
if ((e.key === 'p' || e.key === 'P') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
||||||
togglePrivacyMode(); return;
|
togglePrivacyMode(); return;
|
||||||
}
|
}
|
||||||
|
if ((e.key === 'c' || e.key === 'C') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
||||||
|
if (document.getElementById('studio').classList.contains('open')) {
|
||||||
|
const cb = document.getElementById('sbCheckerboard');
|
||||||
|
const viewer = document.getElementById('studioViewer');
|
||||||
|
const cur = viewer ? viewer.classList.contains('show-checker') : (cb ? cb.checked : false);
|
||||||
|
toggleCheckerboard(!cur);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((e.key === 'a' || e.key === 'A') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
if ((e.key === 'a' || e.key === 'A') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
||||||
if (document.getElementById('studio').classList.contains('open')) {
|
if (document.getElementById('studio').classList.contains('open')) {
|
||||||
startManualPad(); return;
|
startManualPad(); return;
|
||||||
@@ -10178,7 +10228,7 @@
|
|||||||
<span style="font-size:11px;color:#666" title="Expand canvas before generation — gives the model space to outpaint">Pad:</span>
|
<span style="font-size:11px;color:#666" title="Expand canvas before generation — gives the model space to outpaint">Pad:</span>
|
||||||
${['Top','Right','Bottom','Left'].map(side => {
|
${['Top','Right','Bottom','Left'].map(side => {
|
||||||
const val = side==='Top'?_sbPadTop:side==='Right'?_sbPadRight:side==='Bottom'?_sbPadBottom:_sbPadLeft;
|
const val = side==='Top'?_sbPadTop:side==='Right'?_sbPadRight:side==='Bottom'?_sbPadBottom:_sbPadLeft;
|
||||||
const onInput = `updateSbGenBtn(); updatePadPreview()`;
|
const onInput = `syncPadFields(this)`;
|
||||||
const onBlur = `this.value = formatPadValue(this.value); ${onInput}`;
|
const onBlur = `this.value = formatPadValue(this.value); ${onInput}`;
|
||||||
return `<label style="display:flex;align-items:center;gap:2px;font-size:11px;color:#888">${side[0]}
|
return `<label style="display:flex;align-items:center;gap:2px;font-size:11px;color:#888">${side[0]}
|
||||||
<input type="text" id="sbPad${side}" value="${val}" placeholder="px or %"
|
<input type="text" id="sbPad${side}" value="${val}" placeholder="px or %"
|
||||||
@@ -11485,6 +11535,7 @@
|
|||||||
function renderSidebarSegment() {
|
function renderSidebarSegment() {
|
||||||
const panel = document.getElementById('sbPanelSegment');
|
const panel = document.getElementById('sbPanelSegment');
|
||||||
if (!panel) return;
|
if (!panel) return;
|
||||||
|
const isChecked = document.getElementById('studioViewer')?.classList.contains('show-checker');
|
||||||
panel.innerHTML = `
|
panel.innerHTML = `
|
||||||
<div style="font-size:11px;color:#666;margin-bottom:12px;line-height:1.6">
|
<div style="font-size:11px;color:#666;margin-bottom:12px;line-height:1.6">
|
||||||
Remove background using SAM2 or rembg fallback. The original file is
|
Remove background using SAM2 or rembg fallback. The original file is
|
||||||
@@ -11499,7 +11550,7 @@
|
|||||||
<div id="sbSegStatus" style="font-size:11px;color:#aaa;min-height:16px;margin-bottom:10px"></div>
|
<div id="sbSegStatus" style="font-size:11px;color:#aaa;min-height:16px;margin-bottom:10px"></div>
|
||||||
<div class="sb-sep"></div>
|
<div class="sb-sep"></div>
|
||||||
<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;margin-bottom:6px">
|
<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;margin-bottom:6px">
|
||||||
<input type="checkbox" id="sbCheckerboard" onchange="toggleCheckerboard(this.checked)">
|
<input type="checkbox" id="sbCheckerboard" onchange="toggleCheckerboard(this.checked)" ${isChecked ? 'checked' : ''}>
|
||||||
<span>Checkerboard (show transparency)</span>
|
<span>Checkerboard (show transparency)</span>
|
||||||
</label>
|
</label>
|
||||||
<div style="font-size:10px;color:#555;line-height:1.4">
|
<div style="font-size:10px;color:#555;line-height:1.4">
|
||||||
@@ -11598,6 +11649,8 @@
|
|||||||
function toggleCheckerboard(on) {
|
function toggleCheckerboard(on) {
|
||||||
const viewer = document.getElementById('studioViewer');
|
const viewer = document.getElementById('studioViewer');
|
||||||
if (viewer) viewer.classList.toggle('show-checker', on);
|
if (viewer) viewer.classList.toggle('show-checker', on);
|
||||||
|
const cb = document.getElementById('sbCheckerboard');
|
||||||
|
if (cb) cb.checked = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- set preferred ----
|
// ---- set preferred ----
|
||||||
|
|||||||
@@ -1456,7 +1456,7 @@ def _batch_worker(job_id: str, filenames: list, prompts: list[str], poses: list,
|
|||||||
seed: int, max_area: int, group_id: str | None = None,
|
seed: int, max_area: int, group_id: str | None = None,
|
||||||
wireframe_ref: str | None = None, wireframe_time: float = 0.5,
|
wireframe_ref: str | None = None, wireframe_time: float = 0.5,
|
||||||
pad_top: Any = 0, pad_right: Any = 0,
|
pad_top: Any = 0, pad_right: Any = 0,
|
||||||
pad_bottom: Any = 0, pad_left: Any = 0, pad_fill: str = "black",
|
pad_bottom: Any = 0, pad_left: Any = 0, pad_fill: str = "transparent",
|
||||||
pad_outpaint: bool = False):
|
pad_outpaint: bool = False):
|
||||||
output_dir = _load_output_dir()
|
output_dir = _load_output_dir()
|
||||||
for fname in filenames:
|
for fname in filenames:
|
||||||
@@ -3571,13 +3571,13 @@ class PadRequest(BaseModel):
|
|||||||
bottom: int | float | str = 0
|
bottom: int | float | str = 0
|
||||||
left: int | float | str = 0
|
left: int | float | str = 0
|
||||||
as_copy: bool = True
|
as_copy: bool = True
|
||||||
fill: str = "black" # "black", "white", "transparent"
|
fill: str = "transparent" # "black", "white", "transparent"
|
||||||
outpaint: bool = False
|
outpaint: bool = False
|
||||||
prompt: str | None = None
|
prompt: str | None = None
|
||||||
|
|
||||||
|
|
||||||
def _apply_manual_pad(pil: Image.Image, top, right, bottom, left,
|
def _apply_manual_pad(pil: Image.Image, top, right, bottom, left,
|
||||||
fill: str = "black") -> Image.Image:
|
fill: str = "transparent") -> Image.Image:
|
||||||
"""Expand canvas by padding pixels on each side. Fill with black, white, or transparency.
|
"""Expand canvas by padding pixels on each side. Fill with black, white, or transparency.
|
||||||
Supports pixel values (int) or percentages (str like "10%" or float < 1.0).
|
Supports pixel values (int) or percentages (str like "10%" or float < 1.0).
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -55,12 +55,13 @@ Keep full characteristics of reference image.
|
|||||||
|
|
||||||
# Three-quarter (18)
|
# Three-quarter (18)
|
||||||
|
|
||||||
You are in a black empty void.
|
You are in a black empty void, transparent background.
|
||||||
high quality, masterpiece, detailed, detailed skin.
|
masterpiece, high quality, detailed, detailed skin.
|
||||||
Head-on a right-front detailed full-nude-body. Top-to-toe photo.
|
Head-on a right-front.
|
||||||
female teenage, photorealistic, sharp focus, transparent background.
|
Detailed full-nude-body.
|
||||||
Identical person from reference image.
|
Top-to-toe photo.
|
||||||
Keep characteristics of reference image.
|
female teenage, hyper realistic.
|
||||||
|
Anatomically precise. Keep characteristics of reference image.
|
||||||
|
|
||||||
# Three-quarter
|
# Three-quarter
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user