jhh6576 commited on
Commit
2767300
·
verified ·
1 Parent(s): e0f2d51

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +34 -22
app_enhanced.py CHANGED
@@ -509,7 +509,7 @@ class EnhancedComicGenerator:
509
  .panel img { width: 100%; height: 100%; object-fit: cover; object-position: center; transition: transform 0.1s ease-out; }
510
  .panel img.pannable { cursor: grab; }
511
  .panel img.panning { cursor: grabbing; }
512
- .speech-bubble { font-family: 'Comic Neue', cursive; position: absolute; display: flex; justify-content: center; align-items: center; width: 150px; height: 80px; min-width: 50px; max-width: 220px; min-height: 30px; box-sizing: border-box; padding: 8px; box-shadow: 2px 2px 5px rgba(0,0,0,0.3); z-index: 10; cursor: move; overflow: visible; font-size: 13px; font-weight: bold; text-align: center; }
513
  .bubble-text { padding: 2px; word-wrap: break-word; }
514
  .speech-bubble.selected { outline: 2px dashed #4CAF50; }
515
  .speech-bubble textarea { position: absolute; top: 0; left: 0; width: 100%; height: 100%; box-sizing: border-box; border: 1px solid #4CAF50; background: rgba(255,255,255,0.95); font: inherit; text-align: center; resize: none; padding: 8px; z-index: 102; }
@@ -623,8 +623,7 @@ class EnhancedComicGenerator:
623
  let currentlySelectedBubble = null;
624
  let currentlySelectedPanel = null;
625
  let isPanning = false, panStartX, panStartY, panStartTranslateX, panStartTranslateY;
626
- let isResizing = false;
627
- let resizeHandle, originalWidth, originalHeight, originalX, originalY, originalMouseX, originalMouseY;
628
 
629
  function renderComic(data) {
630
  const container = document.getElementById('comic-pages');
@@ -646,14 +645,12 @@ class EnhancedComicGenerator:
646
  const img = document.createElement('img');
647
  img.src = '/frames/final/' + panelData.image;
648
  panelDiv.appendChild(img);
649
- // *** FIX: Corrected logic to show all bubbles ***
650
- if (pageData.bubbles && pageData.bubbles[panelIndex]) {
651
- const bubbleData = pageData.bubbles[panelIndex];
652
  const bubbleDiv = createBubbleElement({
653
  id: `initial-${pageIndex}-${panelIndex}`,
654
- text: bubbleData.dialog || '',
655
- left: `${bubbleData.bubble_offset_x ?? 50}px`,
656
- top: `${bubbleData.bubble_offset_y ?? 20}px`,
657
  });
658
  panelDiv.appendChild(bubbleDiv);
659
  }
@@ -672,14 +669,12 @@ class EnhancedComicGenerator:
672
  });
673
  document.querySelectorAll('.speech-bubble').forEach(initializeBubbleEvents);
674
  document.getElementById('zoom-slider').addEventListener('input', handleZoom);
675
-
676
  document.getElementById('bubble-text-color').addEventListener('input', (e) => {
677
  if(currentlySelectedBubble) currentlySelectedBubble.style.color = e.target.value;
678
  });
679
  document.getElementById('bubble-fill-color').addEventListener('input', (e) => {
680
  if(currentlySelectedBubble) currentlySelectedBubble.style.backgroundColor = e.target.value;
681
  });
682
-
683
  document.addEventListener('mousemove', e => { if (isPanning) panImage(e); if (draggedBubble) drag(e); if(isResizing) resizeBubble(e); });
684
  document.addEventListener('mouseup', e => { if (isPanning) stopPan(e); if (draggedBubble) stopDrag(e); if(isResizing) stopResize(e);});
685
  document.addEventListener('mouseleave', e => { if (isPanning) stopPan(e); if (draggedBubble) stopDrag(e); if(isResizing) stopResize(e);});
@@ -689,7 +684,6 @@ class EnhancedComicGenerator:
689
  bubble.addEventListener('dblclick', e => { e.stopPropagation(); editBubbleText(bubble); });
690
  bubble.addEventListener('mousedown', e => { e.stopPropagation(); startDrag(e); });
691
  bubble.addEventListener('click', e => { e.stopPropagation(); selectBubble(bubble); });
692
-
693
  ['nw', 'ne', 'sw', 'se'].forEach(dir => {
694
  const handle = document.createElement('div');
695
  handle.className = `resize-handle ${dir}`;
@@ -765,28 +759,29 @@ class EnhancedComicGenerator:
765
  panel.classList.add('selected');
766
  currentlySelectedPanel = panel;
767
  selectBubble(null);
768
- const img = currentlySelectedPanel.querySelector('img');
769
- document.getElementById('zoom-slider').value = img.dataset.zoom || 100;
770
- document.getElementById('zoom-slider').disabled = false;
771
  }
772
 
773
  function selectBubble(bubble) {
774
  if (currentlySelectedBubble) currentlySelectedBubble.classList.remove('selected');
775
  currentlySelectedBubble = bubble;
776
  const bubbleControls = ['bubble-text-color', 'bubble-fill-color', 'bubble-type-select', 'font-select'];
 
777
  if (currentlySelectedBubble) {
778
  currentlySelectedBubble.classList.add('selected');
779
  if (currentlySelectedPanel) currentlySelectedPanel.classList.remove('selected');
780
  currentlySelectedPanel = null;
 
781
  const styles = window.getComputedStyle(currentlySelectedBubble);
782
  document.getElementById('bubble-text-color').value = rgbToHex(styles.color);
783
  document.getElementById('bubble-fill-color').value = rgbToHex(styles.backgroundColor);
784
  document.getElementById('bubble-type-select').value = currentlySelectedBubble.dataset.type || 'speech';
785
  document.getElementById('font-select').value = styles.fontFamily.split(',')[0].replace(/"/g, "").replace(/'/g, "").trim();
 
786
  document.getElementById('zoom-slider').disabled = true;
787
  bubbleControls.forEach(id => document.getElementById(id).disabled = false);
788
  } else {
789
  bubbleControls.forEach(id => document.getElementById(id).disabled = true);
 
790
  }
791
  }
792
 
@@ -797,6 +792,7 @@ class EnhancedComicGenerator:
797
  const textarea = document.createElement('textarea');
798
  const originalHeight = bubble.offsetHeight;
799
  bubble.style.height = `${originalHeight}px`;
 
800
  textarea.value = textSpan.textContent;
801
  bubble.appendChild(textarea);
802
  textSpan.style.display = 'none';
@@ -806,7 +802,6 @@ class EnhancedComicGenerator:
806
  bubble.removeChild(textarea);
807
  textSpan.style.display = '';
808
  currentlyEditing = null;
809
- bubble.style.height = 'auto'; // Let it reflow naturally
810
  };
811
  textarea.addEventListener('blur', finishEditing, { once: true });
812
  textarea.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); textarea.blur(); }});
