fotolab 0.25.1__py3-none-any.whl → 0.26.1__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 +12 -10
- fotolab/subcommands/halftone.py +132 -0
- {fotolab-0.25.1.dist-info → fotolab-0.26.1.dist-info}/METADATA +1 -1
- {fotolab-0.25.1.dist-info → fotolab-0.26.1.dist-info}/RECORD +7 -6
- {fotolab-0.25.1.dist-info → fotolab-0.26.1.dist-info}/LICENSE.md +0 -0
- {fotolab-0.25.1.dist-info → fotolab-0.26.1.dist-info}/WHEEL +0 -0
- {fotolab-0.25.1.dist-info → fotolab-0.26.1.dist-info}/entry_points.txt +0 -0
fotolab/__init__.py
CHANGED
@@ -16,12 +16,11 @@
|
|
16
16
|
"""A console program that manipulate images."""
|
17
17
|
|
18
18
|
import logging
|
19
|
-
import os
|
20
19
|
import subprocess
|
21
20
|
import sys
|
22
21
|
from pathlib import Path
|
23
22
|
|
24
|
-
__version__ = "0.
|
23
|
+
__version__ = "0.26.1"
|
25
24
|
|
26
25
|
log = logging.getLogger(__name__)
|
27
26
|
|
@@ -57,11 +56,14 @@ def save_image(args, new_image, output_filename, subcommand):
|
|
57
56
|
|
58
57
|
def _open_image(filename):
|
59
58
|
"""Open generated image using default program."""
|
60
|
-
|
61
|
-
subprocess.call(["xdg-open", filename])
|
62
|
-
|
63
|
-
subprocess.call(["
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
59
|
+
platform_open_func = {
|
60
|
+
"linux": subprocess.call(["xdg-open", filename]),
|
61
|
+
"darwin": subprocess.call(["open", filename]),
|
62
|
+
"windows": subprocess.call(["start", filename]),
|
63
|
+
}
|
64
|
+
try:
|
65
|
+
platform_open_func[sys.platform]
|
66
|
+
except KeyError:
|
67
|
+
print(f"Unsupported platform: {sys.platform}")
|
68
|
+
else:
|
69
|
+
log.info("open image: %s", filename.resolve())
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Copyright (C) 2024,2025 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
|
+
"""Halftone subcommand."""
|
17
|
+
|
18
|
+
import argparse
|
19
|
+
import logging
|
20
|
+
import math
|
21
|
+
from pathlib import Path
|
22
|
+
|
23
|
+
from PIL import Image, ImageDraw
|
24
|
+
|
25
|
+
from fotolab import _open_image, save_image
|
26
|
+
|
27
|
+
log = logging.getLogger(__name__)
|
28
|
+
|
29
|
+
|
30
|
+
def build_subparser(subparsers) -> None:
|
31
|
+
"""Build the subparser."""
|
32
|
+
halftone_parser = subparsers.add_parser(
|
33
|
+
"halftone", help="halftone an image"
|
34
|
+
)
|
35
|
+
|
36
|
+
halftone_parser.set_defaults(func=run)
|
37
|
+
|
38
|
+
halftone_parser.add_argument(
|
39
|
+
dest="image_filenames",
|
40
|
+
help="set the image filename",
|
41
|
+
nargs="+",
|
42
|
+
type=str,
|
43
|
+
default=None,
|
44
|
+
metavar="IMAGE_FILENAMES",
|
45
|
+
)
|
46
|
+
|
47
|
+
halftone_parser.add_argument(
|
48
|
+
"-ba",
|
49
|
+
"--before-after",
|
50
|
+
default=False,
|
51
|
+
action="store_true",
|
52
|
+
dest="before_after",
|
53
|
+
help="generate a GIF showing before and after changes",
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
def run(args: argparse.Namespace) -> None:
|
58
|
+
"""Run halftone subcommand.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
config (argparse.Namespace): Config from command line arguments
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
None
|
65
|
+
"""
|
66
|
+
log.debug(args)
|
67
|
+
|
68
|
+
for image_filename in args.image_filenames:
|
69
|
+
original_image = Image.open(image_filename)
|
70
|
+
grayscale_image = original_image.convert("L")
|
71
|
+
width, height = original_image.size
|
72
|
+
|
73
|
+
halftone_image = Image.new("L", (width, height), "black")
|
74
|
+
draw = ImageDraw.Draw(halftone_image)
|
75
|
+
|
76
|
+
# modified from the circular halftone effect processing.py example from
|
77
|
+
# https://tabreturn.github.io/code/processing/python/2019/02/09/processing.py_in_ten_lessons-6.3-_halftones.html
|
78
|
+
coltotal = 50
|
79
|
+
cellsize = width / coltotal
|
80
|
+
rowtotal = math.ceil(height / cellsize)
|
81
|
+
|
82
|
+
col = 0
|
83
|
+
row = 0
|
84
|
+
|
85
|
+
for _ in range(int(coltotal * rowtotal)):
|
86
|
+
x = int(col * cellsize)
|
87
|
+
y = int(row * cellsize)
|
88
|
+
col += 1
|
89
|
+
|
90
|
+
if col >= coltotal:
|
91
|
+
col = 0
|
92
|
+
row += 1
|
93
|
+
|
94
|
+
x = int(x + cellsize / 2)
|
95
|
+
y = int(y + cellsize / 2)
|
96
|
+
|
97
|
+
brightness = grayscale_image.getpixel((x, y))
|
98
|
+
amp = 10 * brightness / 200
|
99
|
+
draw.ellipse(
|
100
|
+
[x - amp / 2, y - amp / 2, x + amp / 2, y + amp / 2], fill=255
|
101
|
+
)
|
102
|
+
|
103
|
+
if args.before_after:
|
104
|
+
save_gif_image(
|
105
|
+
args, image_filename, original_image, halftone_image
|
106
|
+
)
|
107
|
+
else:
|
108
|
+
save_image(args, halftone_image, image_filename, "halftone")
|
109
|
+
|
110
|
+
|
111
|
+
def save_gif_image(args, image_filename, original_image, sharpen_image):
|
112
|
+
"""Save the original and sharpen image."""
|
113
|
+
image_file = Path(image_filename)
|
114
|
+
new_filename = Path(
|
115
|
+
args.output_dir,
|
116
|
+
image_file.with_name(f"sharpen_gif_{image_file.stem}.gif"),
|
117
|
+
)
|
118
|
+
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
119
|
+
|
120
|
+
log.info("sharpen gif image: %s", new_filename)
|
121
|
+
original_image.save(
|
122
|
+
new_filename,
|
123
|
+
format="gif",
|
124
|
+
append_images=[sharpen_image],
|
125
|
+
save_all=True,
|
126
|
+
duration=2500,
|
127
|
+
loop=0,
|
128
|
+
optimize=True,
|
129
|
+
)
|
130
|
+
|
131
|
+
if args.open:
|
132
|
+
_open_image(new_filename)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
fotolab/__init__.py,sha256=
|
1
|
+
fotolab/__init__.py,sha256=a6JSYO39sXbb5tNuAR07eXw8gXocdIrxeHtn0LS7ZAo,2172
|
2
2
|
fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
|
3
3
|
fotolab/cli.py,sha256=9rhS-yhX1nE_zKBfR05QyEt-S7Y43mIP0yUQA6bsgV8,4326
|
4
4
|
fotolab/subcommands/__init__.py,sha256=l3DlIaJ3u3jGjnC1H1yV8LZ_nPqOLJ6gikD4BCaMAQ0,1129
|
@@ -7,14 +7,15 @@ fotolab/subcommands/auto.py,sha256=p_e1f4mcrIFLqBXMNKvPQRDkNrAlK7FR6sdR5NAR0t8,2
|
|
7
7
|
fotolab/subcommands/border.py,sha256=v5rdLb7Yq1kQI0MTSfVb0iroBroTV8oxOk-jMLB2who,3637
|
8
8
|
fotolab/subcommands/contrast.py,sha256=8uPCd5xI-aUsL7rjdEPmfSskdzMwM-1tv0eRRONkW2M,2100
|
9
9
|
fotolab/subcommands/env.py,sha256=JamU3a2xWPbwlAj5iThHs58KYkLmjpUphZfTQODBp_4,1471
|
10
|
+
fotolab/subcommands/halftone.py,sha256=EEXq3ZZES3h2ZzLTc0IpkkuApR5O_kdeZ7N3vRFv-UI,3820
|
10
11
|
fotolab/subcommands/info.py,sha256=DANbfBNy2SzFfeE4KqOViAZkaME6xujfZvJTHIaZyCY,3312
|
11
12
|
fotolab/subcommands/montage.py,sha256=hhRH9LsWxXa86_qtVDKGvk--Eap2nP17OTy81kq3Xjk,2048
|
12
13
|
fotolab/subcommands/resize.py,sha256=d2Nlslzlvri9L2rqmE-HbmnLozylSk3U1Hi3DF1q3Mc,5023
|
13
14
|
fotolab/subcommands/rotate.py,sha256=vhtiAD5r0i5humpjyAbkoxh2nQsSuBYUD-TgcECwUwE,2149
|
14
15
|
fotolab/subcommands/sharpen.py,sha256=xz8RW8cRPM4eUvJTO1Stsur3G67DBftVGza8kF5j2Pc,3700
|
15
16
|
fotolab/subcommands/watermark.py,sha256=zKIFMreqSRaTD89JPjtLZljfTw-5ZkbZNBAyLeFveGw,8905
|
16
|
-
fotolab-0.
|
17
|
-
fotolab-0.
|
18
|
-
fotolab-0.
|
19
|
-
fotolab-0.
|
20
|
-
fotolab-0.
|
17
|
+
fotolab-0.26.1.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
|
18
|
+
fotolab-0.26.1.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
|
19
|
+
fotolab-0.26.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
20
|
+
fotolab-0.26.1.dist-info/METADATA,sha256=pTDOM47SsAvo1xgsN6RlL2_ocSwcRm5W3TrSkJE9dyw,11058
|
21
|
+
fotolab-0.26.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|