Spaces:
Running on Zero
Running on Zero
Upload app.py
Browse files
app.py
CHANGED
|
@@ -684,31 +684,31 @@ def _snap_canvas(aspect: float, current_canvas: str) -> str:
|
|
| 684 |
return fastest[ratio][0]
|
| 685 |
|
| 686 |
def _cover_crop(image_path: str, canvas_label: str) -> str:
|
| 687 |
-
"""
|
| 688 |
|
| 689 |
-
|
| 690 |
-
|
|
|
|
| 691 |
"""
|
| 692 |
-
from PIL import Image as _Image
|
| 693 |
|
| 694 |
h, w = CANVASES[canvas_label]
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
if abs(img.width / img.height -
|
| 698 |
return image_path
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
img.save(image_path)
|
| 708 |
return image_path
|
| 709 |
|
| 710 |
def _fit_keyframe(image_path, current_canvas):
|
| 711 |
-
"""
|
| 712 |
return _cover_crop(image_path, current_canvas), current_canvas
|
| 713 |
|
| 714 |
def _fit_keyframe_ui(image_path, current_canvas):
|
|
@@ -912,8 +912,13 @@ def generate(
|
|
| 912 |
corrected = path[:-4] + "-canvas.mp4"
|
| 913 |
subprocess.run(
|
| 914 |
[ffmpeg, "-y", "-i", path,
|
| 915 |
-
"-
|
| 916 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 917 |
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18",
|
| 918 |
"-c:a", "aac", "-b:a", "192k", "-movflags", "+faststart", corrected],
|
| 919 |
capture_output=True, text=True, check=True,
|
|
@@ -922,7 +927,7 @@ def generate(
|
|
| 922 |
resized = True
|
| 923 |
print(
|
| 924 |
f"[canvas] Model/encoder output {actual_width}x{actual_height}; "
|
| 925 |
-
f"final MP4
|
| 926 |
flush=True,
|
| 927 |
)
|
| 928 |
|
|
|
|
| 684 |
return fastest[ratio][0]
|
| 685 |
|
| 686 |
def _cover_crop(image_path: str, canvas_label: str) -> str:
|
| 687 |
+
"""Fit the complete keyframe to the selected canvas without cutting off the subject.
|
| 688 |
|
| 689 |
+
If aspect ratios differ, use a softly blurred, full-canvas version as the background and
|
| 690 |
+
place the entire original image, scaled to fit, in the center. This avoids hard bars and
|
| 691 |
+
preserves the original framing instead of center-cropping the person.
|
| 692 |
"""
|
| 693 |
+
from PIL import Image as _Image, ImageOps as _ImageOps, ImageFilter as _ImageFilter
|
| 694 |
|
| 695 |
h, w = CANVASES[canvas_label]
|
| 696 |
+
with _Image.open(image_path) as source:
|
| 697 |
+
img = source.convert("RGB")
|
| 698 |
+
if abs(img.width / img.height - (w / h)) <= 1e-3:
|
| 699 |
return image_path
|
| 700 |
+
|
| 701 |
+
background = _ImageOps.fit(img, (w, h), method=_Image.Resampling.LANCZOS)
|
| 702 |
+
background = background.filter(_ImageFilter.GaussianBlur(radius=max(8, min(w, h) // 35)))
|
| 703 |
+
foreground = _ImageOps.contain(img, (w, h), method=_Image.Resampling.LANCZOS)
|
| 704 |
+
x = (w - foreground.width) // 2
|
| 705 |
+
y = (h - foreground.height) // 2
|
| 706 |
+
background.paste(foreground, (x, y))
|
| 707 |
+
background.save(image_path)
|
|
|
|
| 708 |
return image_path
|
| 709 |
|
| 710 |
def _fit_keyframe(image_path, current_canvas):
|
| 711 |
+
"""Fit a keyframe to the selected canvas ratio without changing the selected resolution."""
|
| 712 |
return _cover_crop(image_path, current_canvas), current_canvas
|
| 713 |
|
| 714 |
def _fit_keyframe_ui(image_path, current_canvas):
|
|
|
|
| 912 |
corrected = path[:-4] + "-canvas.mp4"
|
| 913 |
subprocess.run(
|
| 914 |
[ffmpeg, "-y", "-i", path,
|
| 915 |
+
"-filter_complex",
|
| 916 |
+
f"[0:v]split=2[bg][fg];"
|
| 917 |
+
f"[bg]scale={width}:{height}:force_original_aspect_ratio=increase:flags=lanczos,"
|
| 918 |
+
f"crop={width}:{height},boxblur=20:10[bg];"
|
| 919 |
+
f"[fg]scale={width}:{height}:force_original_aspect_ratio=decrease:flags=lanczos[fg];"
|
| 920 |
+
f"[bg][fg]overlay=(W-w)/2:(H-h)/2,setsar=1[v]",
|
| 921 |
+
"-map", "[v]", "-map", "0:a?",
|
| 922 |
"-c:v", "libx264", "-preset", "veryfast", "-crf", "18",
|
| 923 |
"-c:a", "aac", "-b:a", "192k", "-movflags", "+faststart", corrected],
|
| 924 |
capture_output=True, text=True, check=True,
|
|
|
|
| 927 |
resized = True
|
| 928 |
print(
|
| 929 |
f"[canvas] Model/encoder output {actual_width}x{actual_height}; "
|
| 930 |
+
f"final MP4 fitted to selected Canvas without cropping {width}x{height}.",
|
| 931 |
flush=True,
|
| 932 |
)
|
| 933 |
|