dima0987654321 commited on
Commit
0015047
·
verified ·
1 Parent(s): 12e6b02

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -20
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
- """Center cover-crop the file at ``image_path`` to ``canvas_label``'s aspect ratio, in place.
688
 
689
- The keyframe has to arrive at the model already matching the canvas, otherwise the pipeline
690
- letterboxes/stretches it and the first frame does not line up with the generated ones.
 
691
  """
692
- from PIL import Image as _Image
693
 
694
  h, w = CANVASES[canvas_label]
695
- target = w / h
696
- img = _Image.open(image_path)
697
- if abs(img.width / img.height - target) <= 1e-3:
698
  return image_path
699
- if img.width / img.height > target:
700
- new_w = int(img.height * target)
701
- left = (img.width - new_w) // 2
702
- img = img.crop((left, 0, left + new_w, img.height))
703
- else:
704
- new_h = int(img.width / target)
705
- top = (img.height - new_h) // 2
706
- img = img.crop((0, top, img.width, top + new_h))
707
- img.save(image_path)
708
  return image_path
709
 
710
  def _fit_keyframe(image_path, current_canvas):
711
- """Crop 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,8 +912,13 @@ def generate(
912
  corrected = path[:-4] + "-canvas.mp4"
913
  subprocess.run(
914
  [ffmpeg, "-y", "-i", path,
915
- "-vf", f"scale={width}:{height}:force_original_aspect_ratio=increase:flags=lanczos,"
916
- f"crop={width}:{height}",
 
 
 
 
 
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 normalized to selected Canvas {width}x{height}.",
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