Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -9,89 +9,108 @@ import time
|
|
9 |
# Global variable to store generated GIFs
|
10 |
generated_gifs = []
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
def create_gif(editor1_output, editor2_output, transition_type):
|
13 |
-
img1 = editor1_output["composite"].convert('RGBA')
|
14 |
-
img2 = editor2_output["composite"].convert('RGBA')
|
15 |
-
|
16 |
frames = []
|
17 |
duration = 100 # Duration for each frame in milliseconds
|
18 |
-
total_frames = 18 # Total number of frames
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
|
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
draw = ImageDraw.Draw(mask)
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
end_x2 = center_x - int(size[0] * 1.5 * cos(radians(reverse_angle)))
|
71 |
-
end_y2 = center_y - int(size[1] * 1.5 * sin(radians(reverse_angle)))
|
72 |
-
draw.line([center_x, center_y, end_x1, end_y1], fill=(0, 255, 0), width=6)
|
73 |
-
draw.line([center_x, center_y, end_x2, end_y2], fill=(0, 255, 0), width=6)
|
74 |
-
|
75 |
-
frames.append(frame.convert('P', palette=Image.ADAPTIVE))
|
76 |
-
|
77 |
-
# Save as GIF
|
78 |
-
output = io.BytesIO()
|
79 |
-
frames[0].save(output, format='GIF', save_all=True, append_images=frames[1:], duration=duration, loop=0, optimize=True)
|
80 |
-
output.seek(0)
|
81 |
-
|
82 |
-
# Save the GIF to a file with a unique name
|
83 |
-
os.makedirs("outputs", exist_ok=True)
|
84 |
-
timestamp = int(time.time())
|
85 |
-
output_path = f"outputs/output_{timestamp}.gif"
|
86 |
-
with open(output_path, "wb") as f:
|
87 |
-
f.write(output.getvalue())
|
88 |
-
|
89 |
-
# Add the new GIF to the list of generated GIFs
|
90 |
-
global generated_gifs
|
91 |
-
generated_gifs.append((output_path, f"{transition_type.capitalize()} transition"))
|
92 |
-
|
93 |
-
# Return the updated list of generated GIFs
|
94 |
-
return generated_gifs
|
95 |
|
96 |
# Gradio interface
|
97 |
with gr.Blocks() as iface:
|
|
|
9 |
# Global variable to store generated GIFs
|
10 |
generated_gifs = []
|
11 |
|
12 |
+
def preprocess_image(image):
|
13 |
+
# Ensure the image is square by padding it
|
14 |
+
size = max(image.size)
|
15 |
+
new_image = Image.new("RGBA", (size, size), (255, 255, 255, 0))
|
16 |
+
new_image.paste(image, ((size - image.width) // 2, (size - image.height) // 2))
|
17 |
+
return new_image
|
18 |
+
|
19 |
def create_gif(editor1_output, editor2_output, transition_type):
|
|
|
|
|
|
|
20 |
frames = []
|
21 |
duration = 100 # Duration for each frame in milliseconds
|
22 |
+
total_frames = 18 # Total number of frames
|
23 |
+
|
24 |
+
try:
|
25 |
+
# Open images
|
26 |
+
img1 = editor1_output["composite"].convert('RGBA')
|
27 |
+
img2 = editor2_output["composite"].convert('RGBA')
|
28 |
+
|
29 |
+
# Preprocess images to make them square and same size
|
30 |
+
img1 = preprocess_image(img1)
|
31 |
+
img2 = preprocess_image(img2)
|
32 |
+
|
33 |
+
# Set size for the GIF
|
34 |
+
size = (256, 256)
|
35 |
+
img1 = img1.resize(size, Image.LANCZOS)
|
36 |
+
img2 = img2.resize(size, Image.LANCZOS)
|
37 |
+
|
38 |
+
if transition_type == "slide":
|
39 |
+
# Calculate step size for consistent speed
|
40 |
+
full_width = size[0]
|
41 |
+
step = full_width // (total_frames // 2) # Divide by 2 as we have 2 parts to the animation
|
42 |
|
43 |
+
# Generate frames from left to right
|
44 |
+
for i in range(0, full_width, step):
|
45 |
+
frame = Image.new('RGBA', size)
|
46 |
+
frame.paste(img1, (0, 0))
|
47 |
+
frame.paste(img2.crop((i, 0, full_width, size[1])), (i, 0), mask=img2.crop((i, 0, full_width, size[1])))
|
48 |
|
49 |
+
draw = ImageDraw.Draw(frame)
|
50 |
+
draw.line((i, 0, i, size[1]), fill=(0, 255, 0), width=2)
|
51 |
+
|
52 |
+
# Convert frame to P mode which is a palette-based image
|
53 |
+
frame = frame.convert('P', palette=Image.ADAPTIVE)
|
54 |
+
frames.append(frame)
|
55 |
+
|
56 |
+
# Generate frames from right to left
|
57 |
+
for i in range(full_width, step, -step):
|
58 |
+
frame = Image.new('RGBA', size)
|
59 |
+
frame.paste(img1, (0, 0))
|
60 |
+
frame.paste(img2.crop((i, 0, full_width, size[1])), (i, 0), mask=img2.crop((i, 0, full_width, size[1])))
|
61 |
+
|
62 |
+
draw = ImageDraw.Draw(frame)
|
63 |
+
draw.line((i, 0, i, size[1]), fill=(0, 255, 0), width=2)
|
64 |
+
|
65 |
+
# Convert frame to P mode which is a palette-based image
|
66 |
+
frame = frame.convert('P', palette=Image.ADAPTIVE)
|
67 |
+
frames.append(frame)
|
68 |
+
else: # rotate transition
|
69 |
+
mask_size = (size[0] * 2, size[1] * 2)
|
70 |
+
mask = Image.new('L', mask_size, 0)
|
71 |
draw = ImageDraw.Draw(mask)
|
72 |
+
draw.rectangle([size[0], 0, mask_size[0], mask_size[1]], fill=255)
|
73 |
+
|
74 |
+
center_x, center_y = size[0] // 2, size[1] // 2
|
75 |
+
|
76 |
+
for angle in range(0, 360, 360 // total_frames):
|
77 |
+
rotated_mask = mask.rotate(angle, center=(mask_size[0] // 2, mask_size[1] // 2), expand=False)
|
78 |
+
cropped_mask = rotated_mask.crop((size[0] // 2, size[1] // 2, size[0] // 2 + size[0], size[1] // 2 + size[1]))
|
79 |
+
frame = Image.composite(img1, img2, cropped_mask)
|
80 |
+
|
81 |
+
draw = ImageDraw.Draw(frame)
|
82 |
+
reverse_angle = -angle + 90
|
83 |
+
end_x1 = center_x + int(size[0] * 1.5 * cos(radians(reverse_angle)))
|
84 |
+
end_y1 = center_y + int(size[1] * 1.5 * sin(radians(reverse_angle)))
|
85 |
+
end_x2 = center_x - int(size[0] * 1.5 * cos(radians(reverse_angle)))
|
86 |
+
end_y2 = center_y - int(size[1] * 1.5 * sin(radians(reverse_angle)))
|
87 |
+
draw.line([center_x, center_y, end_x1, end_y1], fill=(0, 255, 0), width=3)
|
88 |
+
draw.line([center_x, center_y, end_x2, end_y2], fill=(0, 255, 0), width=3)
|
89 |
+
|
90 |
+
frame = frame.convert('P', palette=Image.ADAPTIVE)
|
91 |
+
frames.append(frame)
|
92 |
+
|
93 |
+
# Save as GIF
|
94 |
+
output = io.BytesIO()
|
95 |
+
frames[0].save(output, format='GIF', save_all=True, append_images=frames[1:], duration=duration, loop=0, optimize=True)
|
96 |
+
output.seek(0)
|
97 |
+
|
98 |
+
# Save the GIF to a file with a unique name
|
99 |
+
os.makedirs("outputs", exist_ok=True)
|
100 |
+
timestamp = int(time.time())
|
101 |
+
output_path = f"outputs/output_{timestamp}.gif"
|
102 |
+
with open(output_path, "wb") as f:
|
103 |
+
f.write(output.getvalue())
|
104 |
+
|
105 |
+
# Add the new GIF to the list of generated GIFs
|
106 |
+
global generated_gifs
|
107 |
+
generated_gifs.append((output_path, f"{transition_type.capitalize()} transition"))
|
108 |
+
|
109 |
+
# Return the updated list of generated GIFs
|
110 |
+
return generated_gifs
|
111 |
+
|
112 |
+
except Exception as e:
|
113 |
+
raise ValueError(f"Error creating GIF: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
# Gradio interface
|
116 |
with gr.Blocks() as iface:
|