Ajout des fichiers de configuration et du code pour le redimensionnement d'images avec Bottle et Pillow
This commit is contained in:
99
app.py
Normal file
99
app.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from bottle import Bottle, response, request, run, static_file, template, BaseRequest
|
||||
from PIL import Image
|
||||
import os
|
||||
import tempfile
|
||||
import zipfile
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
from functools import partial
|
||||
|
||||
BaseRequest.MEMFILE_MAX = 100 * 1024 * 1024 # Supporte jusqu'à 100 Mo
|
||||
|
||||
app = Bottle()
|
||||
UPLOAD_DIR = tempfile.mkdtemp()
|
||||
OUTPUT_DIR = os.path.join(UPLOAD_DIR, 'resized')
|
||||
ZIP_PATH = os.path.join(UPLOAD_DIR, 'resized_images.zip')
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
def resize_image(filepath, output_dir, ratio):
|
||||
from PIL import Image # Re-importé dans chaque processus
|
||||
import os
|
||||
|
||||
try:
|
||||
with Image.open(filepath) as img:
|
||||
exif_data = img.info.get('exif')
|
||||
width, height = img.size
|
||||
new_size = (int(width / ratio), int(height / ratio))
|
||||
|
||||
try:
|
||||
img = img.resize(new_size, Image.LANCZOS)
|
||||
except ValueError:
|
||||
img = Image.open(filepath).point(lambda x: x / 256).convert("L")
|
||||
img = img.resize(new_size, Image.LANCZOS)
|
||||
|
||||
name, ext = os.path.splitext(os.path.basename(filepath))
|
||||
output_path = os.path.join(output_dir, f"{name}_resized{ext}")
|
||||
img.save(output_path, quality=85, optimize=True, exif=exif_data or [])
|
||||
print(f"✅ Image enregistrée : {output_path} === ({width, height}) => ({new_size})") # DEBUG
|
||||
return output_path
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur pour {filepath}: {e}")
|
||||
return None
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return template('index.tpl')
|
||||
|
||||
|
||||
@app.post('/upload')
|
||||
def upload():
|
||||
files = request.files.getall('files')
|
||||
ratio = float(request.forms.get('ratio', 2))
|
||||
|
||||
if not files:
|
||||
return "Aucun fichier reçu."
|
||||
|
||||
saved_paths = []
|
||||
for file in files:
|
||||
filename = os.path.basename(file.filename)
|
||||
save_path = os.path.join(UPLOAD_DIR, filename)
|
||||
file.save(save_path, overwrite=True)
|
||||
saved_paths.append(save_path)
|
||||
|
||||
# 🧠 Traitement en parallèle
|
||||
resize_func = partial(resize_image, output_dir=OUTPUT_DIR, ratio=ratio)
|
||||
with ProcessPoolExecutor() as executor:
|
||||
resized_files = list(executor.map(resize_func, saved_paths))
|
||||
|
||||
# 📦 Création du ZIP
|
||||
with zipfile.ZipFile(ZIP_PATH, 'w') as zipf:
|
||||
for path in resized_files:
|
||||
if path: # Skip si erreur
|
||||
zipf.write(path, arcname=os.path.basename(path))
|
||||
|
||||
return template(
|
||||
'result.tpl',
|
||||
count=len([p for p in resized_files if p]),
|
||||
ratio=ratio,
|
||||
images=[os.path.basename(p) for p in resized_files if p]
|
||||
)
|
||||
|
||||
|
||||
@app.route('/download')
|
||||
def download():
|
||||
if not os.path.exists(ZIP_PATH):
|
||||
return "ZIP non généré ❌"
|
||||
return static_file('resized_images.zip', root=UPLOAD_DIR, download='images_reduites.zip')
|
||||
|
||||
|
||||
@app.route('/resized/<filename>')
|
||||
def serve_resized(filename):
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return static_file(filename, root=OUTPUT_DIR)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run(app, host='localhost', port=8080, debug=True)
|
||||
Reference in New Issue
Block a user