-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
174 lines (129 loc) · 6.44 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from flask import Flask, request, send_from_directory, render_template, jsonify, send_file
from PIL import Image, ImageFont, ImageDraw
from datetime import datetime
import os, io, zipfile
app = Flask(__name__)
# UPLOAD_FOLDER = 'uploads'
OUTPUT_FOLDER = 'static/outputs'
MD_OVERLAY = 'static/img/overlay.png'
MD_FONT = 'static/fonts/Orbitron-Bold.ttf'
WORKING_AREA_HEIGHT = 800
WORKING_AREA_WIDTH = 800
# Stelle sicher, dass UPLOAD_FOLDER und OUTPUT_FOLDER existieren
os.makedirs('templates', exist_ok=True)
#os.makedirs('static/img', exist_ok=True)
#os.makedirs('static/fonts', exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
def scale_image(input_image, max_width, max_height):
"""
Skaliert ein Bild proportional, so dass es die maximalen Abmessungen nicht überschreitet,
ohne es unter die minimalen Abmessungen (800x500) zu verkleinern.
"""
original_width, original_height = input_image.size
# Verhältnis des Originalbildes berechnen
original_ratio = original_width / original_height
# Zielverhältnis basierend auf den maximalen Abmessungen berechnen
target_ratio = max_width / max_height
# Entscheiden, ob das Bild basierend auf der Breite oder Höhe skaliert werden soll
if original_ratio < target_ratio:
# Skaliere basierend auf der Breite
new_width = min(original_width, max_width)
new_height = int(new_width / original_ratio)
else:
# Skaliere basierend auf der Höhe
new_height = min(original_height, max_height)
new_width = int(new_height * original_ratio)
# Stelle sicher, dass das Bild nicht kleiner als die Mindestgrößen wird
#new_width = max(new_width, 800)
#new_height = max(new_height, 500)
# Skaliere das Bild unter Verwendung von Lanczos-Resampling für eine hochwertige Reduktion
return input_image.resize((new_width, new_height), Image.LANCZOS)
def process_image(file_stream, text, font_size, original_filename, image_area_height):
"""
Verarbeitet ein einzelnes Bild: Skaliert es, fügt ein Overlay hinzu und beschriftet es mit Text.
Gibt den Pfad zum gespeicherten Bild zurück.
"""
# Aktuelles Datum im Format yyyymmdd
current_date = datetime.now().strftime("%Y%m%d%H%M%S")
# Bereinige den Text für den Dateinamen
safe_text = "".join([c if c.isalnum() else "_" for c in text])
safe_filename = "".join([c if c.isalnum() else "_" for c in original_filename.rsplit('.', 1)[0]])
# Erstelle den neuen Dateinamen
# new_filename = f"{current_date}_{safe_text}_{original_filename}"
new_filename = f"{current_date}_{safe_text}_{safe_filename}.png"
# Pfad, unter dem das bearbeitete Bild gespeichert wird
output_filename = os.path.join(OUTPUT_FOLDER, new_filename)
# Bildverarbeitung
canvas = Image.new("RGBA", (WORKING_AREA_WIDTH, WORKING_AREA_HEIGHT), (255, 255, 255, 255))
image = Image.open(file_stream).convert("RGBA")
# Skaliere das Bild, falls notwendig
image = scale_image(image, WORKING_AREA_WIDTH, image_area_height)
# Der Mittelpunkt des oberen Bereiches liegt bei x=400, y=230
# Füge das Bild mittig ein
width, height = image.size
paste_x = int((WORKING_AREA_WIDTH - width) / 2)
paste_y = int((image_area_height - height) / 2)
canvas.paste(image, (paste_x, paste_y), image)
# canvas.paste(image, (0, 0), image)
overlay = Image.open(MD_OVERLAY).convert("RGBA")
overlay = scale_image(overlay, WORKING_AREA_WIDTH, WORKING_AREA_HEIGHT)
canvas.paste(overlay, (0, 0), overlay)
draw = ImageDraw.Draw(canvas)
font = ImageFont.truetype(MD_FONT, font_size)
text_width, text_height = draw.textbbox((0, 0), text, font=font)[2:]
# Zentriere den Text bei y=515
text_x = int((WORKING_AREA_WIDTH - text_width) / 2)
text_y = int(515 - (text_height / 2))
draw.text((text_x, text_y), text, font=font, fill="white")
canvas = scale_image(canvas, 512, 512) # official mission day badge format
canvas.save(output_filename)
return new_filename
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ['png', 'jpg', 'jpeg', 'gif']
def clear_directory(directory_path):
for filename in os.listdir(directory_path):
file_path = os.path.join(directory_path, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
except Exception as e:
print(f"Error deleting {file_path}. Reason: {e}")
@app.route('/')
def index():
return render_template('index.html')
@app.route('/upload', methods=['POST'])
def upload():
clear_directory(OUTPUT_FOLDER)
files = request.files.getlist('user-images')
if not files or files[0].filename == '':
return 'Keine Dateien ausgewählt', 400
text = request.form.get('text', '')
font_size = int(request.form.get('font-size', 20))
image_area_height = int(request.form.get('image-area-height', 460))
result_filenames = [process_image(file.stream, text, font_size, file.filename, image_area_height) for file in files if file and allowed_file(file.filename)]
if not result_filenames:
return jsonify({'error': 'Ungültiges Dateiformat'}), 400
return render_template('gallery.html', images=result_filenames)
# return jsonify({'images': result_paths}), 200
@app.route('/download-image/<filename>')
def download_image(filename):
image_path = os.path.join(app.root_path, 'static', 'outputs', filename)
response: Response = send_file(image_path, mimetype='image/png', as_attachment=True, download_name=filename)
return response
@app.route('/download_all')
def download_all():
# Erstelle eine Byte-Stream für die ZIP-Datei
zip_buffer = io.BytesIO()
# Initialisiere die ZIP-Datei
with zipfile.ZipFile(zip_buffer, 'a', zipfile.ZIP_DEFLATED, False) as zip_file:
for root, dirs, files in os.walk(OUTPUT_FOLDER):
for file in files:
zip_file.write(os.path.join(root, file), file)
# Gehe zurück zum Anfang des Byte-Streams
zip_buffer.seek(0)
# Sende die ZIP-Datei als Download
# return send_file(zip_buffer, mimetype='application/zip', as_attachment=True, attachment_filename='images.zip')
return send_file(zip_buffer, mimetype='application/zip', as_attachment=True, download_name='images.zip')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)