diff --git a/core/utils.py b/core/utils.py index 82fc78a7..a815975b 100644 --- a/core/utils.py +++ b/core/utils.py @@ -82,40 +82,47 @@ def get_semester_code(d: Optional[date] = None) -> str: return "P" + str(start.year)[-2:] -def resize_image(im: Image, edge: int, img_format: str): - """Resize an image to fit the given edge length and format.""" +def resize_image( + im: Image, edge: int, img_format: str, *, optimize: bool = True +) -> ContentFile: + """Resize an image to fit the given edge length and format. + + Args: + im: the image to resize + edge: the length that the greater side of the resized image should have + img_format: the target format of the image ("JPEG", "PNG", "WEBP"...) + optimize: Should the resized image be optimized ? + """ (w, h) = im.size ratio = edge / max(w, h) (width, height) = int(w * ratio), int(h * ratio) - return resize_image_explicit(im, (width, height), img_format) + return resize_image_explicit(im, (width, height), img_format, optimize=optimize) -def resize_image_explicit(im: Image, size: tuple[int, int], img_format: str): - """Resize an image to the given size and format.""" +def resize_image_explicit( + im: Image, size: tuple[int, int], img_format: str, *, optimize: bool = True +) -> ContentFile: + """Resize an image to the given size and format. + + Args: + im: the image to resize + size: the target dimension, as a [width, height] tuple + img_format: the target format of the image ("JPEG", "PNG", "WEBP"...) + optimize: Should the resized image be optimized ? + """ img_format = img_format.upper() content = BytesIO() # use the lanczos filter for antialiasing and discard the alpha channel - im = im.resize((size[0], size[1]), Resampling.LANCZOS) + if size != im.size: + im = im.resize((size[0], size[1]), Resampling.LANCZOS) if img_format == "JPEG": # converting an image with an alpha channel to jpeg would cause a crash im = im.convert("RGB") try: - im.save( - fp=content, - format=img_format, - quality=90, - optimize=True, - progressive=True, - ) + im.save(fp=content, format=img_format, optimize=optimize) except IOError: PIL.ImageFile.MAXBLOCK = im.size[0] * im.size[1] - im.save( - fp=content, - format=img_format, - quality=90, - optimize=True, - progressive=True, - ) + im.save(fp=content, format=img_format, optimize=optimize) return ContentFile(content.getvalue()) diff --git a/sas/models.py b/sas/models.py index e63ef8b0..4248be50 100644 --- a/sas/models.py +++ b/sas/models.py @@ -117,7 +117,11 @@ class Picture(SasFile): # meant to be shown on the website, but rather to keep the real image # for less frequent cases (like downloading the pictures of an user) extension = self.mime_type.split("/")[-1] - file = resize_image(im, max(im.size), extension) + # the HD version of the image doesn't need to be optimized, because : + # - it isn't frequently queried + # - optimizing large images takes a lot time, which greatly hinders the UX + # - photographers usually already optimize their images + file = resize_image(im, max(im.size), extension, optimize=False) thumb = resize_image(im, 200, "webp") compressed = resize_image(im, 1200, "webp") if overwrite: