annotate libervia/backend/tools/image.py @ 4307:6a0155f410bd

test (unit): add test for plugin XEP-0033: those replace the legacy XEP-0033 test from libervia/backend/test/test_plugin_xep_0033.py. rel 450
author Goffi <goffi@goffi.org>
date Thu, 26 Sep 2024 16:12:01 +0200
parents 0d7bb4df2343
children
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
3480
7550ae9cfbac Renamed the project from "Salut à Toi" to "Libervia":
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
3 # Libervia: an XMPP client
3479
be6d91572633 date update
Goffi <goffi@goffi.org>
parents: 3477
diff changeset
4 # Copyright (C) 2009-2021 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
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
22 import mimetypes
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
23 from PIL import Image, ImageOps
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from pathlib import Path
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.internet import threads
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
26 from libervia.backend.core.i18n import _
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
27 from libervia.backend.core import exceptions
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
28 from libervia.backend.core.log import getLogger
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
29
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
30 log = getLogger(__name__)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
31
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
32 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
33 import cairosvg
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
34 except Exception as e:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
35 log.warning(_("SVG support not available, please install cairosvg: {e}").format(e=e))
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
36 cairosvg = None
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
37
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
38
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
39 def check(host, path, max_size=None):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 """Analyze image and return a report
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 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
43 the case
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 @param host: SàT instance
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 @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
46 @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
47 None to use value set in config
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 @return dict: report on image, with following keys:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 - too_large: true if image is oversized
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 - 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
51 """
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 report = {}
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 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
54 if max_size is None:
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3480
diff changeset
55 max_size = tuple(host.memory.config_get(None, "image_max", (1200, 720)))
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 if image.size > max_size:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
57 report["too_large"] = True
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 if image.size[0] > max_size[0]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 factor = max_size[0] / image.size[0]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 if image.size[1] * factor > max_size[1]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 factor = max_size[1] / image.size[1]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 else:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 factor = max_size[1] / image.size[1]
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
64 report["recommended_size"] = [
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
65 int(image.width * factor),
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
66 int(image.height * factor),
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
67 ]
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 else:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
69 report["too_large"] = False
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
70
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 return report
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
72
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
73
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
74 def _resize_blocking(image_path, new_size, dest, fix_orientation):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 im_path = Path(image_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 im = Image.open(im_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 resized = im.resize(new_size, Image.LANCZOS)
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
78 if fix_orientation:
3477
9498f32ba6f7 tools (image): fix bad method name used when `fix_orientation` is set in `resize`
Goffi <goffi@goffi.org>
parents: 3332
diff changeset
79 resized = ImageOps.exif_transpose(resized)
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
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 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
82 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
83 elif isinstance(dest, Path):
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
84 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
85
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
86 with dest as f:
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 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
88
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 return Path(f.name)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
90
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
91
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
92 def resize(image_path, new_size, dest=None, fix_orientation=True):
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
93 """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
94
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 @param image_path(str, Path): path of the original image
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 @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
97 @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
98 - None: use a temporary file
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
99 file will be converted to PNG
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
100 - 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
101 - file: a file object which must be opened for writing in binary mode
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
102 @param fix_orientation: if True, use EXIF data to set orientation
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
103 @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
104 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
105 """
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
106 return threads.deferToThread(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
107 _resize_blocking, image_path, new_size, dest, fix_orientation
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
108 )
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
109
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
110
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
111 def _convert_blocking(image_path, dest, extra):
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
112 media_type = mimetypes.guess_type(str(image_path), strict=False)[0]
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
113
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
114 if dest is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
115 dest = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
116 filepath = Path(dest.name)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
117 elif isinstance(dest, Path):
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
118 filepath = dest
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
119 else:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
120 # we should have a file-like object
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
121 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
122 name = dest.name
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
123 except AttributeError:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
124 name = None
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
125 if name:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
126 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
127 filepath = Path(name)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
128 except TypeError:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
129 filepath = Path("noname.png")
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
130 else:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
131 filepath = Path("noname.png")
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
132
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
133 if media_type == "image/svg+xml":
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
134 if cairosvg is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
135 raise exceptions.MissingModule(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
136 f"Can't convert SVG image at {image_path} due to missing CairoSVG module"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
137 )
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
138 width, height = extra.get("width"), extra.get("height")
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
139 cairosvg.svg2png(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
140 url=str(image_path), write_to=dest, output_width=width, output_height=height
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
141 )
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
142 else:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
143 suffix = filepath.suffix
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
144 if not suffix:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
145 raise ValueError(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
146 "A suffix is missing for destination, it is needed to determine file "
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
147 "format"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
148 )
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
149 if not suffix in Image.EXTENSION:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
150 Image.init()
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
151 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
152 im_format = Image.EXTENSION[suffix]
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
153 except KeyError:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
154 raise ValueError(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
155 "Dest image format can't be determined, {suffix!r} suffix is unknown"
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
156 )
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
157 im = Image.open(image_path)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
158 im.save(dest, format=im_format)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
159
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
160 log.debug(f"image {image_path} has been converted to {filepath}")
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
161 return filepath
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
162
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
163
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
164 def convert(image_path, dest=None, extra=None):
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
165 """Convert an image to a new file, and return its path
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
166
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
167 @param image_path(str, Path): path of the image to convert
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
168 @param dest(None, Path, file): where the converted image must be stored, can be:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
169 - None: use a temporary file
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
170 - Path: path to the file to create/overwrite
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
171 - file: a file object which must be opened for writing in binary mode
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
172 @param extra(None, dict): conversion options
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
173 if image_path link to a SVG file, following options can be used:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
174 - width: destination width
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
175 - height: destination height
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
176 @return (Path): path of the converted file.
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
177 a generic name is used if dest is an unnamed file like object
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
178 """
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
179 image_path = Path(image_path)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
180 if not image_path.is_file():
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
181 raise ValueError(f"There is no file at {image_path}!")
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
182 if extra is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
183 extra = {}
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
184 return threads.deferToThread(_convert_blocking, image_path, dest, extra)
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
185
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
186
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
187 def __fix_orientation_blocking(image_path):
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
188 im = Image.open(image_path)
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
189 im_format = im.format
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
190 exif = im.getexif()
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
191 orientation = exif.get(0x0112)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
192 if orientation is None or orientation < 2:
3332
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
193 # nothing to do
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
194 return False
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
195 im = ImageOps.exif_transpose(im)
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
196 im.save(image_path, im_format)
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
197 log.debug(f"image {image_path} orientation has been fixed")
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
198 return True
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
199
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
200
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
201 def fix_orientation(image_path: Path) -> bool:
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
202 """Apply orientation found in EXIF data if any
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
203
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
204 @param image_path: image location, image will be modified in place
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
205 @return True if image has been modified
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
206 """
1512cbd6c4ac tools (image): fix_orientation on resize + `fix_orientation` method:
Goffi <goffi@goffi.org>
parents: 3259
diff changeset
207 return threads.deferToThread(__fix_orientation_blocking, image_path)
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
208
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
209
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
210 def guess_type(source):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
211 """Guess image media type
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
212
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
213 @param source(str, Path, file): image to guess type
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
214 @return (str, None): media type, or None if we can't guess
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
215 """
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
216 if isinstance(source, str):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
217 source = Path(source)
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
218
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
219 if isinstance(source, Path):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
220 # we first try to guess from file name
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
221 media_type = mimetypes.guess_type(source, strict=False)[0]
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
222 if media_type is not None:
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
223 return media_type
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
224
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
225 # file name is not enough, we try to open it
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
226 img = Image.open(source)
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
227 try:
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
228 return Image.MIME[img.format]
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
229 except KeyError:
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
230 return None