import numpy as np import cv2 from PIL import Image, ImageEnhance import tempfile import os from moviepy.editor import ImageClip, AudioFileClip, CompositeVideoClip import librosa import soundfile as sf import subprocess def process_image_for_video(image, style="static"): """ Process image for video creation based on style Args: image: PIL Image style: Animation style Returns: str: Path to processed image """ # Convert to RGB if necessary if image.mode != 'RGB': image = image.convert('RGB') # Enhance image quality enhancer = ImageEnhance.Contrast(image) image = enhancer.enhance(1.2) enhancer = ImageEnhance.Sharpness(image) image = enhancer.enhance(1.1) # Save processed image temp_path = os.path.join(tempfile.gettempdir(), f"processed_{uuid.uuid4().hex}.jpg") image.save(temp_path, quality=95) return temp_path def extend_audio_to_duration(audio_path, target_duration): """ Extend audio to target duration by looping and fading Args: audio_path: Path to original audio file target_duration: Target duration in seconds Returns: str: Path to extended audio file """ # Load audio y, sr = librosa.load(audio_path) original_duration = len(y) / sr if original_duration >= target_duration: return audio_path # Calculate how many times to loop loops_needed = int(target_duration / original_duration) + 1 # Create extended audio extended_audio = np.tile(y, loops_needed) # Trim to exact duration target_samples = int(target_duration * sr) extended_audio = extended_audio[:target_samples] # Apply fade in/out fade_samples = int(0.5 * sr) # 0.5 second fade extended_audio[:fade_samples] *= np.linspace(0, 1, fade_samples) extended_audio[-fade_samples:] *= np.linspace(1, 0, fade_samples) # Save extended audio output_path = os.path.join(tempfile.gettempdir(), f"extended_{uuid.uuid4().hex}.wav") sf.write(output_path, extended_audio, sr) return output_path def create_video_with_audio(image_path, audio_path, duration): """ Create video by combining image and audio Args: image_path: Path to image file audio_path: Path to audio file duration: Video duration in seconds Returns: str: Path to output video file """ # Create video clip from image image_clip = ImageClip(image_path, duration=duration) # Create audio clip audio_clip = AudioFileClip(audio_path) # Set audio to video video_clip = image_clip.set_audio(audio_clip) # Set fps video_clip.fps = 24 # Output path output_path = os.path.join(tempfile.gettempdir(), f"video_{uuid.uuid4().hex}.mp4") # Write video file video_clip.write_videofile( output_path, codec='libx264', audio_codec='aac', temp_audiofile=os.path.join(tempfile.gettempdir(), f"temp_audio_{uuid.uuid4().hex}.m4a"), remove_temp=True ) # Close clips image_clip.close() audio_clip.close() video_clip.close() return output_path def cleanup_temp_files(file_paths): """Clean up temporary files""" for file_path in file_paths: try: if os.path.exists(file_path): os.remove(file_path) except Exception as e: print(f"Error removing {file_path}: {e}") def apply_video_effects(image_path, style, duration): """ Apply video effects to create animated video from static image Args: image_path: Path to image style: Animation style duration: Duration in seconds Returns: str: Path to animated video """ # Read image image = cv2.imread(image_path) height, width = image.shape[:2] # Create temporary video path temp_video = os.path.join(tempfile.gettempdir(), f"animated_{uuid.uuid4().hex}.mp4") # Setup video writer fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(temp_video, fourcc, 30.0, (width, height)) frames = int(duration * 30) for i in range(frames): progress = i / frames if style == "zoom_in": # Zoom in effect scale = 1.0 + (progress * 0.5) new_height = int(height / scale) new_width = int(width / scale) y_start = (height - new_height) // 2 x_start = (width - new_width) // 2 frame = image[y_start:y_start+new_height, x_start:x_start+new_width] frame = cv2.resize(frame, (width, height)) elif style == "zoom_out": # Zoom out effect scale = 1.5 - (progress * 0.5) new_height = int(height / scale) new_width = int(width / scale) y_start = (height - new_height) // 2 x_start = (width - new_width) // 2 frame = image[y_start:y_start+new_height, x_start:x_start+new_width] frame = cv2.resize(frame, (width, height)) elif style == "pan_left": # Pan left effect offset = int(progress * (width * 0.3)) frame = image[:, offset:offset+width] if offset+width <= width else image[:, -width:] elif style == "pan_right": # Pan right effect offset = int((1 - progress) * (width * 0.3)) frame = image[:, offset:offset+width] if offset+width <= width else image[:, -width:] else: # static frame = image out.write(frame) out.release() return temp_video