from moviepy.editor import *

from moviepy.video.fx.all import resize
import numpy as np
import textwrap
from PIL import Image, ImageDraw, ImageFilter
import os


# Paths to your video and images
video_path = "/Users/jitendersingh/Downloads/bg3.mp4"
# Define the audio file path
audio_path = "/Users/jitendersingh/Downloads/audiotts.mp3"

# Text and parameters
text = "Haier 19 L Inverter Technology, Light Weight, Defrost, 5 Power Levels Solo Microwave Oven"
font_path = "/System/Library/Fonts/Supplemental/Arial Bold.ttf" # Update font if needed
font_size = 60
margin = 100 # Margin for width

# Load the audio file
audio_clip = AudioFileClip(audio_path)

# Set the video duration to match the audio duration
audio_duration = audio_clip.duration


image_paths = [
"/Users/jitendersingh/Downloads/myimages/3.jpeg",
"/Users/jitendersingh/Downloads/myimages/2.jpeg",
"/Users/jitendersingh/Downloads/myimages/3.jpeg",
"/Users/jitendersingh/Downloads/myimages/4.jpeg",
"/Users/jitendersingh/Downloads/myimages/3.jpeg"
]

# Directory to save modified images
temp_dir = "/Users/jitendersingh/Downloads/temp_images"
os.makedirs(temp_dir, exist_ok=True)

# Function to add shadow and rounded corners (unchanged)
def add_shadow_with_rounded_corners(image_path, output_path, corner_radius, shadow_size):
img = Image.open(image_path).convert("RGBA")
original_size = img.size
scaled_size = (original_size[0] - 2 * shadow_size, original_size[1] - 2 * shadow_size)
img = img.resize(scaled_size, Image.ANTIALIAS)
mask = Image.new("L", scaled_size, 0)
draw = ImageDraw.Draw(mask)
draw.rounded_rectangle((0, 0, scaled_size[0], scaled_size[1]), radius=corner_radius, fill=255)
rounded_img = Image.new("RGBA", scaled_size)
rounded_img.paste(img, (0, 0), mask=mask)
shadow = Image.new("RGBA", original_size, (0, 0, 0, 0))
draw = ImageDraw.Draw(shadow)
draw.rounded_rectangle(
(shadow_size, shadow_size, original_size[0] - shadow_size, original_size[1] - shadow_size),
radius=corner_radius,
fill=(0, 0, 0, 128)
)
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=shadow_size // 2))
output = Image.new("RGBA", original_size, (0, 0, 0, 0))
output.paste(shadow, (0, 0))
output.paste(rounded_img, (shadow_size, shadow_size), mask=mask)
output.save(output_path, format="PNG")

# Modify images (unchanged)
corner_radius = 50
shadow_size = 50
modified_image_paths = []

for image_path in image_paths:
output_path = os.path.join(temp_dir, os.path.basename(image_path))
add_shadow_with_rounded_corners(image_path, output_path, corner_radius, shadow_size)
modified_image_paths.append(output_path)

# Load the video
background_video = VideoFileClip(video_path)

# Animation properties (added out animation details)
images_properties = [
{"size": (700, 700), "direction": "first_half", "position": {"x": 0, "y": 0}, "start_time": 0},
{"size": (380, 350), "direction": "right_to_left", "position": {"x": 1000, "y": 180}, "start_time": 0.5},
{"size": (380, 350), "direction": "right_to_left", "position": {"x": 1400, "y": 180}, "start_time": 0.8},
{"size": (380, 350), "direction": "bottom_to_top", "position": {"x": 1000, "y": 620}, "start_time": 1.1},
{"size": (380, 350), "direction": "bottom_to_top", "position": {"x": 1400, "y": 620}, "start_time": 1.3}
]

# Resize function (unchanged)
def resize_image(image, max_width, max_height):
image_width, image_height = image.size
if image_width > max_width or image_height > max_height:
aspect_ratio = image_width / image_height
if image_width > max_width:
new_width = max_width
new_height = int(new_width / aspect_ratio)
else:
new_height = max_height
new_width = int(new_height * aspect_ratio)
image = image.resize(newsize=(new_width, new_height))
return image

def image_animation(image, direction, position, start_time):
def animate(t):
duration = 0.5 # Animation duration
out_start_time = background_video.duration - 0.5 # Start out animation 1 second before the video ends

# Out animation logic: Trigger if the current time (`t`) is after `out_start_time`
if t >= out_start_time:
out_duration = 0.5
out_t_offset = t - out_start_time
x = position['x']
y_start = position['y']
y_end = background_video.h + image.size[1]
y = y_start + (y_end - y_start) * min(out_t_offset / out_duration, 1)
return x, y

