Улучшение системы работы с фото: добавлена команда очистки битых записей и оптимизация обработки изображений
This commit is contained in:
@@ -159,15 +159,15 @@ class ImageProcessor:
|
||||
def _resize_image(img, size):
|
||||
"""
|
||||
Изменяет размер изображения с сохранением пропорций.
|
||||
Если исходное изображение меньше целевого размера, добавляет белый фон.
|
||||
Если больше - уменьшает с сохранением пропорций.
|
||||
НЕ увеличивает маленькие изображения (сохраняет качество).
|
||||
Создает адаптивный квадрат по размеру реального изображения.
|
||||
|
||||
Args:
|
||||
img: PIL Image object
|
||||
size: Кортеж (width, height)
|
||||
size: Кортеж (width, height) - максимальный целевой размер
|
||||
|
||||
Returns:
|
||||
PIL Image object с новым размером
|
||||
PIL Image object - квадратное изображение с минимальным белым фоном
|
||||
"""
|
||||
# Копируем изображение, чтобы не модифицировать оригинал
|
||||
img_copy = img.copy()
|
||||
@@ -190,12 +190,14 @@ class ImageProcessor:
|
||||
if img_copy.width > new_width or img_copy.height > new_height:
|
||||
img_copy = img_copy.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
|
||||
# Создаем новое изображение нужного размера с белым фоном
|
||||
new_img = Image.new('RGB', size, (255, 255, 255))
|
||||
# Создаем адаптивный квадрат по размеру реального изображения (а не по конфигурации)
|
||||
# Это позволяет избежать огромных белых полей для маленьких фото
|
||||
square_size = max(img_copy.width, img_copy.height)
|
||||
new_img = Image.new('RGB', (square_size, square_size), (255, 255, 255))
|
||||
|
||||
# Центрируем исходное изображение на белом фоне
|
||||
offset_x = (size[0] - img_copy.width) // 2
|
||||
offset_y = (size[1] - img_copy.height) // 2
|
||||
offset_x = (square_size - img_copy.width) // 2
|
||||
offset_y = (square_size - img_copy.height) // 2
|
||||
new_img.paste(img_copy, (offset_x, offset_y))
|
||||
|
||||
return new_img
|
||||
|
||||
@@ -105,17 +105,16 @@ class ImageService:
|
||||
|
||||
# Используем default_storage.url() для корректной работы с TenantAwareFileSystemStorage
|
||||
# Это гарантирует что URL будет содержать tenant_id если необходимо
|
||||
# Проверяем существование файла - если не найден, возвращаем пустую строку
|
||||
# (для обработанных файлов миниатюра должна существовать)
|
||||
# Проверяем существование файла - если не найден, возвращаем оригинал как fallback
|
||||
if default_storage.exists(file_path):
|
||||
url = default_storage.url(file_path)
|
||||
logger.debug(f"[ImageService] Returning {size} URL: {file_path} -> {url}")
|
||||
return url
|
||||
else:
|
||||
# Файл нужного размера не найден - возвращаем пустую строку
|
||||
# (файл обработан, но миниатюра не создана - это ошибка)
|
||||
logger.warning(f"[ImageService] {size} file not found: {file_path}, file should be processed")
|
||||
return ''
|
||||
# Файл нужного размера не найден - возвращаем оригинал как fallback
|
||||
# (файл может быть загружен до внедрения системы обработки или обработка не завершена)
|
||||
logger.warning(f"[ImageService] {size} file not found: {file_path}, using original as fallback")
|
||||
return default_storage.url(str(original_image_path))
|
||||
|
||||
except Exception as e:
|
||||
# В случае ошибки возвращаем оригинал
|
||||
|
||||
Reference in New Issue
Block a user