import gradio as gr from PIL import Image import io import numpy as np from math import cos, radians, sin def create_gif(editor1_output, editor2_output, transition_type): img1 = editor1_output["composite"].convert('RGBA') img2 = editor2_output["composite"].convert('RGBA') frames = [] duration = 100 # Duration for each frame in milliseconds total_frames = 18 # Total number of frames size = (256, 256) # Fixed size for both images img1 = img1.resize(size, Image.LANCZOS) img2 = img2.resize(size, Image.LANCZOS) if transition_type == "slide": full_width = size[0] step = full_width // (total_frames // 2) # Create sliding transition for i in range(0, full_width, step): frame = Image.new('RGBA', size) frame.paste(img1, (0, 0)) frame.paste(img2.crop((0, 0, i, size[1])), (full_width - i, 0), mask=img2.crop((0, 0, i, size[1]))) frames.append(frame.convert('P', palette=Image.ADAPTIVE)) for i in range(full_width, 0, -step): frame = Image.new('RGBA', size) frame.paste(img2, (0, 0)) frame.paste(img1.crop((0, 0, i, size[1])), (full_width - i, 0), mask=img1.crop((0, 0, i, size[1]))) frames.append(frame.convert('P', palette=Image.ADAPTIVE)) else: # rotate transition for angle in range(0, 360, 360 // total_frames): mask = Image.new('L', size, 0) draw = Image.Draw(mask) draw.pieslice([0, 0, size[0], size[1]], -90, angle - 90, fill=255) frame = Image.composite(img2, img1, mask) frames.append(frame.convert('P', palette=Image.ADAPTIVE)) # Save as GIF output = io.BytesIO() frames[0].save(output, format='GIF', save_all=True, append_images=frames[1:], duration=duration, loop=0, optimize=True) output.seek(0) # Save the GIF to a temporary file temp_output_path = "output.gif" with open(temp_output_path, "wb") as f: f.write(output.getvalue()) return temp_output_path # Gradio interface with gr.Blocks() as iface: gr.Markdown("# 2GIF Transition Slider") with gr.Row(): with gr.Column(scale=2): image_editor1 = gr.ImageEditor( label="Edit Image 1", brush=gr.Brush(colors=["#ff0000", "#00ff00", "#0000ff"]), eraser=gr.Eraser(default_size=10), height=400, width="100%", crop_size="1:1", layers=True, type="pil" ) with gr.Column(scale=2): image_editor2 = gr.ImageEditor( label="Edit Image 2", brush=gr.Brush(colors=["#ff0000", "#00ff00", "#0000ff"]), eraser=gr.Eraser(default_size=10), height=400, width="100%", crop_size="1:1", layers=True, type="pil" ) with gr.Row(): transition_type = gr.Radio(["slide", "rotate"], label="Transition Type", value="slide") generate_button = gr.Button("Generate GIF") with gr.Row(): output_gif = gr.Image(type="filepath", label="Generated GIF", height=300) generate_button.click( create_gif, inputs=[image_editor1, image_editor2, transition_type], outputs=[output_gif] ) # Launch the interface iface.launch()