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 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'])

View File

@ -4,7 +4,7 @@
<div class = "row">
<div class="col">
<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 }}
</h1>
<h3>{{ utc_dt }}</h3>