comparison sat/tools/images.py @ 3200:5c3bf37f2202

tools (images): max_size can now be manually specified in checkImage and dest in resizeImage: `context` has been removed as it is not used and doesn't seem that useful.
author Goffi <goffi@goffi.org>
date Sun, 01 Mar 2020 18:47:05 +0100
parents 8b4354b5c05f
children
comparison
equal deleted inserted replaced
3199:5afd7416ca2d 3200:5c3bf37f2202
19 19
20 """Methods to manipulate images""" 20 """Methods to manipulate images"""
21 21
22 import tempfile 22 import tempfile
23 from PIL import Image 23 from PIL import Image
24 from sat.core.constants import Const as C
25 from pathlib import Path 24 from pathlib import Path
26 from twisted.internet import threads 25 from twisted.internet import threads
27 26
28 27
29 def checkImage(host, path, context=C.CONTEXT_CHAT): 28 def checkImage(host, path, max_size=None):
30 """Analyze image and return a report 29 """Analyze image and return a report
31 30
32 report will indicate if image is too large, and the recommended new size if this is 31 report will indicate if image is too large, and the recommended new size if this is
33 the case 32 the case
34 @param host: SàT instance 33 @param host: SàT instance
35 @param path(str, pathlib.Path): image to open 34 @param path(str, pathlib.Path): image to open
36 @param context(str): context in which the image is transfered 35 @param max_size(tuple[int, int]): maximum accepted size of image
36 None to use value set in config
37 @return dict: report on image, with following keys: 37 @return dict: report on image, with following keys:
38 - too_large: true if image is oversized 38 - too_large: true if image is oversized
39 - recommended_size: if too_large is True, recommended size to use 39 - recommended_size: if too_large is True, recommended size to use
40 """ 40 """
41 # TODO: context is not used yet
42 report = {} 41 report = {}
43 image = Image.open(path) 42 image = Image.open(path)
44 max_size = tuple(host.memory.getConfig(None, "image_max", (1200, 720))) 43 if max_size is None:
44 max_size = tuple(host.memory.getConfig(None, "image_max", (1200, 720)))
45 if image.size > max_size: 45 if image.size > max_size:
46 report['too_large'] = True 46 report['too_large'] = True
47 if image.size[0] > max_size[0]: 47 if image.size[0] > max_size[0]:
48 factor = max_size[0] / image.size[0] 48 factor = max_size[0] / image.size[0]
49 if image.size[1] * factor > max_size[1]: 49 if image.size[1] * factor > max_size[1]:
55 report['too_large'] = False 55 report['too_large'] = False
56 56
57 return report 57 return report
58 58
59 59
60 def _resizeImageBlocking(image_path, new_size): 60 def _resizeImageBlocking(image_path, new_size, dest=None):
61 im_path = Path(image_path) 61 im_path = Path(image_path)
62 im = Image.open(im_path) 62 im = Image.open(im_path)
63 resized = im.resize(new_size, Image.LANCZOS) 63 resized = im.resize(new_size, Image.LANCZOS)
64 with tempfile.NamedTemporaryFile(suffix=im_path.suffix, delete=False) as f: 64
65 if dest is None:
66 dest = tempfile.NamedTemporaryFile(suffix=im_path.suffix, delete=False)
67 elif isinstance(dest, Path):
68 dest = Path.open('wb')
69
70 with dest as f:
65 resized.save(f, format=im.format) 71 resized.save(f, format=im.format)
72
66 return Path(f.name) 73 return Path(f.name)
67 74
68 75
69 def resizeImage(image_path, new_size): 76 def resizeImage(image_path, new_size, dest=None):
70 """Resize an image to a new temporary file, and return it path 77 """Resize an image to a new file, and return its path
71 78
72 @param image_path(str, Path): path of the original image 79 @param image_path(str, Path): path of the original image
73 @param new_size(tuple[int, int]): size to use for new image 80 @param new_size(tuple[int, int]): size to use for new image
74 @return (Path): path of the resized file. The image at this path must be deleted 81 @param dest(None, Path, file): where the resized image must be stored, can be:
75 after use 82 - None: use a temporary file
83 - Path: path to the file to create/overwrite
84 - file: a file object which must be opened for writing in binary mode
85 @return (Path): path of the resized file.
86 The image at this path should be deleted after use
76 """ 87 """
77 return threads.deferToThread(_resizeImageBlocking, image_path, new_size) 88 return threads.deferToThread(_resizeImageBlocking, image_path, new_size, dest)