Spaces:
Running
Running
File size: 3,500 Bytes
e7f1d57 |
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 |
# Dependencies
import magic
from PIL import Image
from pathlib import Path
from typing import Tuple
from utils.logger import get_logger
from config.settings import settings
from config.constants import MIN_IMAGE_DIMENSION
from config.constants import MAX_IMAGE_DIMENSION
# Setup Logging
logger = get_logger(__name__)
class ValidationError(Exception):
"""
Custom validation error
"""
pass
class ImageValidator:
"""
Validate uploaded images
"""
@staticmethod
def validate_file_size(file_size: int) -> None:
"""
Validate file size
"""
if (file_size > settings.max_file_size_bytes):
raise ValidationError(f"File size {file_size} bytes exceeds maximum {settings.max_file_size_bytes} bytes")
if (file_size == 0):
raise ValidationError("File is empty")
@staticmethod
def validate_file_extension(filename: str) -> None:
"""
Validate file extension
"""
extension = Path(filename).suffix.lower()
if (extension not in settings.ALLOWED_EXTENSIONS):
raise ValidationError(f"File extension {extension} not allowed. Allowed: {', '.join(settings.ALLOWED_EXTENSIONS)}")
@staticmethod
def validate_image_content(file_path: Path) -> Tuple[int, int]:
"""
Validate image can be opened and get dimensions
"""
try:
with Image.open(file_path) as image:
width, height = image.size
# Validate dimensions
if ((width < MIN_IMAGE_DIMENSION) or (height < MIN_IMAGE_DIMENSION)):
raise ValidationError(f"Image dimensions ({width}x{height}) too small. Minimum: {MIN_IMAGE_DIMENSION}px")
if ((width > MAX_IMAGE_DIMENSION) or (height > MAX_IMAGE_DIMENSION)):
raise ValidationError(f"Image dimensions ({width}x{height}) too large. Maximum: {MAX_IMAGE_DIMENSION}px")
# Verify format
if (image.format.lower() not in ['jpeg', 'png', 'webp']):
raise ValidationError(f"Unsupported image format: {image.format}")
return width, height
except ValidationError:
raise
except Exception as e:
raise ValidationError(f"Cannot open image: {str(e)}")
@staticmethod
def validate_mime_type(file_path: Path) -> None:
"""
Validate MIME type matches image
"""
try:
mime = magic.from_file(str(file_path), mime = True)
if (not mime.startswith('image/')):
raise ValidationError(f"File is not an image. MIME type: {mime}")
except Exception as e:
logger.warning(f"MIME type validation failed: {e}")
# Don't fail if python-magic is not available
@classmethod
def validate_image(cls, file_path: Path, filename: str, file_size: int) -> Tuple[int, int]:
"""
Comprehensive image validation
"""
cls.validate_file_size(file_size)
cls.validate_file_extension(filename)
dimensions = cls.validate_image_content(file_path)
cls.validate_mime_type(file_path) # Optional, commented out if python-magic not available
logger.debug(f"Validated image: {filename} ({dimensions[0]}x{dimensions[1]})")
return dimensions |