fotolab 0.22.0__py3-none-any.whl → 0.23.0__py3-none-any.whl
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/__init__.py +1 -1
- fotolab/cli.py +26 -42
- fotolab/subcommands/__init__.py +32 -0
- fotolab/{auto.py → subcommands/auto.py} +8 -8
- fotolab/{info.py → subcommands/info.py} +8 -2
- fotolab/{rotate.py → subcommands/rotate.py} +20 -1
- fotolab/{watermark.py → subcommands/watermark.py} +12 -17
- {fotolab-0.22.0.dist-info → fotolab-0.23.0.dist-info}/METADATA +14 -9
- fotolab-0.23.0.dist-info/RECORD +20 -0
- fotolab-0.22.0.dist-info/RECORD +0 -19
- /fotolab/{animate.py → subcommands/animate.py} +0 -0
- /fotolab/{border.py → subcommands/border.py} +0 -0
- /fotolab/{contrast.py → subcommands/contrast.py} +0 -0
- /fotolab/{env.py → subcommands/env.py} +0 -0
- /fotolab/{montage.py → subcommands/montage.py} +0 -0
- /fotolab/{resize.py → subcommands/resize.py} +0 -0
- /fotolab/{sharpen.py → subcommands/sharpen.py} +0 -0
- {fotolab-0.22.0.dist-info → fotolab-0.23.0.dist-info}/LICENSE.md +0 -0
- {fotolab-0.22.0.dist-info → fotolab-0.23.0.dist-info}/WHEEL +0 -0
- {fotolab-0.22.0.dist-info → fotolab-0.23.0.dist-info}/entry_points.txt +0 -0
fotolab/__init__.py
CHANGED
fotolab/cli.py
CHANGED
@@ -23,46 +23,40 @@
|
|
23
23
|
import argparse
|
24
24
|
import logging
|
25
25
|
import sys
|
26
|
-
from typing import
|
27
|
-
|
28
|
-
import fotolab.
|
29
|
-
import fotolab.auto
|
30
|
-
import fotolab.border
|
31
|
-
import fotolab.contrast
|
32
|
-
import fotolab.env
|
33
|
-
import fotolab.info
|
34
|
-
import fotolab.montage
|
35
|
-
import fotolab.resize
|
36
|
-
import fotolab.rotate
|
37
|
-
import fotolab.sharpen
|
38
|
-
import fotolab.watermark
|
26
|
+
from typing import Optional, Sequence
|
27
|
+
|
28
|
+
import fotolab.subcommands
|
39
29
|
from fotolab import __version__
|
40
30
|
|
41
31
|
log = logging.getLogger(__name__)
|
42
32
|
|
43
33
|
|
44
34
|
def setup_logging(args: argparse.Namespace) -> None:
|
45
|
-
"""
|
46
|
-
if args.verbose == 0:
|
47
|
-
logging.getLogger("PIL").setLevel(logging.ERROR)
|
35
|
+
"""Sets up logging configuration based on command-line arguments.
|
48
36
|
|
37
|
+
Args:
|
38
|
+
args (argparse.Namespace): Namespace containing parsed arguments.
|
39
|
+
"""
|
49
40
|
if args.quiet:
|
50
41
|
logging.disable(logging.NOTSET)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
42
|
+
return
|
43
|
+
|
44
|
+
if args.verbose == 0:
|
45
|
+
logging.getLogger("PIL").setLevel(logging.ERROR)
|
46
|
+
|
47
|
+
level = logging.DEBUG if args.debug else logging.INFO
|
48
|
+
format_string = (
|
49
|
+
"[%(asctime)s] %(levelname)s: %(name)s: %(message)s"
|
50
|
+
if args.debug
|
51
|
+
else "%(message)s"
|
52
|
+
)
|
53
|
+
|
54
|
+
logging.basicConfig(
|
55
|
+
level=level,
|
56
|
+
format=format_string,
|
57
|
+
stream=sys.stdout,
|
58
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
59
|
+
)
|
66
60
|
|
67
61
|
|
68
62
|
def build_parser() -> argparse.ArgumentParser:
|
@@ -136,17 +130,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
136
130
|
)
|
137
131
|
|
138
132
|
subparsers = parser.add_subparsers(help="sub-command help")
|
139
|
-
fotolab.
|
140
|
-
fotolab.auto.build_subparser(subparsers)
|
141
|
-
fotolab.border.build_subparser(subparsers)
|
142
|
-
fotolab.contrast.build_subparser(subparsers)
|
143
|
-
fotolab.info.build_subparser(subparsers)
|
144
|
-
fotolab.resize.build_subparser(subparsers)
|
145
|
-
fotolab.rotate.build_subparser(subparsers)
|
146
|
-
fotolab.montage.build_subparser(subparsers)
|
147
|
-
fotolab.sharpen.build_subparser(subparsers)
|
148
|
-
fotolab.watermark.build_subparser(subparsers)
|
149
|
-
fotolab.env.build_subparser(subparsers)
|
133
|
+
fotolab.subcommands.build_subparser(subparsers)
|
150
134
|
|
151
135
|
return parser
|
152
136
|
|
@@ -0,0 +1,32 @@
|
|
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
|
+
"""Common utils for subcommand."""
|
17
|
+
|
18
|
+
import importlib
|
19
|
+
import pkgutil
|
20
|
+
|
21
|
+
|
22
|
+
def build_subparser(subparsers):
|
23
|
+
"""Build subparser for each subcommands."""
|
24
|
+
iter_namespace = pkgutil.iter_modules(__path__, __name__ + ".")
|
25
|
+
|
26
|
+
subcommands = {
|
27
|
+
name: importlib.import_module(name)
|
28
|
+
for finder, name, ispkg in iter_namespace
|
29
|
+
}
|
30
|
+
|
31
|
+
for subcommand in subcommands.values():
|
32
|
+
subcommand.build_subparser(subparsers)
|
@@ -18,10 +18,10 @@
|
|
18
18
|
import argparse
|
19
19
|
import logging
|
20
20
|
|
21
|
-
import fotolab.contrast
|
22
|
-
import fotolab.resize
|
23
|
-
import fotolab.sharpen
|
24
|
-
import fotolab.watermark
|
21
|
+
import fotolab.subcommands.contrast
|
22
|
+
import fotolab.subcommands.resize
|
23
|
+
import fotolab.subcommands.sharpen
|
24
|
+
import fotolab.subcommands.watermark
|
25
25
|
|
26
26
|
log = logging.getLogger(__name__)
|
27
27
|
|
@@ -77,7 +77,7 @@ def run(args: argparse.Namespace) -> None:
|
|
77
77
|
log.debug(args)
|
78
78
|
log.debug(combined_args)
|
79
79
|
|
80
|
-
fotolab.resize.run(combined_args)
|
81
|
-
fotolab.contrast.run(combined_args)
|
82
|
-
fotolab.sharpen.run(combined_args)
|
83
|
-
fotolab.watermark.run(combined_args)
|
80
|
+
fotolab.subcommands.resize.run(combined_args)
|
81
|
+
fotolab.subcommands.contrast.run(combined_args)
|
82
|
+
fotolab.subcommands.sharpen.run(combined_args)
|
83
|
+
fotolab.subcommands.watermark.run(combined_args)
|
@@ -73,10 +73,16 @@ def run(args: argparse.Namespace) -> None:
|
|
73
73
|
None
|
74
74
|
"""
|
75
75
|
log.debug(args)
|
76
|
+
info = []
|
77
|
+
|
76
78
|
if args.camera:
|
77
|
-
|
79
|
+
info.append(camera_metadata(args.image_filename))
|
80
|
+
|
78
81
|
if args.datetime:
|
79
|
-
|
82
|
+
info.append(datetime(args.image_filename))
|
83
|
+
|
84
|
+
if info:
|
85
|
+
print("\n".join(info))
|
80
86
|
else:
|
81
87
|
exif_tags = extract_exif_tags(args.image_filename)
|
82
88
|
if exif_tags:
|
@@ -40,6 +40,21 @@ def build_subparser(subparsers) -> None:
|
|
40
40
|
metavar="IMAGE_FILENAMES",
|
41
41
|
)
|
42
42
|
|
43
|
+
rotate_parser.add_argument(
|
44
|
+
"-r",
|
45
|
+
"--rotation",
|
46
|
+
type=int,
|
47
|
+
default=0,
|
48
|
+
help="Rotation angle in degrees (default: '%(default)s')",
|
49
|
+
)
|
50
|
+
|
51
|
+
rotate_parser.add_argument(
|
52
|
+
"-cw",
|
53
|
+
"--clockwise",
|
54
|
+
action="store_true",
|
55
|
+
help="Rotate clockwise (default: '%(default)s)",
|
56
|
+
)
|
57
|
+
|
43
58
|
|
44
59
|
def run(args: argparse.Namespace) -> None:
|
45
60
|
"""Run rotate subcommand.
|
@@ -52,10 +67,14 @@ def run(args: argparse.Namespace) -> None:
|
|
52
67
|
"""
|
53
68
|
log.debug(args)
|
54
69
|
|
70
|
+
rotation = args.rotation
|
71
|
+
if args.clockwise:
|
72
|
+
rotation = -rotation
|
73
|
+
|
55
74
|
for image_filename in args.image_filenames:
|
56
75
|
original_image = Image.open(image_filename)
|
57
76
|
rotated_image = original_image.rotate(
|
58
|
-
|
77
|
+
rotation,
|
59
78
|
expand=True,
|
60
79
|
)
|
61
80
|
save_image(args, rotated_image, image_filename, "rotate")
|
@@ -22,7 +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 camera_metadata
|
25
|
+
from fotolab.subcommands.info import camera_metadata
|
26
26
|
|
27
27
|
log = logging.getLogger(__name__)
|
28
28
|
|
@@ -237,19 +237,14 @@ def calc_padding(image, args) -> int:
|
|
237
237
|
|
238
238
|
def calc_position(image, text_width, text_height, position, padding) -> tuple:
|
239
239
|
"""Calculate the boundary coordinates of the watermark text."""
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
elif position == "bottom-right":
|
252
|
-
position_x = image.width - text_width - padding
|
253
|
-
position_y = image.height - text_height - padding
|
254
|
-
|
255
|
-
return (position_x, position_y)
|
240
|
+
positions = {
|
241
|
+
"top-left": (padding, padding),
|
242
|
+
"top-right": (image.width - text_width - padding, padding),
|
243
|
+
"bottom-left": (padding, image.height - text_height - padding),
|
244
|
+
"bottom-right": (
|
245
|
+
image.width - text_width - padding,
|
246
|
+
image.height - text_height - padding,
|
247
|
+
),
|
248
|
+
}
|
249
|
+
|
250
|
+
return positions.get(position, (0, 0))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fotolab
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.23.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>
|
@@ -61,7 +61,7 @@ fotolab -h
|
|
61
61
|
|
62
62
|
```console
|
63
63
|
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-v] [-d] [-V]
|
64
|
-
{animate,auto,border,contrast,info,resize,rotate,
|
64
|
+
{animate,auto,border,contrast,env,info,montage,resize,rotate,sharpen,watermark} ...
|
65
65
|
|
66
66
|
A console program to manipulate photos.
|
67
67
|
|
@@ -70,19 +70,19 @@ changelog: https://github.com/kianmeng/fotolab/blob/master/CHANGELOG.md
|
|
70
70
|
issues: https://github.com/kianmeng/fotolab/issues
|
71
71
|
|
72
72
|
positional arguments:
|
73
|
-
{animate,auto,border,contrast,info,resize,rotate,
|
73
|
+
{animate,auto,border,contrast,env,info,montage,resize,rotate,sharpen,watermark}
|
74
74
|
sub-command help
|
75
75
|
animate animate an image
|
76
76
|
auto auto adjust (resize, contrast, and watermark) a photo
|
77
77
|
border add border to image
|
78
78
|
contrast contrast an image
|
79
|
+
env print environment information for bug reporting
|
79
80
|
info info an image
|
81
|
+
montage montage a list of image
|
80
82
|
resize resize an image
|
81
83
|
rotate rotate an image
|
82
|
-
montage montage a list of image
|
83
84
|
sharpen sharpen an image
|
84
85
|
watermark watermark an image
|
85
|
-
env print environment information for bug reporting
|
86
86
|
|
87
87
|
options:
|
88
88
|
-h, --help show this help message and exit
|
@@ -206,7 +206,7 @@ fotolab info -h
|
|
206
206
|
<!--help-info !-->
|
207
207
|
|
208
208
|
```console
|
209
|
-
usage: fotolab info [-h] [-s] [--camera] IMAGE_FILENAME
|
209
|
+
usage: fotolab info [-h] [-s] [--camera] [--datetime] IMAGE_FILENAME
|
210
210
|
|
211
211
|
positional arguments:
|
212
212
|
IMAGE_FILENAME set the image filename
|
@@ -215,6 +215,7 @@ options:
|
|
215
215
|
-h, --help show this help message and exit
|
216
216
|
-s, --sort show image info by sorted field name
|
217
217
|
--camera show the camera maker details
|
218
|
+
--datetime show the datetime
|
218
219
|
```
|
219
220
|
|
220
221
|
<!--help-info !-->
|
@@ -228,13 +229,17 @@ fotolab rotate -h
|
|
228
229
|
<!--help-rotate !-->
|
229
230
|
|
230
231
|
```console
|
231
|
-
usage: fotolab rotate [-h]
|
232
|
+
usage: fotolab rotate [-h] [-r ROTATION] [-cw]
|
233
|
+
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
232
234
|
|
233
235
|
positional arguments:
|
234
|
-
IMAGE_FILENAMES
|
236
|
+
IMAGE_FILENAMES set the image filenames
|
235
237
|
|
236
238
|
options:
|
237
|
-
-h, --help
|
239
|
+
-h, --help show this help message and exit
|
240
|
+
-r, --rotation ROTATION
|
241
|
+
Rotation angle in degrees (default: '0')
|
242
|
+
-cw, --clockwise Rotate clockwise (default: 'False)
|
238
243
|
```
|
239
244
|
|
240
245
|
<!--help-rotate !-->
|
@@ -0,0 +1,20 @@
|
|
1
|
+
fotolab/__init__.py,sha256=kuoG8pds6QFs3Dr-rEOqncyEAq-1X7KN5yIR2TBcn90,2061
|
2
|
+
fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
|
3
|
+
fotolab/cli.py,sha256=vUS7eVcwEy2CWn4g5wTujLXS_GAzug9Np7j8-sM6GHU,4321
|
4
|
+
fotolab/subcommands/__init__.py,sha256=5ncuu_LxuWphjNohm32Z_lD0FmJPWrAynBzeza0lyCU,1124
|
5
|
+
fotolab/subcommands/animate.py,sha256=ejimhTozo9DN7BbqqcV4x8zLnanZRKq1pxBBFeOdr6Q,2967
|
6
|
+
fotolab/subcommands/auto.py,sha256=ljvC0Z88Dva18YHyn3auAjlvVHqGrxsky-HGXwaIMZo,2391
|
7
|
+
fotolab/subcommands/border.py,sha256=5ch2d7LVPhB2OFuuXSW5ci6Cn967CPDQu0qSfaO7uMg,3591
|
8
|
+
fotolab/subcommands/contrast.py,sha256=l7Bs5p8W8ypN9Cg3fFHnU-A20UwMKtjTiPk6D0PRwpM,2095
|
9
|
+
fotolab/subcommands/env.py,sha256=fzUoRWgYEiYJIWYEiiSLEb7dH_xVUOnhMpQgc1yjrTY,1457
|
10
|
+
fotolab/subcommands/info.py,sha256=bkB41ZB5BewUCvY5XBn21D1pOyLcTjsI10dseYEARfE,3354
|
11
|
+
fotolab/subcommands/montage.py,sha256=lUVY-zDSH7mwH-s34_XefdNp7CoDJHkwpbTUGiyJGgs,2037
|
12
|
+
fotolab/subcommands/resize.py,sha256=2bH1Kgoe_DqU8ozJ1E_oA6a9JPtuwIlo5a4sq_4Yles,5018
|
13
|
+
fotolab/subcommands/rotate.py,sha256=27Xrc8iV9n8WI6tOE-vBBMUeSYu2CtZAh-PGcF7JL-k,2144
|
14
|
+
fotolab/subcommands/sharpen.py,sha256=wUPtJdtB6mCRmcHrA0CoEVO0O0ROBJWhejTvUeL67QU,2655
|
15
|
+
fotolab/subcommands/watermark.py,sha256=1-5gpVCHYd7myZtsPWrrwcubTFDBdDzFmth7TSfBAgM,7073
|
16
|
+
fotolab-0.23.0.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
|
17
|
+
fotolab-0.23.0.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
|
18
|
+
fotolab-0.23.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
19
|
+
fotolab-0.23.0.dist-info/METADATA,sha256=L0KRYDKyddFDqwFLtfYhkgI45P7JzVnVEaFnlMbY8Ms,10975
|
20
|
+
fotolab-0.23.0.dist-info/RECORD,,
|
fotolab-0.22.0.dist-info/RECORD
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
fotolab/__init__.py,sha256=pw2AneRyAlWbI9FH4Ikuepdam_hEWBbqqmTUXny6WP4,2061
|
2
|
-
fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
|
3
|
-
fotolab/animate.py,sha256=ejimhTozo9DN7BbqqcV4x8zLnanZRKq1pxBBFeOdr6Q,2967
|
4
|
-
fotolab/auto.py,sha256=l_-Kf5V5Anvwz1QV1ET-42YsDWEeHf_okHkXWOycWAI,2295
|
5
|
-
fotolab/border.py,sha256=5ch2d7LVPhB2OFuuXSW5ci6Cn967CPDQu0qSfaO7uMg,3591
|
6
|
-
fotolab/cli.py,sha256=FBFSeMNqcOiJ6MuAcy0qUvc9cscdFUG946HlWZXBPtY,4984
|
7
|
-
fotolab/contrast.py,sha256=l7Bs5p8W8ypN9Cg3fFHnU-A20UwMKtjTiPk6D0PRwpM,2095
|
8
|
-
fotolab/env.py,sha256=fzUoRWgYEiYJIWYEiiSLEb7dH_xVUOnhMpQgc1yjrTY,1457
|
9
|
-
fotolab/info.py,sha256=jIWmsDAk8ikKb3uZ568DHu3m21OW2-1Erg9PRYa4giw,3281
|
10
|
-
fotolab/montage.py,sha256=lUVY-zDSH7mwH-s34_XefdNp7CoDJHkwpbTUGiyJGgs,2037
|
11
|
-
fotolab/resize.py,sha256=2bH1Kgoe_DqU8ozJ1E_oA6a9JPtuwIlo5a4sq_4Yles,5018
|
12
|
-
fotolab/rotate.py,sha256=l_vQgf0IcI8AR1TSVsk4PrMZtJ3j_wpU77rKiGJ-KTA,1715
|
13
|
-
fotolab/sharpen.py,sha256=wUPtJdtB6mCRmcHrA0CoEVO0O0ROBJWhejTvUeL67QU,2655
|
14
|
-
fotolab/watermark.py,sha256=XuVj-Cg1duNtW1Z9S8Y0AN4Q268lTM3dne5HnzLWgj0,7252
|
15
|
-
fotolab-0.22.0.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
|
16
|
-
fotolab-0.22.0.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
|
17
|
-
fotolab-0.22.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
18
|
-
fotolab-0.22.0.dist-info/METADATA,sha256=4pqzWJZoXD0c7sSRQM5RrSlC6HuEFFf9o2K-Yx6C_m0,10724
|
19
|
-
fotolab-0.22.0.dist-info/RECORD,,
|
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
|