fotolab 0.28.0__py3-none-any.whl → 0.28.2__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
@@ -23,7 +23,7 @@ from pathlib import Path
23
23
 
24
24
  from PIL import Image
25
25
 
26
- __version__ = "0.28.0"
26
+ __version__ = "0.28.2"
27
27
 
28
28
  log = logging.getLogger(__name__)
29
29
 
@@ -43,7 +43,7 @@ def save_gif_image(
43
43
  )
44
44
  new_filename.parent.mkdir(parents=True, exist_ok=True)
45
45
 
46
- log.info("f{subcommand} gif image: %s", new_filename)
46
+ log.info("%s gif image: %s", subcommand, new_filename)
47
47
  original_image.save(
48
48
  new_filename,
49
49
  format="gif",
@@ -79,7 +79,9 @@ def save_image(args, new_image, output_filename, subcommand):
79
79
  _open_image(new_filename)
80
80
 
81
81
 
82
- def _get_output_filename(args, image_file, subcommand):
82
+ def _get_output_filename(
83
+ args: argparse.Namespace, image_file: Path, subcommand: str
84
+ ) -> Path:
83
85
  """Build and return output filename based on the command line options."""
84
86
  if args.overwrite:
85
87
  return image_file.with_name(image_file.name)
@@ -91,14 +93,14 @@ def _get_output_filename(args, image_file, subcommand):
91
93
 
92
94
  def _open_image(filename):
93
95
  """Open generated image using default program."""
94
- platform_open_func = {
95
- "linux": subprocess.call(["xdg-open", filename]),
96
- "darwin": subprocess.call(["open", filename]),
97
- "windows": subprocess.call(["start", filename]),
98
- }
99
96
  try:
100
- platform_open_func[sys.platform]
101
- except KeyError:
102
- print(f"Unsupported platform: {sys.platform}")
103
- else:
97
+ if sys.platform == "linux":
98
+ subprocess.call(["xdg-open", filename])
99
+ elif sys.platform == "darwin":
100
+ subprocess.call(["open", filename])
101
+ elif sys.platform == "windows":
102
+ subprocess.Popen(["open", filename])
104
103
  log.info("open image: %s", filename.resolve())
104
+
105
+ except OSError as e:
106
+ log.error("Error opening image: %s -> %s", filename, e)
@@ -17,6 +17,7 @@
17
17
 
18
18
  import argparse
19
19
  import logging
20
+ from typing import Tuple, Union
20
21
 
21
22
  from PIL import Image, ImageColor, ImageOps
22
23
 
@@ -54,9 +55,9 @@ def build_subparser(subparsers) -> None:
54
55
  "-w",
55
56
  "--width",
56
57
  dest="width",
57
- type=str,
58
+ type=int,
58
59
  default=10,
59
- help="set the width of border (default: '%(default)s')",
60
+ help="set the width of border in pixels (default: '%(default)s')",
60
61
  metavar="WIDTH",
61
62
  )
62
63
 
@@ -64,9 +65,9 @@ def build_subparser(subparsers) -> None:
64
65
  "-wt",
65
66
  "--width-top",
66
67
  dest="width_top",
67
- type=str,
68
+ type=int,
68
69
  default=0,
69
- help="set the width of top border (default: '%(default)s')",
70
+ help="set the width of top border in pixels (default: '%(default)s')",
70
71
  metavar="WIDTH",
71
72
  )
72
73
 
@@ -74,9 +75,12 @@ def build_subparser(subparsers) -> None:
74
75
  "-wr",
75
76
  "--width-right",
76
77
  dest="width_right",
77
- type=str,
78
+ type=int,
78
79
  default=0,
79
- help="set the width of right border (default: '%(default)s')",
80
+ help=(
81
+ "set the width of right border in pixels"
82
+ " (default: '%(default)s')"
83
+ ),
80
84
  metavar="WIDTH",
81
85
  )
82
86
 
@@ -84,9 +88,12 @@ def build_subparser(subparsers) -> None:
84
88
  "-wb",
