import io from typing import Any, TypeVar import cv2 import numpy as np from numpy.typing import NDArray from PIL.Image import new as new_image from app.image import Image T = TypeVar("T", bound=np.uint8) def create_mock_image( size: tuple[int, int, int] = (64, 64, 3), color1: tuple[int, int, int] = (255, 0, 0), color2: tuple[int, int, int] = (0, 255, 0), ) -> bytes: """Create a mock RGB image with two colors.""" image = np.zeros((size[1], size[0], size[2]), dtype=np.uint8) image[:, : size[0] // 2] = color1 image[:, size[0] // 2 :] = color2 _, encoded_image = cv2.imencode(".jpg", image) return encoded_image.tobytes() def calculate_ssim( img1: NDArray[T], img2: NDArray[T], dynamic_range: int = 255, ) -> Any: """Calculate Structural Similarity Index (SSIM) between two images.""" # Constants for SSIM calculation k1 = 0.01 k2 = 0.03 L = dynamic_range # Mean of the images mu1 = np.mean(img1) mu2 = np.mean(img2) # Variance of the images var1 = np.var(img1) var2 = np.var(img2) # Covariance between the images cov = np.cov(img1.flatten(), img2.flatten())[0, 1] # Constants for SSIM formula c1 = (k1 * L) ** 2 c2 = (k2 * L) ** 2 # SSIM calculation numerator = (2 * mu1 * mu2 + c1) * (2 * cov + c2) denominator = (mu1**2 + mu2**2 + c1) * (var1 + var2 + c2) ssim_value = numerator / denominator return ssim_value def test_image_crop_to_square() -> None: test_image = new_image(mode="RGB", size=(400, 200)) with io.BytesIO() as cropped_image_fo: test_image.save(cropped_image_fo, format="PNG") cropped_image = Image(cropped_image_fo.getvalue()) cropped_image.crop_to_square() assert cropped_image.size[0] == min(test_image.size) assert cropped_image.size[1] == min(test_image.size) def test_image_thumbnail() -> None: test_image = new_image(mode="RGB", size=(400, 200)) with io.BytesIO() as cropped_image_fo: test_image.save(cropped_image_fo, format="PNG") cropped_image = Image(cropped_image_fo.getvalue()) assert cropped_image.thumbnail.size[0] == 64 assert cropped_image.thumbnail.size[1] == 64 def test_image_format() -> None: test_image = new_image(mode="RGB", size=(400, 200)) with io.BytesIO() as cropped_image_fo: test_image.save(cropped_image_fo, format="PNG") image = Image(cropped_image_fo.getvalue()) assert image.format == "png" def test_image_mime_type() -> None: test_image = new_image(mode="RGB", size=(400, 200)) with io.BytesIO() as cropped_image_fo: test_image.save(cropped_image_fo, format="PNG") image = Image(cropped_image_fo.getvalue()) assert image.mime_type == "image/png" def test_thumbnail_similarity() -> None: # Generate mock images for original and thumbnail original_image = create_mock_image((320, 180, 3)) thumbnail_image = create_mock_image((64, 64, 3)) # Resize the original image to match the dimensions of the thumbnail original_image_thumbnail = Image(original_image).thumbnail # Decode byte data into NumPy arrays original_image_np: np.ndarray[Any, Any] = cv2.imdecode( # type: ignore np.frombuffer(original_image_thumbnail.image_bytes, dtype=np.uint8), cv2.IMREAD_COLOR, ) thumbnail_image_np: np.ndarray[Any, Any] = cv2.imdecode( # type: ignore np.frombuffer(thumbnail_image, dtype=np.uint8), cv2.IMREAD_COLOR, ) # Calculate the similarity between the original and thumbnail images (using MSE) mse = np.mean((original_image_np - thumbnail_image_np) ** 2) # type: ignore # Assuming a threshold of 100 for MSE assert mse <= 100, "MSE should be less than or equal to 100" # Alternatively, calculate SSIM ssim_score = calculate_ssim(original_image_np, thumbnail_image_np) # Assuming a threshold of 0.9 for SSIM assert ssim_score >= 0.9, "SSIM should be greater than or equal to 0.9"