# Existing animations
t_offset = t - start_time
if direction == "left_to_right":
x_start = -image.size[0]
x_end = position['x']
y = position['y']
x = x_start + (x_end - x_start) * min(t_offset / duration, 1)
elif direction == "right_to_left":
x_start = background_video.w
x_end = position['x']
y = position['y']
x = x_start - (x_start - x_end) * min(t_offset / duration, 1)
elif direction == "top_to_bottom":
y_start = -image.size[1]
y_end = position['y']
x = position['x']
y = y_start + (y_end - y_start) * min(t_offset / duration, 1)
elif direction == "bottom_to_top":
y_start = background_video.h
y_end = position['y']
x = position['x']
y = y_start - (y_start - y_end) * min(t_offset / duration, 1)
elif direction == "first_half":
first_half_width = background_video.w // 2
first_half_height = background_video.h // 2
image_width, image_height = image.size

start_x = -image_width
end_x = (background_video.w // 4) - (image_width // 2)
x = start_x + (end_x - start_x) * min(t / duration, 1)
y = (background_video.h - image_height) // 2 + 80
elif direction == "second_half":
# Second half animation logic
image_width, image_height = image.size

# Start and end positions for the x-axis
start_x = background_video.w
end_x = (3 * background_video.w // 4) - (image_width // 2)
x = start_x - (start_x - end_x) * min(t_offset / duration, 1)

# Set the final y-position for out animation compatibility
position['x'] = end_x # Ensure out animation moves down from the second half center
y = (background_video.h - image_height) // 2 + 130 # Second half top margin
else:
x, y = position['x'], position['y'] # Default position

return x, y
return animate

if background_video.duration > audio_duration:
background_video = background_video.subclip(0, audio_duration)
print(f"Background video trimmed to: {background_video.duration} seconds")

# Process images and create animated images
animated_images = []
for i, image_path in enumerate(modified_image_paths):
# Load each image
image = ImageClip(image_path).set_duration(audio_duration) # Set duration equal to audio duration
image = image.set_start(0) # Ensure all images start at the beginning

# Resize the image according to specified properties
resized_image = resize_image(image.copy(), images_properties[i]["size"][0], images_properties[i]["size"][1])

# Create an animation for the resized image
animation = image_animation(
resized_image,
images_properties[i]["direction"],
images_properties[i]["position"],
images_properties[i]["start_time"]
)

# Set the position of the animated image
animated_image = resized_image.set_position(animation)

# Append the animated image to the list
animated_images.append(animated_image)




def create_rounded_rectangle(size, color, radius):
"""Creates a rounded rectangle as a NumPy array."""
width, height = size
img = Image.new("RGBA", (width, height), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
draw.rounded_rectangle(
[(0, 0), (width, height)],
radius=radius,
fill=color,
)
return np.array(img)

def wrap_text(text, font_size, max_width, font_path):
"""Wrap text to fit within max_width."""
text_clip = TextClip(text, fontsize=font_size, color="white", font=font_path)
line_width = text_clip.w
char_count = len(text)
avg_char_width = line_width / char_count
max_chars_per_line = int(max_width / avg_char_width)
wrapped_text = "\n".join(textwrap.wrap(text, width=max_chars_per_line))
return wrapped_text

video = background_video

if video.duration > audio_duration:
video = video.subclip(0, audio_duration)
print(f"Video trimmed to: {video.duration} seconds")


max_text_width = video.w - 2 * margin # Maximum width available for the text

# Wrap the text to fit within the frame, only applying margin on width
wrapped_text = wrap_text(text, font_size, max_text_width, font_path)

# Create the text clip with the wrapped text
text_clip = TextClip(wrapped_text, fontsize=font_size, color='white', font=font_path, align='center').set_duration(audio_duration)

# Create a rounded rectangle background for the text (apply margin only in width)
bg_size = (text_clip.w + 60, text_clip.h + 20) # Add 20px padding for background
bg_color = (0, 0, 255, 255) # Blue background
rounded_rect = create_rounded_rectangle(bg_size, bg_color, radius=15)
background_clip = ImageClip(rounded_rect).set_duration(audio_duration)

# Combine text and background
text_with_bg = CompositeVideoClip([
background_clip.set_position('center'),
text_clip.set_position('center')
]).set_duration(audio_duration)

# Add animation: move from top center to 200px below the top
def animated_position(t):
final_y = 20 # Final Y position
initial_y = -text_with_bg.h # Start off-screen
return ('center', initial_y + (final_y - initial_y) * min(t / 0.5, 1)) # 0.5 seconds for animation

animated_text = text_with_bg.set_position(animated_position)

# Combine the background video with all animated images
final_video = CompositeVideoClip([background_video] + animated_images + [animated_text])


# Set the final video duration to match the audio's duration (ensures consistency)
final_video = final_video.set_duration(audio_duration)

# Add the audio to the final video
final_video = final_video.set_audio(audio_clip)

# Write the output video to a file with proper audio codec
output_path = "/Users/jitendersingh/Downloads/output_with_trimmed_background_and_audio.mp4"
final_video.write_videofile(
output_path,
codec="libx264",
fps=30,
audio_codec="aac" # Ensure compatibility for audio playback
)

print(f"Video with trimmed background and audio completed! Output saved to: {output_path}")

0 comments:

Post a Comment

 
Top