You've already forked Openterface_assets
mirror of
https://github.com/TechxArtisanStudio/Openterface_assets.git
synced 2025-12-17 14:02:32 -08:00
282 lines
9.5 KiB
Python
Executable File
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()
|
|
|