fotolab 0.16.17__py2.py3-none-any.whl → 0.18.1__py2.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
@@ -21,7 +21,7 @@ import subprocess
21
21
  import sys
22
22
  from pathlib import Path
23
23
 
24
- __version__ = "0.16.17"
24
+ __version__ = "0.18.1"
25
25
 
26
26
  log = logging.getLogger(__name__)
27
27
 
fotolab/auto.py CHANGED
@@ -67,6 +67,8 @@ def run(args: argparse.Namespace) -> None:
67
67
  "outline_width": 2,
68
68
  "outline_color": "black",
69
69
  "padding": 15,
70
+ "camera": False,
71
+ "lowercase": False,
70
72
  }
71
73
  combined_args = argparse.Namespace(**vars(args), **extra_args)
72
74
  combined_args.overwrite = True
fotolab/cli.py CHANGED
@@ -132,7 +132,7 @@ def build_parser() -> argparse.ArgumentParser:
132
132
  "-V",
133
133
  "--version",
134
134
  action="version",
135
- version=f"fotolab {__version__}",
135
+ version=f"%(prog)s {__version__}",
136
136
  )
137
137
 
138
138
  subparsers = parser.add_subparsers(help="sub-command help")
@@ -154,7 +154,6 @@ def build_parser() -> argparse.ArgumentParser:
154
154
  def main(args: Optional[Sequence[str]] = None) -> None:
155
155
  """Run the main program flow."""
156
156
  args = args or sys.argv[1:]
157
- parsed_args = argparse.Namespace(debug=True)
158
157
  log.debug(args)
159
158
 
160
159
  try:
@@ -175,7 +174,7 @@ def main(args: Optional[Sequence[str]] = None) -> None:
175
174
  log.error(
176
175
  "error: %s",
177
176
  getattr(error, "message", str(error)),
178
- exc_info=getattr(parsed_args, "debug", True),
177
+ exc_info=("-d" in args or "--debug" in args),
179
178
  )
180
179
 
181
180
  raise SystemExit(1) from None
fotolab/env.py CHANGED
@@ -34,7 +34,7 @@ def build_subparser(subparsers) -> None:
34
34
  env_parser.set_defaults(func=run)
35
35
 
36
36
 
37
- def run(args: argparse.Namespace) -> None:
37
+ def run(_args: argparse.Namespace) -> None:
38
38
  """Run env subcommand.
39
39
 
40
40
  Args:
@@ -43,8 +43,6 @@ def run(args: argparse.Namespace) -> None:
43
43
  Returns:
44
44
  None
45
45
  """
46
- log.debug(args)
47
-
48
46
  sys_version = sys.version.replace("\n", "")
49
47
  print(
50
48
  f"fotolab: {__version__}",
fotolab/info.py CHANGED
@@ -37,6 +37,15 @@ def build_subparser(subparsers) -> None:
37
37
  metavar="IMAGE_FILENAME",
38
38
  )
39
39
 
40
+ info_parser.add_argument(
41
+ "-s",
42
+ "--sort",
43
+ default=False,
44
+ action="store_true",
45
+ dest="sort",
46
+ help="show image info by sorted field name",
47
+ )
48
+
40
49
 
41
50
  def run(args: argparse.Namespace) -> None:
42
51
  """Run info subcommand.
@@ -49,10 +58,22 @@ def run(args: argparse.Namespace) -> None:
49
58
  """
50
59
  log.debug(args)
51
60
 
52
- image = Image.open(args.image_filename)
61
+ exif_tags = extract_exif_tags(args.image.filename)
62
+ tag_name_width = max(map(len, exif_tags))
63
+ for tag_name, tag_value in exif_tags.items():
64
+ print(f"{tag_name:<{tag_name_width}}: {tag_value}")
65
+
66
+
67
+ def extract_exif_tags(image_filename: str, sort: bool = False) -> dict:
68
+ """Extract Exif metadata from image."""
69
+ image = Image.open(image_filename)
53
70
  exif = image._getexif()
54
71
  info = {ExifTags.TAGS.get(tag_id): exif.get(tag_id) for tag_id in exif}
55
72
 
56
- tag_name_width = max(map(len, info))
57
- for tag_name, tag_value in info.items():
58
- print(f"{tag_name:<{tag_name_width}}: {tag_value}")
73
+ filtered_info = {
74
+ key: value for key, value in info.items() if key is not None
75
+ }
76
+ if sort:
77
+ filtered_info = dict(sorted(filtered_info.items()))
78
+
79
+ return filtered_info
fotolab/watermark.py CHANGED
@@ -22,6 +22,7 @@ import math
22
22
  from PIL import Image, ImageColor, ImageDraw, ImageFont
23
23
 
24
24
  from fotolab import save_image
25
+ from fotolab.info import extract_exif_tags
25
26
 