@@ -841,7 +836,7 @@ class EnhancedComicGenerator:
841
  selectBubble(null);
842
  }
843
  }
844
-
845
  function startResize(e, dir) {
846
  e.preventDefault();
847
  e.stopPropagation();
@@ -863,10 +858,16 @@ class EnhancedComicGenerator:
863
  const dy = e.clientY - originalMouseY;
864
  const bubble = currentlySelectedBubble;
865
 
866
- if (resizeHandle.includes('e')) { bubble.style.width = `${originalWidth + dx}px`; }
867
- if (resizeHandle.includes('w')) { bubble.style.width = `${originalWidth - dx}px`; bubble.style.left = `${originalX + dx}px`; }
868
- if (resizeHandle.includes('s')) { bubble.style.height = `${originalHeight + dy}px`; }
869
- if (resizeHandle.includes('n')) { bubble.style.height = `${originalHeight - dy}px`; bubble.style.top = `${originalY + dy}px`; }
 
 
 
 
 
 
870
  }
871
 
872
  function stopResize() { isResizing = false; }
@@ -879,7 +880,18 @@ class EnhancedComicGenerator:
879
  }
880
 
881
  async function exportPagesToPNG() {
882
- // function content...
 
 
 
 
 
 
 
 
 
 
 
883
  }
