From: Michael Tremer Date: Tue, 7 May 2019 16:27:54 +0000 (+0100) Subject: Cache generated thumbnails X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ef115cd800c7fc30a8396e7e9c30bee55597eb1;p=ipfire.org.git Cache generated thumbnails Signed-off-by: Michael Tremer --- diff --git a/src/backend/accounts.py b/src/backend/accounts.py index e2352f55..8f6659bc 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -767,30 +767,24 @@ class Account(Object): return url def get_avatar(self, size=None): - avatar = self._get_bytes("jpegPhoto") - if not avatar: - return - - if not size: - return avatar + photo = self._get_bytes("jpegPhoto") - return self._resize_avatar(avatar, size) + # Return the raw image if no size was requested + if size is None: + return photo - def _resize_avatar(self, image, size): - image = PIL.Image.open(io.BytesIO(image)) + # Try to retrieve something from the cache + avatar = self.memcache.get("accounts:%s:avatar:%s" % (self.uid, size)) + if avatar: + return avatar - # Resize the image to the desired resolution (and make it square) - thumbnail = PIL.ImageOps.fit(image, (size, size), PIL.Image.ANTIALIAS) + # Generate a new thumbnail + avatar = util.generate_thumbnail(photo, size) - with io.BytesIO() as f: - # If writing out the image does not work with optimization, - # we try to write it out without any optimization. - try: - thumbnail.save(f, image.format, optimize=True, quality=98) - except: - thumbnail.save(f, image.format, quality=98) + # Save to cache for 15m + self.memcache.set("accounts:%s:avatar:%s" % (self.uid, size), avatar, 900) - return f.getvalue() + return avatar def upload_avatar(self, avatar): self._set("jpegPhoto", avatar) diff --git a/src/backend/util.py b/src/backend/util.py index 89e7f0f5..aaa2b62c 100644 --- a/src/backend/util.py +++ b/src/backend/util.py @@ -1,5 +1,9 @@ #!/usr/bin/python3 +import PIL.Image +import PIL.ImageFilter +import io +import logging import random import re import string @@ -70,3 +74,49 @@ def normalize(s): s = re.sub(r"[^\w]+", " ", s) return "-".join(s.split()) + +def generate_thumbnail(data, size, **args): + assert data, "No image data received" + + image = PIL.Image.open(io.BytesIO(data)) + + # Save image format + format = image.format + + # Remove any alpha-channels + if image.format == "JPEG" and not image.mode == "RGB": + # Make a white background + background = PIL.Image.new("RGBA", image.size, (255,255,255)) + + # Convert image to RGBA if not in RGBA, yet + if not image.mode == "RGBA": + image = image.convert("RGBA") + + # Flatten both images together + flattened_image = PIL.Image.alpha_composite(background, image) + + # Remove the alpha channel + image = flattened_image.convert("RGB") + + # Resize the image to the desired resolution + image.thumbnail((size, size), PIL.Image.LANCZOS) + + if image.format == "JPEG": + # Apply a gaussian blur to make compression easier + image = image.filter(PIL.ImageFilter.GaussianBlur(radius=0.05)) + + # Arguments to optimise the compression + args.update({ + "subsampling" : "4:2:0", + "quality" : 70, + }) + + with io.BytesIO() as f: + # If writing out the image does not work with optimization, + # we try to write it out without any optimization. + try: + image.save(f, format, optimize=True, **args) + except: + image.save(f, format, **args) + + return f.getvalue() diff --git a/src/backend/wiki.py b/src/backend/wiki.py index b5aaa5fb..c50d8ea1 100644 --- a/src/backend/wiki.py +++ b/src/backend/wiki.py @@ -1,9 +1,6 @@ #!/usr/bin/python3 -import PIL -import PIL.ImageFilter import difflib -import io import logging import os.path import re @@ -526,46 +523,9 @@ class File(misc.Object): return thumbnail # Generate the thumbnail - thumbnail = self._generate_thumbnail(size) + thumbnail = util.generate_thumbnail(self.blob, size) # Put it into the cache for forever self.memcache.set(cache_key, thumbnail) return thumbnail - - def _generate_thumbnail(self, size, **args): - image = PIL.Image.open(io.BytesIO(self.blob)) - - # Remove any alpha-channels - if image.format == "JPEG" and not image.mode == "RGB": - # Make a white background - background = PIL.Image.new("RGBA", image.size, (255,255,255)) - - # Flatten both images together - flattened_image = PIL.Image.alpha_composite(background, image) - - # Remove the alpha channel - image = flattened_image.convert("RGB") - - # Resize the image to the desired resolution - image.thumbnail((size, size), PIL.Image.LANCZOS) - - if image.format == "JPEG": - # Apply a gaussian blur to make compression easier - image = image.filter(PIL.ImageFilter.GaussianBlur(radius=0.05)) - - # Arguments to optimise the compression - args.update({ - "subsampling" : "4:2:0", - "quality" : 70, - }) - - with io.BytesIO() as f: - # If writing out the image does not work with optimization, - # we try to write it out without any optimization. - try: - image.save(f, image.format, optimize=True, **args) - except: - image.save(f, image.format, **args) - - return f.getvalue()