fotolab 0.31.0__py3-none-any.whl → 0.31.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 CHANGED
@@ -24,7 +24,7 @@ from pathlib import Path
24
24
 
25
25
  from PIL import Image
26
26
 
27
- __version__ = "0.31.0"
27
+ __version__ = "0.31.1"
28
28
 
29
29
  log = logging.getLogger(__name__)
30
30
 
@@ -73,7 +73,10 @@ def build_subparser(subparsers) -> None:
73
73
  dest="duration",
74
74
  type=_validate_duration,
75
75
  default=2500,
76
- help="set the duration in milliseconds (must be a positive integer, default: '%(default)s')",
76
+ help=(
77
+ "set the duration in milliseconds "
78
+ "(must be a positive integer, default: '%(default)s')"
79
+ ),
77
80
  metavar="DURATION",
78
81
  )
79
82
 
@@ -120,7 +123,10 @@ def build_subparser(subparsers) -> None:
120
123
  type=int,
121
124
  default=4,
122
125
  choices=range(0, 7),
123
- help="set WEBP encoding method (0=fast, 6=slow/best, default: '%(default)s')",
126
+ help=(
127
+ "set WEBP encoding method "
128
+ "(0=fast, 6=slow/best, default: '%(default)s')"
129
+ ),
124
130
  metavar="METHOD",
125
131
  )
126
132
 
@@ -170,17 +176,17 @@ def run(args: argparse.Namespace) -> None:
170
176
  "save_all": True,
171
177
  "duration": args.duration,
172
178
  "loop": args.loop,
173
- "optimize": True, # General optimization, good for GIF
179
+ "optimize": True,
174
180
  }
175
181
 
182
+ # Pillow's WEBP save doesn't use a general 'optimize' like GIF.
183
+ # Specific WEBP params like 'method' and 'quality' control this. We
184
+ # can remove 'optimize' if it causes issues or is ignored for WEBP.
185
+ # For now, let's keep it, Pillow might handle it or ignore it.
176
186
  if args.format == "webp":
177
187
  save_kwargs["quality"] = args.webp_quality
178
188
  save_kwargs["lossless"] = args.webp_lossless
179
189
  save_kwargs["method"] = args.webp_method
180
- # Pillow's WEBP save doesn't use a general 'optimize' like GIF.
181
- # Specific WEBP params like 'method' and 'quality' control this.
182
- # We can remove 'optimize' if it causes issues or is ignored for WEBP.
183
- # For now, let's keep it, Pillow might handle it or ignore it.
184
190
 
185
191
  main_frame.save(new_filename, **save_kwargs)
186
192
  finally:
@@ -71,6 +71,7 @@ def run(args: argparse.Namespace) -> None:
71
71
  "canvas": False,
72
72
  "lowercase": False,
73
73
  "before_after": False,
74
+ "alpha": 128,
74
75
  }
75
76
  combined_args = argparse.Namespace(**vars(args), **extra_args)
76
77
  combined_args.overwrite = True
@@ -17,7 +17,7 @@
17
17
 
18
18
  import argparse
19
19
  import logging
20
- from typing import Tuple, Union
20
+ from typing import Tuple
21
21
 
22
22
  from PIL import Image, ImageColor, ImageOps
23
23
 
@@ -81,31 +81,25 @@ def run(args: argparse.Namespace) -> None:
81
81
  return
82
82
 
83
83
  output_info = []
84
- specific_info_requested = False
85
84
 
86
- if args.camera:
87
- specific_info_requested = True
88
- output_info.append(camera_metadata(exif_tags))
85
+ if args.camera:
86
+ output_info.append(get_formatted_camera_info(exif_tags))
89
87
 
90
- if args.datetime:
91
- specific_info_requested = True
92
- output_info.append(datetime(exif_tags))
88
+ if args.datetime:
89
+ output_info.append(get_formatted_datetime_info(exif_tags))
93
90
 
94
- if specific_info_requested:
95
- print("\n".join(output_info))
96
- else:
97
- # Print all tags if no specific info was requested
98
- tag_name_width = max(map(len, exif_tags))
99
- for tag_name, tag_value in exif_tags.items():
100
- print(f"{tag_name:<{tag_name_width}}: {tag_value}")
91
+ if output_info: # Check if any specific info was added
92
+ print("\n".join(output_info))
93
+ else:
94
+ # Print all tags if no specific info was requested
95
+ tag_name_width = max(map(len, exif_tags))
96
+ for tag_name, tag_value in exif_tags.items():
97
+ print(f"{tag_name:<{tag_name_width}}: {tag_value}")
101
98
 
102
99
 
103
100
  def extract_exif_tags(image: Image.Image, sort: bool = False) -> dict:
104
101
  """Extract Exif metadata from image."""
105
- try:
106
- exif = image._getexif()
107
- except AttributeError:
108
- exif = None
102
+ exif = image.getexif()
109
103
 
110
104
  log.debug(exif)
111
105
 
@@ -122,13 +116,13 @@ def extract_exif_tags(image: Image.Image, sort: bool = False) -> dict:
122
116
  return filtered_info
123
117
 
124
118
 
125
- def datetime(exif_tags: dict):
126
- """Extract datetime metadata."""
119
+ def get_formatted_datetime_info(exif_tags: dict):
120
+ """Extract and format datetime metadata."""
127
121
  return exif_tags.get("DateTime", "Not available")
