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.
Files changed (40) hide show
  1. {fotolab-0.14.0 → fotolab-0.15.0}/CHANGELOG.md +14 -0
  2. {fotolab-0.14.0 → fotolab-0.15.0}/PKG-INFO +4 -6
  3. {fotolab-0.14.0 → fotolab-0.15.0}/Pipfile.lock +72 -72
  4. {fotolab-0.14.0 → fotolab-0.15.0}/README.md +3 -5
  5. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/__init__.py +3 -3
  6. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/cli.py +12 -0
  7. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/resize.py +39 -5
  8. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/sharpen.py +3 -3
  9. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/watermark.py +46 -7
  10. {fotolab-0.14.0 → fotolab-0.15.0}/.coveragerc +0 -0
  11. {fotolab-0.14.0 → fotolab-0.15.0}/.gitignore +0 -0
  12. {fotolab-0.14.0 → fotolab-0.15.0}/.pre-commit-config.yaml +0 -0
  13. {fotolab-0.14.0 → fotolab-0.15.0}/.python-version +0 -0
  14. {fotolab-0.14.0 → fotolab-0.15.0}/CONTRIBUTING.md +0 -0
  15. {fotolab-0.14.0 → fotolab-0.15.0}/LICENSE.md +0 -0
  16. {fotolab-0.14.0 → fotolab-0.15.0}/Pipfile +0 -0
  17. {fotolab-0.14.0 → fotolab-0.15.0}/docs/Makefile +0 -0
  18. {fotolab-0.14.0 → fotolab-0.15.0}/docs/make.bat +0 -0
  19. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/CHANGELOG.md +0 -0
  20. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/CONTRIBUTING.md +0 -0
  21. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/LICENSE.md +0 -0
  22. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/README.md +0 -0
  23. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/_static/logo.jpg +0 -0
  24. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/conf.py +0 -0
  25. {fotolab-0.14.0 → fotolab-0.15.0}/docs/source/index.rst +0 -0
  26. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/__main__.py +0 -0
  27. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/animate.py +0 -0
  28. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/auto.py +0 -0
  29. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/border.py +0 -0
  30. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/contrast.py +0 -0
  31. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/env.py +0 -0
  32. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/info.py +0 -0
  33. {fotolab-0.14.0 → fotolab-0.15.0}/fotolab/montage.py +0 -0
  34. {fotolab-0.14.0 → fotolab-0.15.0}/pyproject.toml +0 -0
  35. {fotolab-0.14.0 → fotolab-0.15.0}/tests/__init__.py +0 -0
  36. {fotolab-0.14.0 → fotolab-0.15.0}/tests/conftest.py +0 -0
  37. {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_env.py +0 -0
  38. {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_help_flag.py +0 -0
  39. {fotolab-0.14.0 → fotolab-0.15.0}/tests/test_quiet_flag.py +0 -0
  40. {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.14.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] [-ht HEIGHT]
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:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c",
119
- "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63",
120
- "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7",
121
- "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f",
122
- "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8",
123
- "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf",
124
- "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0",
125
- "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384",
126
- "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76",
127
- "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7",
128
- "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d",
129
- "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70",
130
- "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f",
131
- "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818",
132
- "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b",
133
- "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d",
134
- "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec",
135
- "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083",
136
- "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2",
137
- "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9",
138
- "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd",
139
- "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade",
140
- "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e",
141
- "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a",
142
- "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227",
143
- "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87",
144
- "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c",
145
- "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e",
146
- "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c",
147
- "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e",
148
- "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd",
149
- "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec",
150
- "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562",
151
- "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8",
152
- "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677",
153
- "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357",
154
- "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c",
155
- "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd",
156
- "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49",
157
- "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286",
158
- "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1",
159
- "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf",
160
- "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51",
161
- "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409",
162
- "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384",
163
- "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e",
164
- "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978",
165
- "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57",
166
- "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e",
167
- "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2",
168
- "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48",
169
- "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"
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.4.4"
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:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f",
201
- "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"
200
+ "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f",
201
+ "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"
202
202
  ],
203
203
  "markers": "python_version >= '3.8'",
204
- "version": "==3.13.4"
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:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068",
390
- "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"
389
+ "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf",
390
+ "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"
391
391
  ],
392
392
  "markers": "python_version >= '3.8'",
393
- "version": "==4.2.0"
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:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7",
447
- "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"
446
+ "sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233",
447
+ "sha256:d507d4482197eac0ba2bae2e9babf0672eb333017bcedaa5fb1a3d42c1174b3f"
448
448
  ],
449
449
  "index": "pypi",
450
450
  "markers": "python_version >= '3.8'",
451
- "version": "==8.1.1"
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:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a",
474
- "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"
473
+ "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7",
474
+ "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"
475
475
  ],
476
476
  "index": "pypi",
477
- "markers": "python_version >= '3.7'",
478
- "version": "==3.5.0"
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:7bb554bbdfeaacc3349fa614ea5bff6ac300fc7c335e9facf3a3bcfc703f45be",
596
- "sha256:8aac4332f2ea6ef519c648d0bc48a5b1d324994753519919bddbb1aff25a104e"
595
+ "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b",
596
+ "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"
597
597
  ],
598
598
  "markers": "python_version >= '3.7'",
599
- "version": "==20.25.3"
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:0b4ae0b33a45800a748260cb40348c37089a8a456c35120609240bd1b32f9255",
864
- "sha256:8ee926557b8e4c2940a1e62c5720e1667cfaf8480b94b1b9c77dc38e31d104aa"
863
+ "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1",
864
+ "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"
865
865
  ],
866
866
  "index": "pypi",
867
867
  "markers": "python_version >= '3.8'",
868
- "version": "==3.0.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] [-ht HEIGHT]
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.14.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 using default program.", filename.resolve())
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.add_argument(
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="600",
55
+ default=DEFAULT_WIDTH,
50
56
  metavar="WIDTH",
51
57
  )
52
58
 
53
- resize_parser.add_argument(
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="277",
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
- (args.width, args.height), Image.Resampling.LANCZOS
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=str,
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=str,
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=str,
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("arial.ttf", args.font_size)
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) = calculate_position(
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.padding,
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.outline_width,
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 calculate_position(
171
- image, text_width, text_height, position, padding
172
- ) -> tuple:
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