Update app_enhanced.py
Browse files- app_enhanced.py +88 -36
app_enhanced.py
CHANGED
|
@@ -100,7 +100,6 @@ def generate_comic_gpu(video_path, user_dir, frames_dir, metadata_path, status_p
|
|
| 100 |
frame_metadata[fname] = {'dialogue': moment['text'], 'time': mid}
|
| 101 |
frame_files_ordered.append(fname)
|
| 102 |
count += 1
|
| 103 |
-
# Update progress periodically
|
| 104 |
if count % 2 == 0:
|
| 105 |
prog = 30 + int((count / total_panels_needed) * 20)
|
| 106 |
update_status_file(status_path, f"Extracted Frame {count}/{total_panels_needed}", prog)
|
|
@@ -375,70 +374,74 @@ INDEX_HTML = '''
|
|
| 375 |
overflow: hidden;
|
| 376 |
border: 2px solid #000;
|
| 377 |
padding: 0;
|
| 378 |
-
/* SCALING FOR EDITOR VIEW
|
| 379 |
transform-origin: top center;
|
| 380 |
-
|
| 381 |
-
margin-bottom:
|
| 382 |
}
|
| 383 |
|
| 384 |
/* === 5-PANEL TEMPLATE (2 TOP, 3 BOTTOM) === */
|
| 385 |
-
/* Background White for
|
| 386 |
.comic-grid { width: 100%; height: 100%; position: relative; background: #ffffff; }
|
| 387 |
|
| 388 |
/* Panel Background White */
|
| 389 |
-
.panel { position: absolute; overflow: hidden; background: #ffffff; cursor: pointer; border: 0; }
|
| 390 |
.panel.selected { z-index: 20; }
|
| 391 |
.panel.selected img { outline: 3px solid #2196F3; outline-offset: -3px; }
|
| 392 |
|
| 393 |
/*
|
| 394 |
-
|
| 395 |
Row 1 Split: Top=63.2%, Bottom=59.5%
|
| 396 |
Row 2 Left Split: Top=33.0%, Bottom=35.7%
|
| 397 |
Row 2 Right Split: Top=64.8%, Bottom=68.2%
|
| 398 |
-
|
| 399 |
*/
|
| 400 |
|
| 401 |
-
/* --- ROW 1 (TOP) --- Height
|
| 402 |
|
| 403 |
-
/* Panel 1: Right ends at 63.2% / 59.5% */
|
| 404 |
.panel:nth-child(1) {
|
| 405 |
-
top: 0; left: 0; height:
|
| 406 |
-
clip-path: polygon(0% 0%,
|
| 407 |
}
|
| 408 |
-
/* Panel 2: Left starts at 63.2% / 59.5% */
|
| 409 |
.panel:nth-child(2) {
|
| 410 |
-
top: 0; left: 0; height:
|
| 411 |
-
clip-path: polygon(63.
|
| 412 |
}
|
| 413 |
|
| 414 |
-
/* --- ROW 2 (BOTTOM) --- Top: 50
|
| 415 |
|
| 416 |
-
/* Panel 3: Right ends at 33.0% / 35.7% */
|
| 417 |
.panel:nth-child(3) {
|
| 418 |
-
top: 50%; left: 0; height:
|
| 419 |
-
clip-path: polygon(0% 0%,
|
| 420 |
}
|
| 421 |
-
/* Panel 4: Left starts 33.0
|
| 422 |
.panel:nth-child(4) {
|
| 423 |
-
top: 50%; left: 0; height:
|
| 424 |
-
clip-path: polygon(33.
|
| 425 |
}
|
| 426 |
-
/* Panel 5: Left starts 64.8
|
| 427 |
.panel:nth-child(5) {
|
| 428 |
-
top: 50%; left: 0; height:
|
| 429 |
-
clip-path: polygon(
|
| 430 |
}
|
| 431 |
|
| 432 |
/* ====================== */
|
| 433 |
|
| 434 |
/*
|
| 435 |
-
IMAGE FIT: 'fill'
|
|
|
|
|
|
|
|
|
|
| 436 |
*/
|
| 437 |
.panel img {
|
| 438 |
width: 100%; height: 100%;
|
| 439 |
-
object-fit: fill;
|
| 440 |
transition: transform 0.1s ease-out;
|
| 441 |
transform-origin: center center;
|
|
|
|
| 442 |
}
|
| 443 |
/* Toggle classes */
|
| 444 |
.panel img.fit-cover { object-fit: cover !important; }
|
|
@@ -969,12 +972,51 @@ INDEX_HTML = '''
|
|
| 969 |
document.getElementById('bubble-text-color').addEventListener('change', (e) => { if(selectedBubble) { selectedBubble.style.setProperty('--bubble-text-color', e.target.value); saveDraft(true); } });
|
| 970 |
document.getElementById('bubble-fill-color').addEventListener('change', (e) => { if(selectedBubble) { selectedBubble.style.setProperty('--bubble-fill-color', e.target.value); saveDraft(true); } });
|
| 971 |
|
| 972 |
-
function handleZoom(el) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 973 |
document.getElementById('zoom-slider').addEventListener('change', () => saveDraft(true));
|
| 974 |
-
|
| 975 |
-
function
|
| 976 |
-
|
| 977 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 978 |
|
| 979 |
function replacePanelImage() { if(!selectedPanel) return alert("Select a panel"); const inp = document.getElementById('image-uploader'); inp.onchange = async (e) => { const fd = new FormData(); fd.append('image', e.target.files[0]); const img = selectedPanel.querySelector('img'); const r = await fetch(`/replace_panel?sid=${sid}`, {method:'POST', body:fd}); const d = await r.json(); if(d.success) { img.src = `/frames/${d.new_filename}?sid=${sid}`; saveDraft(true); } inp.value = ''; }; inp.click(); }
|
| 980 |
async function adjustFrame(dir) { if(isProcessing) return; if(!selectedPanel) return alert("Select a panel"); const img = selectedPanel.querySelector('img'); let fname = img.src.split('/').pop().split('?')[0]; setProcessing(true); img.style.opacity = '0.5'; try { const r = await fetch(`/regenerate_frame?sid=${sid}`, { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({filename:fname, direction:dir}) }); const d = await r.json(); if(d.success) { img.src = `/frames/${fname}?sid=${sid}&t=${Date.now()}`; } else { alert('Error: ' + d.message); } } catch(e) { console.error(e); } img.style.opacity = '1'; setProcessing(false); saveDraft(true); }
|
|
@@ -1000,6 +1042,13 @@ INDEX_HTML = '''
|
|
| 1000 |
if(selectedPanel) selectedPanel.classList.remove('selected');
|
| 1001 |
alert(`Exporting ${pgs.length} page(s)...`);
|
| 1002 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1003 |
// --- 0% ERROR FIX ---
|
| 1004 |
// 1. Lock specific pixel dimensions + 1px buffer to prevent word wrapping
|
| 1005 |
const bubbles = document.querySelectorAll('.speech-bubble');
|
|
@@ -1017,8 +1066,8 @@ INDEX_HTML = '''
|
|
| 1017 |
for(let i = 0; i < pgs.length; i++) {
|
| 1018 |
try {
|
| 1019 |
const u = await htmlToImage.toPng(pgs[i], {
|
| 1020 |
-
pixelRatio: 2, // High quality
|
| 1021 |
-
style: { transform: 'none' }
|
| 1022 |
});
|
| 1023 |
const a = document.createElement('a');
|
| 1024 |
a.href = u;
|
|
@@ -1030,8 +1079,11 @@ INDEX_HTML = '''
|
|
| 1030 |
}
|
| 1031 |
}
|
| 1032 |
|
| 1033 |
-
//
|
| 1034 |
-
|
|
|
|
|
|
|
|
|
|
| 1035 |
}
|
| 1036 |
|
| 1037 |
function goBackToUpload() { if(confirm('Go home? Unsaved changes will be lost.')) { document.getElementById('editor-container').style.display = 'none'; document.getElementById('upload-container').style.display = 'flex'; document.getElementById('loading-view').style.display = 'none'; } }
|
|
|
|
| 100 |
frame_metadata[fname] = {'dialogue': moment['text'], 'time': mid}
|
| 101 |
frame_files_ordered.append(fname)
|
| 102 |
count += 1
|
|
|
|
| 103 |
if count % 2 == 0:
|
| 104 |
prog = 30 + int((count / total_panels_needed) * 20)
|
| 105 |
update_status_file(status_path, f"Extracted Frame {count}/{total_panels_needed}", prog)
|
|
|
|
| 374 |
overflow: hidden;
|
| 375 |
border: 2px solid #000;
|
| 376 |
padding: 0;
|
| 377 |
+
/* SCALING FOR EDITOR VIEW */
|
| 378 |
transform-origin: top center;
|
| 379 |
+
transform: scale(0.6);
|
| 380 |
+
margin-bottom: -280px; /* Compensate for scale empty space */
|
| 381 |
}
|
| 382 |
|
| 383 |
/* === 5-PANEL TEMPLATE (2 TOP, 3 BOTTOM) === */
|
| 384 |
+
/* Background White for 12px Gutter (1.2% width, 1.7% height of 712px) */
|
| 385 |
.comic-grid { width: 100%; height: 100%; position: relative; background: #ffffff; }
|
| 386 |
|
| 387 |
/* Panel Background White */
|
| 388 |
+
.panel { position: absolute; overflow: hidden; background: #ffffff; cursor: pointer; border: 0; display:flex; justify-content:center; align-items:center; }
|
| 389 |
.panel.selected { z-index: 20; }
|
| 390 |
.panel.selected img { outline: 3px solid #2196F3; outline-offset: -3px; }
|
| 391 |
|
| 392 |
/*
|
| 393 |
+
COORDINATES from Green Text:
|
| 394 |
Row 1 Split: Top=63.2%, Bottom=59.5%
|
| 395 |
Row 2 Left Split: Top=33.0%, Bottom=35.7%
|
| 396 |
Row 2 Right Split: Top=64.8%, Bottom=68.2%
|
| 397 |
+
Tier Height: 350px (approx 49.15% of 712px)
|
| 398 |
*/
|
| 399 |
|
| 400 |
+
/* --- ROW 1 (TOP) --- Height 49.15% */
|
| 401 |
|
| 402 |
+
/* Panel 1: Right ends at (63.2 - 0.6)% / (59.5 - 0.6)% */
|
| 403 |
.panel:nth-child(1) {
|
| 404 |
+
top: 0; left: 0; height: 49.15%; width: 100%;
|
| 405 |
+
clip-path: polygon(0% 0%, 62.6% 0%, 58.9% 100%, 0% 100%);
|
| 406 |
}
|
| 407 |
+
/* Panel 2: Left starts at (63.2 + 0.6)% / (59.5 + 0.6)% */
|
| 408 |
.panel:nth-child(2) {
|
| 409 |
+
top: 0; left: 0; height: 49.15%; width: 100%;
|
| 410 |
+
clip-path: polygon(63.8% 0%, 100% 0%, 100% 100%, 60.1% 100%);
|
| 411 |
}
|
| 412 |
|
| 413 |
+
/* --- ROW 2 (BOTTOM) --- Top: 50.85% (Gap ~1.7%), Height: 49.15% */
|
| 414 |
|
| 415 |
+
/* Panel 3: Right ends at (33.0 - 0.6)% / (35.7 - 0.6)% */
|
| 416 |
.panel:nth-child(3) {
|
| 417 |
+
top: 50.85%; left: 0; height: 49.15%; width: 100%;
|
| 418 |
+
clip-path: polygon(0% 0%, 32.4% 0%, 35.1% 100%, 0% 100%);
|
| 419 |
}
|
| 420 |
+
/* Panel 4: Left starts (33.0 + 0.6)% / (35.7 + 0.6)%. Right ends (64.8 - 0.6)% / (68.2 - 0.6)% */
|
| 421 |
.panel:nth-child(4) {
|
| 422 |
+
top: 50.85%; left: 0; height: 49.15%; width: 100%;
|
| 423 |
+
clip-path: polygon(33.6% 0%, 64.2% 0%, 67.6% 100%, 36.3% 100%);
|
| 424 |
}
|
| 425 |
+
/* Panel 5: Left starts (64.8 + 0.6)% / (68.2 + 0.6)% */
|
| 426 |
.panel:nth-child(5) {
|
| 427 |
+
top: 50.85%; left: 0; height: 49.15%; width: 100%;
|
| 428 |
+
clip-path: polygon(65.4% 0%, 100% 0%, 100% 100%, 68.8% 100%);
|
| 429 |
}
|
| 430 |
|
| 431 |
/* ====================== */
|
| 432 |
|
| 433 |
/*
|
| 434 |
+
IMAGE FIT: 'fill' to STRETCH fully into the panel shape
|
| 435 |
+
WITHOUT empty space and WITHOUT zooming.
|
| 436 |
+
(User accepted distortion over empty space/cutting)
|
| 437 |
+
Allowed to be transformed (panned/scaled) via JS if user wants.
|
| 438 |
*/
|
| 439 |
.panel img {
|
| 440 |
width: 100%; height: 100%;
|
| 441 |
+
object-fit: fill; /* STRETCH: No gaps, no cut */
|
| 442 |
transition: transform 0.1s ease-out;
|
| 443 |
transform-origin: center center;
|
| 444 |
+
display: block;
|
| 445 |
}
|
| 446 |
/* Toggle classes */
|
| 447 |
.panel img.fit-cover { object-fit: cover !important; }
|
|
|
|
| 972 |
document.getElementById('bubble-text-color').addEventListener('change', (e) => { if(selectedBubble) { selectedBubble.style.setProperty('--bubble-text-color', e.target.value); saveDraft(true); } });
|
| 973 |
document.getElementById('bubble-fill-color').addEventListener('change', (e) => { if(selectedBubble) { selectedBubble.style.setProperty('--bubble-fill-color', e.target.value); saveDraft(true); } });
|
| 974 |
|
| 975 |
+
function handleZoom(el) {
|
| 976 |
+
if(!selectedPanel) return;
|
| 977 |
+
const img = selectedPanel.querySelector('img');
|
| 978 |
+
img.dataset.zoom = el.value;
|
| 979 |
+
updateImageTransform(img);
|
| 980 |
+
}
|
| 981 |
document.getElementById('zoom-slider').addEventListener('change', () => saveDraft(true));
|
| 982 |
+
|
| 983 |
+
function startPan(e, img) {
|
| 984 |
+
// REMOVED ZOOM CHECK - ALLOW PAN ALWAYS
|
| 985 |
+
e.preventDefault();
|
| 986 |
+
isPanning = true;
|
| 987 |
+
selectedPanel = img.closest('.panel');
|
| 988 |
+
panStartX = e.clientX;
|
| 989 |
+
panStartY = e.clientY;
|
| 990 |
+
panStartTx = parseFloat(img.dataset.translateX || 0);
|
| 991 |
+
panStartTy = parseFloat(img.dataset.translateY || 0);
|
| 992 |
+
img.classList.add('panning');
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
function panImage(e) {
|
| 996 |
+
if(!isPanning || !selectedPanel) return;
|
| 997 |
+
const img = selectedPanel.querySelector('img');
|
| 998 |
+
img.dataset.translateX = panStartTx + (e.clientX - panStartX);
|
| 999 |
+
img.dataset.translateY = panStartTy + (e.clientY - panStartY);
|
| 1000 |
+
updateImageTransform(img);
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
function updateImageTransform(img) {
|
| 1004 |
+
const z = (img.dataset.zoom || 100) / 100;
|
| 1005 |
+
const x = img.dataset.translateX || 0;
|
| 1006 |
+
const y = img.dataset.translateY || 0;
|
| 1007 |
+
img.style.transform = `translateX(${x}px) translateY(${y}px) scale(${z})`;
|
| 1008 |
+
}
|
| 1009 |
+
|
| 1010 |
+
function resetPanelTransform() {
|
| 1011 |
+
if(!selectedPanel) return alert("Select a panel");
|
| 1012 |
+
const img = selectedPanel.querySelector('img');
|
| 1013 |
+
img.dataset.zoom = 100;
|
| 1014 |
+
img.dataset.translateX = 0;
|
| 1015 |
+
img.dataset.translateY = 0;
|
| 1016 |
+
document.getElementById('zoom-slider').value = 100;
|
| 1017 |
+
updateImageTransform(img);
|
| 1018 |
+
saveDraft(true);
|
| 1019 |
+
}
|
| 1020 |
|
| 1021 |
function replacePanelImage() { if(!selectedPanel) return alert("Select a panel"); const inp = document.getElementById('image-uploader'); inp.onchange = async (e) => { const fd = new FormData(); fd.append('image', e.target.files[0]); const img = selectedPanel.querySelector('img'); const r = await fetch(`/replace_panel?sid=${sid}`, {method:'POST', body:fd}); const d = await r.json(); if(d.success) { img.src = `/frames/${d.new_filename}?sid=${sid}`; saveDraft(true); } inp.value = ''; }; inp.click(); }
|
| 1022 |
async function adjustFrame(dir) { if(isProcessing) return; if(!selectedPanel) return alert("Select a panel"); const img = selectedPanel.querySelector('img'); let fname = img.src.split('/').pop().split('?')[0]; setProcessing(true); img.style.opacity = '0.5'; try { const r = await fetch(`/regenerate_frame?sid=${sid}`, { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({filename:fname, direction:dir}) }); const d = await r.json(); if(d.success) { img.src = `/frames/${fname}?sid=${sid}&t=${Date.now()}`; } else { alert('Error: ' + d.message); } } catch(e) { console.error(e); } img.style.opacity = '1'; setProcessing(false); saveDraft(true); }
|
|
|
|
| 1042 |
if(selectedPanel) selectedPanel.classList.remove('selected');
|
| 1043 |
alert(`Exporting ${pgs.length} page(s)...`);
|
| 1044 |
|
| 1045 |
+
// --- PREPARE FOR EXPORT: Remove editor scaling ---
|
| 1046 |
+
const comicPages = document.querySelectorAll('.comic-page');
|
| 1047 |
+
comicPages.forEach(page => {
|
| 1048 |
+
page.style.transform = 'none'; // Remove scaling from comic-page
|
| 1049 |
+
page.style.marginBottom = '0'; // Remove margin compensation
|
| 1050 |
+
});
|
| 1051 |
+
|
| 1052 |
// --- 0% ERROR FIX ---
|
| 1053 |
// 1. Lock specific pixel dimensions + 1px buffer to prevent word wrapping
|
| 1054 |
const bubbles = document.querySelectorAll('.speech-bubble');
|
|
|
|
| 1066 |
for(let i = 0; i < pgs.length; i++) {
|
| 1067 |
try {
|
| 1068 |
const u = await htmlToImage.toPng(pgs[i], {
|
| 1069 |
+
pixelRatio: 2, // High quality for print
|
| 1070 |
+
style: { transform: 'none' } // Ensure no transforms for html-to-image
|
| 1071 |
});
|
| 1072 |
const a = document.createElement('a');
|
| 1073 |
a.href = u;
|
|
|
|
| 1079 |
}
|
| 1080 |
}
|
| 1081 |
|
| 1082 |
+
// --- RESTORE EDITOR SCALING AFTER EXPORT ---
|
| 1083 |
+
comicPages.forEach(page => {
|
| 1084 |
+
page.style.transform = 'scale(0.6)';
|
| 1085 |
+
page.style.marginBottom = '-280px';
|
| 1086 |
+
});
|
| 1087 |
}
|
| 1088 |
|
| 1089 |
function goBackToUpload() { if(confirm('Go home? Unsaved changes will be lost.')) { document.getElementById('editor-container').style.display = 'none'; document.getElementById('upload-container').style.display = 'flex'; document.getElementById('loading-view').style.display = 'none'; } }
|