fotolab 0.9.1__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fotolab-0.9.1 → fotolab-0.12.0}/.pre-commit-config.yaml +3 -3
- {fotolab-0.9.1 → fotolab-0.12.0}/CHANGELOG.md +44 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/PKG-INFO +63 -7
- {fotolab-0.9.1 → fotolab-0.12.0}/Pipfile.lock +161 -159
- {fotolab-0.9.1 → fotolab-0.12.0}/README.md +62 -6
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/__init__.py +10 -7
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/auto.py +1 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/border.py +1 -1
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/cli.py +5 -1
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/contrast.py +1 -1
- fotolab-0.12.0/fotolab/info.py +58 -0
- fotolab-0.12.0/fotolab/montage.py +70 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/resize.py +1 -1
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/sharpen.py +1 -1
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/watermark.py +20 -6
- {fotolab-0.9.1 → fotolab-0.12.0}/.coveragerc +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/.gitignore +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/.python-version +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/CONTRIBUTING.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/LICENSE.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/Pipfile +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/Makefile +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/make.bat +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/CHANGELOG.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/CONTRIBUTING.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/LICENSE.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/README.md +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/_static/logo.jpg +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/conf.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/docs/source/index.rst +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/__main__.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/fotolab/env.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/pyproject.toml +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tests/__init__.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tests/conftest.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tests/test_env.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tests/test_help_flag.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tests/test_quiet_flag.py +0 -0
- {fotolab-0.9.1 → fotolab-0.12.0}/tox.ini +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
# See https://pre-commit.com/hooks.html for more hooks
|
3
3
|
repos:
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
5
|
-
rev: v4.
|
5
|
+
rev: v4.6.0
|
6
6
|
hooks:
|
7
7
|
- id: check-case-conflict
|
8
8
|
- id: check-merge-conflict
|
@@ -45,7 +45,7 @@ repos:
|
|
45
45
|
- --py=312
|
46
46
|
|
47
47
|
- repo: https://github.com/psf/black
|
48
|
-
rev: 24.
|
48
|
+
rev: 24.4.0
|
49
49
|
hooks:
|
50
50
|
- id: black
|
51
51
|
language_version: python3.12
|
@@ -104,7 +104,7 @@ repos:
|
|
104
104
|
- fotolab
|
105
105
|
- tests
|
106
106
|
- --unsafe-load-any-extension=y
|
107
|
-
- --disable=R0801
|
107
|
+
- --disable=R0801,W0212
|
108
108
|
|
109
109
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
110
110
|
rev: v1.9.0
|
@@ -7,6 +7,50 @@ and this project adheres to [0-based versioning](https://0ver.org/).
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## v0.12.0 (2024-04-14)
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add `-pd` or `--padding` option to set the padding of watermark text block
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- Bump deps, `pre-commit` hooks, and Python versions for `pyenv`
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
|
22
|
+
- Fix `auto` subcommand missing `padding` field
|
23
|
+
- Fix missing closing parenthesis in help message
|
24
|
+
- Update missing subcommand help message in README
|
25
|
+
|
26
|
+
## v0.11.0 (2024-04-07)
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
- Add `montage` subcommand to join multiple images
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
|
34
|
+
- Bump deps
|
35
|
+
- Update missing subcommand help message in README
|
36
|
+
|
37
|
+
## v0.10.0 (2024-03-31)
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- Add `info` subcommand to show EXIF data from image
|
42
|
+
|
43
|
+
### Changed
|
44
|
+
|
45
|
+
- Bump deps
|
46
|
+
- Update help message in README
|
47
|
+
- Ignore `pylint` W0212 rule
|
48
|
+
|
49
|
+
### Fix
|
50
|
+
|
51
|
+
- Fix incorrect action in log when running `auto` subcommand
|
52
|
+
- Update incorrect comment for `save_image` helper function
|
53
|
+
|
10
54
|
## v0.9.1 (2024-03-24)
|
11
55
|
|
12
56
|
### Changed
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fotolab
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.12.0
|
4
4
|
Summary: A console program that manipulate images.
|
5
5
|
Keywords: photography,photo
|
6
6
|
Author-email: Kian-Meng Ang <kianmeng@cpan.org>
|
@@ -57,9 +57,8 @@ fotolab -h
|
|
57
57
|
```
|
58
58
|
|
59
59
|
```console
|
60
|
-
|
61
60
|
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
62
|
-
{auto,border,contrast,resize,sharpen,watermark,env} ...
|
61
|
+
{auto,border,contrast,info,resize,sharpen,watermark,env} ...
|
63
62
|
|
64
63
|
A console program to manipulate photos.
|
65
64
|
|
@@ -68,11 +67,12 @@ A console program to manipulate photos.
|
|
68
67
|
issues: https://github.com/kianmeng/fotolab/issues
|
69
68
|
|
70
69
|
positional arguments:
|
71
|
-
{auto,border,contrast,resize,sharpen,watermark,env}
|
70
|
+
{auto,border,contrast,info,resize,sharpen,watermark,env}
|
72
71
|
sub-command help
|
73
72
|
auto auto adjust (resize, contrast, and watermark) a photo
|
74
73
|
border add border to image
|
75
74
|
contrast contrast an image
|
75
|
+
info info an image
|
76
76
|
resize resize an image
|
77
77
|
sharpen sharpen an image
|
78
78
|
watermark watermark an image
|
@@ -89,6 +89,22 @@ optional arguments:
|
|
89
89
|
-V, --version show program's version number and exit
|
90
90
|
```
|
91
91
|
|
92
|
+
### fotolab auto
|
93
|
+
|
94
|
+
```console
|
95
|
+
fotolab auto -h
|
96
|
+
```
|
97
|
+
|
98
|
+
```console
|
99
|
+
usage: fotolab auto [-h] IMAGE_FILENAME
|
100
|
+
|
101
|
+
positional arguments:
|
102
|
+
IMAGE_FILENAME set the image filename
|
103
|
+
|
104
|
+
optional arguments:
|
105
|
+
-h, --help show this help message and exit
|
106
|
+
```
|
107
|
+
|
92
108
|
### fotolab border
|
93
109
|
|
94
110
|
```console
|
@@ -135,6 +151,43 @@ optional arguments:
|
|
135
151
|
-h, --help show this help message and exit
|
136
152
|
```
|
137
153
|
|
154
|
+
### fotolab info
|
155
|
+
|
156
|
+
```console
|
157
|
+
fotolab info -h
|
158
|
+
```
|
159
|
+
|
160
|
+
```console
|
161
|
+
usage: fotolab info [-h] IMAGE_FILENAME
|
162
|
+
|
163
|
+
positional arguments:
|
164
|
+
IMAGE_FILENAME set the image filename
|
165
|
+
|
166
|
+
optional arguments:
|
167
|
+
-h, --help show this help message and exit
|
168
|
+
```
|
169
|
+
|
170
|
+
### fotolab resize
|
171
|
+
|
172
|
+
```console
|
173
|
+
fotolab resize -h
|
174
|
+
```
|
175
|
+
|
176
|
+
```console
|
177
|
+
|
178
|
+
usage: fotolab resize [-h] [-wh WIDTH] [-ht HEIGHT] IMAGE_FILENAME
|
179
|
+
|
180
|
+
positional arguments:
|
181
|
+
IMAGE_FILENAME set the image filename
|
182
|
+
|
183
|
+
optional arguments:
|
184
|
+
-h, --help show this help message and exit
|
185
|
+
-wh WIDTH, --width WIDTH
|
186
|
+
set the width of the image (default: '600')
|
187
|
+
-ht HEIGHT, --height HEIGHT
|
188
|
+
set the height of the image (default: '277')
|
189
|
+
```
|
190
|
+
|
138
191
|
### fotolab sharpen
|
139
192
|
|
140
193
|
```console
|
@@ -160,20 +213,23 @@ fotolab watermark -h
|
|
160
213
|
```console
|
161
214
|
usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
|
162
215
|
[-p {top-left,top-right,bottom-left,bottom-right}]
|
163
|
-
[-
|
164
|
-
[-oc OUTLINE_COLOR]
|
216
|
+
[-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
|
217
|
+
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
|
165
218
|
IMAGE_FILENAME
|
166
219
|
|
167
220
|
positional arguments:
|
168
221
|
IMAGE_FILENAME set the image filename
|
169
222
|
|
170
|
-
|
223
|
+
optional arguments:
|
171
224
|
-h, --help show this help message and exit
|
172
225
|
-t WATERMARK_TEXT, --text WATERMARK_TEXT
|
173
226
|
set the watermark text (default: 'kianmeng.org')
|
174
227
|
-p {top-left,top-right,bottom-left,bottom-right}, --position {top-left,top-right,bottom-left,bottom-right}
|
175
228
|
set position of the watermark text (default: 'bottom-
|
176
229
|
left')
|
230
|
+
-pd PADDING, --padding PADDING
|
231
|
+
set the padding of the watermark text relative to the
|
232
|
+
image (default: '15')
|
177
233
|
-fs FONT_SIZE, --font-size FONT_SIZE
|
178
234
|
set the font size of watermark text (default: '12')
|
179
235
|
-fc FONT_COLOR, --font-color FONT_COLOR
|
@@ -18,78 +18,79 @@
|
|
18
18
|
"default": {
|
19
19
|
"pillow": {
|
20
20
|
"hashes": [
|
21
|
-
"sha256:
|
22
|
-
"sha256:
|
23
|
-
"sha256:
|
24
|
-
"sha256:
|
25
|
-
"sha256:
|
26
|
-
"sha256:
|
27
|
-
"sha256:
|
28
|
-
"sha256:
|
29
|
-
"sha256:
|
30
|
-
"sha256:
|
31
|
-
"sha256:
|
32
|
-
"sha256:
|
33
|
-
"sha256:
|
34
|
-
"sha256:
|
35
|
-
"sha256:
|
36
|
-
"sha256:
|
37
|
-
"sha256:
|
38
|
-
"sha256:
|
39
|
-
"sha256:
|
40
|
-
"sha256:
|
41
|
-
"sha256:
|
42
|
-
"sha256:
|
43
|
-
"sha256:
|
44
|
-
"sha256:
|
45
|
-
"sha256:
|
46
|
-
"sha256:
|
47
|
-
"sha256:
|
48
|
-
"sha256:
|
49
|
-
"sha256:
|
50
|
-
"sha256:
|
51
|
-
"sha256:
|
52
|
-
"sha256:
|
53
|
-
"sha256:
|
54
|
-
"sha256:
|
55
|
-
"sha256:
|
56
|
-
"sha256:
|
57
|
-
"sha256:
|
58
|
-
"sha256:
|
59
|
-
"sha256:
|
60
|
-
"sha256:
|
61
|
-
"sha256:
|
62
|
-
"sha256:
|
63
|
-
"sha256:
|
64
|
-
"sha256:
|
65
|
-
"sha256:
|
66
|
-
"sha256:
|
67
|
-
"sha256:
|
68
|
-
"sha256:
|
69
|
-
"sha256:
|
70
|
-
"sha256:
|
71
|
-
"sha256:
|
72
|
-
"sha256:
|
73
|
-
"sha256:
|
74
|
-
"sha256:
|
75
|
-
"sha256:
|
76
|
-
"sha256:
|
77
|
-
"sha256:
|
78
|
-
"sha256:
|
79
|
-
"sha256:
|
80
|
-
"sha256:
|
81
|
-
"sha256:
|
82
|
-
"sha256:
|
83
|
-
"sha256:
|
84
|
-
"sha256:
|
85
|
-
"sha256:
|
86
|
-
"sha256:
|
87
|
-
"sha256:
|
88
|
-
"sha256:
|
21
|
+
"sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c",
|
22
|
+
"sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2",
|
23
|
+
"sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb",
|
24
|
+
"sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d",
|
25
|
+
"sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa",
|
26
|
+
"sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3",
|
27
|
+
"sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1",
|
28
|
+
"sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a",
|
29
|
+
"sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd",
|
30
|
+
"sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8",
|
31
|
+
"sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999",
|
32
|
+
"sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599",
|
33
|
+
"sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936",
|
34
|
+
"sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375",
|
35
|
+
"sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d",
|
36
|
+
"sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b",
|
37
|
+
"sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60",
|
38
|
+
"sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572",
|
39
|
+
"sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3",
|
40
|
+
"sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced",
|
41
|
+
"sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f",
|
42
|
+
"sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b",
|
43
|
+
"sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19",
|
44
|
+
"sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f",
|
45
|
+
"sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d",
|
46
|
+
"sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383",
|
47
|
+
"sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795",
|
48
|
+
"sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355",
|
49
|
+
"sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57",
|
50
|
+
"sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09",
|
51
|
+
"sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b",
|
52
|
+
"sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462",
|
53
|
+
"sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf",
|
54
|
+
"sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f",
|
55
|
+
"sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a",
|
56
|
+
"sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad",
|
57
|
+
"sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9",
|
58
|
+
"sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d",
|
59
|
+
"sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45",
|
60
|
+
"sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994",
|
61
|
+
"sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d",
|
62
|
+
"sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338",
|
63
|
+
"sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463",
|
64
|
+
"sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451",
|
65
|
+
"sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591",
|
66
|
+
"sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c",
|
67
|
+
"sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd",
|
68
|
+
"sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32",
|
69
|
+
"sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9",
|
70
|
+
"sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf",
|
71
|
+
"sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5",
|
72
|
+
"sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828",
|
73
|
+
"sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3",
|
74
|
+
"sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5",
|
75
|
+
"sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2",
|
76
|
+
"sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b",
|
77
|
+
"sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2",
|
78
|
+
"sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475",
|
79
|
+
"sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3",
|
80
|
+
"sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb",
|
81
|
+
"sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef",
|
82
|
+
"sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015",
|
83
|
+
"sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002",
|
84
|
+
"sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170",
|
85
|
+
"sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84",
|
86
|
+
"sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57",
|
87
|
+
"sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f",
|
88
|
+
"sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27",
|
89
|
+
"sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"
|
89
90
|
],
|
90
91
|
"index": "pypi",
|
91
92
|
"markers": "python_version >= '3.8'",
|
92
|
-
"version": "==10.
|
93
|
+
"version": "==10.3.0"
|
93
94
|
}
|
94
95
|
},
|
95
96
|
"develop": {
|
@@ -188,19 +189,19 @@
|
|
188
189
|
},
|
189
190
|
"execnet": {
|
190
191
|
"hashes": [
|
191
|
-
"sha256:
|
192
|
-
"sha256:
|
192
|
+
"sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc",
|
193
|
+
"sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"
|
193
194
|
],
|
194
|
-
"markers": "python_version >= '3.
|
195
|
-
"version": "==2.
|
195
|
+
"markers": "python_version >= '3.8'",
|
196
|
+
"version": "==2.1.1"
|
196
197
|
},
|
197
198
|
"filelock": {
|
198
199
|
"hashes": [
|
199
|
-
"sha256:
|
200
|
-
"sha256:
|
200
|
+
"sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f",
|
201
|
+
"sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"
|
201
202
|
],
|
202
203
|
"markers": "python_version >= '3.8'",
|
203
|
-
"version": "==3.13.
|
204
|
+
"version": "==3.13.4"
|
204
205
|
},
|
205
206
|
"flake8": {
|
206
207
|
"hashes": [
|
@@ -238,12 +239,12 @@
|
|
238
239
|
},
|
239
240
|
"flake8-pytest-style": {
|
240
241
|
"hashes": [
|
241
|
-
"sha256:
|
242
|
-
"sha256:
|
242
|
+
"sha256:919c328cacd4bc4f873ea61ab4db0d8f2c32e0db09a3c73ab46b1de497556464",
|
243
|
+
"sha256:abcb9f56f277954014b749e5a0937fae215be01a21852e9d05e7600c3de6aae5"
|
243
244
|
],
|
244
245
|
"index": "pypi",
|
245
|
-
"markers": "python_full_version >= '3.
|
246
|
-
"version": "==
|
246
|
+
"markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'",
|
247
|
+
"version": "==2.0.0"
|
247
248
|
},
|
248
249
|
"flake8-simplify": {
|
249
250
|
"hashes": [
|
@@ -309,78 +310,79 @@
|
|
309
310
|
},
|
310
311
|
"pillow": {
|
311
312
|
"hashes": [
|
312
|
-
"sha256:
|
313
|
-
"sha256:
|
314
|
-
"sha256:
|
315
|
-
"sha256:
|
316
|
-
"sha256:
|
317
|
-
"sha256:
|
318
|
-
"sha256:
|
319
|
-
"sha256:
|
320
|
-
"sha256:
|
321
|
-
"sha256:
|
322
|
-
"sha256:
|
323
|
-
"sha256:
|
324
|
-
"sha256:
|
325
|
-
"sha256:
|
326
|
-
"sha256:
|
327
|
-
"sha256:
|
328
|
-
"sha256:
|
329
|
-
"sha256:
|
330
|
-
"sha256:
|
331
|
-
"sha256:
|
332
|
-
"sha256:
|
333
|
-
"sha256:
|
334
|
-
"sha256:
|
335
|
-
"sha256:
|
336
|
-
"sha256:
|
337
|
-
"sha256:
|
338
|
-
"sha256:
|
339
|
-
"sha256:
|
340
|
-
"sha256:
|
341
|
-
"sha256:
|
342
|
-
"sha256:
|
343
|
-
"sha256:
|
344
|
-
"sha256:
|
345
|
-
"sha256:
|
346
|
-
"sha256:
|
347
|
-
"sha256:
|
348
|
-
"sha256:
|
349
|
-
"sha256:
|
350
|
-
"sha256:
|
351
|
-
"sha256:
|
352
|
-
"sha256:
|
353
|
-
"sha256:
|
354
|
-
"sha256:
|
355
|
-
"sha256:
|
356
|
-
"sha256:
|
357
|
-
"sha256:
|
358
|
-
"sha256:
|
359
|
-
"sha256:
|
360
|
-
"sha256:
|
361
|
-
"sha256:
|
362
|
-
"sha256:
|
363
|
-
"sha256:
|
364
|
-
"sha256:
|
365
|
-
"sha256:
|
366
|
-
"sha256:
|
367
|
-
"sha256:
|
368
|
-
"sha256:
|
369
|
-
"sha256:
|
370
|
-
"sha256:
|
371
|
-
"sha256:
|
372
|
-
"sha256:
|
373
|
-
"sha256:
|
374
|
-
"sha256:
|
375
|
-
"sha256:
|
376
|
-
"sha256:
|
377
|
-
"sha256:
|
378
|
-
"sha256:
|
379
|
-
"sha256:
|
313
|
+
"sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c",
|
314
|
+
"sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2",
|
315
|
+
"sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb",
|
316
|
+
"sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d",
|
317
|
+
"sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa",
|
318
|
+
"sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3",
|
319
|
+
"sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1",
|
320
|
+
"sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a",
|
321
|
+
"sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd",
|
322
|
+
"sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8",
|
323
|
+
"sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999",
|
324
|
+
"sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599",
|
325
|
+
"sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936",
|
326
|
+
"sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375",
|
327
|
+
"sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d",
|
328
|
+
"sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b",
|
329
|
+
"sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60",
|
330
|
+
"sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572",
|
331
|
+
"sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3",
|
332
|
+
"sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced",
|
333
|
+
"sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f",
|
334
|
+
"sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b",
|
335
|
+
"sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19",
|
336
|
+
"sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f",
|
337
|
+
"sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d",
|
338
|
+
"sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383",
|
339
|
+
"sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795",
|
340
|
+
"sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355",
|
341
|
+
"sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57",
|
342
|
+
"sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09",
|
343
|
+
"sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b",
|
344
|
+
"sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462",
|
345
|
+
"sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf",
|
346
|
+
"sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f",
|
347
|
+
"sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a",
|
348
|
+
"sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad",
|
349
|
+
"sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9",
|
350
|
+
"sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d",
|
351
|
+
"sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45",
|
352
|
+
"sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994",
|
353
|
+
"sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d",
|
354
|
+
"sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338",
|
355
|
+
"sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463",
|
356
|
+
"sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451",
|
357
|
+
"sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591",
|
358
|
+
"sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c",
|
359
|
+
"sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd",
|
360
|
+
"sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32",
|
361
|
+
"sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9",
|
362
|
+
"sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf",
|
363
|
+
"sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5",
|
364
|
+
"sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828",
|
365
|
+
"sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3",
|
366
|
+
"sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5",
|
367
|
+
"sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2",
|
368
|
+
"sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b",
|
369
|
+
"sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2",
|
370
|
+
"sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475",
|
371
|
+
"sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3",
|
372
|
+
"sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb",
|
373
|
+
"sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef",
|
374
|
+
"sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015",
|
375
|
+
"sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002",
|
376
|
+
"sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170",
|
377
|
+
"sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84",
|
378
|
+
"sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57",
|
379
|
+
"sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f",
|
380
|
+
"sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27",
|
381
|
+
"sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"
|
380
382
|
],
|
381
383
|
"index": "pypi",
|
382
384
|
"markers": "python_version >= '3.8'",
|
383
|
-
"version": "==10.
|
385
|
+
"version": "==10.3.0"
|
384
386
|
},
|
385
387
|
"platformdirs": {
|
386
388
|
"hashes": [
|
@@ -450,12 +452,12 @@
|
|
450
452
|
},
|
451
453
|
"pytest-cov": {
|
452
454
|
"hashes": [
|
453
|
-
"sha256:
|
454
|
-
"sha256:
|
455
|
+
"sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652",
|
456
|
+
"sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"
|
455
457
|
],
|
456
458
|
"index": "pypi",
|
457
|
-
"markers": "python_version >= '3.
|
458
|
-
"version": "==
|
459
|
+
"markers": "python_version >= '3.8'",
|
460
|
+
"version": "==5.0.0"
|
459
461
|
},
|
460
462
|
"pytest-randomly": {
|
461
463
|
"hashes": [
|
@@ -736,11 +738,11 @@
|
|
736
738
|
},
|
737
739
|
"idna": {
|
738
740
|
"hashes": [
|
739
|
-
"sha256:
|
740
|
-
"sha256:
|
741
|
+
"sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
|
742
|
+
"sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
|
741
743
|
],
|
742
744
|
"markers": "python_version >= '3.5'",
|
743
|
-
"version": "==3.
|
745
|
+
"version": "==3.7"
|
744
746
|
},
|
745
747
|
"imagesize": {
|
746
748
|
"hashes": [
|
@@ -972,12 +974,12 @@
|
|
972
974
|
},
|
973
975
|
"sphinx-autodoc-typehints": {
|
974
976
|
"hashes": [
|
975
|
-
"sha256:
|
976
|
-
"sha256:
|
977
|
+
"sha256:60ed1e3b2c970acc0aa6e877be42d48029a9faec7378a17838716cacd8c10b12",
|
978
|
+
"sha256:f73ae89b43a799e587e39266672c1075b2ef783aeb382d3ebed77c38a3fc0149"
|
977
979
|
],
|
978
980
|
"index": "pypi",
|
979
981
|
"markers": "python_version >= '3.8'",
|
980
|
-
"version": "==2.0.
|
982
|
+
"version": "==2.0.1"
|
981
983
|
},
|
982
984
|
"sphinx-copybutton": {
|
983
985
|
"hashes": [
|
@@ -35,9 +35,8 @@ fotolab -h
|
|
35
35
|
```
|
36
36
|
|
37
37
|
```console
|
38
|
-
|
39
38
|
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
40
|
-
{auto,border,contrast,resize,sharpen,watermark,env} ...
|
39
|
+
{auto,border,contrast,info,resize,sharpen,watermark,env} ...
|
41
40
|
|
42
41
|
A console program to manipulate photos.
|
43
42
|
|
@@ -46,11 +45,12 @@ A console program to manipulate photos.
|
|
46
45
|
issues: https://github.com/kianmeng/fotolab/issues
|
47
46
|
|
48
47
|
positional arguments:
|
49
|
-
{auto,border,contrast,resize,sharpen,watermark,env}
|
48
|
+
{auto,border,contrast,info,resize,sharpen,watermark,env}
|
50
49
|
sub-command help
|
51
50
|
auto auto adjust (resize, contrast, and watermark) a photo
|
52
51
|
border add border to image
|
53
52
|
contrast contrast an image
|
53
|
+
info info an image
|
54
54
|
resize resize an image
|
55
55
|
sharpen sharpen an image
|
56
56
|
watermark watermark an image
|
@@ -67,6 +67,22 @@ optional arguments:
|
|
67
67
|
-V, --version show program's version number and exit
|
68
68
|
```
|
69
69
|
|
70
|
+
### fotolab auto
|
71
|
+
|
72
|
+
```console
|
73
|
+
fotolab auto -h
|
74
|
+
```
|
75
|
+
|
76
|
+
```console
|
77
|
+
usage: fotolab auto [-h] IMAGE_FILENAME
|
78
|
+
|
79
|
+
positional arguments:
|
80
|
+
IMAGE_FILENAME set the image filename
|
81
|
+
|
82
|
+
optional arguments:
|
83
|
+
-h, --help show this help message and exit
|
84
|
+
```
|
85
|
+
|
70
86
|
### fotolab border
|
71
87
|
|
72
88
|
```console
|
@@ -113,6 +129,43 @@ optional arguments:
|
|
113
129
|
-h, --help show this help message and exit
|
114
130
|
```
|
115
131
|
|
132
|
+
### fotolab info
|
133
|
+
|
134
|
+
```console
|
135
|
+
fotolab info -h
|
136
|
+
```
|
137
|
+
|
138
|
+
```console
|
139
|
+
usage: fotolab info [-h] IMAGE_FILENAME
|
140
|
+
|
141
|
+
positional arguments:
|
142
|
+
IMAGE_FILENAME set the image filename
|
143
|
+
|
144
|
+
optional arguments:
|
145
|
+
-h, --help show this help message and exit
|
146
|
+
```
|
147
|
+
|
148
|
+
### fotolab resize
|
149
|
+
|
150
|
+
```console
|
151
|
+
fotolab resize -h
|
152
|
+
```
|
153
|
+
|
154
|
+
```console
|
155
|
+
|
156
|
+
usage: fotolab resize [-h] [-wh WIDTH] [-ht HEIGHT] IMAGE_FILENAME
|
157
|
+
|
158
|
+
positional arguments:
|
159
|
+
IMAGE_FILENAME set the image filename
|
160
|
+
|
161
|
+
optional arguments:
|
162
|
+
-h, --help show this help message and exit
|
163
|
+
-wh WIDTH, --width WIDTH
|
164
|
+
set the width of the image (default: '600')
|
165
|
+
-ht HEIGHT, --height HEIGHT
|
166
|
+
set the height of the image (default: '277')
|
167
|
+
```
|
168
|
+
|
116
169
|
### fotolab sharpen
|
117
170
|
|
118
171
|
```console
|
@@ -138,20 +191,23 @@ fotolab watermark -h
|
|
138
191
|
```console
|
139
192
|
usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
|
140
193
|
[-p {top-left,top-right,bottom-left,bottom-right}]
|
141
|
-
[-
|
142
|
-
[-oc OUTLINE_COLOR]
|
194
|
+
[-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
|
195
|
+
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
|
143
196
|
IMAGE_FILENAME
|
144
197
|
|
145
198
|
positional arguments:
|
146
199
|
IMAGE_FILENAME set the image filename
|
147
200
|
|
148
|
-
|
201
|
+
optional arguments:
|
149
202
|
-h, --help show this help message and exit
|
150
203
|
-t WATERMARK_TEXT, --text WATERMARK_TEXT
|
151
204
|
set the watermark text (default: 'kianmeng.org')
|
152
205
|
-p {top-left,top-right,bottom-left,bottom-right}, --position {top-left,top-right,bottom-left,bottom-right}
|
153
206
|
set position of the watermark text (default: 'bottom-
|
154
207
|
left')
|
208
|
+
-pd PADDING, --padding PADDING
|
209
|
+
set the padding of the watermark text relative to the
|
210
|
+
image (default: '15')
|
155
211
|
-fs FONT_SIZE, --font-size FONT_SIZE
|
156
212
|
set the font size of watermark text (default: '12')
|
157
213
|
-fc FONT_COLOR, --font-color FONT_COLOR
|
@@ -21,34 +21,37 @@ import subprocess
|
|
21
21
|
import sys
|
22
22
|
from pathlib import Path
|
23
23
|
|
24
|
-
__version__ = "0.
|
24
|
+
__version__ = "0.12.0"
|
25
25
|
|
26
26
|
log = logging.getLogger(__name__)
|
27
27
|
|
28
28
|
|
29
|
-
def save_image(args, new_image):
|
30
|
-
"""
|
29
|
+
def save_image(args, new_image, subcommand):
|
30
|
+
"""Save image after image operation.
|
31
31
|
|
32
32
|
Args:
|
33
33
|
args (argparse.Namespace): Config from command line arguments
|
34
34
|
new_image(PIL.Image.Image): Modified image
|
35
|
+
subcommand(str): Subcommand used to call this function
|
35
36
|
|
36
37
|
Returns:
|
37
38
|
None
|
38
39
|
"""
|
39
|
-
|
40
|
-
|
40
|
+
if "image_filenames" in args:
|
41
|
+
image_file = Path(args.image_filenames[0].name)
|
42
|
+
else:
|
43
|
+
image_file = Path(args.image_filename)
|
41
44
|
|
42
45
|
if args.overwrite:
|
43
46
|
new_filename = image_file.with_name(image_file.name)
|
44
47
|
else:
|
45
48
|
new_filename = Path(
|
46
49
|
args.output_dir,
|
47
|
-
image_file.with_name(f"{
|
50
|
+
image_file.with_name(f"{subcommand}_{image_file.name}"),
|
48
51
|
)
|
49
52
|
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
50
53
|
|
51
|
-
log.info("%s image: %s",
|
54
|
+
log.info("%s image: %s", subcommand, new_filename)
|
52
55
|
new_image.save(new_filename)
|
53
56
|
|
54
57
|
if args.open:
|
@@ -29,6 +29,8 @@ import fotolab.auto
|
|
29
29
|
import fotolab.border
|
30
30
|
import fotolab.contrast
|
31
31
|
import fotolab.env
|
32
|
+
import fotolab.info
|
33
|
+
import fotolab.montage
|
32
34
|
import fotolab.resize
|
33
35
|
import fotolab.sharpen
|
34
36
|
import fotolab.watermark
|
@@ -82,7 +84,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
82
84
|
default=False,
|
83
85
|
action="store_true",
|
84
86
|
dest="open",
|
85
|
-
help="open the image using default program (default: '%(default)s'",
|
87
|
+
help="open the image using default program (default: '%(default)s')",
|
86
88
|
)
|
87
89
|
|
88
90
|
parser.add_argument(
|
@@ -122,7 +124,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
122
124
|
fotolab.auto.build_subparser(subparsers)
|
123
125
|
fotolab.border.build_subparser(subparsers)
|
124
126
|
fotolab.contrast.build_subparser(subparsers)
|
127
|
+
fotolab.info.build_subparser(subparsers)
|
125
128
|
fotolab.resize.build_subparser(subparsers)
|
129
|
+
fotolab.montage.build_subparser(subparsers)
|
126
130
|
fotolab.sharpen.build_subparser(subparsers)
|
127
131
|
fotolab.watermark.build_subparser(subparsers)
|
128
132
|
fotolab.env.build_subparser(subparsers)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (C) 2024 Kian-Meng Ang
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify it under
|
4
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
5
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
6
|
+
# later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
9
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
10
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
11
|
+
# details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Affero General Public License
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
"""Info subcommand."""
|
17
|
+
|
18
|
+
import argparse
|
19
|
+
import logging
|
20
|
+
|
21
|
+
from PIL import ExifTags, Image
|
22
|
+
|
23
|
+
log = logging.getLogger(__name__)
|
24
|
+
|
25
|
+
|
26
|
+
def build_subparser(subparsers) -> None:
|
27
|
+
"""Build the subparser."""
|
28
|
+
info_parser = subparsers.add_parser("info", help="info an image")
|
29
|
+
|
30
|
+
info_parser.set_defaults(func=run)
|
31
|
+
|
32
|
+
info_parser.add_argument(
|
33
|
+
dest="image_filename",
|
34
|
+
help="set the image filename",
|
35
|
+
type=str,
|
36
|
+
default=None,
|
37
|
+
metavar="IMAGE_FILENAME",
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
def run(args: argparse.Namespace) -> None:
|
42
|
+
"""Run info subcommand.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
config (argparse.Namespace): Config from command line arguments
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
None
|
49
|
+
"""
|
50
|
+
log.debug(args)
|
51
|
+
|
52
|
+
image = Image.open(args.image_filename)
|
53
|
+
exif = image._getexif()
|
54
|
+
info = {ExifTags.TAGS.get(tag_id): exif.get(tag_id) for tag_id in exif}
|
55
|
+
|
56
|
+
tag_name_width = max(map(len, info))
|
57
|
+
for tag_name, tag_value in info.items():
|
58
|
+
print(f"{tag_name:<{tag_name_width}}: {tag_value}")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Copyright (C) 2024 Kian-Meng Ang
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify it under
|
4
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
5
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
6
|
+
# later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
9
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
10
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
11
|
+
# details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Affero General Public License
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
"""Montage subcommand."""
|
17
|
+
|
18
|
+
import argparse
|
19
|
+
import logging
|
20
|
+
|
21
|
+
from PIL import Image
|
22
|
+
|
23
|
+
from fotolab import save_image
|
24
|
+
|
25
|
+
log = logging.getLogger(__name__)
|
26
|
+
|
27
|
+
|
28
|
+
def build_subparser(subparsers) -> None:
|
29
|
+
"""Build the subparser."""
|
30
|
+
montage_parser = subparsers.add_parser(
|
31
|
+
"montage", help="montage a list of image"
|
32
|
+
)
|
33
|
+
|
34
|
+
montage_parser.set_defaults(func=run)
|
35
|
+
|
36
|
+
montage_parser.add_argument(
|
37
|
+
dest="image_filenames",
|
38
|
+
help="set the image filenames",
|
39
|
+
nargs="+",
|
40
|
+
type=argparse.FileType("r"),
|
41
|
+
default=None,
|
42
|
+
metavar="IMAGE_FILENAMES",
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
def run(args: argparse.Namespace) -> None:
|
47
|
+
"""Run montage subcommand.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
config (argparse.Namespace): Config from command line arguments
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
None
|
54
|
+
"""
|
55
|
+
log.debug(args)
|
56
|
+
images = []
|
57
|
+
for image_filename in args.image_filenames:
|
58
|
+
images.append(Image.open(image_filename.name))
|
59
|
+
|
60
|
+
total_width = sum(img.width for img in images)
|
61
|
+
total_height = max(img.height for img in images)
|
62
|
+
|
63
|
+
montaged_image = Image.new("RGB", (total_width, total_height))
|
64
|
+
|
65
|
+
x_offset = 0
|
66
|
+
for img in images:
|
67
|
+
montaged_image.paste(img, (x_offset, 0))
|
68
|
+
x_offset += img.width
|
69
|
+
|
70
|
+
save_image(args, montaged_image, "montage")
|
@@ -62,6 +62,19 @@ def build_subparser(subparsers) -> None:
|
|
62
62
|
default="bottom-left",
|
63
63
|
)
|
64
64
|
|
65
|
+
watermark_parser.add_argument(
|
66
|
+
"-pd",
|
67
|
+
"--padding",
|
68
|
+
dest="padding",
|
69
|
+
type=int,
|
70
|
+
default=15,
|
71
|
+
help=(
|
72
|
+
"set the padding of the watermark text relative to the image "
|
73
|
+
"(default: '%(default)s')"
|
74
|
+
),
|
75
|
+
metavar="PADDING",
|
76
|
+
)
|
77
|
+
|
65
78
|
watermark_parser.add_argument(
|
66
79
|
"-fs",
|
67
80
|
"--font-size",
|
@@ -133,24 +146,25 @@ def run(args: argparse.Namespace) -> None:
|
|
133
146
|
text_width = right - left
|
134
147
|
text_height = bottom - top
|
135
148
|
(position_x, position_y) = calculate_position(
|
136
|
-
watermarked_image, text_width, text_height, args.position
|
149
|
+
watermarked_image, text_width, text_height, args.position, args.padding
|
137
150
|
)
|
138
151
|
|
139
152
|
draw.text(
|
140
153
|
(position_x, position_y),
|
141
154
|
args.text,
|
142
155
|
font=font,
|
143
|
-
fill=ImageColor.getrgb(args.font_color),
|
156
|
+
fill=(*ImageColor.getrgb(args.font_color), 128),
|
144
157
|
stroke_width=args.outline_width,
|
145
|
-
stroke_fill=ImageColor.getrgb(args.outline_color),
|
158
|
+
stroke_fill=(*ImageColor.getrgb(args.outline_color), 128),
|
146
159
|
)
|
147
160
|
|
148
|
-
save_image(args, watermarked_image)
|
161
|
+
save_image(args, watermarked_image, "watermark")
|
149
162
|
|
150
163
|
|
151
|
-
def calculate_position(
|
164
|
+
def calculate_position(
|
165
|
+
image, text_width, text_height, position, padding
|
166
|
+
) -> tuple:
|
152
167
|
"""Calculate the boundary coordinates of the watermark text."""
|
153
|
-
padding = 10
|
154
168
|
if position == "top-left":
|
155
169
|
position_x = 0 + padding
|
156
170
|
position_y = 0 + padding
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|