fotolab 0.30.0__py3-none-any.whl → 0.31.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
@@ -24,7 +24,7 @@ from pathlib import Path
24
24
 
25
25
  from PIL import Image
26
26
 
27
- __version__ = "0.30.0"
27
+ __version__ = "0.31.0"
28
28
 
29
29
  log = logging.getLogger(__name__)
30
30
 
@@ -59,15 +59,14 @@ def save_gif_image(
59
59
  _open_image(new_filename)
60
60
 
61
61
 
62
- def save_image(args, new_image, output_filename, subcommand):
62
+ def save_image(
63
+ args: argparse.Namespace,
64
+ new_image: Image.Image,
65
+ output_filename: str,
66
+ subcommand: str,
67
+ ) -> None:
63
68
  """Save image after image operation.
64
69
 
65
- Args:
66
- args (argparse.Namespace): Config from command line arguments
67
- new_image(PIL.Image.Image): Modified image
68
- output_filename(str): Save filename image
69
- subcommand(str): Subcommand used to call this function
70
-
71
70
  Returns:
72
71
  None
73
72
  """
@@ -26,7 +26,7 @@ from fotolab import save_image
26
26
  log = logging.getLogger(__name__)
27
27
 
28
28
 
29
- def build_subparser(subparsers) -> None:
29
+ def build_subparser(subparsers: argparse._SubParsersAction) -> None:
30
30
  """Build the subparser."""
31
31
  border_parser = subparsers.add_parser("border", help="add border to image")
32
32
 
@@ -150,17 +150,16 @@ def run(args: argparse.Namespace) -> None:
150
150
 
151
151
  def get_border(
152
152
  args: argparse.Namespace,
153
- ) -> Union[Tuple[int, int, int, int], int]:
153
+ ) -> Tuple[int, int, int, int]:
154
154
  """Calculate the border dimensions.
155
155
 
156
156
  Args:
157
157
  args (argparse.Namespace): Command line arguments
158
158
 
159
159
  Returns:
160
- Union[Tuple[int, int, int, int], int]: Border dimensions in pixels.
161
- If individual widths are specified, returns a tuple of (left, top,
162
- right, bottom) widths. Otherwise, returns a uniform width for all
163
- sides.
160
+ Tuple[int, int, int, int]: Border dimensions in pixels as (left, top,
161
+ right, bottom) widths. If individual widths are not specified,
162
+ a uniform width is returned for all sides.
164
163
  """