884
 
885
  function replacePanelImage() {
 
509
  .panel img { width: 100%; height: 100%; object-fit: cover; object-position: center; transition: transform 0.1s ease-out; }
510
  .panel img.pannable { cursor: grab; }
511
  .panel img.panning { cursor: grabbing; }
512
+ .speech-bubble { font-family: 'Comic Neue', cursive; position: absolute; display: flex; justify-content: center; align-items: center; width: 150px; height: 80px; min-width: 50px; min-height: 30px; box-sizing: border-box; padding: 8px; box-shadow: 2px 2px 5px rgba(0,0,0,0.3); z-index: 10; cursor: move; overflow: visible; font-size: 13px; font-weight: bold; text-align: center; }
513
  .bubble-text { padding: 2px; word-wrap: break-word; }
514
  .speech-bubble.selected { outline: 2px dashed #4CAF50; }
515
  .speech-bubble textarea { position: absolute; top: 0; left: 0; width: 100%; height: 100%; box-sizing: border-box; border: 1px solid #4CAF50; background: rgba(255,255,255,0.95); font: inherit; text-align: center; resize: none; padding: 8px; z-index: 102; }
 
623
  let currentlySelectedBubble = null;
624
  let currentlySelectedPanel = null;
625
  let isPanning = false, panStartX, panStartY, panStartTranslateX, panStartTranslateY;
626
+ let isResizing = false, resizeHandle, originalWidth, originalHeight, originalX, originalY, originalMouseX, originalMouseY;
 
627
 
628
  function renderComic(data) {
629
  const container = document.getElementById('comic-pages');
 
645
  const img = document.createElement('img');
646
  img.src = '/frames/final/' + panelData.image;
647
  panelDiv.appendChild(img);
648
+ if (pageData.bubbles && pageData.bubbles[panelIndex] && pageData.bubbles[panelIndex].dialog) {
 
 
649
  const bubbleDiv = createBubbleElement({
650
  id: `initial-${pageIndex}-${panelIndex}`,
651
+ text: pageData.bubbles[panelIndex].dialog || '',
652
+ left: `${pageData.bubbles[panelIndex].bubble_offset_x ?? 50}px`,
653
+ top: `${pageData.bubbles[panelIndex].bubble_offset_y ?? 20}px`,
654
  });
655
  panelDiv.appendChild(bubbleDiv);
656
  }
 
669
  });
670
  document.querySelectorAll('.speech-bubble').forEach(initializeBubbleEvents);
671
  document.getElementById('zoom-slider').addEventListener('input', handleZoom);
 
672
  document.getElementById('bubble-text-color').addEventListener('input', (e) => {
673
  if(currentlySelectedBubble) currentlySelectedBubble.style.color = e.target.value;
674
  });
675
  document.getElementById('bubble-fill-color').addEventListener('input', (e) => {
676
  if(currentlySelectedBubble) currentlySelectedBubble.style.backgroundColor = e.target.value;
677
  });
 
678
  document.addEventListener('mousemove', e => { if (isPanning) panImage(e); if (draggedBubble) drag(e); if(isResizing) resizeBubble(e); });
679
  document.addEventListener('mouseup', e => { if (isPanning) stopPan(e); if (draggedBubble) stopDrag(e); if(isResizing) stopResize(e);});
680
  document.addEventListener('mouseleave', e => { if (isPanning) stopPan(e); if (draggedBubble) stopDrag(e); if(isResizing) stopResize(e);});
 
684
  bubble.addEventListener('dblclick', e => { e.stopPropagation(); editBubbleText(bubble); });
685
  bubble.addEventListener('mousedown', e => { e.stopPropagation(); startDrag(e); });
686
  bubble.addEventListener('click', e => { e.stopPropagation(); selectBubble(bubble); });
 
687
  ['nw', 'ne', 'sw', 'se'].forEach(dir => {
688
  const handle = document.createElement('div');
689
  handle.className = `resize-handle ${dir}`;
 
759
  panel.classList.add('selected');
760
  currentlySelectedPanel = panel;
761
  selectBubble(null);
 
 
 
762
  }
763
 
764
  function selectBubble(bubble) {
765
  if (currentlySelectedBubble) currentlySelectedBubble.classList.remove('selected');
766
  currentlySelectedBubble = bubble;
767
  const bubbleControls = ['bubble-text-color', 'bubble-fill-color', 'bubble-type-select', 'font-select'];
768
+
769
  if (currentlySelectedBubble) {
770
  currentlySelectedBubble.classList.add('selected');
771
  if (currentlySelectedPanel) currentlySelectedPanel.classList.remove('selected');
772
  currentlySelectedPanel = null;
773
+
774
  const styles = window.getComputedStyle(currentlySelectedBubble);
775
  document.getElementById('bubble-text-color').value = rgbToHex(styles.color);
776
  document.getElementById('bubble-fill-color').value = rgbToHex(styles.backgroundColor);
777
  document.getElementById('bubble-type-select').value = currentlySelectedBubble.dataset.type || 'speech';
778
  document.getElementById('font-select').value = styles.fontFamily.split(',')[0].replace(/"/g, "").replace(/'/g, "").trim();
779
+
780
  document.getElementById('zoom-slider').disabled = true;
781
  bubbleControls.forEach(id => document.getElementById(id).disabled = false);
782
  } else {
783
  bubbleControls.forEach(id => document.getElementById(id).disabled = true);
784
+ if(currentlySelectedPanel) document.getElementById('zoom-slider').disabled = false;
785
  }
786
  }
787
 
 
792
  const textarea = document.createElement('textarea');
793
  const originalHeight = bubble.offsetHeight;
794
  bubble.style.height = `${originalHeight}px`;
795
+
796
  textarea.value = textSpan.textContent;
797
  bubble.appendChild(textarea);
798
  textSpan.style.display = 'none';
 
802
  bubble.removeChild(textarea);
803
  textSpan.style.display = '';
804
  currentlyEditing = null;
 
805
  };
806
  textarea.addEventListener('blur', finishEditing, { once: true });
807
  textarea.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); textarea.blur(); }});
 