26
27
  log = logging.getLogger(__name__)
27
28
 
@@ -126,12 +127,29 @@ def build_subparser(subparsers) -> None:
126
127
  metavar="OUTLINE_COLOR",
127
128
  )
128
129
 
130
+ watermark_parser.add_argument(
131
+ "--camera",
132
+ default=False,
133
+ action="store_true",
134
+ dest="camera",
135
+ help="use camera metadata as watermark",
136
+ )
137
+
138
+ watermark_parser.add_argument(
139
+ "-l",
140
+ "--lowercase",
141
+ default=True,
142
+ action="store_true",
143
+ dest="lowercase",
144
+ help="lowercase the watermark text",
145
+ )
146
+
129
147
 
130
148
  def run(args: argparse.Namespace) -> None:
131
149
  """Run watermark subcommand.
132
150
 
133
151
  Args:
134
- config (argparse.Namespace): Config from command line arguments
152
+ args (argparse.Namespace): Config from command line arguments
135
153
 
136
154
  Returns:
137
155
  None
@@ -147,8 +165,15 @@ def run(args: argparse.Namespace) -> None:
147
165
  font = ImageFont.load_default(calc_font_size(original_image, args))
148
166
  log.debug("default font: %s", " ".join(font.getname()))
149
167
 
168
+ text = args.text
169
+ if args.camera and camera_metadata(image_filename):
170
+ text = camera_metadata(image_filename)
171
+
172
+ if args.lowercase:
173
+ text = text.lower()
174
+
150
175
  (left, top, right, bottom) = draw.textbbox(
151
- xy=(0, 0), text=args.text, font=font
176
+ xy=(0, 0), text=text, font=font
152
177
  )
153
178
  text_width = right - left
154
179
  text_height = bottom - top
@@ -162,7 +187,7 @@ def run(args: argparse.Namespace) -> None:
162
187
 
163
188
  draw.text(
164
189
  (position_x, position_y),
165
- args.text,
190
+ text,
166
191
  font=font,
167
192
  fill=(*ImageColor.getrgb(args.font_color), 128),
168
193
  stroke_width=calc_font_outline_width(original_image, args),
@@ -172,6 +197,13 @@ def run(args: argparse.Namespace) -> None:
172
197
  save_image(args, watermarked_image, image_filename, "watermark")
173
198
 
174
199
 
200
+ def camera_metadata(image_filename):
201
+ """Extract camera and model metadata."""
202
+ exif_tags = extract_exif_tags(image_filename)
203
+ metadata = f'{exif_tags["Make"]} {exif_tags["Model"]}'
204
+ return metadata.strip()
205
+
206
+
175
207
  def calc_font_size(image, args) -> int:
176
208
  """Calculate the font size based on the width of the image."""
177
209
  width, _height = image.size
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fotolab
3
- Version: 0.16.17
3
+ Version: 0.18.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>
@@ -210,13 +210,14 @@ fotolab info -h
210
210
  <!--help-info !-->
211
211
 
212
212
  ```console
213
- usage: fotolab info [-h] IMAGE_FILENAME
213
+ usage: fotolab info [-h] [-s] IMAGE_FILENAME
214
214
 
215
215
  positional arguments:
216
216
  IMAGE_FILENAME set the image filename
217
217
 
218
218
  options:
219
219
  -h, --help show this help message and exit
220
+ -s, --sort show image info by sorted field name
220
221
  ```
221
222
 
222
223
  <!--help-info !-->
@@ -327,7 +328,7 @@ fotolab watermark -h
327
328
  usage: fotolab watermark [-h] [-t WATERMARK_TEXT]
328
329
  [-p {top-left,top-right,bottom-left,bottom-right}]
329
330
  [-pd PADDING] [-fs FONT_SIZE] [-fc FONT_COLOR]
330
- [-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR]
331
+ [-ow OUTLINE_WIDTH] [-oc OUTLINE_COLOR] [--camera]
331
332
  IMAGE_FILENAMES [IMAGE_FILENAMES ...]
332
333
 
333
334
  positional arguments:
@@ -354,6 +355,7 @@ options:
354
355
  -oc OUTLINE_COLOR, --outline-color OUTLINE_COLOR
355
356
  set the outline color of the watermark text (default:
356
357
  'black')
358
+ --camera use camera metadata as watermark
357
359
  ```
358
360
 
359
361
  <!--help-watermark !-->
@@ -0,0 +1,19 @@
1
+ fotolab/__init__.py,sha256=XvtFiEJ4C6qZB4LfH3agFbx98-wD8x7tEH50NSKU8iE,2061
2
+ fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
3
+ fotolab/animate.py,sha256=ejimhTozo9DN7BbqqcV4x8zLnanZRKq1pxBBFeOdr6Q,2967
4
+ fotolab/auto.py,sha256=SmEEbTXFiP1BiqaAFxPNTcGguVSUbAmLbSuWf_LgsBY,2270
5
+ fotolab/border.py,sha256=5ch2d7LVPhB2OFuuXSW5ci6Cn967CPDQu0qSfaO7uMg,3591
6
+ fotolab/cli.py,sha256=FBFSeMNqcOiJ6MuAcy0qUvc9cscdFUG946HlWZXBPtY,4984
7
+ fotolab/contrast.py,sha256=l7Bs5p8W8ypN9Cg3fFHnU-A20UwMKtjTiPk6D0PRwpM,2095
8
+ fotolab/env.py,sha256=fzUoRWgYEiYJIWYEiiSLEb7dH_xVUOnhMpQgc1yjrTY,1457
9
+ fotolab/info.py,sha256=kbKMIqdkK-Wn2lWLvnFL_Efc45K9KCaR_euTv9LIGzw,2256
10
+ fotolab/montage.py,sha256=lUVY-zDSH7mwH-s34_XefdNp7CoDJHkwpbTUGiyJGgs,2037
11
+ fotolab/resize.py,sha256=cvPfh4wUfydM23Do7VnP6Bx2EqMHKfYFYrpiNhyWzCU,3259
12
+ fotolab/rotate.py,sha256=l_vQgf0IcI8AR1TSVsk4PrMZtJ3j_wpU77rKiGJ-KTA,1715
13
+ fotolab/sharpen.py,sha256=wUPtJdtB6mCRmcHrA0CoEVO0O0ROBJWhejTvUeL67QU,2655
14
+ fotolab/watermark.py,sha256=WlZF6aV1iR6Bh6Y3pXLvCFyLkpo-IHyKbS4UlUcvhNU,7382
15
+ fotolab-0.18.1.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
16
+ fotolab-0.18.1.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
17
+ fotolab-0.18.1.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
18
+ fotolab-0.18.1.dist-info/METADATA,sha256=LdK1HE2kcKwjLyEeci6Rr5ax_0I-Buhvl1LrY6Z3LsY,10676
19
+ fotolab-0.18.1.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- fotolab/__init__.py,sha256=qP6gvbqFk1sDJ5TBEb93V94RXlDx6CLNo3Td6D-12nQ,2062
2
- fotolab/__main__.py,sha256=aboOURPs_snOXTEWYR0q8oq1UTY9e-NxCd1j33V0wHI,833
3
- fotolab/animate.py,sha256=ejimhTozo9DN7BbqqcV4x8zLnanZRKq1pxBBFeOdr6Q,2967
4
- fotolab/auto.py,sha256=1Toxe8pA_tq15g1-imMFuHf1L94Ac7EthPTu7E8SAzE,2217
5
- fotolab/border.py,sha256=5ch2d7LVPhB2OFuuXSW5ci6Cn967CPDQu0qSfaO7uMg,3591
6
- fotolab/cli.py,sha256=XENJqvvMxOTHVYfch8gZJhkzGxhex0LUAe75ISNNWPo,5032
7
- fotolab/contrast.py,sha256=l7Bs5p8W8ypN9Cg3fFHnU-A20UwMKtjTiPk6D0PRwpM,2095
8
- fotolab/env.py,sha256=u63uuy1LG9bXy5Q-x1JfPiQaGCGwTYy-GJmWtzSkeFc,1477
9
- fotolab/info.py,sha256=DawXTQJiQDBwy0Ml5Ysk8MvKga3ikp_aIw73AR3LdZo,1687
10
- fotolab/montage.py,sha256=lUVY-zDSH7mwH-s34_XefdNp7CoDJHkwpbTUGiyJGgs,2037
11
- fotolab/resize.py,sha256=cvPfh4wUfydM23Do7VnP6Bx2EqMHKfYFYrpiNhyWzCU,3259
12
- fotolab/rotate.py,sha256=l_vQgf0IcI8AR1TSVsk4PrMZtJ3j_wpU77rKiGJ-KTA,1715
13
- fotolab/sharpen.py,sha256=wUPtJdtB6mCRmcHrA0CoEVO0O0ROBJWhejTvUeL67QU,2655
14
- fotolab/watermark.py,sha256=JnCIB--WZ2COG1BNrFY14GaWznz7BqBlwOVz4uW8H3Q,6546
15
- fotolab-0.16.17.dist-info/entry_points.txt,sha256=mvw7AY_yZkIyjAxPtHNed9X99NZeLnMxEeAfEJUbrCM,44
16
- fotolab-0.16.17.dist-info/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
17
- fotolab-0.16.17.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
18
- fotolab-0.16.17.dist-info/METADATA,sha256=f8SorvhIK70fPa4tyenLO4Nr6RN44gRtfu8wHQJaXk8,10549
19
- fotolab-0.16.17.dist-info/RECORD,,