Update app_enhanced.py
Browse files- app_enhanced.py +48 -56
app_enhanced.py
CHANGED
|
@@ -73,6 +73,10 @@ INDEX_HTML = '''
|
|
| 73 |
<meta charset="UTF-8">
|
| 74 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 75 |
<title>Movie to Comic Generator</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
<style>
|
| 77 |
body {
|
| 78 |
background-color: #fdf6e3;
|
|
@@ -562,85 +566,75 @@ class EnhancedComicGenerator:
|
|
| 562 |
.speech-bubble.selected { outline: 2px dashed #4CAF50; }
|
| 563 |
.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; }
|
| 564 |
|
| 565 |
-
/* <<<
|
| 566 |
.speech-bubble.speech {
|
| 567 |
-
|
| 568 |
-
--
|
| 569 |
-
--
|
| 570 |
-
--t: 0.6; /* thickness factor */
|
| 571 |
-
--p: var(--tail-pos, 50%); /* Slider position */
|
| 572 |
-
--r: 15px; /* Border Radius */
|
| 573 |
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
padding: 1em;
|
| 578 |
-
|
| 579 |
-
/* Robust border-radius calculation using calc() for compatibility */
|
| 580 |
-
/* TopLeft TopRight BottomRight BottomLeft / VerticalRadius */
|
| 581 |
-
border-radius: var(--r) var(--r)
|
| 582 |
-
min(var(--r), calc(100% - var(--p) - (1 - var(--t)) * var(--b) / 2))
|
| 583 |
-
min(var(--r), calc(var(--p) - (1 - var(--t)) * var(--b) / 2))
|
| 584 |
-
/ var(--r);
|
| 585 |
-
|
| 586 |
-
/* Ensure it stays absolute to position on image */
|
| 587 |
-
position: absolute;
|
| 588 |
}
|
| 589 |
|
| 590 |
-
/* The Tail Pseudo-Element */
|
| 591 |
.speech-bubble.speech:before {
|
| 592 |
content: "";
|
| 593 |
position: absolute;
|
| 594 |
-
width:
|
| 595 |
-
height:
|
| 596 |
-
|
| 597 |
-
border-bottom-left-radius: 100%;
|
| 598 |
pointer-events: none;
|
| 599 |
|
| 600 |
-
/*
|
| 601 |
-
|
| 602 |
-
mask: radial-gradient(calc(var(--t)*100%) 105% at 100% 0, #0000 99%, #000 101%);
|
| 603 |
}
|
| 604 |
|
| 605 |
-
/* BOTTOM TAIL
|
| 606 |
.speech-bubble.speech.tail-bottom:before {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
top: 100%;
|
| 608 |
-
left:
|
|
|
|
| 609 |
}
|
| 610 |
|
| 611 |
-
/* TOP TAIL
|
| 612 |
-
.speech-bubble.speech.tail-top {
|
| 613 |
-
/* Flip border radius logic for top */
|
| 614 |
-
border-radius: min(var(--r), calc(var(--p) - (1 - var(--t)) * var(--b) / 2))
|
| 615 |
-
min(var(--r), calc(100% - var(--p) - (1 - var(--t)) * var(--b) / 2))
|
| 616 |
-
var(--r) var(--r) / var(--r);
|
| 617 |
-
}
|
| 618 |
.speech-bubble.speech.tail-top:before {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 619 |
bottom: 100%;
|
| 620 |
-
left:
|
| 621 |
-
transform:
|
| 622 |
}
|
| 623 |
|
| 624 |
-
/* LEFT TAIL
|
| 625 |
-
.speech-bubble.speech.tail-left {
|
| 626 |
-
border-radius: var(--r); /* Simplification for side tails to avoid breakage */
|
| 627 |
-
}
|
| 628 |
.speech-bubble.speech.tail-left:before {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 629 |
right: 100%;
|
| 630 |
-
top:
|
| 631 |
-
transform:
|
| 632 |
-
transform-origin: right top;
|
| 633 |
}
|
| 634 |
|
| 635 |
-
/* RIGHT TAIL
|
| 636 |
-
.speech-bubble.speech.tail-right {
|
| 637 |
-
border-radius: var(--r);
|
| 638 |
-
}
|
| 639 |
.speech-bubble.speech.tail-right:before {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 640 |
left: 100%;
|
| 641 |
-
top:
|
| 642 |
-
transform: rotate(
|
| 643 |
-
transform-origin: left
|
| 644 |
}
|
| 645 |
|
| 646 |
.speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
|
|
@@ -1072,11 +1066,10 @@ class EnhancedComicGenerator:
|
|
| 1072 |
const pages = document.querySelectorAll('.comic-page');
|
| 1073 |
if (pages.length === 0) return alert("No pages found.");
|
| 1074 |
|
| 1075 |
-
// 1. FREEZE DIMENSIONS BEFORE EXPORT
|
| 1076 |
const bubbles = document.querySelectorAll('.speech-bubble');
|
| 1077 |
bubbles.forEach(b => {
|
| 1078 |
const rect = b.getBoundingClientRect();
|
| 1079 |
-
// Force explicit dimensions to prevent html2canvas reflow
|
| 1080 |
b.style.width = rect.width + 'px';
|
| 1081 |
b.style.height = rect.height + 'px';
|
| 1082 |
b.style.minWidth = rect.width + 'px';
|
|
@@ -1102,7 +1095,6 @@ class EnhancedComicGenerator:
|
|
| 1102 |
b.style.minHeight = '30px';
|
| 1103 |
b.style.maxWidth = '';
|
| 1104 |
b.style.maxHeight = '';
|
| 1105 |
-
// We keep current width/height as user set them
|
| 1106 |
});
|
| 1107 |
}
|
| 1108 |
|
|
|
|
| 73 |
<meta charset="UTF-8">
|
| 74 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 75 |
<title>Movie to Comic Generator</title>
|
| 76 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
| 77 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 78 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 79 |
+
<link href="https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@700&family=Gloria+Hallelujah&family=Lato&display=swap" rel="stylesheet">
|
| 80 |
<style>
|
| 81 |
body {
|
| 82 |
background-color: #fdf6e3;
|
|
|
|
| 566 |
.speech-bubble.selected { outline: 2px dashed #4CAF50; }
|
| 567 |
.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; }
|
| 568 |
|
| 569 |
+
/* <<< ROBUST BORDER-BASED SHARK FIN TAIL >>> */
|
| 570 |
.speech-bubble.speech {
|
| 571 |
+
--bubble-fill-color: #4ECDC4; /* Default fill */
|
| 572 |
+
--bubble-text-color: #ffffff;
|
| 573 |
+
--tail-pos: 50%;
|
|
|
|
|
|
|
|
|
|
| 574 |
|
| 575 |
+
background: var(--bubble-fill-color);
|
| 576 |
+
color: var(--bubble-text-color);
|
| 577 |
+
border-radius: 12px;
|
| 578 |
padding: 1em;
|
| 579 |
+
position: absolute;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
}
|
| 581 |
|
| 582 |
+
/* The Tail Pseudo-Element using BORDERS (Export Safe) */
|
| 583 |
.speech-bubble.speech:before {
|
| 584 |
content: "";
|
| 585 |
position: absolute;
|
| 586 |
+
width: 0;
|
| 587 |
+
height: 0;
|
| 588 |
+
border-style: solid;
|
|
|
|
| 589 |
pointer-events: none;
|
| 590 |
|
| 591 |
+
/* Shark Fin Shape: Right Angled Triangle logic */
|
| 592 |
+
/* This creates a solid triangle that works in html2canvas */
|
|
|
|
| 593 |
}
|
| 594 |
|
| 595 |
+
/* BOTTOM TAIL */
|
| 596 |
.speech-bubble.speech.tail-bottom:before {
|
| 597 |
+
/* Triangle pointing down */
|
| 598 |
+
border-width: 25px 20px 0 0;
|
| 599 |
+
border-color: var(--bubble-fill-color) transparent transparent transparent;
|
| 600 |
+
|
| 601 |
top: 100%;
|
| 602 |
+
left: var(--tail-pos);
|
| 603 |
+
transform: translateX(-50%); /* Center the tip horizontally */
|
| 604 |
}
|
| 605 |
|
| 606 |
+
/* TOP TAIL */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
.speech-bubble.speech.tail-top:before {
|
| 608 |
+
/* Triangle pointing up */
|
| 609 |
+
border-width: 0 20px 25px 0;
|
| 610 |
+
border-color: transparent transparent var(--bubble-fill-color) transparent;
|
| 611 |
+
|
| 612 |
bottom: 100%;
|
| 613 |
+
left: var(--tail-pos);
|
| 614 |
+
transform: translateX(-50%);
|
| 615 |
}
|
| 616 |
|
| 617 |
+
/* LEFT TAIL */
|
|
|
|
|
|
|
|
|
|
| 618 |
.speech-bubble.speech.tail-left:before {
|
| 619 |
+
/* Triangle pointing left */
|
| 620 |
+
border-width: 0 25px 20px 0;
|
| 621 |
+
border-color: transparent var(--bubble-fill-color) transparent transparent;
|
| 622 |
+
|
| 623 |
right: 100%;
|
| 624 |
+
top: var(--tail-pos);
|
| 625 |
+
transform: translateY(-50%);
|
|
|
|
| 626 |
}
|
| 627 |
|
| 628 |
+
/* RIGHT TAIL */
|
|
|
|
|
|
|
|
|
|
| 629 |
.speech-bubble.speech.tail-right:before {
|
| 630 |
+
/* Triangle pointing right */
|
| 631 |
+
border-width: 20px 25px 0 0;
|
| 632 |
+
border-color: var(--bubble-fill-color) transparent transparent transparent;
|
| 633 |
+
|
| 634 |
left: 100%;
|
| 635 |
+
top: var(--tail-pos);
|
| 636 |
+
transform: translateY(-50%) rotate(90deg); /* Rotate standard triangle */
|
| 637 |
+
transform-origin: top left;
|
| 638 |
}
|
| 639 |
|
| 640 |
.speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
|
|
|
|
| 1066 |
const pages = document.querySelectorAll('.comic-page');
|
| 1067 |
if (pages.length === 0) return alert("No pages found.");
|
| 1068 |
|
| 1069 |
+
// 1. FREEZE DIMENSIONS BEFORE EXPORT (Prevents size reset bug)
|
| 1070 |
const bubbles = document.querySelectorAll('.speech-bubble');
|
| 1071 |
bubbles.forEach(b => {
|
| 1072 |
const rect = b.getBoundingClientRect();
|
|
|
|
| 1073 |
b.style.width = rect.width + 'px';
|
| 1074 |
b.style.height = rect.height + 'px';
|
| 1075 |
b.style.minWidth = rect.width + 'px';
|
|
|
|
| 1095 |
b.style.minHeight = '30px';
|
| 1096 |
b.style.maxWidth = '';
|
| 1097 |
b.style.maxHeight = '';
|
|
|
|
| 1098 |
});
|
| 1099 |
}
|
| 1100 |
|