836
  selectBubble(null);
837
  }
838
  }
839
+
840
  function startResize(e, dir) {
841
  e.preventDefault();
842
  e.stopPropagation();
 
858
  const dy = e.clientY - originalMouseY;
859
  const bubble = currentlySelectedBubble;
860
 
861
+ if (resizeHandle.includes('e')) bubble.style.width = `${originalWidth + dx}px`;
862
+ if (resizeHandle.includes('w')) {
863
+ bubble.style.width = `${originalWidth - dx}px`;
864
+ bubble.style.left = `${originalX + dx}px`;
865
+ }
866
+ if (resizeHandle.includes('s')) bubble.style.height = `${originalHeight + dy}px`;
867
+ if (resizeHandle.includes('n')) {
868
+ bubble.style.height = `${originalHeight - dy}px`;
869
+ bubble.style.top = `${originalY + dy}px`;
870
+ }
871
  }
872
 
873
  function stopResize() { isResizing = false; }
 
880
  }
881
 
882
  async function exportPagesToPNG() {
883
+ const pages = document.querySelectorAll('.comic-page');
884
+ if (pages.length === 0) return alert("No pages found.");
885
+ alert(`Starting export of ${pages.length} page(s).`);
886
+ for (let i = 0; i < pages.length; i++) {
887
+ try {
888
+ const canvas = await html2canvas(pages[i], { scale: 2 });
889
+ const link = document.createElement('a');
890
+ link.download = `comic-page-${i + 1}.png`;
891
+ link.href = canvas.toDataURL('image/png');
892
+ link.click();
893
+ } catch (err) { alert(`Failed to export page ${i + 1}.`); }
894
+ }
895
  }
896
 
897
  function replacePanelImage() {