85
89
  "--width-bottom",
86
90
  dest="width_bottom",
87
- type=str,
91
+ type=int,
88
92
  default=0,
89
- help="set the width of bottom border (default: '%(default)s')",
93
+ help=(
94
+ "set the width of bottom border in pixels"
95
+ " (default: '%(default)s')"
96
+ ),
90
97
  metavar="WIDTH",
91
98
  )
92
99
 
@@ -94,9 +101,9 @@ def build_subparser(subparsers) -> None:
94
101
  "-wl",
95
102
  "--width-left",
96
103
  dest="width_left",
97
- type=str,
104
+ type=int,
98
105
  default=0,
99
- help="set the width of left border (default: '%(default)s')",
106
+ help="set the width of left border in pixels (default: '%(default)s')",
100
107
  metavar="WIDTH",
101
108
  )
102
109
 
@@ -130,27 +137,34 @@ def run(args: argparse.Namespace) -> None:
130
137
  log.debug(args)
131
138
 
132
139
  for image_filename in args.image_filenames:
133
- original_image = Image.open(image_filename)
134
-
135
- border = get_border(args)
136
- bordered_image = ImageOps.expand(
137
- original_image,
138
- border=border,
139
- fill=ImageColor.getrgb(args.color),
140
- )
140
+ try:
141
+ original_image = Image.open(image_filename)
142
+ border = get_border(args)
143
+ bordered_image = ImageOps.expand(
144
+ original_image,
145
+ border=border,
146
+ fill=ImageColor.getrgb(args.color),
147
+ )
148
+ except Exception as e:
149
+ log.error("Error adding border to %s: %s", image_filename, e)
150
+ continue
141
151
 
142
152
  save_image(args, bordered_image, image_filename, "border")
143
153
 
144
154
 
145
- def get_border(args: argparse.Namespace) -> tuple[int, int, int, int]:
155
+ def get_border(
156
+ args: argparse.Namespace,
157
+ ) -> Union[Tuple[int, int, int, int], int]:
146
158
  """Calculate the border dimensions.
147
159
 
148
160
  Args:
149
161
  args (argparse.Namespace): Command line arguments
150
162
 
151
163
  Returns:
152
- tuple[int, int, int, int]: Border dimensions in pixesl. If individual
153
- widths are not specified, returns a uniform width for all sides.
164
+ Union[Tuple[int, int, int, int], int]: Border dimensions in pixels.
165
+ If individual widths are specified, returns a tuple of (left, top,
166
+ right, bottom) widths. Otherwise, returns a uniform width for all
167
+ sides.
154
168
  """
155
169
  if any(
156
170
  [
@@ -161,9 +175,9 @@ def get_border(args: argparse.Namespace) -> tuple[int, int, int, int]:
161
175
  ]
162
176
  ):
163
177
  return (
164
- int(args.width_left),
165
- int(args.width_top),
166
- int(args.width_right),
167
- int(args.width_bottom),
178
+ args.width_left,
179
+ args.width_top,
180
+ args.width_right,
181
+ args.width_bottom,
168
182
  )
169
183
  return args.width
@@ -86,9 +86,14 @@ def run(args: argparse.Namespace) -> None:
86
86
  log.debug(args)
87
87
 
88
88
  for image_filename in args.image_filenames:
