outsidellms / video_generator.py
antonelli's picture
zfff
ed56c60
from PIL import Image, ImageDraw, ImageFont
import cv2
import numpy as np
import textwrap
def generate_lyric_frame(lyric, image_size):
# If image_size is None, provide a default value
if image_size is None:
image_size = (800, 600) # Example default size, you can change this
# Ensure image_size is a tuple
image_size = tuple(image_size)
image = Image.new('RGB', image_size, color='black')
draw = ImageDraw.Draw(image)
# Use PIL's default font
font = ImageFont.load_default()
# Wrap text
max_width = image_size[0] - 40 # Keeping 20 pixels margin on each side
wrapped_text = textwrap.fill(lyric, width=40)
lines = wrapped_text.split('\n')
# Calculate text width and height
text_width = max(draw.textlength(line, font=font) for line in lines) # Corrected line here
text_height = sum([font.getmask(line).getbbox()[3] for line in lines if font.getmask(line).getbbox()]) # Corrected line here
# Calculate starting coordinates to center the text block
text_x = (image_size[0] - text_width) / 2
text_y = (image_size[1] - text_height) / 2
# Draw the wrapped text on the image
y = text_y
for line in lines:
draw.text((text_x, y), line, font=font, fill='white')
y += font.getmask(line).getbbox()[3] if font.getmask(line).getbbox() else 0 # Corrected line here
return image
def generate_video(lyrics_with_timing, image_size=(800, 600), frame_rate=30):
frames = []
for start_time, end_time, lyric in lyrics_with_timing:
# Calculate the number of frames for this lyric segment
num_frames = int((end_time - start_time) * frame_rate)
# Create frames with the lyric text
for _ in range(num_frames):
frame = generate_lyric_frame(lyric, image_size)
frames.append(frame)
# Combine frames into a video
video = combine_frames_into_video(frames, frame_rate)
return video
def combine_frames_into_video(frames, frame_rate):
# Convert the first frame to a NumPy array to get its shape
first_frame_np = np.array(frames[0])
height, width, _ = first_frame_np.shape
# Define the codec and create a video writer object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, frame_rate, (width, height))
# Write each frame to the video file
for frame in frames:
# Convert PIL image to NumPy array
frame_np = np.array(frame)
# Convert RGB to BGR as OpenCV uses BGR format
frame_bgr = cv2.cvtColor(frame_np, cv2.COLOR_RGB2BGR)
# Write the BGR frame to the video
out.write(frame_bgr)
# Release the video writer object
out.release()
return 'output.avi'