Coverage for website/utils/media/processors.py: 63.64%
32 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from da_vinci import Image as DaVinciImage
2from PIL import Image, ImageOps
5def process_upload(image: DaVinciImage, **kwargs):
6 """Process an incoming image.
8 - Rotate and flip the image based on EXIF data.
9 - Resize the image to the maximum allowed size if it is larger.
10 - Convert the image to RGB colors, or keep RGBA for PNGs.
12 Warning: for django-thumbnails to save the image with the right filename, the
13 format must also be set on the '<size>.FORMAT' key in settings.THUMBNAILS_SIZES.
14 """
15 # Get the PIL image out of the DaVinci image wrapper,
16 # so we can manipulate it more completely.
17 pil_image = image.get_pil_image()
19 # Rotate and flip the image based on EXIF
20 # data, so the image is stored upright.
21 pil_image = ImageOps.exif_transpose(pil_image)
23 # Resize the image to at most the maximum allowed size.
24 pil_image.thumbnail(kwargs["size"])
26 if kwargs["format"] == "jpg": 26 ↛ 30line 26 didn't jump to line 30 because the condition on line 26 was always true
27 # Store in RGB colors.
28 pil_image = pil_image.convert("RGB")
29 image.format = "JPEG"
30 elif kwargs["format"] == "png":
31 image.format = "PNG"
32 if pil_image.mode not in ("RGBA", "RGB"):
33 pil_image = pil_image.convert("RGB")
34 else:
35 raise ValueError(f"Unsupported format: {kwargs['format']}")
37 # Put the PIL image back into the wrapper.
38 image.set_pil_image(pil_image)
39 return image
42def thumbnail(image: DaVinciImage, **kwargs):
43 """Thumbnail an image to at most the given size.
45 If `mode="contain"` (the default), the image is resized to fit within the given size.
46 The original aspect ratio is preserved, so the image may be smaller than specified.
48 If `mode="cover"`, the image is cropped to the aspect ratio of the given size.
49 The thumbnails are saved to WebP format with lossy compression.
51 If `mode="pad"`, the image is resized to fit within the given size.
52 Padding is added to the edges to make the image the exact size specified.
54 Warning: for django-thumbnails to save the image with the right filename,
55 the '<size>.FORMAT' key in settings.THUMBNAILS_SIZES must be set to 'webp'.
57 """
58 pil_image = image.get_pil_image()
60 size = kwargs["size"]
61 mode = kwargs.get("mode", "contain")
63 match mode:
64 case "contain":
65 pil_image = ImageOps.contain(pil_image, size, Image.Resampling.LANCZOS)
66 case "cover": 66 ↛ 68line 66 didn't jump to line 68 because the pattern on line 66 always matched
67 pil_image = ImageOps.fit(pil_image, size, Image.Resampling.LANCZOS)
68 case "pad":
69 pil_image = pil_image.convert("RGBA")
70 pil_image = ImageOps.pad(pil_image, size, Image.Resampling.LANCZOS)
72 image.set_pil_image(pil_image)
73 image.format = "WEBP"
74 image.quality = 90
76 return image