Mercurial > libervia-backend
annotate libervia/backend/tools/image.py @ 4318:27bb22eace65
tests (unit/email gateway): add test for XEP-0131 handling:
rel 451
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 28 Sep 2024 15:59:48 +0200 |
parents | 0d7bb4df2343 |
children |
rev | line source |
---|---|
3066
2cc2f65379f7
core: added imageCheck and imageResize methods:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
1 #!/usr/bin/env python3 |
3137 | 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 | 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 | 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 |