-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfix_gif_compatibility.py
More file actions
163 lines (135 loc) · 5.9 KB
/
fix_gif_compatibility.py
File metadata and controls
163 lines (135 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env python3
"""
Improved GIF creation with better macOS compatibility
"""
import os
from PIL import Image, ImageSequence
import sys
def create_compatible_gif(input_frames_dir, output_gif_path, duration=100, max_frames=100):
"""
Create a GIF with enhanced macOS compatibility
"""
try:
# Get all frame files
frame_files = sorted([f for f in os.listdir(input_frames_dir) if f.endswith('.png')])
if not frame_files:
print(f"❌ No PNG frames found in {input_frames_dir}")
return False
if len(frame_files) < 2:
print(f"❌ Need at least 2 frames, found {len(frame_files)}")
return False
print(f"📸 Processing {len(frame_files)} frames...")
# Load and process images
frames = []
step = max(1, len(frame_files) // max_frames)
for i in range(0, len(frame_files), step):
frame_path = os.path.join(input_frames_dir, frame_files[i])
try:
img = Image.open(frame_path)
# Convert to RGB first, then to palette mode for better compatibility
if img.mode != 'RGB':
img = img.convert('RGB')
# Resize for manageable file size
width, height = img.size
if width > 800:
new_width = 800
new_height = int(height * new_width / width)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# Convert to palette mode with dithering for better compression
img = img.convert('P', palette=Image.ADAPTIVE, colors=256)
frames.append(img)
except Exception as e:
print(f"⚠️ Skipping frame {frame_files[i]}: {e}")
continue
if len(frames) < 2:
print(f"❌ Not enough valid frames processed")
return False
print(f"✅ Processed {len(frames)} frames")
# Create GIF with specific settings for macOS compatibility
frames[0].save(
output_gif_path,
save_all=True,
append_images=frames[1:],
duration=duration,
loop=0,
disposal=2, # Clear frame before next
optimize=False, # Don't optimize for better compatibility
transparency=None # No transparency
)
# Verify the GIF was created correctly
if os.path.exists(output_gif_path):
with Image.open(output_gif_path) as gif:
print(f"✅ GIF created successfully:")
print(f" Path: {output_gif_path}")
print(f" Size: {gif.size}")
print(f" Frames: {getattr(gif, 'n_frames', 1)}")
print(f" Animated: {getattr(gif, 'is_animated', False)}")
print(f" File size: {os.path.getsize(output_gif_path) / 1024:.1f} KB")
return True
else:
print(f"❌ GIF file was not created")
return False
except Exception as e:
print(f"❌ Error creating GIF: {e}")
import traceback
traceback.print_exc()
return False
def fix_existing_gif(input_gif_path, output_gif_path=None):
"""
Fix an existing GIF for better compatibility
"""
if not output_gif_path:
output_gif_path = input_gif_path.replace('.gif', '_fixed.gif')
try:
with Image.open(input_gif_path) as img:
if not getattr(img, 'is_animated', False):
print(f"❌ {input_gif_path} is not animated")
return False
frames = []
durations = []
for frame in ImageSequence.Iterator(img):
# Convert frame to RGB then to palette
frame = frame.convert('RGB')
frame = frame.convert('P', palette=Image.ADAPTIVE, colors=256)
frames.append(frame)
durations.append(frame.info.get('duration', 100))
# Save with fixed settings
frames[0].save(
output_gif_path,
save_all=True,
append_images=frames[1:],
duration=durations,
loop=0,
disposal=2,
optimize=False,
transparency=None
)
print(f"✅ Fixed GIF saved as: {output_gif_path}")
return True
except Exception as e:
print(f"❌ Error fixing GIF: {e}")
return False
if __name__ == "__main__":
print("=== GIF Compatibility Fixer ===")
# Check if we have frame directories
recordings_dir = "recordings"
if os.path.exists(recordings_dir):
# Look for frame directories
for item in os.listdir(recordings_dir):
item_path = os.path.join(recordings_dir, item)
if os.path.isdir(item_path):
# Check if it has PNG frames
png_files = [f for f in os.listdir(item_path) if f.endswith('.png')]
if png_files:
print(f"\\n📁 Found frame directory: {item}")
gif_name = f"{item}.gif"
gif_path = os.path.join(recordings_dir, gif_name)
if create_compatible_gif(item_path, gif_path):
print(f"\\n🎬 Testing GIF playback...")
os.system(f"open '{gif_path}'")
# Also fix existing GIFs
print("\\n=== Fixing existing GIFs ===")
for gif_file in ["recordings/bubble_sort.gif", "recordings/test_algorithm.gif"]:
if os.path.exists(gif_file):
print(f"\\n🔧 Fixing {gif_file}...")
fix_existing_gif(gif_file)