-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimage-resizer.py
More file actions
108 lines (87 loc) · 3.75 KB
/
image-resizer.py
File metadata and controls
108 lines (87 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python3
"""
Bulk Image Resizer — Resize all images in a directory to a given max width/height.
Usage:
python image-resizer.py <input_dir> [--width 800] [--height 600] [--output output_dir]
python image-resizer.py <input_dir> --percent 50
Options:
--width W Max width in pixels (default: 800)
--height H Max height in pixels (default: 600)
--percent P Resize by percentage (overrides width/height)
--output DIR Output directory (default: <input_dir>/resized)
--keep-aspect Maintain aspect ratio (default: True)
--help Show this help message and exit
Requirements:
pip install Pillow
"""
import os
import sys
import argparse
from pathlib import Path
try:
from PIL import Image
except ImportError:
print("Error: Pillow is required. Install with: pip install Pillow")
sys.exit(1)
SUPPORTED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".webp"}
def resize_image(img_path: Path, out_path: Path, width: int, height: int,
percent: float | None, keep_aspect: bool) -> bool:
"""Resize a single image and save to out_path."""
try:
img = Image.open(img_path)
orig_w, orig_h = img.size
if percent is not None:
new_w = int(orig_w * percent / 100)
new_h = int(orig_h * percent / 100)
elif keep_aspect:
ratio = min(width / orig_w, height / orig_h)
new_w = int(orig_w * ratio)
new_h = int(orig_h * ratio)
else:
new_w, new_h = width, height
resized = img.resize((new_w, new_h), Image.LANCZOS)
out_path.parent.mkdir(parents=True, exist_ok=True)
resized.save(out_path)
print(f" ✓ {img_path.name} {orig_w}x{orig_h} → {new_w}x{new_h}")
return True
except Exception as e:
print(f" ✗ {img_path.name} ERROR: {e}")
return False
def main():
parser = argparse.ArgumentParser(
description="Bulk resize images in a directory.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=(
"Examples:\n"
" python image-resizer.py ./photos --width 1280 --height 720\n"
" python image-resizer.py ./photos --percent 50\n"
" python image-resizer.py ./photos --output ./small_photos\n"
),
)
parser.add_argument("input_dir", help="Directory containing images")
parser.add_argument("--width", type=int, default=800, help="Max width (default: 800)")
parser.add_argument("--height", type=int, default=600, help="Max height (default: 600)")
parser.add_argument("--percent", type=float, help="Resize by percentage (overrides width/height)")
parser.add_argument("--output", help="Output directory (default: <input_dir>/resized)")
parser.add_argument("--keep-aspect", action="store_true", default=True, help="Maintain aspect ratio")
args = parser.parse_args()
input_path = Path(args.input_dir)
if not input_path.is_dir():
print(f"Error: '{args.input_dir}' is not a valid directory.")
sys.exit(1)
out_dir = Path(args.output) if args.output else input_path / "resized"
images = [f for f in input_path.iterdir()
if f.suffix.lower() in SUPPORTED_EXTENSIONS]
if not images:
print(f"No supported images found in '{input_path}'.")
print(f"Supported: {', '.join(SUPPORTED_EXTENSIONS)}")
sys.exit(0)
print(f"Resizing {len(images)} image(s)...")
success = 0
for img_path in images:
if resize_image(img_path, out_dir / img_path.name,
args.width, args.height, args.percent, args.keep_aspect):
success += 1
print(f"\nDone: {success}/{len(images)} resized → {out_dir}")
if __name__ == "__main__":
main()