89
- original_image = Image.open(image_filename)
90
- contrast_image = ImageOps.autocontrast(
91
- original_image, cutoff=args.cutoff
92
- )
93
-
94
- save_image(args, contrast_image, image_filename, "contrast")
89
+ try:
90
+ original_image = Image.open(image_filename)
91
+ contrast_image = ImageOps.autocontrast(
92
+ original_image, cutoff=args.cutoff
93
+ )
94
+
95
+ save_image(args, contrast_image, image_filename, "contrast")
96
+ except FileNotFoundError:
97
+ log.error(f"Image file not found: {image_filename}")
98
+ except IOError:
99
+ log.error(f"Cannot open or read image file: {image_filename}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fotolab
3
- Version: 0.28.0
3
+ Version: 0.28.2
4
4
  Summary: A console program that manipulate images.
5
5
  Keywords: photography,photo
6
6
  Author-email: Kian-Meng Ang <kianmeng@cpan.org>
@@ -1,11 +1,11 @@
1
- fotolab/__init__.py,sha256=oEYK38X-ysh2Mm2tDG8SuAKgfqaT3R8_RKtbUbvmVaM,3169
1
+ fotolab/__init__.py,sha256=OHLey_plZNWMw-8lpxpw7YdsztO4PVD_NK5xhpmd-M4,3239
2
2
  fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
3
3
  fotolab/cli.py,sha256=fIApD9C4Vkn-u4CejOFTboSV5f-Ks9vBGxeb-_ca-Nw,3935
4
4
  fotolab/subcommands/__init__.py,sha256=l3DlIaJ3u3jGjnC1H1yV8LZ_nPqOLJ6gikD4BCaMAQ0,1129
5
5
  fotolab/subcommands/animate.py,sha256=OcS6Q6JM1TW6HF0dSgBsV9mpEGwDMcJlQssupkf0_ZA,3393
6
6
  fotolab/subcommands/auto.py,sha256=ia-xegV1Z4HvYsbKgmTzf1NfNFdTDPWfZe7vQ1_90Ik,2425
7
- fotolab/subcommands/border.py,sha256=zTRVnaifFcE8k_xEMhonbaiZaU_b1bDF2nBy8Hk0VXs,4360
8
- fotolab/subcommands/contrast.py,sha256=Z_YoCqtc3s5jhFq-30-46Nu_1P5o_8xDYRh5BDybK0g,2523
7
+ fotolab/subcommands/border.py,sha256=npL5dXTl6zpMnxPsMApgm6p9FS32WZy6sEy-_IuB5_4,4775
8
+ fotolab/subcommands/contrast.py,sha256=fkY_Xd405eifObGoqR4AsLSNriNBpkFjDR_pZ1AMqcc,2754
9
9
  fotolab/subcommands/env.py,sha256=QoxRvzZKgmoHTUxDV4QYhdChCpMWs5TbXFY_qIpIQpE,1469
10
10
  fotolab/subcommands/halftone.py,sha256=bRGG_Bg1T5ZV3UWsdMszOdPmc6g9_R0yNp5mb0g8hcE,4152
11
11
  fotolab/subcommands/info.py,sha256=Qp-Zu7Xp1ptLK211hOkFM5oxZWGTrlNBqCpbx2IjL9Y,3371
@@ -14,8 +14,8 @@ fotolab/subcommands/resize.py,sha256=UOb2rg_5ArRj0gxPTDOww_ix3tqJRC0W5b_S-Lt1G4w
14
14
  fotolab/subcommands/rotate.py,sha256=uBFjHyjiBSQLtrtH1p9myODIHUDr1gkL4PpU-6Y1Ofo,2575
15
15
  fotolab/subcommands/sharpen.py,sha256=YNho2IPbc-lPvSy3Bsjehc2JOEy27LPqFSGRULs9MyY,3492
16
16
  fotolab/subcommands/watermark.py,sha256=A_dUy_yf9wPHUexB9aIicFIS-BpWrjjfI8Hr4WCCBoc,9449
17
- fotolab-0.28.0.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
18
- fotolab-0.28.0.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
19
- fotolab-0.28.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
20
- fotolab-0.28.0.dist-info/METADATA,sha256=x_b-sB6pmSChwsnVf76YB9ffAaWuaf8WxS8Umc74MFE,12896
21
- fotolab-0.28.0.dist-info/RECORD,,
17
+ fotolab-0.28.2.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
18
+ fotolab-0.28.2.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
19
+ fotolab-0.28.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
20
+ fotolab-0.28.2.dist-info/METADATA,sha256=GNIrGD_H3-wNlOIoxbv-dSUFpsSQnZVqUXo8fOVtwac,12896
21
+ fotolab-0.28.2.dist-info/RECORD,,