fotolab 0.33.1__py3-none-any.whl → 0.34.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 CHANGED
@@ -15,16 +15,17 @@
15
15
 
16
16
  """A console program that manipulate images."""
17
17
 
18
+ from importlib import metadata
19
+ from pathlib import Path
18
20
  import argparse
19
21
  import logging
20
22
  import os
21
23
  import subprocess
22
24
  import sys
23
- from pathlib import Path
24
25
 
25
26
  from PIL import Image
26
27
 
27
- __version__ = "0.31.15"
28
+ __version__ = metadata.version("fotolab")
28
29
 
29
30
  log = logging.getLogger(__name__)
30
31
 
@@ -45,12 +46,10 @@ def save_gif_image(
45
46
  "loop": 0,
46
47
  "optimize": True,
47
48
  }
48
- _save_image_with_options(
49
- args, original_image, image_filepath, subcommand, **gif_kwargs
50
- )
49
+ save_image(args, original_image, image_filepath, subcommand, **gif_kwargs)
51
50
 
52
51
 
53
- def _save_image_with_options(
52
+ def save_image(
54
53
  args: argparse.Namespace,
55
54
  image: Image.Image,
56
55
  output_filepath: Path,
@@ -71,21 +70,7 @@ def _save_image_with_options(
71
70
  image.save(new_filename, **kwargs)
72
71
 
73
72
  if args.open:
74
- _open_image(new_filename)
75
-
76
-
77
- def save_image(
78
- args: argparse.Namespace,
79
- new_image: Image.Image,
80
- output_filepath: Path,
81
- subcommand: str,
82
- ) -> None:
83
- """Save image after image operation.
84
-
85
- Returns:
86
- None
87
- """
88
- _save_image_with_options(args, new_image, output_filepath, subcommand)
73
+ open_image(new_filename)
89
74
 
90
75
 
91
76
  def _get_output_filename(
@@ -100,7 +85,7 @@ def _get_output_filename(
100
85
  return output_dir / image_file.with_name(f"{subcommand}_{image_file.name}")
101
86
 
102
87
 
103
- def _open_image(filename: Path):
88
+ def open_image(filename: Path):
104
89
  """Open generated image using default program."""
105
90
  try:
106
91
  if sys.platform == "linux":
fotolab/__main__.py CHANGED
@@ -19,4 +19,3 @@ from fotolab.cli import main
19
19
 
20
20
  if __name__ == "__main__":
21
21
  main()
22
- raise SystemExit()
fotolab/cli.py CHANGED
@@ -23,7 +23,9 @@ issues: https://github.com/kianmeng/fotolab/issues
23
23
  import argparse
24
24
  import logging
25
25
  import sys
26
- from typing import Optional, Sequence
26
+ from typing import Sequence
27
+
28
+ from PIL import Image
27
29
 
28
30
  import fotolab.subcommands
29
31
  from fotolab import __version__
@@ -122,7 +124,7 @@ def build_parser() -> argparse.ArgumentParser:
122
124
  return parser
123
125
 
124
126
 
125
- def main(args: Optional[Sequence[str]] = None) -> None:
127
+ def main(args: Sequence[str] | None = None) -> None:
126
128
  """Run the main program flow."""
127
129
  args = args or sys.argv[1:]
128
130
  log.debug(args)
@@ -150,7 +152,11 @@ def main(args: Optional[Sequence[str]] = None) -> None:
150
152
  else:
151
153
  parser.print_help(sys.stderr)
152
154
 
153
- except Exception as error:
155
+ except (
156
+ FileNotFoundError,
157
+ ValueError,
158
+ Image.UnidentifiedImageError,
159
+ ) as error:
154
160
  log.error(
155
161
  "error: %s",
156
162
  getattr(error, "message", str(error)),
@@ -22,7 +22,7 @@ from contextlib import ExitStack
22
22
 
23
23
  from PIL import Image
24
24
 
25
- from fotolab import _open_image
25
+ from fotolab import open_image
26
26
 
27
27
  log = logging.getLogger(__name__)
28
28
 
@@ -205,4 +205,4 @@ def run(args: argparse.Namespace) -> None:
205
205
  main_frame.save(new_filename, **save_kwargs)
206
206
 
207
207
  if args.open:
208
- _open_image(new_filename)
208
+ open_image(new_filename)
@@ -104,8 +104,24 @@ def run(args: argparse.Namespace) -> None:
104
104
 
105
105
  for image_filename in args.image_filenames:
106
106
  original_image = Image.open(image_filename)
107
- contrast_image = ImageOps.autocontrast(
108
- original_image, cutoff=args.cutoff
109
- )
107
+
108
+ if original_image.mode == "RGBA":
109
+ # Split the image into RGB and Alpha channels
110
+ rgb_image = original_image.convert("RGB")
111
+ alpha_channel = original_image.getchannel("A")
112
+
113
+ # Apply autocontrast to the RGB part
114
+ contrasted_rgb = ImageOps.autocontrast(
115
+ rgb_image, cutoff=args.cutoff
116
+ )
117
+
118
+ # Merge the contrasted RGB part with the original Alpha channel
119
+ contrasted_rgb.putalpha(alpha_channel)
120
+ contrast_image = contrasted_rgb
121
+ else:
122
+ # For other modes (like RGB, L, etc.), apply autocontrast directly
123
+ contrast_image = ImageOps.autocontrast(
124
+ original_image, cutoff=args.cutoff
125
+ )
110
126
 
111
127
  save_image(args, contrast_image, Path(image_filename), "contrast")
@@ -19,7 +19,7 @@ import argparse
19
19
  import logging
20
20
  import math
21
21
  from pathlib import Path
22
- from typing import NamedTuple, Union
22
+ from typing import NamedTuple
23
23
 
24
24
  from PIL import Image, ImageDraw
25
25
 
@@ -200,7 +200,7 @@ def create_halftone_image(
200
200
  Image.Image: The halftone converted image
201
201
  """
202
202
  output_mode: str
203
- fill_color_black: Union[int, tuple[int, int, int]]
203
+ fill_color_black: int | tuple[int, int, int]
204
204
  fill_color_dot_for_grayscale: int
205
205
 
206
206
  if grayscale:
@@ -1,6 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fotolab
3
- Version: 0.33.1
3
+ Version: 0.34.0
4
+ Summary: A console program to manipulate photos.
4
5
  Author-email: Kian-Meng Ang <kianmeng@cpan.org>
5
6
  License-Expression: AGPL-3.0-or-later
6
7
  Project-URL: Changelog, https://github.com/kianmeng/fotolab/blob/master/CHANGELOG.md
@@ -10,13 +11,13 @@ Keywords: photography,photo
10
11
  Classifier: Development Status :: 3 - Alpha
11
12
  Classifier: Environment :: Console
12
13
  Classifier: Programming Language :: Python :: 3 :: Only
13
- Classifier: Programming Language :: Python :: 3.9
14
14
  Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
18
19
  Classifier: Programming Language :: Python
19
- Requires-Python: >=3.9
20
+ Requires-Python: >=3.10
20
21
  Description-Content-Type: text/markdown
21
22
  License-File: LICENSE.md
22
23
  Requires-Dist: pillow
@@ -1,22 +1,22 @@
1
- fotolab/__init__.py,sha256=Wb9aauJu-aXInocnVSuzUwpWoMSC6moNLQ1dLORbEgQ,3442
2
- fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
3
- fotolab/cli.py,sha256=oFiQXmsu3wIsM_DpZnL4B94sAoB62L16Am-cjxGmosY,4406
1
+ fotolab/__init__.py,sha256=0UZ6OZFCRkc2Fwc4LT1UtE9JdK3uq0uL8fSSVSOuVyo,3161
2
+ fotolab/__main__.py,sha256=Wk11t_zKs3wJ-okM3yv7Mtj1pRwQZu3NCmpteBwn4Hs,810
3
+ fotolab/cli.py,sha256=Ebx6RQM5Dr8PsIqQ4NOySxnGMzGGI0U7CTawYfHROlk,4499
4
4
  fotolab/subcommands/__init__.py,sha256=l3DlIaJ3u3jGjnC1H1yV8LZ_nPqOLJ6gikD4BCaMAQ0,1129
5
- fotolab/subcommands/animate.py,sha256=iEor831HVQtQ04Y2-kHxnU4--BfS75mXggVIblxrO6g,5881
5
+ fotolab/subcommands/animate.py,sha256=pyoMfRtE-07EhFni2yS8xEoRV9up5T4VcF4Qw8me4Hs,5879
6
6
  fotolab/subcommands/auto.py,sha256=gkpZ15JwzSlQPYSqGSeeGu0SLKps3A2cEn1dYpyQEyk,3584
7
7
  fotolab/subcommands/border.py,sha256=TSr1rqAPWe1ZThkZan_WiMQdSTuua2YPXg6fYcvFitQ,4715
8
- fotolab/subcommands/contrast.py,sha256=1RD3B-7NTIReMvACmb_FQtLxx_RZdmpqKmvsEuYjy2Y,3058
8
+ fotolab/subcommands/contrast.py,sha256=yoIcJbqz3S0kzMOD39MVIcLMj2GTtVN3uPI8wsoHysQ,3711
9
9
  fotolab/subcommands/env.py,sha256=QoxRvzZKgmoHTUxDV4QYhdChCpMWs5TbXFY_qIpIQpE,1469
10
- fotolab/subcommands/halftone.py,sha256=56RRkyIhCyc6MPBujV2PIbuR9HobuFhqVQaq58A5ivQ,6781
10
+ fotolab/subcommands/halftone.py,sha256=a0rZWE6elXhMSCyE-w_FKEMoDGK9Afs9oF3yT09ZhcA,6768
11
11
  fotolab/subcommands/info.py,sha256=H3voMi67cKoHT2Mu4RUNQBPdb_MspetPjhOvy-YyNnE,3563
12
12
  fotolab/subcommands/montage.py,sha256=ax-TG5FixBRFHPGkVTq8kOtRL900K6nujeBYHZ0yBAE,2622
13
13
  fotolab/subcommands/resize.py,sha256=d1-_xoTB8Vf62bm7H_9MfXrMaJhlzLiUbePgTdYzaKs,5816
14
14
  fotolab/subcommands/rotate.py,sha256=-yZ7pNW7PDOPBWbKPDut9z8bBe1NocfVBV_6V6tqq-4,2945
15
15
  fotolab/subcommands/sharpen.py,sha256=vGBJHHHUaQ2_SHS-E1mHfNVIfnnNYcCk5ritajWTik8,3594
16
16
  fotolab/subcommands/watermark.py,sha256=BkUa1tH86Ii_u03ypj9Tm0u9v7s9y9Jiz3aLpjmFDb8,11355
17
- fotolab-0.33.1.dist-info/licenses/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
18
- fotolab-0.33.1.dist-info/METADATA,sha256=ZtAGsATHK5aXwOeCLN2x_nTYrIq-O1duinmONnfCHxo,14765
19
- fotolab-0.33.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- fotolab-0.33.1.dist-info/entry_points.txt,sha256=0e1go9plFpqj5FP-OpV2acxTAx3ViI59PMXuhejvgcQ,45
21
- fotolab-0.33.1.dist-info/top_level.txt,sha256=XUJ3gdpsbjohoZCLdVlbQrxAUDkbQg7WwGQG2DaN0t4,8
22
- fotolab-0.33.1.dist-info/RECORD,,
17
+ fotolab-0.34.0.dist-info/licenses/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
18
+ fotolab-0.34.0.dist-info/METADATA,sha256=AFHeSlX8rf-ueN9HHsJ9nBzfu_Nw2UoeGSJaqsFDBrc,14816
19
+ fotolab-0.34.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ fotolab-0.34.0.dist-info/entry_points.txt,sha256=0e1go9plFpqj5FP-OpV2acxTAx3ViI59PMXuhejvgcQ,45
21
+ fotolab-0.34.0.dist-info/top_level.txt,sha256=XUJ3gdpsbjohoZCLdVlbQrxAUDkbQg7WwGQG2DaN0t4,8
22
+ fotolab-0.34.0.dist-info/RECORD,,