annotate sat/tools/image.py @ 3330:7b47f48d31f3

plugin XEP-0264: fix orientation of thumbnails: Rotation of thumbnailis is now modified according to EXIF orientation data. Original image is not modified as user may want to keep it, and orientation transformation can modify encoding parameters. Update `pillow` minimum version to the first one with `exif_transpose` implementation.
author Goffi <goffi@goffi.org>
date Thu, 13 Aug 2020 23:46:18 +0200
parents f300d78f08f3
children 1512cbd6c4ac
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
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
22 import mimetypes
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from PIL import Image
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
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
26 from sat.core.i18n import _
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
27 from sat.core import exceptions
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
28 from sat.core.log import getLogger
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:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
35 log.warning(_("SVG support not available, please install cairosvg: {e}").format(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
36 e=e))
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
37 cairosvg = None
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
38
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
39
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
40 def check(host, path, max_size=None):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 """Analyze image and return a report
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
42
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 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
44 the case
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 @param host: SàT instance
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 @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
47 @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
48 None to use value set in config
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 @return dict: report on image, with following keys:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 - too_large: true if image is oversized
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 - 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
52 """
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 report = {}
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 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
55 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
56 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
57 if image.size > max_size:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 report['too_large'] = True
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 if image.size[0] > max_size[0]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 factor = max_size[0] / image.size[0]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 if image.size[1] * factor > max_size[1]:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 factor = max_size[1] / image.size[1]
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 else:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 factor = max_size[1] / image.size[1]
3157
8b4354b5c05f tools (images): fixed type for recommended_size.
Goffi <goffi@goffi.org>
parents: 3137
diff changeset
65 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
66 else:
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 report['too_large'] = False
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
68
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 return report
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
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
72 def _resizeBlocking(image_path, new_size, dest):
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 im_path = Path(image_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 im = Image.open(im_path)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 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
76
5c3bf37f2202 tools (images): max_size can now be manually specified in checkImage and dest in resizeImage:
Goffi <goffi@goffi.org>
parents: 3157
diff changeset
77 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
78 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
79 elif isinstance(dest, Path):
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
80 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
81
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 with dest as f:
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 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
84
3066
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 return Path(f.name)
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
86
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
87
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
88 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
89 """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
90
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 @param image_path(str, Path): path of the original image
2cc2f65379f7 core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 @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
93 @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
94 - None: use a temporary file
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
95 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
96 - 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
97 - 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
98 @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
99 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
100 """
3220
4fbea7f1e012 tools (images): methods renaming
Goffi <goffi@goffi.org>
parents: 3200
diff changeset
101 return threads.deferToThread(_resizeBlocking, image_path, new_size, dest)
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
102
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
103
3259
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
104 def _convertBlocking(image_path, dest, extra):
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
105 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
106
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
107 if dest is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
108 dest = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
109 filepath = Path(dest.name)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
110 elif isinstance(dest, Path):
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
111 filepath = dest
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
112 else:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
113 # we should have a file-like object
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
114 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
115 name = dest.name
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
116 except AttributeError:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
117 name = None
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
118 if name:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
119 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
120 filepath = Path(name)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
121 except TypeError:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
122 filepath = Path('noname.png')
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
123 else:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
124 filepath = Path('noname.png')
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
125
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
126 if media_type == "image/svg+xml":
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
127 if cairosvg is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
128 raise exceptions.MissingModule(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
129 f"Can't convert SVG image at {image_path} due to missing CairoSVG module")
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
130 width, height = extra.get('width'), extra.get('height')
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
131 cairosvg.svg2png(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
132 url=str(image_path), write_to=dest,
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
133 output_width=width, output_height=height
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
134 )
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
135 else:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
136 suffix = filepath.suffix
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
137 if not suffix:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
138 raise ValueError(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
139 "A suffix is missing for destination, it is needed to determine file "
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
140 "format")
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
141 if not suffix in Image.EXTENSION:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
142 Image.init()
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
143 try:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
144 im_format = Image.EXTENSION[suffix]
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
145 except KeyError:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
146 raise ValueError(
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
147 "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
148 )
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
149 im = Image.open(image_path)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
150 im.save(dest, format=im_format)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
151
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
152 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
153 return filepath
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
154
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
155
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
156 def convert(image_path, dest=None, extra=None):
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
157 """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
158
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
159 @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
160 @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
161 - None: use a temporary file
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
162 - Path: path to the file to create/overwrite
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
163 - 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
164 @param extra(None, dict): conversion options
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
165 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
166 - width: destination width
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
167 - height: destination height
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
168 @return (Path): path of the converted file.
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
169 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
170 """
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
171 image_path = Path(image_path)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
172 if not image_path.is_file():
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
173 raise ValueError(f"There is no file at {image_path}!")
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
174 if extra is None:
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
175 extra = {}
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
176 return threads.deferToThread(_convertBlocking, image_path, dest, extra)
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
177
f300d78f08f3 core: image convertion + SVG support:
Goffi <goffi@goffi.org>
parents: 3252
diff changeset
178
3252
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
179 def guess_type(source):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
180 """Guess image media type
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
181
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
182 @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
183 @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
184 """
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
185 if isinstance(source, str):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
186 source = Path(source)
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
187
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
188 if isinstance(source, Path):
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
189 # 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
190 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
191 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
192 return media_type
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
193
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
194 # file name is not enough, we try to open it
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
195 img = Image.open(source)
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
196 try:
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
197 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
198 except KeyError:
54934ee3f69c tools (image): added a guess_type method to guess media type:
Goffi <goffi@goffi.org>
parents: 3220
diff changeset
199 return None