Last active
November 4, 2023 09:46
-
-
Save antonsteenvoorden/228b239a880f2aec831ec6d13eb5a205 to your computer and use it in GitHub Desktop.
Resize image to 1920 width or height, depending on orientation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
import os | |
import math | |
import argparse | |
from PIL import Image | |
from pathlib import Path | |
import tkinter | |
from tkinter import filedialog | |
# Set the target limits for resize | |
TARGET_WIDTH = 1920 | |
TARGET_HEIGHT = 1080 | |
def get_date_taken(path): | |
exif = Image.open(path)._getexif() | |
if not exif: | |
raise Exception('Image {0} does not have EXIF data.'.format(path)) | |
return exif[36867] | |
def resize_width(image, size, resample=Image.LANCZOS): | |
""" | |
Resize image according to size. | |
image: a Pillow image instance | |
size: an integer or a list or tuple of two integers [width, height] | |
""" | |
try: | |
width = size[0] | |
except: | |
width = size | |
img_format = image.format | |
img = image.copy() | |
img_size = img.size | |
if img_size[0] == width: | |
return image | |
new_height = int(math.ceil((width / img_size[0]) * img_size[1])) | |
img.thumbnail((width, new_height), resample) | |
img.format = img_format | |
return img | |
def resize_height(image, size, resample=Image.LANCZOS): | |
""" | |
Resize image according to size. | |
image: a Pillow image instance | |
size: an integer or a list or tuple of two integers [width, height] | |
""" | |
try: | |
height = size[1] | |
except: | |
height = size | |
img_format = image.format | |
img = image.copy() | |
img_size = img.size | |
if img_size[1] == height: | |
return image | |
new_width = int(math.ceil((height / img_size[1]) * img_size[0])) | |
img.thumbnail((new_width, height), resample) | |
img.format = img_format | |
return img | |
def resize_folder(input_folder, output_folder): | |
folder_length = len(list(input_folder.iterdir())) | |
processed = 0 | |
for entry in input_folder.iterdir(): | |
processed += 1 | |
if not entry.is_file(): | |
continue | |
output_path = output_folder / entry.name | |
try: | |
image = Image.open(entry) | |
except: | |
print(f"{processed}/{folder_length} Skip Processing {entry}") | |
continue | |
# Process metadata | |
image_exif = image.getexif() | |
if image_exif.get(306, None): | |
# Format is like '2023:08:30 20:09:08' | |
unparsed = image_exif[306] | |
parsed_date = datetime.datetime.strptime(unparsed, "%Y:%m:%d %H:%M:%S") | |
else: | |
parsed_date = datetime.datetime.now() | |
width, height = image.size | |
ratio = height / width | |
if width < TARGET_WIDTH and height < TARGET_HEIGHT: | |
print(f"{processed}/{folder_length} Processing {entry} - no change {width}x{height}") | |
try: | |
image.save(output_path, format=image.format, optimize=True, exif=image_exif, creationDate=parsed_date) | |
except TypeError: | |
image.save(output_path, format=image.format, optimize=True, creationDate=parsed_date) | |
continue | |
if width > TARGET_WIDTH and height > TARGET_HEIGHT: | |
# Tall picture - use y for scale | |
if ratio > 1.0: | |
resized = resize_height(image, TARGET_WIDTH) # Make it as tall as normally is wide | |
else: | |
resized = resize_width(image, TARGET_WIDTH) | |
new_width, new_height = resized.size | |
print( | |
f"{processed}/{folder_length} Processing {entry} - scaling down from {width}x{height} to {new_width}x{new_height}" | |
) | |
image = resized | |
else: | |
# already right size | |
print(f"{processed}/{folder_length} Processing {entry} - no change {width}x{height}") | |
try: | |
image.save(output_path, format=image.format, optimize=True, exif=image_exif, creationDate=parsed_date) | |
except TypeError: | |
image.save(output_path, format=image.format, optimize=True, creationDate=parsed_date) | |
# Set the creation and modification datetime of the file to the original | |
os.utime(output_path, (parsed_date.timestamp(), parsed_date.timestamp())) | |
if __name__ == '__main__': | |
args = argparse.ArgumentParser() | |
args.add_argument("-i", dest="input_folder", type=str, default="") | |
args.add_argument("-r", dest="recursive", action="store_true") | |
arguments = args.parse_args() | |
root = tkinter.Tk() | |
root.withdraw() | |
input_folder = filedialog.askdirectory() | |
input_folder = Path(input_folder) | |
if input_folder == Path("."): | |
raise ValueError("Input folder is folder of script. Double check value.") | |
if arguments.recursive: | |
print("Resizing all folders from the selected folder") | |
root = tkinter.Tk() | |
root.withdraw() | |
general_output_folder = filedialog.askdirectory() | |
general_output_folder = Path(general_output_folder) | |
print(f"{general_output_folder=}") | |
folders = list(input_folder.iterdir()) | |
for entry in folders: | |
print(f"Input folder: {input_folder}") | |
if entry.is_file(): | |
continue | |
output_folder = general_output_folder / entry.name | |
output_folder.mkdir(exist_ok=True) | |
print(f"Resizing from {entry} into {output_folder}") | |
resize_folder(entry, output_folder) | |
else: | |
print(f"Input folder: {input_folder}") | |
output_folder = input_folder.parent / f"{input_folder.name} resized" | |
output_folder.mkdir(exist_ok=True) | |
resize_folder(input_folder, output_folder) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment