diff --git a/app.py b/app.py index e6a9542..fc255dc 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,9 @@ import datetime import hashlib import os -from PIL import Image + +from PIL import Image, ImageSequence +import concurrent.futures from flask import Flask, render_template, redirect, url_for, request, jsonify from flask_login import login_required, LoginManager, login_user, logout_user, current_user @@ -782,43 +784,47 @@ def save_profile_image(image_file): # Get the filename from the image path saved in the user filename = os.path.basename(current_user.profile_image) - image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) - os.remove(image_path) - - # Check if the image is an animated gif - if file_extension == 'gif': - gif_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".jpg", ".gif")) - image_file.save(gif_path) - - current_user.profile_image = gif_path - current_user.update() - return # Open the uploaded image image = Image.open(image_file) - # Convert the image to RGB mode (required for JPEG) - image = image.convert('RGB') + # Function to crop and resize frames + def process_frame(frame, size): + new_size = min(frame.size) + left = (frame.width - new_size) // 2 + top = (frame.height - new_size) // 2 + right = left + new_size + bottom = top + new_size + cropped_frame = frame.crop((left, top, right, bottom)) + return cropped_frame.resize(size) - # Determine the size of the square image - min_dimension = min(image.size) - square_size = (min_dimension, min_dimension) + # Function to process frames in parallel + def process_frames_parallel(frames, size): + with concurrent.futures.ThreadPoolExecutor() as executor: + resized_frames = list(executor.map(lambda f: process_frame(f, size), frames)) + return resized_frames - # Calculate the coordinates for cropping - left = (image.width - min_dimension) / 2 - top = (image.height - min_dimension) / 2 - right = (image.width + min_dimension) / 2 - bottom = (image.height + min_dimension) / 2 + # Check if the image is an animated gif + if file_extension == 'gif': + # Process frames + gif_frames = [frame.copy() for frame in ImageSequence.Iterator(image)] + processed_frames = process_frames_parallel(gif_frames, size=(128, 128)) - # Crop the image to a square and resize it - image = image.crop((left, top, right, bottom)) - image.thumbnail(square_size) - image = image.resize((256, 256)) + # Save the modified frames as a new GIF + output_gif_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".jpg", ".gif")) + processed_frames[0].save(output_gif_path, save_all=True, append_images=processed_frames[1:], loop=0) + current_user.profile_image = output_gif_path + else: + # Process single image + processed_image = process_frame(image, size=(256, 256)) + processed_image = processed_image.convert('RGB') - # Save the processed image - image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg")) - image.save(image_path, 'JPEG', quality=100) - current_user.profile_image = image_path + # Save the processed image + image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg")) + processed_image.save(image_path, 'JPEG', quality=100) + current_user.profile_image = image_path + + # Update user profile current_user.update() @app.route('/upload', methods=['POST']) diff --git a/templates/index.html b/templates/index.html index 3626897..7402023 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,7 +4,7 @@

- {% if (current_user.is_authenticated) %}failed to load image{% endif %} + {% if (current_user.is_authenticated) %}no image{% endif %} {{ title }}

{{ utc_dt }}