128
122
 
129
123
 
130
- def camera_metadata(exif_tags: dict):
131
- """Extract camera and model metadata."""
124
+ def get_formatted_camera_info(exif_tags: dict):
125
+ """Extract and format camera make and model metadata."""
132
126
  make = exif_tags.get("Make", "")
133
127
  model = exif_tags.get("Model", "")
134
128
  metadata = f"{make} {model}"
@@ -24,7 +24,7 @@ from typing import Tuple
24
24
  from PIL import Image, ImageColor, ImageDraw, ImageFont, ImageSequence
25
25
 
26
26
  from fotolab import save_image
27
- from fotolab.subcommands.info import camera_metadata
27
+ from fotolab.subcommands.info import get_formatted_camera_info
28
28
 
29
29
  log: logging.Logger = logging.getLogger(__name__)
30
30
 
@@ -312,10 +312,10 @@ def watermark_image(
312
312
 
313
313
  def prepare_text(args: argparse.Namespace, image: Image.Image) -> str:
314
314
  """Prepare the watermark text."""
315
- text: str = args.text # Default text
315
+ text = args.text
316
316
  if args.camera:
317
- metadata_text: str | None = camera_metadata(image)
318
- if metadata_text: # Use metadata only if it's not None or empty
317
+ metadata_text = get_formatted_camera_info(image)
318
+ if metadata_text:
319
319
  text = metadata_text
320
320
  else:
321
321
  log.warning(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fotolab
3
- Version: 0.31.0
3
+ Version: 0.31.1
4
4
  Summary: A console program that manipulate images.
5
5
  Keywords: photography,photo
6
6
  Author-email: Kian-Meng Ang <kianmeng@cpan.org>
@@ -371,7 +371,8 @@ fotolab watermark -h
371
371
  usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
372
372
  [-p {top-left,top-right,bottom-left,bottom-right}]
373
373
  [-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
374
- [-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR] [--camera]
374
+ [-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
375
+ [-a ALPHA_VALUE] [--camera]
375
376
  [-l | --lowercase | --no-lowercase] [-op]
376
377
  [-od OUTPUT_DIR]
377
378
  IMAGE_FILENAMES [IMAGE_FILENAMES ...]
@@ -400,6 +401,10 @@ options:
400
401
  -oc, --outline-color OUTLINE_COLOR
401
402
  set the outline color of the watermark text (default:
402
403
  'black')
404
+ -a, --alpha ALPHA_VALUE
405
+ set the transparency of the watermark text (0-255,
406
+ where 0 is fully transparent and 255 is fully opaque;
407
+ default: '128')
403
408
  --camera use camera metadata as watermark
404
409
  -l, --lowercase, --no-lowercase
405
410
  lowercase the watermark text
@@ -1,21 +1,21 @@
1
- fotolab/__init__.py,sha256=TKTFXeMPGcnb4yYlrnCjAsghD_bbcPvtFrlRNRWVX6U,3087
1
+ fotolab/__init__.py,sha256=KWNA2ZPAuWOJFMr7zE2Lqnp2yOIi8e7vNdeo9uanRsQ,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
- fotolab/subcommands/animate.py,sha256=vmviz3cLnHfVENxFKiTimhx8nmbGbzumOP6dUd_UiUI,5524
6
- fotolab/subcommands/auto.py,sha256=ia-xegV1Z4HvYsbKgmTzf1NfNFdTDPWfZe7vQ1_90Ik,2425
7
- fotolab/subcommands/border.py,sha256=3RbTAMyKZRRTWKXHHsM584_Z6qzl5_leQn-U9DD4dCk,4702
5
+ fotolab/subcommands/animate.py,sha256=_tfIJOcwft-OP1PluPThWMsO6RAunj5RbhxeRi8Gf9w,5549
6
+ fotolab/subcommands/auto.py,sha256=3Hl1cCdu65GcfwvwiMRAcex6c7zA-KqIY6AFnB6nI3w,2447
7
+ fotolab/subcommands/border.py,sha256=-RNAYVcVTVrySzkmu3bIf__FTzog1BFC1jXqozF7PVM,4695
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
11
- fotolab/subcommands/info.py,sha256=vie578cEOesAyHohm0xCWwZBqXpblYJtdHGSyBgxsoU,3581
11
+ fotolab/subcommands/info.py,sha256=H3voMi67cKoHT2Mu4RUNQBPdb_MspetPjhOvy-YyNnE,3563
12
12
  fotolab/subcommands/montage.py,sha256=d_3EcyRSFS8fKkczlHO8IRP-mrKhQUtkQndjfd0MKsc,2566
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=_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,,
16
+ fotolab/subcommands/watermark.py,sha256=wKv_8eREUZ20hNF2xKs1XZlcSNbB2kdG_kbBlaXhJ1I,11298
17
+ fotolab-0.31.1.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
18
+ fotolab-0.31.1.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
19
+ fotolab-0.31.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
20
+ fotolab-0.31.1.dist-info/METADATA,sha256=UjjTDVhNEU_PHEGJE-Cc_Z2zNugHVnxycHU3lzpBLIM,13656
21
+ fotolab-0.31.1.dist-info/RECORD,,