annotate sat/tools/image.py @ 3234:78fea49735c5

core (memory/persistent): added `aset` method in LazyPersistentBinaryDict: this method does the same as `force` but is there to be consistent with PersistentDict. `force` should be removed in the future.
author Goffi <goffi@goffi.org>
date Fri, 27 Mar 2020 09:53:00 +0100
parents 4fbea7f1e012
children 54934ee3f69c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python3
3137
559a625a236b fixed shebangs
Goffi <goffi@goffi.org>
parents: 3136
diff changeset
2
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
3 # SàT: an XMPP client
3136
9d0df638c8b4 dates update
Goffi <goffi@goffi.org>
parents: 3066
diff changeset
4 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org)
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
5
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
10
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
15
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
18
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
19 """Methods to manipulate images"""
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
20
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 import tempfile
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from PIL import Image
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from pathlib import Path
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from twisted.internet import threads
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
25
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
26
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
27 def check(host, path, max_size=None):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 """Analyze image and return a report
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 report will indicate if image is too large, and the recommended new size if this is
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 the case
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 @param host: SàT instance
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 @param path(str, pathlib.Path): image to open
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
34 @param max_size(tuple[int, int]): maximum accepted size of image
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
35 None to use value set in config
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 @return dict: report on image, with following keys:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 - too_large: true if image is oversized
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 - recommended_size: if too_large is True, recommended size to use
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 """
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 report = {}
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 image = Image.open(path)
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
42 if max_size is None:
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
43 max_size = tuple(host.memory.getConfig(None, "image_max", (1200, 720)))
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 if image.size > max_size:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 report['too_large'] = True
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 if image.size[0] > max_size[0]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 factor = max_size[0] / image.size[0]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 if image.size[1] * factor > max_size[1]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 factor = max_size[1] / image.size[1]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 else:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 factor = max_size[1] / image.size[1]
3157
8b4354b5c05f tools (images): fixed type for recommended_size.
Goffi <goffi@goffi.org>
parents: 3137
diff changeset
52 report['recommended_size'] = [int(image.width*factor), int(image.height*factor)]
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 else:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 report['too_large'] = False
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
55
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 return report
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
57
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
58
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
59 def _resizeBlocking(image_path, new_size, dest=None):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 im_path = Path(image_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 im = Image.open(im_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 resized = im.resize(new_size, Image.LANCZOS)
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
63
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
64 if dest is None:
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
65 dest = tempfile.NamedTemporaryFile(suffix=im_path.suffix, delete=False)
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
66 elif isinstance(dest, Path):
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
67 dest = dest.open('wb')
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
68
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
69 with dest as f:
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 resized.save(f, format=im.format)
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
71
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 return Path(f.name)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
73
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
74
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
75 def resize(image_path, new_size, dest=None):
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
76 """Resize an image to a new file, and return its path
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
77
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 @param image_path(str, Path): path of the original image
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 @param new_size(tuple[int, int]): size to use for new image
3200
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
80 @param dest(None, Path, file): where the resized image must be stored, can be:
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
81 - None: use a temporary file
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
82 - Path: path to the file to create/overwrite
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
83 - file: a file object which must be opened for writing in binary mode
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
84 @return (Path): path of the resized file.
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
85 The image at this path should be deleted after use
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 """
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
87 return threads.deferToThread(_resizeBlocking, image_path, new_size, dest)