Spaces:
Sleeping
Sleeping
import gradio as gr | |
from PIL import Image | |
import os | |
from io import BytesIO | |
def get_gif_info(gif_file): | |
"""Get GIF dimensions and frame count.""" | |
try: | |
with Image.open(gif_file) as img: | |
width, height = img.size | |
frames = 0 | |
try: | |
while True: | |
img.seek(img.tell() + 1) | |
frames += 1 | |
except EOFError: | |
img.seek(0) # Reset to first frame | |
return width, height, frames + 1, "Success" | |
except Exception as e: | |
return None, None, None, f"Error: {str(e)}" | |
def resize_gif(gif_file, width, height, lock_ratio): | |
"""Resize GIF while maintaining quality and aspect ratio.""" | |
try: | |
# Open the GIF | |
with Image.open(gif_file) as img: | |
original_width, original_height = img.size | |
frames = [] | |
# If lock_ratio is enabled, calculate height based on width | |
if lock_ratio and width: | |
height = int((width / original_width) * original_height) | |
if not width or not height: | |
return None, "Please provide valid width and/or height" | |
# Process each frame | |
try: | |
while True: | |
# Convert frame to RGB if needed | |
frame = img.convert('RGBA') | |
# Resize frame using LANCZOS for better quality | |
resized_frame = frame.resize((int(width), int(height)), Image.LANCZOS) | |
frames.append(resized_frame) | |
img.seek(img.tell() + 1) | |
except EOFError: | |
pass | |
# Create output BytesIO object | |
output = BytesIO() | |
# Save the resized GIF | |
frames[0].save( | |
output, | |
format='GIF', | |
save_all=True, | |
append_images=frames[1:], | |
loop=0, | |
duration=img.info.get('duration', 100), | |
optimize=True, | |
quality=95 | |
) | |
# Get new file size | |
new_size = len(output.getvalue()) / 1024 # Size in KB | |
# Reset BytesIO cursor and return | |
output.seek(0) | |
return output, f"Original Size: {original_width}x{original_height}\nNew Size: {width}x{height}\nFile Size: {new_size:.2f} KB" | |
except Exception as e: | |
return None, f"Error processing GIF: {str(e)}" | |
def update_height(width, original_width, original_height, lock_ratio): | |
"""Update height input when aspect ratio is locked.""" | |
if lock_ratio and width and original_width and original_height: | |
try: | |
return int((int(width) / original_width) * original_height) | |
except: | |
return None | |
return None | |
def process_gif(gif_file, width, height, lock_ratio): | |
"""Main function to process the uploaded GIF.""" | |
if not gif_file: | |
return None, "Please upload a GIF file", None | |
# Get GIF info | |
original_width, original_height, frame_count, error = get_gif_info(gif_file) | |
if error: | |
return None, error, None | |
# Resize GIF | |
output, message = resize_gif(gif_file, width, height, lock_ratio) | |
return output, f"GIF Info:\nWidth: {original_width}px\nHeight: {original_height}px\nFrames: {frame_count}\n\n{message}", output | |
# Gradio Interface | |
with gr.Blocks() as demo: | |
gr.Markdown("# GIF Resizer") | |
gr.Markdown("Upload a GIF, set the desired dimensions, and download the resized version.") | |
msg = gr.Markdown() | |
with gr.Row(): | |
with gr.Column(): | |
gif_input = gr.File(label="Upload GIF", file_types=[".gif"]) | |
lock_ratio = gr.Checkbox(label="Lock Aspect Ratio", value=True) | |
with gr.Row(): | |
width_input = gr.Number(label="Width (px)", value=None) | |
height_input = gr.Number(label="Height (px)", value=None) | |
resize_button = gr.Button("Resize GIF") | |
with gr.Column(): | |
output_info = gr.Textbox(label="GIF Information") | |
output_gif = gr.Image(label="Resized GIF", type="filepath") | |
download_button = gr.File(label="Download Resized GIF") | |
# Event handlers | |
gif_input.change( | |
fn=get_gif_info, | |
inputs=gif_input, | |
outputs=[width_input, height_input, output_info, msg] | |
) | |
width_input.change( | |
fn=update_height, | |
inputs=[width_input, width_input, height_input, lock_ratio], | |
outputs=height_input | |
) | |
resize_button.click( | |
fn=process_gif, | |
inputs=[gif_input, width_input, height_input, lock_ratio], | |
outputs=[output_gif, output_info, download_button] | |
) | |
demo.launch() |