fotolab 0.13.0__tar.gz → 0.14.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.13.0 → fotolab-0.14.0}/.pre-commit-config.yaml +2 -2
- {fotolab-0.13.0 → fotolab-0.14.0}/CHANGELOG.md +10 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/PKG-INFO +28 -3
- {fotolab-0.13.0 → fotolab-0.14.0}/Pipfile.lock +9 -9
- {fotolab-0.13.0 → fotolab-0.14.0}/README.md +27 -2
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/__init__.py +1 -1
- fotolab-0.14.0/fotolab/animate.py +114 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/cli.py +2 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/.coveragerc +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/.gitignore +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/.python-version +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/CONTRIBUTING.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/LICENSE.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/Pipfile +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/Makefile +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/make.bat +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/CHANGELOG.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/CONTRIBUTING.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/LICENSE.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/README.md +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/_static/logo.jpg +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/conf.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/docs/source/index.rst +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/__main__.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/auto.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/border.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/contrast.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/env.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/info.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/montage.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/resize.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/sharpen.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/fotolab/watermark.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/pyproject.toml +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tests/__init__.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tests/conftest.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tests/test_env.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tests/test_help_flag.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tests/test_quiet_flag.py +0 -0
- {fotolab-0.13.0 → fotolab-0.14.0}/tox.ini +0 -0
@@ -45,7 +45,7 @@ repos:
|
|
45
45
|
- --py=312
|
46
46
|
|
47
47
|
- repo: https://github.com/psf/black
|
48
|
-
rev: 24.4.
|
48
|
+
rev: 24.4.2
|
49
49
|
hooks:
|
50
50
|
- id: black
|
51
51
|
language_version: python3.12
|
@@ -107,7 +107,7 @@ repos:
|
|
107
107
|
- --disable=R0801,W0212
|
108
108
|
|
109
109
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
110
|
-
rev: v1.
|
110
|
+
rev: v1.10.0
|
111
111
|
hooks:
|
112
112
|
- id: mypy
|
113
113
|
exclude: docs/
|
@@ -7,6 +7,16 @@ and this project adheres to [0-based versioning](https://0ver.org/).
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## v0.14.0 (2024-04-28)
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add `animate` subcommand to create animated `gif` image
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- Bump deps and `pre-commit` hooks
|
19
|
+
|
10
20
|
## v0.13.0 (2024-04-21)
|
11
21
|
|
12
22
|
### Changed
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fotolab
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.14.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,9 @@ fotolab -h
|
|
57
57
|
```
|
58
58
|
|
59
59
|
```console
|
60
|
+
|
60
61
|
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
61
|
-
{auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
62
|
+
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
62
63
|
...
|
63
64
|
|
64
65
|
A console program to manipulate photos.
|
@@ -68,8 +69,9 @@ A console program to manipulate photos.
|
|
68
69
|
issues: https://github.com/kianmeng/fotolab/issues
|
69
70
|
|
70
71
|
positional arguments:
|
71
|
-
{auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
72
|
+
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
72
73
|
sub-command help
|
74
|
+
animate animate an image
|
73
75
|
auto auto adjust (resize, contrast, and watermark) a photo
|
74
76
|
border add border to image
|
75
77
|
contrast contrast an image
|
@@ -91,6 +93,29 @@ optional arguments:
|
|
91
93
|
-V, --version show program's version number and exit
|
92
94
|
```
|
93
95
|
|
96
|
+
### fotolab animate
|
97
|
+
|
98
|
+
```console
|
99
|
+
fotolab animate -h
|
100
|
+
```
|
101
|
+
|
102
|
+
```console
|
103
|
+
|
104
|
+
usage: fotolab animate [-h] [-f FORMAT] [-d DURATION] [-l LOOP]
|
105
|
+
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
106
|
+
|
107
|
+
positional arguments:
|
108
|
+
IMAGE_FILENAMES set the image filenames
|
109
|
+
|
110
|
+
optional arguments:
|
111
|
+
-h, --help show this help message and exit
|
112
|
+
-f FORMAT, --format FORMAT
|
113
|
+
set the image format (default: 'gif')
|
114
|
+
-d DURATION, --duration DURATION
|
115
|
+
set the duration in milliseconds (default: '2500')
|
116
|
+
-l LOOP, --loop LOOP set the loop cycle (default: '0')
|
117
|
+
```
|
118
|
+
|
94
119
|
### fotolab auto
|
95
120
|
|
96
121
|
```console
|
@@ -261,11 +261,11 @@
|
|
261
261
|
},
|
262
262
|
"identify": {
|
263
263
|
"hashes": [
|
264
|
-
"sha256:
|
265
|
-
"sha256:
|
264
|
+
"sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa",
|
265
|
+
"sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"
|
266
266
|
],
|
267
267
|
"markers": "python_version >= '3.8'",
|
268
|
-
"version": "==2.5.
|
268
|
+
"version": "==2.5.36"
|
269
269
|
},
|
270
270
|
"importlib-metadata": {
|
271
271
|
"hashes": [
|
@@ -394,11 +394,11 @@
|
|
394
394
|
},
|
395
395
|
"pluggy": {
|
396
396
|
"hashes": [
|
397
|
-
"sha256:
|
398
|
-
"sha256:
|
397
|
+
"sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1",
|
398
|
+
"sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"
|
399
399
|
],
|
400
400
|
"markers": "python_version >= '3.8'",
|
401
|
-
"version": "==1.
|
401
|
+
"version": "==1.5.0"
|
402
402
|
},
|
403
403
|
"pre-commit": {
|
404
404
|
"hashes": [
|
@@ -860,12 +860,12 @@
|
|
860
860
|
},
|
861
861
|
"myst-parser": {
|
862
862
|
"hashes": [
|
863
|
-
"sha256:
|
864
|
-
"sha256:
|
863
|
+
"sha256:0b4ae0b33a45800a748260cb40348c37089a8a456c35120609240bd1b32f9255",
|
864
|
+
"sha256:8ee926557b8e4c2940a1e62c5720e1667cfaf8480b94b1b9c77dc38e31d104aa"
|
865
865
|
],
|
866
866
|
"index": "pypi",
|
867
867
|
"markers": "python_version >= '3.8'",
|
868
|
-
"version": "==
|
868
|
+
"version": "==3.0.0"
|
869
869
|
},
|
870
870
|
"packaging": {
|
871
871
|
"hashes": [
|
@@ -35,8 +35,9 @@ fotolab -h
|
|
35
35
|
```
|
36
36
|
|
37
37
|
```console
|
38
|
+
|
38
39
|
usage: fotolab [-h] [-o] [-op] [-od OUTPUT_DIR] [-q] [-d] [-V]
|
39
|
-
{auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
40
|
+
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
40
41
|
...
|
41
42
|
|
42
43
|
A console program to manipulate photos.
|
@@ -46,8 +47,9 @@ A console program to manipulate photos.
|
|
46
47
|
issues: https://github.com/kianmeng/fotolab/issues
|
47
48
|
|
48
49
|
positional arguments:
|
49
|
-
{auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
50
|
+
{animate,auto,border,contrast,info,resize,montage,sharpen,watermark,env}
|
50
51
|
sub-command help
|
52
|
+
animate animate an image
|
51
53
|
auto auto adjust (resize, contrast, and watermark) a photo
|
52
54
|
border add border to image
|
53
55
|
contrast contrast an image
|
@@ -69,6 +71,29 @@ optional arguments:
|
|
69
71
|
-V, --version show program's version number and exit
|
70
72
|
```
|
71
73
|
|
74
|
+
### fotolab animate
|
75
|
+
|
76
|
+
```console
|
77
|
+
fotolab animate -h
|
78
|
+
```
|
79
|
+
|
80
|
+
```console
|
81
|
+
|
82
|
+
usage: fotolab animate [-h] [-f FORMAT] [-d DURATION] [-l LOOP]
|
83
|
+
IMAGE_FILENAMES [IMAGE_FILENAMES ...]
|
84
|
+
|
85
|
+
positional arguments:
|
86
|
+
IMAGE_FILENAMES set the image filenames
|
87
|
+
|
88
|
+
optional arguments:
|
89
|
+
-h, --help show this help message and exit
|
90
|
+
-f FORMAT, --format FORMAT
|
91
|
+
set the image format (default: 'gif')
|
92
|
+
-d DURATION, --duration DURATION
|
93
|
+
set the duration in milliseconds (default: '2500')
|
94
|
+
-l LOOP, --loop LOOP set the loop cycle (default: '0')
|
95
|
+
```
|
96
|
+
|
72
97
|
### fotolab auto
|
73
98
|
|
74
99
|
```console
|
@@ -0,0 +1,114 @@
|
|
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
|
+
"""Animate subcommand."""
|
17
|
+
|
18
|
+
import argparse
|
19
|
+
import logging
|
20
|
+
from pathlib import Path
|
21
|
+
|
22
|
+
from PIL import Image
|
23
|
+
|
24
|
+
from fotolab import _open_image
|
25
|
+
|
26
|
+
log = logging.getLogger(__name__)
|
27
|
+
|
28
|
+
|
29
|
+
def build_subparser(subparsers) -> None:
|
30
|
+
"""Build the subparser."""
|
31
|
+
animate_parser = subparsers.add_parser("animate", help="animate an image")
|
32
|
+
|
33
|
+
animate_parser.set_defaults(func=run)
|
34
|
+
|
35
|
+
animate_parser.add_argument(
|
36
|
+
dest="image_filenames",
|
37
|
+
help="set the image filenames",
|
38
|
+
nargs="+",
|
39
|
+
type=str,
|
40
|
+
default=None,
|
41
|
+
metavar="IMAGE_FILENAMES",
|
42
|
+
)
|
43
|
+
|
44
|
+
animate_parser.add_argument(
|
45
|
+
"-f",
|
46
|
+
"--format",
|
47
|
+
dest="format",
|
48
|
+
type=str,
|
49
|
+
choices=["gif", "webp"],
|
50
|
+
default="gif",
|
51
|
+
help="set the image format (default: '%(default)s')",
|
52
|
+
metavar="FORMAT",
|
53
|
+
)
|
54
|
+
|
55
|
+
animate_parser.add_argument(
|
56
|
+
"-d",
|
57
|
+
"--duration",
|
58
|
+
dest="duration",
|
59
|
+
type=int,
|
60
|
+
default=2500,
|
61
|
+
help="set the duration in milliseconds (default: '%(default)s')",
|
62
|
+
metavar="DURATION",
|
63
|
+
)
|
64
|
+
|
65
|
+
animate_parser.add_argument(
|
66
|
+
"-l",
|
67
|
+
"--loop",
|
68
|
+
dest="loop",
|
69
|
+
type=int,
|
70
|
+
default=0,
|
71
|
+
help="set the loop cycle (default: '%(default)s')",
|
72
|
+
metavar="LOOP",
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
def run(args: argparse.Namespace) -> None:
|
77
|
+
"""Run animate subcommand.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
config (argparse.Namespace): Config from command line arguments
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
None
|
84
|
+
"""
|
85
|
+
log.debug(args)
|
86
|
+
|
87
|
+
first_image = args.image_filenames[0]
|
88
|
+
animated_image = Image.open(first_image)
|
89
|
+
|
90
|
+
append_images = []
|
91
|
+
for image_filename in args.image_filenames[1:]:
|
92
|
+
append_images.append(Image.open(image_filename))
|
93
|
+
|
94
|
+
image_file = Path(first_image)
|
95
|
+
new_filename = Path(
|
96
|
+
args.output_dir,
|
97
|
+
image_file.with_name(f"animate_{image_file.stem}.{args.format}"),
|
98
|
+
)
|
99
|
+
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
100
|
+
|
101
|
+
log.info("animate image: %s", new_filename)
|
102
|
+
|
103
|
+
animated_image.save(
|
104
|
+
new_filename,
|
105
|
+
format=args.format,
|
106
|
+
append_images=append_images,
|
107
|
+
save_all=True,
|
108
|
+
duration=args.duration,
|
109
|
+
loop=args.loop,
|
110
|
+
optimize=True,
|
111
|
+
)
|
112
|
+
|
113
|
+
if args.open:
|
114
|
+
_open_image(new_filename)
|
@@ -25,6 +25,7 @@ import logging
|
|
25
25
|
import sys
|
26
26
|
from typing import Dict, Optional, Sequence
|
27
27
|
|
28
|
+
import fotolab.animate
|
28
29
|
import fotolab.auto
|
29
30
|
import fotolab.border
|
30
31
|
import fotolab.contrast
|
@@ -121,6 +122,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
121
122
|
)
|
122
123
|
|
123
124
|
subparsers = parser.add_subparsers(help="sub-command help")
|
125
|
+
fotolab.animate.build_subparser(subparsers)
|
124
126
|
fotolab.auto.build_subparser(subparsers)
|
125
127
|
fotolab.border.build_subparser(subparsers)
|
126
128
|
fotolab.contrast.build_subparser(subparsers)
|
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
|
File without changes
|