Profile Image Optimizations

made it as fast as i could, maybe there are faster solutions but I'm fine with this
This commit is contained in:
Yapollon 2024-03-09 14:24:02 +01:00
parent be16821be2
commit 9d945f5edc
2 changed files with 37 additions and 31 deletions

66
app.py
View File

@ -1,7 +1,9 @@
import datetime import datetime
import hashlib import hashlib
import os 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 import Flask, render_template, redirect, url_for, request, jsonify
from flask_login import login_required, LoginManager, login_user, logout_user, current_user 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 # Get the filename from the image path saved in the user
filename = os.path.basename(current_user.profile_image) 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 # Open the uploaded image
image = Image.open(image_file) image = Image.open(image_file)
# Convert the image to RGB mode (required for JPEG) # Function to crop and resize frames
image = image.convert('RGB') 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 # Function to process frames in parallel
min_dimension = min(image.size) def process_frames_parallel(frames, size):
square_size = (min_dimension, min_dimension) 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 # Check if the image is an animated gif
left = (image.width - min_dimension) / 2 if file_extension == 'gif':
top = (image.height - min_dimension) / 2 # Process frames
right = (image.width + min_dimension) / 2 gif_frames = [frame.copy() for frame in ImageSequence.Iterator(image)]
bottom = (image.height + min_dimension) / 2 processed_frames = process_frames_parallel(gif_frames, size=(128, 128))
# Crop the image to a square and resize it # Save the modified frames as a new GIF
image = image.crop((left, top, right, bottom)) output_gif_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".jpg", ".gif"))
image.thumbnail(square_size) processed_frames[0].save(output_gif_path, save_all=True, append_images=processed_frames[1:], loop=0)
image = image.resize((256, 256)) 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 # Save the processed image
image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg")) image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg"))
image.save(image_path, 'JPEG', quality=100) processed_image.save(image_path, 'JPEG', quality=100)
current_user.profile_image = image_path current_user.profile_image = image_path
# Update user profile
current_user.update() current_user.update()
@app.route('/upload', methods=['POST']) @app.route('/upload', methods=['POST'])

View File

@ -4,7 +4,7 @@
<div class = "row"> <div class = "row">
<div class="col"> <div class="col">
<h1> <h1>
{% if (current_user.is_authenticated) %}<img class="avatar avatar-xl" src="{{user.profile_image}}" alt="failed to load image"/>{% endif %} {% if (current_user.is_authenticated) %}<img class="avatar avatar-xl" src="{{user.profile_image}}" alt="no image"/>{% endif %}
{{ title }} {{ title }}
</h1> </h1>
<h3>{{ utc_dt }}</h3> <h3>{{ utc_dt }}</h3>