diff --git a/backend/modules/fleet/views.py b/backend/modules/fleet/views.py index aa782d6..2ef0abc 100644 --- a/backend/modules/fleet/views.py +++ b/backend/modules/fleet/views.py @@ -468,15 +468,18 @@ def _compress_image_for_pdf(image_field, max_width=1280, quality=75): """ Otvori image_field (Django FileField), kompresiraj na max_width JPEG u memoriji, vrati ImageReader spreman za reportlab. Vraća None ako slika nije dostupna. + + Koristi Image.draft() + thumbnail() kako bi se izbjeglo učitavanje pune rezolucije + velikih fotografija u RAM (sprječava OOM kill Gunicorn workera). """ try: image_field.open('rb') with Image.open(image_field) as src: + # draft() smanjuje dekodiranu rezoluciju za JPEG na serveru (hint, ne garantija) + src.draft('RGB', (max_width, max_width * 4)) img = src.convert('RGB') - if img.width > max_width: - ratio = max_width / float(img.width) - new_h = max(1, int(img.height * ratio)) - img = img.resize((max_width, new_h), Image.LANCZOS) + # thumbnail() radi in-place i ne alocira novu sliku pune veličine + img.thumbnail((max_width, max_width * 4), Image.LANCZOS) buf = BytesIO() img.save(buf, format='JPEG', quality=quality, optimize=True) buf.seek(0) @@ -493,15 +496,16 @@ def _compress_image_for_pdf(image_field, max_width=1280, quality=75): def _compress_image_for_docx(image_field, max_width=1600, quality=80): """ Pripremi sliku za python-docx kao JPEG stream razumne veličine. + + Koristi Image.draft() + thumbnail() kako bi se izbjeglo učitavanje pune rezolucije + velikih fotografija u RAM (sprječava OOM kill Gunicorn workera). """ try: image_field.open('rb') with Image.open(image_field) as src: + src.draft('RGB', (max_width, max_width * 4)) img = src.convert('RGB') - if img.width > max_width: - ratio = max_width / float(img.width) - new_h = max(1, int(img.height * ratio)) - img = img.resize((max_width, new_h), Image.LANCZOS) + img.thumbnail((max_width, max_width * 4), Image.LANCZOS) buf = BytesIO() img.save(buf, format='JPEG', quality=quality, optimize=True) buf.seek(0)