"""Сервис обработки изображений.""" import io from pathlib import Path from typing import Optional, Tuple from PIL import Image class ImageProcessor: """Сервис для обработки изображений заданий.""" MAX_SIZE = (800, 800) SUPPORTED_FORMATS = {"JPEG", "PNG", "WEBP"} QUALITY = 85 @staticmethod def resize_image( image_data: bytes, max_size: Tuple[int, int] = MAX_SIZE, quality: int = QUALITY ) -> bytes: """ Изменить размер изображения. Args: image_data: Байты изображения max_size: Максимальный размер (width, height) quality: Качество JPEG (1-100) Returns: Байты обработанного изображения """ image = Image.open(io.BytesIO(image_data)) image_format = image.format or "JPEG" # Конвертируем в RGB если нужно if image_format == "PNG" and image.mode in ("RGBA", "LA"): background = Image.new("RGB", image.size, (255, 255, 255)) if image.mode == "RGBA": background.paste(image, mask=image.split()[3]) else: background.paste(image) image = background elif image.mode != "RGB": image = image.convert("RGB") # Изменяем размер с сохранением пропорций image.thumbnail(max_size, Image.Resampling.LANCZOS) # Сохраняем в байты output = io.BytesIO() image.save(output, format="JPEG", quality=quality, optimize=True) return output.getvalue() @staticmethod def validate_image(image_data: bytes) -> Tuple[bool, Optional[str]]: """ Валидировать изображение. Args: image_data: Байты изображения Returns: (is_valid, error_message) """ try: image = Image.open(io.BytesIO(image_data)) image_format = image.format if image_format not in ImageProcessor.SUPPORTED_FORMATS: return False, f"Неподдерживаемый формат: {image_format}" # Проверяем размер width, height = image.size if width > 2000 or height > 2000: return False, "Изображение слишком большое (максимум 2000x2000)" # Проверяем файл на валидность image.verify() return True, None except Exception as e: return False, f"Ошибка валидации: {str(e)}" @staticmethod def get_image_info(image_data: bytes) -> dict: """ Получить информацию об изображении. Args: image_data: Байты изображения Returns: Словарь с информацией (format, size, mode) """ image = Image.open(io.BytesIO(image_data)) return { "format": image.format, "size": image.size, "mode": image.mode, }