fotolab 0.16.18__tar.gz → 0.18.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.16.18 → fotolab-0.18.0}/.pre-commit-config.yaml +1 -1
- fotolab-0.18.0/.python-version +5 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/CHANGELOG.md +12 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/PKG-INFO +5 -3
- {fotolab-0.16.18 → fotolab-0.18.0}/Pipfile.lock +18 -18
- {fotolab-0.16.18 → fotolab-0.18.0}/README.md +4 -2
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/__init__.py +1 -1
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/auto.py +2 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/info.py +25 -4
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/watermark.py +34 -2
- {fotolab-0.16.18 → fotolab-0.18.0}/noxfile.py +1 -6
- fotolab-0.16.18/.python-version +0 -5
- {fotolab-0.16.18 → fotolab-0.18.0}/.coveragerc +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/.gitignore +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/CONTRIBUTING.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/LICENSE.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/Pipfile +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/Makefile +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/make.bat +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/CHANGELOG.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/CONTRIBUTING.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/LICENSE.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/README.md +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/_static/logo.jpg +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/conf.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/docs/source/index.rst +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/__main__.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/animate.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/border.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/cli.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/contrast.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/env.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/montage.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/resize.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/rotate.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/fotolab/sharpen.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/pyproject.toml +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/tests/__init__.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/tests/conftest.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/tests/test_env.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/tests/test_help_flag.py +0 -0
- {fotolab-0.16.18 → fotolab-0.18.0}/tests/test_quiet_flag.py +0 -0
@@ -7,6 +7,18 @@ and this project adheres to [0-based versioning](https://0ver.org/).
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## v0.18.0 (2024-09-29)
|
11
|
+
|
12
|
+
- Add `--camera` flag to `watermark` subcommand to use camera's metadata as text
|
13
|
+
- Add `--lowercase` flag to `watermark` subcommand to use lowercase the watermark text
|
14
|
+
- Bump deps and `pre-commit` hooks
|
15
|
+
|
16
|
+
## v0.17.0 (2024-09-22)
|
17
|
+
|
18
|
+
- Bump Python versions for `pyenv`
|
19
|
+
- Filter out image with `None` info field name
|
20
|
+
- Show image info by sorted field name using `-s` or `--sort` flag
|
21
|
+
|
10
22
|
## v0.16.18 (2024-09-15)
|
11
23
|
|
12
24
|
- Bump deps
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fotolab
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.18.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>
|
@@ -210,13 +210,14 @@ fotolab info -h
|
|
210
210
|
<!--help-info !-->
|
211
211
|
|
212
212
|
```console
|
213
|
-
usage: fotolab info [-h] IMAGE_FILENAME
|
213
|
+
usage: fotolab info [-h] [-s] IMAGE_FILENAME
|
214
214
|
|
215
215
|
positional arguments:
|
216
216
|
IMAGE_FILENAME set the image filename
|
217
217
|
|
218
218
|
options:
|
219
219
|
-h, --help show this help message and exit
|
220
|
+
-s, --sort show image info by sorted field name
|
220
221
|
```
|
221
222
|
|
222
223
|
<!--help-info !-->
|
@@ -327,7 +328,7 @@ fotolab watermark -h
|
|
327
328
|
usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
|
328
329
|
[-p {top-left,top-right,bottom-left,bottom-right}]
|
329
330
|
[-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
|
330
|
-
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
|
331
|
+
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR] [--camera]
|
331
332
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
332
333
|
|
333
334
|
positional arguments:
|
@@ -354,6 +355,7 @@ options:
|
|
354
355
|
-oc OUTLINE_COLOR, --outline-color OUTLINE_COLOR
|
355
356
|
set the outline color of the watermark text (default:
|
356
357
|
'black')
|
358
|
+
--camera use camera metadata as watermark
|
357
359
|
```
|
358
360
|
|
359
361
|
<!--help-watermark !-->
|
@@ -372,11 +372,11 @@
|
|
372
372
|
},
|
373
373
|
"filelock": {
|
374
374
|
"hashes": [
|
375
|
-
"sha256:
|
376
|
-
"sha256:
|
375
|
+
"sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0",
|
376
|
+
"sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"
|
377
377
|
],
|
378
378
|
"markers": "python_version >= '3.8'",
|
379
|
-
"version": "==3.16.
|
379
|
+
"version": "==3.16.1"
|
380
380
|
},
|
381
381
|
"flake8": {
|
382
382
|
"hashes": [
|
@@ -436,19 +436,19 @@
|
|
436
436
|
},
|
437
437
|
"identify": {
|
438
438
|
"hashes": [
|
439
|
-
"sha256:
|
440
|
-
"sha256:
|
439
|
+
"sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0",
|
440
|
+
"sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"
|
441
441
|
],
|
442
442
|
"markers": "python_version >= '3.8'",
|
443
|
-
"version": "==2.6.
|
443
|
+
"version": "==2.6.1"
|
444
444
|
},
|
445
445
|
"idna": {
|
446
446
|
"hashes": [
|
447
|
-
"sha256:
|
448
|
-
"sha256:
|
447
|
+
"sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
|
448
|
+
"sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
|
449
449
|
],
|
450
450
|
"markers": "python_version >= '3.6'",
|
451
|
-
"version": "==3.
|
451
|
+
"version": "==3.10"
|
452
452
|
},
|
453
453
|
"imagesize": {
|
454
454
|
"hashes": [
|
@@ -704,11 +704,11 @@
|
|
704
704
|
},
|
705
705
|
"platformdirs": {
|
706
706
|
"hashes": [
|
707
|
-
"sha256:
|
708
|
-
"sha256:
|
707
|
+
"sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907",
|
708
|
+
"sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"
|
709
709
|
],
|
710
710
|
"markers": "python_version >= '3.8'",
|
711
|
-
"version": "==4.3.
|
711
|
+
"version": "==4.3.6"
|
712
712
|
},
|
713
713
|
"pluggy": {
|
714
714
|
"hashes": [
|
@@ -887,12 +887,12 @@
|
|
887
887
|
},
|
888
888
|
"sphinx-autodoc-typehints": {
|
889
889
|
"hashes": [
|
890
|
-
"sha256:
|
891
|
-
"sha256:
|
890
|
+
"sha256:940de2951fd584d147e46772579fdc904f945c5f1ee1a78c614646abfbbef18b",
|
891
|
+
"sha256:e743512da58b67a06579a1462798a6907664ab77460758a43234adeac350afbf"
|
892
892
|
],
|
893
893
|
"index": "pypi",
|
894
894
|
"markers": "python_version >= '3.10'",
|
895
|
-
"version": "==2.4.
|
895
|
+
"version": "==2.4.4"
|
896
896
|
},
|
897
897
|
"sphinx-copybutton": {
|
898
898
|
"hashes": [
|
@@ -970,11 +970,11 @@
|
|
970
970
|
},
|
971
971
|
"virtualenv": {
|
972
972
|
"hashes": [
|
973
|
-
"sha256:
|
974
|
-
"sha256:
|
973
|
+
"sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6",
|
974
|
+
"sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4"
|
975
975
|
],
|
976
976
|
"markers": "python_version >= '3.7'",
|
977
|
-
"version": "==20.26.
|
977
|
+
"version": "==20.26.5"
|
978
978
|
},
|
979
979
|
"zipp": {
|
980
980
|
"hashes": [
|
@@ -188,13 +188,14 @@ fotolab info -h
|
|
188
188
|
<!--help-info !-->
|
189
189
|
|
190
190
|
```console
|
191
|
-
usage: fotolab info [-h] IMAGE_FILENAME
|
191
|
+
usage: fotolab info [-h] [-s] IMAGE_FILENAME
|
192
192
|
|
193
193
|
positional arguments:
|
194
194
|
IMAGE_FILENAME set the image filename
|
195
195
|
|
196
196
|
options:
|
197
197
|
-h, --help show this help message and exit
|
198
|
+
-s, --sort show image info by sorted field name
|
198
199
|
```
|
199
200
|
|
200
201
|
<!--help-info !-->
|
@@ -305,7 +306,7 @@ fotolab watermark -h
|
|
305
306
|
usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
|
306
307
|
[-p {top-left,top-right,bottom-left,bottom-right}]
|
307
308
|
[-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
|
308
|
-
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
|
309
|
+
[-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR] [--camera]
|
309
310
|
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
310
311
|
|
311
312
|
positional arguments:
|
@@ -332,6 +333,7 @@ options:
|
|
332
333
|
-oc OUTLINE_COLOR, --outline-color OUTLINE_COLOR
|
333
334
|
set the outline color of the watermark text (default:
|
334
335
|
'black')
|
336
|
+
--camera use camera metadata as watermark
|
335
337
|
```
|
336
338
|
|
337
339
|
<!--help-watermark !-->
|
@@ -67,6 +67,8 @@ def run(args: argparse.Namespace) -> None:
|
|
67
67
|
"outline_width": 2,
|
68
68
|
"outline_color": "black",
|
69
69
|
"padding": 15,
|
70
|
+
"camera": False,
|
71
|
+
"lowercase": False,
|
70
72
|
}
|
71
73
|
combined_args = argparse.Namespace(**vars(args), **extra_args)
|
72
74
|
combined_args.overwrite = True
|
@@ -37,6 +37,15 @@ def build_subparser(subparsers) -> None:
|
|
37
37
|
metavar="IMAGE_FILENAME",
|
38
38
|
)
|
39
39
|
|
40
|
+
info_parser.add_argument(
|
41
|
+
"-s",
|
42
|
+
"--sort",
|
43
|
+
default=False,
|
44
|
+
action="store_true",
|
45
|
+
dest="sort",
|
46
|
+
help="show image info by sorted field name",
|
47
|
+
)
|
48
|
+
|
40
49
|
|
41
50
|
def run(args: argparse.Namespace) -> None:
|
42
51
|
"""Run info subcommand.
|
@@ -49,10 +58,22 @@ def run(args: argparse.Namespace) -> None:
|
|
49
58
|
"""
|
50
59
|
log.debug(args)
|
51
60
|
|
52
|
-
|
61
|
+
exif_tags = extract_exif_tags(args.image.filename)
|
62
|
+
tag_name_width = max(map(len, exif_tags))
|
63
|
+
for tag_name, tag_value in exif_tags.items():
|
64
|
+
print(f"{tag_name:<{tag_name_width}}: {tag_value}")
|
65
|
+
|
66
|
+
|
67
|
+
def extract_exif_tags(image_filename: str, sort: bool = False) -> dict:
|
68
|
+
"""Extract Exif metadata from image."""
|
69
|
+
image = Image.open(image_filename)
|
53
70
|
exif = image._getexif()
|
54
71
|
info = {ExifTags.TAGS.get(tag_id): exif.get(tag_id) for tag_id in exif}
|
55
72
|
|
56
|
-
|
57
|
-
|
58
|
-
|
73
|
+
filtered_info = {
|
74
|
+
key: value for key, value in info.items() if key is not None
|
75
|
+
}
|
76
|
+
if sort:
|
77
|
+
filtered_info = dict(sorted(filtered_info.items()))
|
78
|
+
|
79
|
+
return filtered_info
|
@@ -22,6 +22,7 @@ import math
|
|
22
22
|
from PIL import Image, ImageColor, ImageDraw, ImageFont
|
23
23
|
|
24
24
|
from fotolab import save_image
|
25
|
+
from fotolab.info import extract_exif_tags
|
25
26
|
|
26
27
|
log = logging.getLogger(__name__)
|
27
28
|
|
@@ -126,6 +127,23 @@ def build_subparser(subparsers) -> None:
|
|
126
127
|
metavar="OUTLINE_COLOR",
|
127
128
|
)
|
128
129
|
|
130
|
+
watermark_parser.add_argument(
|
131
|
+
"--camera",
|
132
|
+
default=False,
|
133
|
+
action="store_true",
|
134
|
+
dest="camera",
|
135
|
+
help="use camera metadata as watermark",
|
136
|
+
)
|
137
|
+
|
138
|
+
watermark_parser.add_argument(
|
139
|
+
"-l",
|
140
|
+
"--lowercase",
|
141
|
+
default=False,
|
142
|
+
action="store_true",
|
143
|
+
dest="lowercase",
|
144
|
+
help="lowercase the watermark text",
|
145
|
+
)
|
146
|
+
|
129
147
|
|
130
148
|
def run(args: argparse.Namespace) -> None:
|
131
149
|
"""Run watermark subcommand.
|
@@ -147,8 +165,15 @@ def run(args: argparse.Namespace) -> None:
|
|
147
165
|
font = ImageFont.load_default(calc_font_size(original_image, args))
|
148
166
|
log.debug("default font: %s", " ".join(font.getname()))
|
149
167
|
|
168
|
+
text = args.text
|
169
|
+
if args.camera and camera_metadata(image_filename):
|
170
|
+
text = camera_metadata(image_filename)
|
171
|
+
|
172
|
+
if args.lowercase:
|
173
|
+
text = text.lower()
|
174
|
+
|
150
175
|
(left, top, right, bottom) = draw.textbbox(
|
151
|
-
xy=(0, 0), text=
|
176
|
+
xy=(0, 0), text=text, font=font
|
152
177
|
)
|
153
178
|
text_width = right - left
|
154
179
|
text_height = bottom - top
|
@@ -162,7 +187,7 @@ def run(args: argparse.Namespace) -> None:
|
|
162
187
|
|
163
188
|
draw.text(
|
164
189
|
(position_x, position_y),
|
165
|
-
|
190
|
+
text,
|
166
191
|
font=font,
|
167
192
|
fill=(*ImageColor.getrgb(args.font_color), 128),
|
168
193
|
stroke_width=calc_font_outline_width(original_image, args),
|
@@ -172,6 +197,13 @@ def run(args: argparse.Namespace) -> None:
|
|
172
197
|
save_image(args, watermarked_image, image_filename, "watermark")
|
173
198
|
|
174
199
|
|
200
|
+
def camera_metadata(image_filename):
|
201
|
+
"""Extract camera and model metadata."""
|
202
|
+
exif_tags = extract_exif_tags(image_filename)
|
203
|
+
metadata = f'{exif_tags["Make"]} {exif_tags["Model"]}'
|
204
|
+
return metadata.strip()
|
205
|
+
|
206
|
+
|
175
207
|
def calc_font_size(image, args) -> int:
|
176
208
|
"""Calculate the font size based on the width of the image."""
|
177
209
|
width, _height = image.size
|
@@ -152,12 +152,7 @@ def release(_session: nox.Session) -> None:
|
|
152
152
|
|
153
153
|
def _pipenv_install(session: nox.Session) -> None:
|
154
154
|
session.install("pipenv")
|
155
|
-
session.run(
|
156
|
-
"pipenv",
|
157
|
-
"install",
|
158
|
-
"--dev",
|
159
|
-
env={"PIPENV_VERBOSITY": "-1"}
|
160
|
-
)
|
155
|
+
session.run("pipenv", "install", "--dev", env={"PIPENV_VERBOSITY": "-1"})
|
161
156
|
|
162
157
|
|
163
158
|
def _search_and_replace(file, search, replace) -> None:
|
fotolab-0.16.18/.python-version
DELETED
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
|