Files
Openterface_assets/image_resizer.py
2025-12-12 15:18:57 +08:00

282 lines
9.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Interactive Image Resizer
Allows you to select an image from the project, view its properties,
and resize it proportionally.
"""
import os
from pathlib import Path
from PIL import Image
import sys
# Supported image formats
SUPPORTED_FORMATS = {'.png', '.jpg', '.jpeg', '.webp', '.gif', '.bmp', '.tiff', '.tif'}
def find_images(directory):
"""Recursively find all image files in the directory."""
images = []
directory_path = Path(directory)
for ext in SUPPORTED_FORMATS:
images.extend(directory_path.rglob(f'*{ext}'))
images.extend(directory_path.rglob(f'*{ext.upper()}'))
return sorted(images)
def format_file_size(size_bytes):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB']:
if size_bytes < 1024.0:
return f"{size_bytes:.2f} {unit}"
size_bytes /= 1024.0
return f"{size_bytes:.2f} TB"
def display_image_info(image_path):
"""Display image information."""
try:
with Image.open(image_path) as img:
width, height = img.size
file_size = os.path.getsize(image_path)
print("\n" + "="*60)
print(f"Image: {image_path}")
print(f"Dimensions: {width} x {height} pixels")
print(f"File Size: {format_file_size(file_size)}")
print(f"Format: {img.format}")
print(f"Mode: {img.mode}")
print("="*60 + "\n")
return width, height, file_size
except Exception as e:
print(f"Error reading image: {e}")
return None, None, None
def resize_image_proportionally(image_path, target_width=None, target_height=None, scale_factor=None):
"""Resize image proportionally based on target width, height, or scale factor."""
try:
with Image.open(image_path) as img:
original_width, original_height = img.size
if scale_factor:
new_width = int(original_width * scale_factor)
new_height = int(original_height * scale_factor)
elif target_width:
scale = target_width / original_width
new_width = target_width
new_height = int(original_height * scale)
elif target_height:
scale = target_height / original_height
new_width = int(original_width * scale)
new_height = target_height
else:
print("Error: No resize parameter provided")
return False
print(f"\nResizing from {original_width}x{original_height} to {new_width}x{new_height}")
# Resize with high-quality resampling
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# Ask for output filename
original_path = Path(image_path)
default_name = f"{original_path.stem}_resized{original_path.suffix}"
output_name = input(f"Enter output filename (default: {default_name}): ").strip()
if not output_name:
output_name = default_name
output_path = original_path.parent / output_name
# Handle overwrite confirmation
if output_path.exists():
confirm = input(f"File {output_path} already exists. Overwrite? (y/n): ").strip().lower()
if confirm != 'y':
print("Operation cancelled.")
return False
# Save the resized image
resized_img.save(output_path, quality=95, optimize=True)
new_size = os.path.getsize(output_path)
print(f"\n✓ Image saved to: {output_path}")
print(f" New dimensions: {new_width} x {new_height} pixels")
print(f" New file size: {format_file_size(new_size)}")
return True
except Exception as e:
print(f"Error resizing image: {e}")
return False
def handle_image_resize_menu(image_path):
"""Handle the resize menu for a specific image."""
width, height, file_size = display_image_info(image_path)
if width is None:
return False
# Resize options
while True:
print("\nResize Options:")
print("1. Resize by scale factor (e.g., 0.5 for 50%, 2.0 for 200%)")
print("2. Resize by target width (maintains aspect ratio)")
print("3. Resize by target height (maintains aspect ratio)")
print("4. Exit")
resize_choice = input("\nChoose an option (1-4): ").strip()
if resize_choice == '1':
try:
scale = float(input("Enter scale factor (e.g., 0.5, 1.5, 2.0): ").strip())
if scale <= 0:
print("Scale factor must be positive.")
continue
resize_image_proportionally(image_path, scale_factor=scale)
except ValueError:
print("Invalid scale factor. Please enter a number.")
elif resize_choice == '2':
try:
target_w = int(input(f"Enter target width (current: {width}): ").strip())
if target_w <= 0:
print("Width must be positive.")
continue
resize_image_proportionally(image_path, target_width=target_w)
except ValueError:
print("Invalid width. Please enter a number.")
elif resize_choice == '3':
try:
target_h = int(input(f"Enter target height (current: {height}): ").strip())
if target_h <= 0:
print("Height must be positive.")
continue
resize_image_proportionally(image_path, target_height=target_h)
except ValueError:
print("Invalid height. Please enter a number.")
elif resize_choice == '4':
return True
else:
print("Invalid option. Please try again.")
def main():
"""Main interactive function."""
# Get the project root directory (parent of script location)
script_dir = Path(__file__).parent
project_root = script_dir
# Check if image path is provided as command-line argument
if len(sys.argv) > 1:
image_path_arg = sys.argv[1]
image_path = Path(image_path_arg)
# Handle both absolute and relative paths
if not image_path.is_absolute():
# Try relative to current directory first
if not image_path.exists():
# Try relative to project root
image_path = project_root / image_path
else:
image_path = Path(image_path_arg).resolve()
else:
image_path = Path(image_path_arg)
# Validate the image file
if not image_path.exists():
print(f"Error: Image file not found: {image_path}")
print(f"Please check the path and try again.")
sys.exit(1)
if image_path.suffix.lower() not in SUPPORTED_FORMATS:
print(f"Error: Unsupported image format: {image_path.suffix}")
print(f"Supported formats: {', '.join(sorted(SUPPORTED_FORMATS))}")
sys.exit(1)
# Direct mode: process the specified image
print("="*60)
print("Interactive Image Resizer")
print("="*60)
print(f"Processing image: {image_path}")
try:
handle_image_resize_menu(image_path)
except KeyboardInterrupt:
print("\n\nInterrupted by user. Goodbye!")
except Exception as e:
print(f"An error occurred: {e}")
sys.exit(1)
return
# Interactive mode: show menu to select image
print("="*60)
print("Interactive Image Resizer")
print("="*60)
print(f"Scanning images in: {project_root}")
# Find all images
images = find_images(project_root)
if not images:
print("No supported image files found in the project.")
return
print(f"\nFound {len(images)} image(s)\n")
while True:
# Display image list
print("\n" + "-"*60)
print("Available Images:")
print("-"*60)
for idx, img_path in enumerate(images, 1):
rel_path = img_path.relative_to(project_root)
print(f"{idx:3d}. {rel_path}")
print(f"\n{len(images) + 1:3d}. Exit")
print("-"*60)
# Get user selection
try:
choice = input(f"\nSelect an image (1-{len(images) + 1}): ").strip()
if not choice:
continue
choice_num = int(choice)
if choice_num == len(images) + 1:
print("Goodbye!")
break
if choice_num < 1 or choice_num > len(images):
print("Invalid selection. Please try again.")
continue
selected_image = images[choice_num - 1]
# Handle resize menu
handle_image_resize_menu(selected_image)
except ValueError:
print("Invalid input. Please enter a number.")
except KeyboardInterrupt:
print("\n\nInterrupted by user. Goodbye!")
break
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()