+
Hidden from preview
@@ -2051,7 +2058,7 @@
-
+
@@ -2220,8 +2227,8 @@
// --- HYDRATION_START ---
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_232843_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",
@@ -6914,19 +6921,61 @@
updatePadPreview();
}
+ function getImageDisplayRect(img) {
+ if (!img || !img.naturalWidth) return null;
+ const rect = img.getBoundingClientRect();
+ const container = img.parentElement;
+ const crect = container.getBoundingClientRect();
+
+ const iw = img.naturalWidth;
+ const ih = img.naturalHeight;
+ const cw = rect.width;
+ const ch = rect.height;
+
+ const aspect = iw / ih;
+ const caspect = cw / ch;
+
+ let dw, dh, dl, dt;
+ if (aspect > caspect) {
+ dw = cw;
+ dh = cw / aspect;
+ dl = 0;
+ dt = (ch - dh) / 2;
+ } else {
+ dh = ch;
+ dw = ch * aspect;
+ dt = 0;
+ dl = (cw - dw) / 2;
+ }
+
+ // Adjust relative to container if needed, but since img is a flex item
+ // centered in .studio-viewer, its rect.left/top might already be offset.
+ // Actually, dl and dt above are relative to the img element's box.
+ // We want coordinates relative to .studio-viewer.
+ const finalLeft = rect.left - crect.left + dl;
+ const finalTop = rect.top - crect.top + dt;
+
+ return { left: finalLeft, top: finalTop, width: dw, height: dh };
+ }
+
function updatePadPreview() {
const viewer = document.getElementById('studioViewer');
- if (!viewer) return;
+ const img = document.getElementById('lbImg');
+ if (!viewer || !img || img.style.display === 'none') return;
+
// Clean up existing preview overlays
viewer.querySelectorAll('.pad-preview-overlay').forEach(el => el.remove());
+ const rect = getImageDisplayRect(img);
+ if (!rect) return;
+
const isManual = !!document.getElementById('padBar');
const getV = (side) => {
const el = document.getElementById(isManual ? 'pad' + side : 'sbPad' + side);
return el ? el.value : '0';
};
- const sides = ['Left', 'Right'];
+ const sides = ['Left', 'Right', 'Top', 'Bottom'];
sides.forEach(side => {
const vStr = getV(side);
if (!vStr || vStr === '0' || vStr === '0.00') return;
@@ -6934,19 +6983,24 @@
const val = parseFloat(vStr);
if (isNaN(val) || val <= 0) return;
- const isPercent = vStr.includes('%') || vStr.includes('.');
- const width = isPercent ? (val + '%') : (val + 'px');
-
+ const isPercent = vStr.includes('%') || (vStr.indexOf('.') !== -1 && !isNaN(vStr));
const overlay = document.createElement('div');
overlay.className = 'pad-preview-overlay';
- overlay.style.top = '0';
- overlay.style.bottom = '0';
- if (side === 'Left') {
- overlay.style.left = '0';
- overlay.style.width = width;
+
+ if (side === 'Left' || side === 'Right') {
+ const w = isPercent ? (rect.width * val / 100) : val;
+ overlay.style.width = w + 'px';
+ overlay.style.top = rect.top + 'px';
+ overlay.style.height = rect.height + 'px';
+ if (side === 'Left') overlay.style.left = (rect.left - w) + 'px';
+ else overlay.style.left = (rect.left + rect.width) + 'px';
} else {
- overlay.style.right = '0';
- overlay.style.width = width;
+ const h = isPercent ? (rect.height * val / 100) : val;
+ overlay.style.height = h + 'px';
+ overlay.style.left = rect.left + 'px';
+ overlay.style.width = rect.width + 'px';
+ if (side === 'Top') overlay.style.top = (rect.top - h) + 'px';
+ else overlay.style.top = (rect.top + rect.height) + 'px';
}
viewer.appendChild(overlay);
});
@@ -7075,6 +7129,29 @@
const isVid = isVideo(fname) || fileContentType[fname] === 'video';
const lbImgEl = document.getElementById('lbImg');
const lbVideoEl = document.getElementById('lbVideo');
+
+ lbImgEl.onload = () => {
+ const dimEl = document.getElementById('lbImgDims');
+ if (dimEl) dimEl.textContent = `${lbImgEl.naturalWidth} x ${lbImgEl.naturalHeight}`;
+
+ // Use requestAnimationFrame to ensure layout has updated before measuring for checkerboard/previews
+ requestAnimationFrame(() => {
+ updatePadPreview();
+ const cb = document.getElementById('sbCheckerboard');
+ if (cb && cb.checked) toggleCheckerboard(true);
+ });
+ };
+
+ // Show image dimensions
+ const dimEl = document.getElementById('lbImgDims');
+ if (dimEl) {
+ if (!isVid && lbImgEl.naturalWidth) {
+ dimEl.textContent = `${lbImgEl.naturalWidth} x ${lbImgEl.naturalHeight}`;
+ } else {
+ dimEl.textContent = '';
+ }
+ }
+
if (isVid) {
lbImgEl.style.display = 'none';
lbVideoEl.style.display = '';
@@ -8201,7 +8278,7 @@
return `
`;
};
bar.innerHTML =
- `
Pad canvas (px or %):`
+ `
Expand canvas (px or %):`
+ numInput('padTop','↑')
+ numInput('padRight','→')
+ numInput('padBottom','↓')
@@ -8216,7 +8293,7 @@
+ `
`
+ `
`
- + `
`;
+ + `
`;
viewer.appendChild(bar);
updatePadPreview();
}
@@ -8279,12 +8356,11 @@
refreshNow(true);
} else {
showToast('Padded', 'success');
- lbUrls[lbIdx] = IMAGE_FOLDER + fname + '?t=' + Date.now();
- updateStudio();
+ _bustStudioImage(fname);
}
} else {
showToast('Pad failed: ' + await r.text(), 'error');
- if (btn) { btn.disabled = false; btn.textContent = 'Pad'; }
+ if (btn) { btn.disabled = false; btn.textContent = 'Expand'; }
}
} catch (e) {
showToast('Pad error: ' + e, 'error');
@@ -9802,6 +9878,15 @@
// Initialize
document.addEventListener('DOMContentLoaded', () => {
+ window.addEventListener('resize', () => {
+ if (_isStudioOpen()) {
+ requestAnimationFrame(() => {
+ updatePadPreview();
+ const cb = document.getElementById('sbCheckerboard');
+ if (cb && cb.checked) toggleCheckerboard(true);
+ });
+ }
+ });
loadPromptHistory();
loadImages();
autoRefreshTimer = setInterval(_timedRefresh, REFRESH_INTERVAL * 1000);
@@ -11648,7 +11733,28 @@
function toggleCheckerboard(on) {
const viewer = document.getElementById('studioViewer');
+ const cbLayer = document.getElementById('studioCheckerboard');
+ const img = document.getElementById('lbImg');
+
if (viewer) viewer.classList.toggle('show-checker', on);
+
+ if (cbLayer) {
+ if (on && img && img.style.display !== 'none') {
+ const rect = getImageDisplayRect(img);
+ if (rect) {
+ cbLayer.style.display = 'block';
+ cbLayer.style.left = rect.left + 'px';
+ cbLayer.style.top = rect.top + 'px';
+ cbLayer.style.width = rect.width + 'px';
+ cbLayer.style.height = rect.height + 'px';
+ } else {
+ cbLayer.style.display = 'none';
+ }
+ } else {
+ cbLayer.style.display = 'none';
+ }
+ }
+
const cb = document.getElementById('sbCheckerboard');
if (cb) cb.checked = on;
}