fotolab 0.14.0__tar.gz → 0.15.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.14.0 → fotolab-0.15.0}/CHANGELOG.md +14 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/PKG-INFO +4 -6
- {fotolab-0.14.0 → fotolab-0.15.0}/Pipfile.lock +72 -72
- {fotolab-0.14.0 → fotolab-0.15.0}/README.md +3 -5
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/__init__.py +3 -3
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/cli.py +12 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/resize.py +39 -5
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/sharpen.py +3 -3
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/watermark.py +46 -7
- {fotolab-0.14.0 → fotolab-0.15.0}/.coveragerc +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/.gitignore +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/.pre-commit-config.yaml +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/.python-version +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/CONTRIBUTING.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/LICENSE.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/Pipfile +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/Makefile +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/make.bat +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/CHANGELOG.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/CONTRIBUTING.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/LICENSE.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/README.md +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/_static/logo.jpg +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/conf.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/index.rst +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/__main__.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/animate.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/auto.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/border.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/contrast.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/env.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/info.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/montage.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/pyproject.toml +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tests/__init__.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tests/conftest.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_env.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_help_flag.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_quiet_flag.py +0 -0
- {fotolab-0.14.0 → fotolab-0.15.0}/tox.ini +0 -0
@@ -7,6 +7,20 @@ and this project adheres to [0-based versioning](https://0ver.org/).
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## v0.15.0 (2024-05-05)
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add `-v` or `--verbose` flag to toggle the debug logs of PIL
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- Bump deps and `pre-commit` hooks
|
19
|
+
- Resize image to the right aspect ratio based on image's dimension
|
20
|
+
- Resize watermark font based on the image's dimension
|
21
|
+
- Remove empty lines in help message
|
22
|
+
- Show absolute image path in logs
|
23
|
+
|
10
24
|
## v0.14.0 (2024-04-28)
|
11
25
|
|
12
26
|
### Added
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fotolab
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.15.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,8 +57,7 @@ fotolab -h
|
|
57
57
|
```
|
58
58
|
|
59
59
|
```console
|
60
|
-
|
61
|
-
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
60
|
+
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-v] [-d] [-V]
|
62
61
|
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
63
62
|
...
|
64
63
|
|
@@ -89,6 +88,7 @@ optional arguments:
|
|
89
88
|
-od OUTPUT_DIR, --output-dir OUTPUT_DIR
|
90
89
|
set default output folder (default: 'output')
|
91
90
|
-q, --quiet suppress all logging
|
91
|
+
-v, --verbose show verbosity of debugging log, use -vv, -vvv for more details
|
92
92
|
-d, --debug show debugging log and stacktrace
|
93
93
|
-V, --version show program's version number and exit
|
94
94
|
```
|
@@ -100,7 +100,6 @@ fotolab animate -h
|
|
100
100
|
```
|
101
101
|
|
102
102
|
```console
|
103
|
-
|
104
103
|
usage: fotolab animate [-h] [-f FORMAT] [-d DURATION] [-l LOOP]
|
105
104
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
106
105
|
|
@@ -204,7 +203,6 @@ fotolab montage -h
|
|
204
203
|
```
|
205
204
|
|
206
205
|
```console
|
207
|
-
|
208
206
|
usage: fotolab montage [-h] IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
209
207
|
|
210
208
|
positional arguments:
|
@@ -221,7 +219,7 @@ fotolab resize -h
|
|
221
219
|
```
|
222
220
|
|
223
221
|
```console
|
224
|
-
usage: fotolab resize [-h] [-wh WIDTH
|
222
|
+
usage: fotolab resize [-h] [-wh WIDTH | -ht HEIGHT]
|
225
223
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
226
224
|
|
227
225
|
positional arguments:
|
@@ -115,61 +115,61 @@
|
|
115
115
|
"toml"
|
116
116
|
],
|
117
117
|
"hashes": [
|
118
|
-
"sha256:
|
119
|
-
"sha256:
|
120
|
-
"sha256:
|
121
|
-
"sha256:
|
122
|
-
"sha256:
|
123
|
-
"sha256:
|
124
|
-
"sha256:
|
125
|
-
"sha256:
|
126
|
-
"sha256:
|
127
|
-
"sha256:
|
128
|
-
"sha256:
|
129
|
-
"sha256:
|
130
|
-
"sha256:
|
131
|
-
"sha256:
|
132
|
-
"sha256:
|
133
|
-
"sha256:
|
134
|
-
"sha256:
|
135
|
-
"sha256:
|
136
|
-
"sha256:
|
137
|
-
"sha256:
|
138
|
-
"sha256:
|
139
|
-
"sha256:
|
140
|
-
"sha256:
|
141
|
-
"sha256:
|
142
|
-
"sha256:
|
143
|
-
"sha256:
|
144
|
-
"sha256:
|
145
|
-
"sha256:
|
146
|
-
"sha256:
|
147
|
-
"sha256:
|
148
|
-
"sha256:
|
149
|
-
"sha256:
|
150
|
-
"sha256:
|
151
|
-
"sha256:
|
152
|
-
"sha256:
|
153
|
-
"sha256:
|
154
|
-
"sha256:
|
155
|
-
"sha256:
|
156
|
-
"sha256:
|
157
|
-
"sha256:
|
158
|
-
"sha256:
|
159
|
-
"sha256:
|
160
|
-
"sha256:
|
161
|
-
"sha256:
|
162
|
-
"sha256:
|
163
|
-
"sha256:
|
164
|
-
"sha256:
|
165
|
-
"sha256:
|
166
|
-
"sha256:
|
167
|
-
"sha256:
|
168
|
-
"sha256:
|
169
|
-
"sha256:
|
118
|
+
"sha256:075299460948cd12722a970c7eae43d25d37989da682997687b34ae6b87c0ef0",
|
119
|
+
"sha256:07dfdd492d645eea1bd70fb1d6febdcf47db178b0d99161d8e4eed18e7f62fe7",
|
120
|
+
"sha256:0cbdf2cae14a06827bec50bd58e49249452d211d9caddd8bd80e35b53cb04631",
|
121
|
+
"sha256:2055c4fb9a6ff624253d432aa471a37202cd8f458c033d6d989be4499aed037b",
|
122
|
+
"sha256:262fffc1f6c1a26125d5d573e1ec379285a3723363f3bd9c83923c9593a2ac25",
|
123
|
+
"sha256:280132aada3bc2f0fac939a5771db4fbb84f245cb35b94fae4994d4c1f80dae7",
|
124
|
+
"sha256:2b57780b51084d5223eee7b59f0d4911c31c16ee5aa12737c7a02455829ff067",
|
125
|
+
"sha256:2bd7065249703cbeb6d4ce679c734bef0ee69baa7bff9724361ada04a15b7e3b",
|
126
|
+
"sha256:3235d7c781232e525b0761730e052388a01548bd7f67d0067a253887c6e8df46",
|
127
|
+
"sha256:33c020d3322662e74bc507fb11488773a96894aa82a622c35a5a28673c0c26f5",
|
128
|
+
"sha256:357754dcdfd811462a725e7501a9b4556388e8ecf66e79df6f4b988fa3d0b39a",
|
129
|
+
"sha256:39793731182c4be939b4be0cdecde074b833f6171313cf53481f869937129ed3",
|
130
|
+
"sha256:3c2b77f295edb9fcdb6a250f83e6481c679335ca7e6e4a955e4290350f2d22a4",
|
131
|
+
"sha256:41327143c5b1d715f5f98a397608f90ab9ebba606ae4e6f3389c2145410c52b1",
|
132
|
+
"sha256:427e1e627b0963ac02d7c8730ca6d935df10280d230508c0ba059505e9233475",
|
133
|
+
"sha256:432949a32c3e3f820af808db1833d6d1631664d53dd3ce487aa25d574e18ad1c",
|
134
|
+
"sha256:4ba01d9ba112b55bfa4b24808ec431197bb34f09f66f7cb4fd0258ff9d3711b1",
|
135
|
+
"sha256:4d0e206259b73af35c4ec1319fd04003776e11e859936658cb6ceffdeba0f5be",
|
136
|
+
"sha256:51431d0abbed3a868e967f8257c5faf283d41ec882f58413cf295a389bb22e58",
|
137
|
+
"sha256:565b2e82d0968c977e0b0f7cbf25fd06d78d4856289abc79694c8edcce6eb2de",
|
138
|
+
"sha256:6782cd6216fab5a83216cc39f13ebe30adfac2fa72688c5a4d8d180cd52e8f6a",
|
139
|
+
"sha256:6afd2e84e7da40fe23ca588379f815fb6dbbb1b757c883935ed11647205111cb",
|
140
|
+
"sha256:710c62b6e35a9a766b99b15cdc56d5aeda0914edae8bb467e9c355f75d14ee95",
|
141
|
+
"sha256:84921b10aeb2dd453247fd10de22907984eaf80901b578a5cf0bb1e279a587cb",
|
142
|
+
"sha256:85a5dbe1ba1bf38d6c63b6d2c42132d45cbee6d9f0c51b52c59aa4afba057517",
|
143
|
+
"sha256:9c6384cc90e37cfb60435bbbe0488444e54b98700f727f16f64d8bfda0b84656",
|
144
|
+
"sha256:9dd88fce54abbdbf4c42fb1fea0e498973d07816f24c0e27a1ecaf91883ce69e",
|
145
|
+
"sha256:a81eb64feded34f40c8986869a2f764f0fe2db58c0530d3a4afbcde50f314880",
|
146
|
+
"sha256:a898c11dca8f8c97b467138004a30133974aacd572818c383596f8d5b2eb04a9",
|
147
|
+
"sha256:a9960dd1891b2ddf13a7fe45339cd59ecee3abb6b8326d8b932d0c5da208104f",
|
148
|
+
"sha256:a9a7ef30a1b02547c1b23fa9a5564f03c9982fc71eb2ecb7f98c96d7a0db5cf2",
|
149
|
+
"sha256:ad97ec0da94b378e593ef532b980c15e377df9b9608c7c6da3506953182398af",
|
150
|
+
"sha256:adf032b6c105881f9d77fa17d9eebe0ad1f9bfb2ad25777811f97c5362aa07f2",
|
151
|
+
"sha256:bbfe6389c5522b99768a93d89aca52ef92310a96b99782973b9d11e80511f932",
|
152
|
+
"sha256:bd4bacd62aa2f1a1627352fe68885d6ee694bdaebb16038b6e680f2924a9b2cc",
|
153
|
+
"sha256:bf0b4b8d9caa8d64df838e0f8dcf68fb570c5733b726d1494b87f3da85db3a2d",
|
154
|
+
"sha256:c379cdd3efc0658e652a14112d51a7668f6bfca7445c5a10dee7eabecabba19d",
|
155
|
+
"sha256:c58536f6892559e030e6924896a44098bc1290663ea12532c78cef71d0df8493",
|
156
|
+
"sha256:cbe6581fcff7c8e262eb574244f81f5faaea539e712a058e6707a9d272fe5b64",
|
157
|
+
"sha256:ced268e82af993d7801a9db2dbc1d2322e786c5dc76295d8e89473d46c6b84d4",
|
158
|
+
"sha256:cf3539007202ebfe03923128fedfdd245db5860a36810136ad95a564a2fdffff",
|
159
|
+
"sha256:cf62d17310f34084c59c01e027259076479128d11e4661bb6c9acb38c5e19bb8",
|
160
|
+
"sha256:d0194d654e360b3e6cc9b774e83235bae6b9b2cac3be09040880bb0e8a88f4a1",
|
161
|
+
"sha256:d3d117890b6eee85887b1eed41eefe2e598ad6e40523d9f94c4c4b213258e4a4",
|
162
|
+
"sha256:db2de4e546f0ec4b2787d625e0b16b78e99c3e21bc1722b4977c0dddf11ca84e",
|
163
|
+
"sha256:e768d870801f68c74c2b669fc909839660180c366501d4cc4b87efd6b0eee375",
|
164
|
+
"sha256:e7c211f25777746d468d76f11719e64acb40eed410d81c26cefac641975beb88",
|
165
|
+
"sha256:eed462b4541c540d63ab57b3fc69e7d8c84d5957668854ee4e408b50e92ce26a",
|
166
|
+
"sha256:f0bfe42523893c188e9616d853c47685e1c575fe25f737adf473d0405dcfa7eb",
|
167
|
+
"sha256:f609ebcb0242d84b7adeee2b06c11a2ddaec5464d21888b2c8255f5fd6a98ae4",
|
168
|
+
"sha256:fea9d3ca80bcf17edb2c08a4704259dadac196fe5e9274067e7a20511fad1743",
|
169
|
+
"sha256:fed7a72d54bd52f4aeb6c6e951f363903bd7d70bc1cad64dd1f087980d309ab9"
|
170
170
|
],
|
171
171
|
"markers": "python_version >= '3.8'",
|
172
|
-
"version": "==7.
|
172
|
+
"version": "==7.5.0"
|
173
173
|
},
|
174
174
|
"distlib": {
|
175
175
|
"hashes": [
|
@@ -197,11 +197,11 @@
|
|
197
197
|
},
|
198
198
|
"filelock": {
|
199
199
|
"hashes": [
|
200
|
-
"sha256:
|
201
|
-
"sha256:
|
200
|
+
"sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f",
|
201
|
+
"sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"
|
202
202
|
],
|
203
203
|
"markers": "python_version >= '3.8'",
|
204
|
-
"version": "==3.
|
204
|
+
"version": "==3.14.0"
|
205
205
|
},
|
206
206
|
"flake8": {
|
207
207
|
"hashes": [
|
@@ -386,11 +386,11 @@
|
|
386
386
|
},
|
387
387
|
"platformdirs": {
|
388
388
|
"hashes": [
|
389
|
-
"sha256:
|
390
|
-
"sha256:
|
389
|
+
"sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf",
|
390
|
+
"sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"
|
391
391
|
],
|
392
392
|
"markers": "python_version >= '3.8'",
|
393
|
-
"version": "==4.2.
|
393
|
+
"version": "==4.2.1"
|
394
394
|
},
|
395
395
|
"pluggy": {
|
396
396
|
"hashes": [
|
@@ -443,12 +443,12 @@
|
|
443
443
|
},
|
444
444
|
"pytest": {
|
445
445
|
"hashes": [
|
446
|
-
"sha256:
|
447
|
-
"sha256:
|
446
|
+
"sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233",
|
447
|
+
"sha256:d507d4482197eac0ba2bae2e9babf0672eb333017bcedaa5fb1a3d42c1174b3f"
|
448
448
|
],
|
449
449
|
"index": "pypi",
|
450
450
|
"markers": "python_version >= '3.8'",
|
451
|
-
"version": "==8.
|
451
|
+
"version": "==8.2.0"
|
452
452
|
},
|
453
453
|
"pytest-cov": {
|
454
454
|
"hashes": [
|
@@ -470,12 +470,12 @@
|
|
470
470
|
},
|
471
471
|
"pytest-xdist": {
|
472
472
|
"hashes": [
|
473
|
-
"sha256:
|
474
|
-
"sha256:
|
473
|
+
"sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7",
|
474
|
+
"sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"
|
475
475
|
],
|
476
476
|
"index": "pypi",
|
477
|
-
"markers": "python_version >= '3.
|
478
|
-
"version": "==3.
|
477
|
+
"markers": "python_version >= '3.8'",
|
478
|
+
"version": "==3.6.1"
|
479
479
|
},
|
480
480
|
"pyyaml": {
|
481
481
|
"hashes": [
|
@@ -592,11 +592,11 @@
|
|
592
592
|
},
|
593
593
|
"virtualenv": {
|
594
594
|
"hashes": [
|
595
|
-
"sha256:
|
596
|
-
"sha256:
|
595
|
+
"sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b",
|
596
|
+
"sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"
|
597
597
|
],
|
598
598
|
"markers": "python_version >= '3.7'",
|
599
|
-
"version": "==20.
|
599
|
+
"version": "==20.26.1"
|
600
600
|
},
|
601
601
|
"zipp": {
|
602
602
|
"hashes": [
|
@@ -860,12 +860,12 @@
|
|
860
860
|
},
|
861
861
|
"myst-parser": {
|
862
862
|
"hashes": [
|
863
|
-
"sha256:
|
864
|
-
"sha256:
|
863
|
+
"sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1",
|
864
|
+
"sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"
|
865
865
|
],
|
866
866
|
"index": "pypi",
|
867
867
|
"markers": "python_version >= '3.8'",
|
868
|
-
"version": "==3.0.
|
868
|
+
"version": "==3.0.1"
|
869
869
|
},
|
870
870
|
"packaging": {
|
871
871
|
"hashes": [
|
@@ -35,8 +35,7 @@ fotolab -h
|
|
35
35
|
```
|
36
36
|
|
37
37
|
```console
|
38
|
-
|
39
|
-
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
38
|
+
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-v] [-d] [-V]
|
40
39
|
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
41
40
|
...
|
42
41
|
|
@@ -67,6 +66,7 @@ optional arguments:
|
|
67
66
|
-od OUTPUT_DIR, --output-dir OUTPUT_DIR
|
68
67
|
set default output folder (default: 'output')
|
69
68
|
-q, --quiet suppress all logging
|
69
|
+
-v, --verbose show verbosity of debugging log, use -vv, -vvv for more details
|
70
70
|
-d, --debug show debugging log and stacktrace
|
71
71
|
-V, --version show program's version number and exit
|
72
72
|
```
|
@@ -78,7 +78,6 @@ fotolab animate -h
|
|
78
78
|
```
|
79
79
|
|
80
80
|
```console
|
81
|
-
|
82
81
|
usage: fotolab animate [-h] [-f FORMAT] [-d DURATION] [-l LOOP]
|
83
82
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
84
83
|
|
@@ -182,7 +181,6 @@ fotolab montage -h
|
|
182
181
|
```
|
183
182
|
|
184
183
|
```console
|
185
|
-
|
186
184
|
usage: fotolab montage [-h] IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
187
185
|
|
188
186
|
positional arguments:
|
@@ -199,7 +197,7 @@ fotolab resize -h
|
|
199
197
|
```
|
200
198
|
|
201
199
|
```console
|
202
|
-
usage: fotolab resize [-h] [-wh WIDTH
|
200
|
+
usage: fotolab resize [-h] [-wh WIDTH | -ht HEIGHT]
|
203
201
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
204
202
|
|
205
203
|
positional arguments:
|
@@ -21,7 +21,7 @@ import subprocess
|
|
21
21
|
import sys
|
22
22
|
from pathlib import Path
|
23
23
|
|
24
|
-
__version__ = "0.
|
24
|
+
__version__ = "0.15.0"
|
25
25
|
|
26
26
|
log = logging.getLogger(__name__)
|
27
27
|
|
@@ -48,7 +48,7 @@ def save_image(args, new_image, output_filename, subcommand):
|
|
48
48
|
)
|
49
49
|
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
50
50
|
|
51
|
-
log.info("%s image: %s", subcommand, new_filename)
|
51
|
+
log.info("%s image: %s", subcommand, new_filename.resolve())
|
52
52
|
new_image.save(new_filename)
|
53
53
|
|
54
54
|
if args.open:
|
@@ -64,4 +64,4 @@ def _open_image(filename):
|
|
64
64
|
elif sys.platform == "windows":
|
65
65
|
os.startfile(filename)
|
66
66
|
|
67
|
-
log.info("open image: %s
|
67
|
+
log.info("open image: %s", filename.resolve())
|
@@ -42,6 +42,9 @@ log = logging.getLogger(__name__)
|
|
42
42
|
|
43
43
|
def setup_logging(args: argparse.Namespace) -> None:
|
44
44
|
"""Set up logging by level."""
|
45
|
+
if args.verbose == 0:
|
46
|
+
logging.getLogger("PIL").setLevel(logging.ERROR)
|
47
|
+
|
45
48
|
if args.quiet:
|
46
49
|
logging.disable(logging.NOTSET)
|
47
50
|
else:
|
@@ -105,6 +108,15 @@ def build_parser() -> argparse.ArgumentParser:
|
|
105
108
|
help="suppress all logging",
|
106
109
|
)
|
107
110
|
|
111
|
+
parser.add_argument(
|
112
|
+
"-v",
|
113
|
+
"--verbose",
|
114
|
+
default=0,
|
115
|
+
action="count",
|
116
|
+
dest="verbose",
|
117
|
+
help="show verbosity of debugging log, use -vv, -vvv for more details",
|
118
|
+
)
|
119
|
+
|
108
120
|
parser.add_argument(
|
109
121
|
"-d",
|
110
122
|
"--debug",
|
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
import argparse
|
19
19
|
import logging
|
20
|
+
import math
|
20
21
|
|
21
22
|
from PIL import Image
|
22
23
|
|
@@ -24,6 +25,9 @@ from fotolab import save_image
|
|
24
25
|
|
25
26
|
log = logging.getLogger(__name__)
|
26
27
|
|
28
|
+
DEFAULT_WIDTH = 600
|
29
|
+
DEFAULT_HEIGHT = 277
|
30
|
+
|
27
31
|
|
28
32
|
def build_subparser(subparsers) -> None:
|
29
33
|
"""Build the subparser."""
|
@@ -40,23 +44,25 @@ def build_subparser(subparsers) -> None:
|
|
40
44
|
metavar="IMAGE_FILENAMES",
|
41
45
|
)
|
42
46
|
|
43
|
-
resize_parser.
|
47
|
+
group = resize_parser.add_mutually_exclusive_group(required=False)
|
48
|
+
|
49
|
+
group.add_argument(
|
44
50
|
"-wh",
|
45
51
|
"--width",
|
46
52
|
dest="width",
|
47
53
|
help="set the width of the image (default: '%(default)s')",
|
48
54
|
type=int,
|
49
|
-
default=
|
55
|
+
default=DEFAULT_WIDTH,
|
50
56
|
metavar="WIDTH",
|
51
57
|
)
|
52
58
|
|
53
|
-
|
59
|
+
group.add_argument(
|
54
60
|
"-ht",
|
55
61
|
"--height",
|
56
62
|
dest="height",
|
57
63
|
help="set the height of the image (default: '%(default)s')",
|
58
64
|
type=int,
|
59
|
-
default=
|
65
|
+
default=DEFAULT_HEIGHT,
|
60
66
|
metavar="HEIGHT",
|
61
67
|
)
|
62
68
|
|
@@ -74,9 +80,37 @@ def run(args: argparse.Namespace) -> None:
|
|
74
80
|
|
75
81
|
for image_filename in args.image_filenames:
|
76
82
|
original_image = Image.open(image_filename)
|
83
|
+
|
84
|
+
new_width, new_height = _calc_new_image_dimension(original_image, args)
|
77
85
|
resized_image = original_image.copy()
|
78
86
|
resized_image = resized_image.resize(
|
79
|
-
(
|
87
|
+
(new_width, new_height), Image.Resampling.LANCZOS
|
80
88
|
)
|
81
89
|
|
82
90
|
save_image(args, resized_image, image_filename, "resize")
|
91
|
+
|
92
|
+
|
93
|
+
def _calc_new_image_dimension(image, args) -> tuple:
|
94
|
+
new_width = args.width
|
95
|
+
new_height = args.height
|
96
|
+
|
97
|
+
old_width, old_height = image.size
|
98
|
+
log.debug("old image dimension: %d x %d", old_width, old_height)
|
99
|
+
|
100
|
+
if args.width != DEFAULT_WIDTH:
|
101
|
+
aspect_ratio = old_height / old_width
|
102
|
+
log.debug("aspect ratio: %f", aspect_ratio)
|
103
|
+
|
104
|
+
new_height = math.ceil(args.width * aspect_ratio)
|
105
|
+
log.debug("new height: %d", new_height)
|
106
|
+
|
107
|
+
if args.height != DEFAULT_HEIGHT:
|
108
|
+
aspect_ratio = old_width / old_height
|
109
|
+
log.debug("aspect ratio: %f", aspect_ratio)
|
110
|
+
|
111
|
+
new_width = math.floor(args.height * aspect_ratio)
|
112
|
+
log.debug("new width: %d", new_width)
|
113
|
+
|
114
|
+
log.debug("new image dimension: %d x %d", new_width, new_height)
|
115
|
+
|
116
|
+
return (new_width, new_height)
|
@@ -44,7 +44,7 @@ def build_subparser(subparsers) -> None:
|
|
44
44
|
"-r",
|
45
45
|
"--radius",
|
46
46
|
dest="radius",
|
47
|
-
type=
|
47
|
+
type=int,
|
48
48
|
default=1,
|
49
49
|
help="set the radius or size of edges (default: '%(default)s')",
|
50
50
|
metavar="RADIUS",
|
@@ -54,7 +54,7 @@ def build_subparser(subparsers) -> None:
|
|
54
54
|
"-p",
|
55
55
|
"--percent",
|
56
56
|
dest="percent",
|
57
|
-
type=
|
57
|
+
type=int,
|
58
58
|
default=100,
|
59
59
|
help=(
|
60
60
|
"set the amount of overall strength of sharpening effect "
|
@@ -67,7 +67,7 @@ def build_subparser(subparsers) -> None:
|
|
67
67
|
"-t",
|
68
68
|
"--threshold",
|
69
69
|
dest="threshold",
|
70
|
-
type=
|
70
|
+
type=int,
|
71
71
|
default=3,
|
72
72
|
help=(
|
73
73
|
"set the minimum brightness changed to be sharpened "
|
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
import argparse
|
19
19
|
import logging
|
20
|
+
import math
|
20
21
|
|
21
22
|
from PIL import Image, ImageColor, ImageDraw, ImageFont
|
22
23
|
|
@@ -24,6 +25,9 @@ from fotolab import save_image
|
|
24
25
|
|
25
26
|
log = logging.getLogger(__name__)
|
26
27
|
|
28
|
+
FONT_SIZE_ASPECT_RATIO = 12 / 600
|
29
|
+
FONT_PADDING_ASPECT_RATIO = 15 / 600
|
30
|
+
FONT_OUTLINE_WIDTH_ASPECT_RATIO = 2 / 600
|
27
31
|
POSITIONS = ["top-left", "top-right", "bottom-left", "bottom-right"]
|
28
32
|
|
29
33
|
|
@@ -140,19 +144,21 @@ def run(args: argparse.Namespace) -> None:
|
|
140
144
|
|
141
145
|
draw = ImageDraw.Draw(watermarked_image)
|
142
146
|
|
143
|
-
font = ImageFont.truetype(
|
147
|
+
font = ImageFont.truetype(
|
148
|
+
"arial.ttf", calc_font_size(original_image, args)
|
149
|
+
)
|
144
150
|
|
145
151
|
(left, top, right, bottom) = draw.textbbox(
|
146
152
|
xy=(0, 0), text=args.text, font=font
|
147
153
|
)
|
148
154
|
text_width = right - left
|
149
155
|
text_height = bottom - top
|
150
|
-
(position_x, position_y) =
|
156
|
+
(position_x, position_y) = calc_position(
|
151
157
|
watermarked_image,
|
152
158
|
text_width,
|
153
159
|
text_height,
|
154
160
|
args.position,
|
155
|
-
args
|
161
|
+
calc_padding(original_image, args),
|
156
162
|
)
|
157
163
|
|
158
164
|
draw.text(
|
@@ -160,16 +166,49 @@ def run(args: argparse.Namespace) -> None:
|
|
160
166
|
args.text,
|
161
167
|
font=font,
|
162
168
|
fill=(*ImageColor.getrgb(args.font_color), 128),
|
163
|
-
stroke_width=args
|
169
|
+
stroke_width=calc_font_outline_width(original_image, args),
|
164
170
|
stroke_fill=(*ImageColor.getrgb(args.outline_color), 128),
|
165
171
|
)
|
166
172
|
|
167
173
|
save_image(args, watermarked_image, image_filename, "watermark")
|
168
174
|
|
169
175
|
|
170
|
-
def
|
171
|
-
|
172
|
-
|
176
|
+
def calc_font_size(image, args) -> int:
|
177
|
+
"""Calculate the font size based on the width of the image."""
|
178
|
+
width, _height = image.size
|
179
|
+
new_font_size = args.font_size
|
180
|
+
if width > 600:
|
181
|
+
new_font_size = math.floor(FONT_SIZE_ASPECT_RATIO * width)
|
182
|
+
|
183
|
+
log.debug("new font size: %d", new_font_size)
|
184
|
+
return new_font_size
|
185
|
+
|
186
|
+
|
187
|
+
def calc_font_outline_width(image, args) -> int:
|
188
|
+
"""Calculate the font padding based on the width of the image."""
|
189
|
+
width, _height = image.size
|
190
|
+
new_font_outline_width = args.outline_width
|
191
|
+
if width > 600:
|
192
|
+
new_font_outline_width = math.floor(
|
193
|
+
FONT_OUTLINE_WIDTH_ASPECT_RATIO * width
|
194
|
+
)
|
195
|
+
|
196
|
+
log.debug("new font outline width: %d", new_font_outline_width)
|
197
|
+
return new_font_outline_width
|
198
|
+
|
199
|
+
|
200
|
+
def calc_padding(image, args) -> int:
|
201
|
+
"""Calculate the font padding based on the width of the image."""
|
202
|
+
width, _height = image.size
|
203
|
+
new_padding = args.padding
|
204
|
+
if width > 600:
|
205
|
+
new_padding = math.floor(FONT_PADDING_ASPECT_RATIO * width)
|
206
|
+
|
207
|
+
log.debug("new padding: %d", new_padding)
|
208
|
+
return new_padding
|
209
|
+
|
210
|
+
|
211
|
+
def calc_position(image, text_width, text_height, position, padding) -> tuple:
|
173
212
|
"""Calculate the boundary coordinates of the watermark text."""
|
174
213
|
if position == "top-left":
|
175
214
|
position_x = 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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|