mod: minor
This commit is contained in:
@@ -234,14 +234,14 @@ from НАШ_ПРОЕКТ.settings import (
|
|||||||
pillow_heif.register_heif_opener()
|
pillow_heif.register_heif_opener()
|
||||||
|
|
||||||
# Настройка параллельного декодирования HEIF/HEIC файлов
|
# Настройка параллельного декодирования HEIF/HEIC файлов
|
||||||
# DECODE_THREADS: количество потоков для декодирования
|
# DECODE_THREADS: количество потоков для декодирования
|
||||||
# - 0 = использовать количество ядер процессора (рекомендуется)
|
# - 0 = использовать количество ядер процессора (рекомендуется)
|
||||||
# - N > 0 = использовать N потоков (больше потоков = быстрее, но больше памяти)
|
# - N > 0 = использовать N потоков (больше потоков = быстрее, но жрёт больше памяти)
|
||||||
pillow_heif.options.DECODE_THREADS = 0
|
pillow_heif.options.DECODE_THREADS = 0
|
||||||
|
|
||||||
# Дополнительные опции Pillow для обработки изображений
|
# Дополнительные опции Pillow для обработки изображений
|
||||||
# LOAD_TRUNCATED_IMAGES: загружать некорректно завершенные изображения
|
# LOAD_TRUNCATED_IMAGES: загружать некорректно завершенные изображения
|
||||||
# (полезно для некачественных или поврежденных файлов)
|
# (полезно для некачественных или поврежденных файлов)
|
||||||
PILImage.LOAD_TRUNCATED_IMAGES = True
|
PILImage.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -258,7 +258,7 @@ class CustomFilerConfig(AppConfig):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _convert_to_webp_if_needed(
|
def _convert_to_webp_if_needed(
|
||||||
name: str, content: File
|
name: str, content: File
|
||||||
) -> Tuple[File, str, bool, int | None, int | None]:
|
) -> Tuple[File, str, bool, int | None, int | None]:
|
||||||
"""
|
"""
|
||||||
Конвертирует JPEG/PNG/BMP/TIFF/HEIC/HEIF в WebP.
|
Конвертирует JPEG/PNG/BMP/TIFF/HEIC/HEIF в WebP.
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ class CustomFilerConfig(AppConfig):
|
|||||||
(content, new_name, was_converted, image_width, image_height)
|
(content, new_name, was_converted, image_width, image_height)
|
||||||
"""
|
"""
|
||||||
_, original_ext = os.path.splitext(name)
|
_, original_ext = os.path.splitext(name)
|
||||||
convertible_extensions = [".jpg», ".jpeg», ".png», ".bmp», ".tiff», ".heic», ".heif»]
|
convertible_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.heic', '.heif']
|
||||||
|
|
||||||
if original_ext.lower() in convertible_extensions:
|
if original_ext.lower() in convertible_extensions:
|
||||||
try:
|
try:
|
||||||
@@ -284,15 +284,15 @@ class CustomFilerConfig(AppConfig):
|
|||||||
|
|
||||||
# Сохраняем в WebP
|
# Сохраняем в WebP
|
||||||
webp_buffer = BytesIO()
|
webp_buffer = BytesIO()
|
||||||
img.save(webp_buffer, format="WEBP», quality=THUMBNAIL_WEBP_QUALITY)
|
img.save(webp_buffer, format='WEBP', quality=THUMBNAIL_WEBP_QUALITY)
|
||||||
webp_data = webp_buffer.getvalue()
|
webp_data = webp_buffer.getvalue()
|
||||||
|
|
||||||
new_name = os.path.splitext(name)[0] + ".webp»
|
new_name = os.path.splitext(name)[0] + '.webp'
|
||||||
return ContentFile(webp_data), new_name, True, image_width, image_height
|
return ContentFile(webp_data), new_name, True, image_width, image_height
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# логируем и выбразывсаем ошибку валидации в админку django
|
# логируем и выбразывсаем ошибку валидации в админку django
|
||||||
error_msg = f"Ошибка при конвертации '{name}' в WebP: {str(e)}"
|
error_msg = f'Ошибка при конвертации \'{name}\' в WebP: {str(e)}'
|
||||||
logger.error(error_msg, exc_info=True)
|
logger.error(error_msg, exc_info=True)
|
||||||
raise ValidationError(error_msg)
|
raise ValidationError(error_msg)
|
||||||
|
|
||||||
@@ -300,8 +300,8 @@ class CustomFilerConfig(AppConfig):
|
|||||||
content.seek(0)
|
content.seek(0)
|
||||||
return content, name, False, None, None
|
return content, name, False, None, None
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
""«Патчим MultiStorageFieldFile.save() для WebP конвертации.»""
|
"""Патчим MultiStorageFieldFile.save() для WebP конвертации."""
|
||||||
from filer.fields.multistorage_file import MultiStorageFieldFile
|
from filer.fields.multistorage_file import MultiStorageFieldFile
|
||||||
from filer import settings as filer_settings
|
from filer import settings as filer_settings
|
||||||
|
|
||||||
@@ -315,15 +315,15 @@ class CustomFilerConfig(AppConfig):
|
|||||||
set(filer_settings.IMAGE_MIME_TYPES + ['heic', 'heif'])
|
set(filer_settings.IMAGE_MIME_TYPES + ['heic', 'heif'])
|
||||||
)
|
)
|
||||||
|
|
||||||
def patched_save(self_instance, name: str, content: File, save: bool = True) -> str | None:
|
def patched_save(self_instance, name: str, content: File, save: bool = True) -> str | None:
|
||||||
""«Патчированный save() с конвертацией в WebP.»""
|
"""Патчированный save() с конвертацией в WebP."""
|
||||||
new_content, new_name, converted, img_width, img_height = (
|
new_content, new_name, converted, img_width, img_height = (
|
||||||
CustomFilerConfig._convert_to_webp_if_needed(name, content)
|
CustomFilerConfig._convert_to_webp_if_needed(name, content)
|
||||||
)
|
)
|
||||||
|
|
||||||
if converted:
|
if converted:
|
||||||
# Устанавливаем MIME тип WebP
|
# Устанавливаем MIME тип WebP
|
||||||
self_instance.instance.mime_type = «image/webp»
|
self_instance.instance.mime_type = 'image/webp'
|
||||||
|
|
||||||
# Обновляем original_filename
|
# Обновляем original_filename
|
||||||
if hasattr(self_instance.instance, 'original_filename'):
|
if hasattr(self_instance.instance, 'original_filename'):
|
||||||
@@ -331,7 +331,7 @@ class CustomFilerConfig(AppConfig):
|
|||||||
original_filename, _ = os.path.splitext(
|
original_filename, _ = os.path.splitext(
|
||||||
self_instance.instance.original_filename
|
self_instance.instance.original_filename
|
||||||
)
|
)
|
||||||
self_instance.instance.original_filename = f"{original_filename}.webp»
|
self_instance.instance.original_filename = f'{original_filename}.webp'
|
||||||
|
|
||||||
# КРИТИЧНО: Обновляем _file_size и sha1 на основе уже сконвертированного WebP, а не исходника
|
# КРИТИЧНО: Обновляем _file_size и sha1 на основе уже сконвертированного WebP, а не исходника
|
||||||
new_content.seek(0)
|
new_content.seek(0)
|
||||||
@@ -386,7 +386,7 @@ if converted:
|
|||||||
**Решение:** Устанавливаем ПЕРЕД вызовом `original_save()`:
|
**Решение:** Устанавливаем ПЕРЕД вызовом `original_save()`:
|
||||||
```python
|
```python
|
||||||
if converted:
|
if converted:
|
||||||
self_instance.instance.mime_type = «image/webp» # ← ДО save()
|
self_instance.instance.mime_type = 'image/webp' # ← ДО save()
|
||||||
# Теперь filer видит image/webp и создает Image запись
|
# Теперь filer видит image/webp и создает Image запись
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -428,7 +428,7 @@ img = PILImage.open(BytesIO(content.read()))
|
|||||||
image_width, image_height = img.size # Получаем размеры
|
image_width, image_height = img.size # Получаем размеры
|
||||||
|
|
||||||
# Теперь конвертируем
|
# Теперь конвертируем
|
||||||
img.convert('RGB').save(webp_buffer, format="WEBP»)
|
img.convert('RGB').save(webp_buffer, format('WEBP')
|
||||||
|
|
||||||
# Размеры image_width и image_height останутся теми же
|
# Размеры image_width и image_height останутся теми же
|
||||||
# (пиксели не меняются, меняется только качество)
|
# (пиксели не меняются, меняется только качество)
|
||||||
|
|||||||
Reference in New Issue
Block a user