"""This module contains image validation methods.""" from PIL import Image from PIL import UnidentifiedImageError from src.common.constants import errors from src.common.lambda_exceptions import LambdaStatusError from src.constants import image_standards class InvalidImageError(LambdaStatusError): """Exception class for image validation errors.""" def __init__(self, code, msg=None): """Initialize instance.""" LambdaStatusError.__init__( self, error_code=code, error_params={'message': msg} ) class InvalidImageColor(InvalidImageError): """Exception class for invalid image color.""" class InvalidImageDimensions(InvalidImageError): """Exception class for invalid image dimensions.""" def validate_image(file_contents): """Validate the contents of an image. Args: file_contents (io.BytesIO): Image file contents. Returns: bool: True if validation is successful. Raises: Exception: If a validation fails. """ try: file_contents.seek(0) image = Image.open(file_contents) if not validate_mode(image.mode): raise InvalidImageColor(errors.IMAGE_INVALID_MODE_CODE, image.mode) length, width = image.size validation_result = validate_dimensions(length, width) if validation_result != image_standards.VALID_DIMENSIONS_CODE: raise InvalidImageDimensions(validation_result) return True except UnidentifiedImageError: raise InvalidImageError(errors.IMAGE_INVALID_FILE_CODE, 'it can not be identified by PIL.') def validate_dimensions(width, height): """Check image dimensions for cover images. Args: width (int): Image width. height (int): Image height. Returns: str: The result of image dimensions validation. Error code in case of an error """ if width != height: return errors.IMAGE_WRONG_ASPECT_RATIO_CODE if width < image_standards.MIN_IMAGE_DIMENSION: return errors.IMAGE_TOO_SMALL_DIMENSIONS_CODE if width > image_standards.MAX_IMAGE_DIMENSION: return errors.IMAGE_TOO_LARGE_DIMENSIONS_CODE return image_standards.VALID_DIMENSIONS_CODE def validate_mode(mode): """Check image mode. https://pillow.readthedocs.io/en/5.2.x/handbook/concepts.html#concept-modes Args: mode (str): image mode value Returns: bool: True if mode is valid, False otherwise """ return mode in image_standards.VALID_MODES