165
164
  if any(
166
165
  [
@@ -176,4 +175,5 @@ def get_border(
176
175
  args.width_right,
177
176
  args.width_bottom,
178
177
  )
179
- return args.width
178
+ # If no individual widths are specified, use the general width for all sides
179
+ return (args.width, args.width, args.width, args.width)
@@ -129,6 +129,21 @@ def build_subparser(subparsers: argparse._SubParsersAction) -> None:
129
129
  metavar="OUTLINE_COLOR",
130
130
  )
131
131
 
132
+ watermark_parser.add_argument(
133
+ "-a",
134
+ "--alpha",
135
+ dest="alpha",
136
+ type=int,
137
+ default=128,
138
+ choices=range(0, 256),
139
+ metavar="ALPHA_VALUE",
140
+ help=(
141
+ "set the transparency of the watermark text (0-255, "
142
+ "where 0 is fully transparent and 255 is fully opaque; "
143
+ "default: '%(default)s')"
144
+ ),
145
+ )
146
+
132
147
  watermark_parser.add_argument(
133
148
  "--camera",
134
149
  default=False,
@@ -176,7 +191,15 @@ def run(args: argparse.Namespace) -> None:
176
191
  log.debug(args)
177
192
 
178
193
  for image_filename in args.image_filenames:
179
- image: Image.Image = Image.open(image_filename)
194
+ try:
195
+ image: Image.Image = Image.open(image_filename)
196
+ except FileNotFoundError:
197
+ log.error("Image file not found: %s", image_filename)
198
+ continue
199
+ except Exception as e:
200
+ log.error("Could not open image %s: %s", image_filename, e)
201
+ continue
202
+
180
203
  if image.format == "GIF":
181
204
  watermark_gif_image(image, image_filename, args)
182
205
  else:
@@ -202,7 +225,7 @@ def watermark_gif_image(
202
225
  frames: list[Image.Image] = []
203
226
  for frame in ImageSequence.Iterator(original_image):
204
227
  watermarked_frame: Image.Image = watermark_image(
205
- args, frame.convert("RGBA")
228
+ args, frame.convert("RGBA"), args.alpha
206
229
  )
207
230
  frames.append(watermarked_frame)
208
231
 
@@ -241,11 +264,11 @@ def watermark_non_gif_image(
241
264
  Returns:
242
265
  Image.Image: The watermarked image
243
266
  """
244
- return watermark_image(args, original_image)
267
+ return watermark_image(args, original_image, args.alpha)
245
268
 
246
269
 
247
270
  def watermark_image(
248
- args: argparse.Namespace, original_image: Image.Image
271
+ args: argparse.Namespace, original_image: Image.Image, alpha: int
249
272
  ) -> Image.Image:
250
273
  """Watermark an image."""
251
274
  watermarked_image: Image.Image = original_image.copy()
@@ -268,13 +291,21 @@ def watermark_image(
268
291
  calc_padding(original_image, args),
269
292
  )
270
293
 
294
+ try:
295
+ font_fill_color = ImageColor.getrgb(args.font_color)
296
+ stroke_fill_color = ImageColor.getrgb(args.outline_color)
297
+ except ValueError:
298
+ log.error("Invalid font or outline color specified. Using defaults.")
299
+ font_fill_color = ImageColor.getrgb("white")
300
+ stroke_fill_color = ImageColor.getrgb("black")
301
+
271
302
  draw.text(
272
303
  (position_x, position_y),
273
304
  text,
274
305
  font=font,
275
- fill=(*ImageColor.getrgb(args.font_color), 128),
306
+ fill=(*font_fill_color, alpha),
276
307
  stroke_width=calc_font_outline_width(original_image, args),
277
- stroke_fill=(*ImageColor.getrgb(args.outline_color), 128),
308
+ stroke_fill=(*stroke_fill_color, alpha),
278
309
  )
279
310
  return watermarked_image
280
311
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fotolab
3
- Version: 0.30.0
3
+ Version: 0.31.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>
@@ -1,10 +1,10 @@
1
- fotolab/__init__.py,sha256=RNGEVnKSQe-y5yy2fi65zOV5cJGZk9tw9o7id0xBMX4,3262
1
+ fotolab/__init__.py,sha256=TKTFXeMPGcnb4yYlrnCjAsghD_bbcPvtFrlRNRWVX6U,3087
2
2
  fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
3
3
  fotolab/cli.py,sha256=oFiQXmsu3wIsM_DpZnL4B94sAoB62L16Am-cjxGmosY,4406
4
4
  fotolab/subcommands/__init__.py,sha256=l3DlIaJ3u3jGjnC1H1yV8LZ_nPqOLJ6gikD4BCaMAQ0,1129
5
5
  fotolab/subcommands/animate.py,sha256=vmviz3cLnHfVENxFKiTimhx8nmbGbzumOP6dUd_UiUI,5524
6
6
  fotolab/subcommands/auto.py,sha256=ia-xegV1Z4HvYsbKgmTzf1NfNFdTDPWfZe7vQ1_90Ik,2425
7
- fotolab/subcommands/border.py,sha256=BS3BHytdWiNumxdKulKYK-WigbsKtPxECdvInUhUjSQ,4608
7
+ fotolab/subcommands/border.py,sha256=3RbTAMyKZRRTWKXHHsM584_Z6qzl5_leQn-U9DD4dCk,4702
8
8
  fotolab/subcommands/contrast.py,sha256=fcXmHnxDw74j5ZUDQ5cwWh0N4tpyqqvEjymnpITgrEk,3027
9
9
  fotolab/subcommands/env.py,sha256=QoxRvzZKgmoHTUxDV4QYhdChCpMWs5TbXFY_qIpIQpE,1469
10
10
  fotolab/subcommands/halftone.py,sha256=lt6RV0OuZkGs1LigTC1EcCCY42CocPFHWaJTDjJ5LFM,6693
@@ -13,9 +13,9 @@ fotolab/subcommands/montage.py,sha256=d_3EcyRSFS8fKkczlHO8IRP-mrKhQUtkQndjfd0MKs
13
13
  fotolab/subcommands/resize.py,sha256=UOb2rg_5ArRj0gxPTDOww_ix3tqJRC0W5b_S-Lt1G4w,5444
14
14
  fotolab/subcommands/rotate.py,sha256=uBFjHyjiBSQLtrtH1p9myODIHUDr1gkL4PpU-6Y1Ofo,2575
15
15
  fotolab/subcommands/sharpen.py,sha256=YNho2IPbc-lPvSy3Bsjehc2JOEy27LPqFSGRULs9MyY,3492
16
- fotolab/subcommands/watermark.py,sha256=qRGUp1Lc22fZSJDFRqQGPiz8RSB293ebvOVTdsDLUE4,10351
17
- fotolab-0.30.0.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
18
- fotolab-0.30.0.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
19
- fotolab-0.30.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
20
- fotolab-0.30.0.dist-info/METADATA,sha256=tPOkSTJz_hy0seegQ60vrMKDyAcbwZWcIBwPl0ZU5Ac,13395
21
- fotolab-0.30.0.dist-info/RECORD,,
16
+ fotolab/subcommands/watermark.py,sha256=_l7u-l1D6LWd5G8B1l1XpUVw2HCyacjloWX2hOSRb7c,11358
17
+ fotolab-0.31.0.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
18
+ fotolab-0.31.0.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
19
+ fotolab-0.31.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
20
+ fotolab-0.31.0.dist-info/METADATA,sha256=T9NbfLt9R31dDV8BaBeHVM9aBWH-xNyfo0CsF7llIAI,13395
21
+ fotolab-0.31.0.dist-info/RECORD,,