Skip to content

Instantly share code, notes, and snippets.

@antonsteenvoorden
Last active November 4, 2023 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonsteenvoorden/228b239a880f2aec831ec6d13eb5a205 to your computer and use it in GitHub Desktop.
Save antonsteenvoorden/228b239a880f2aec831ec6d13eb5a205 to your computer and use it in GitHub Desktop.
Resize image to 1920 width or height, depending on orientation
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