150 lines
4.6 KiB
Python
150 lines
4.6 KiB
Python
from PIL import Image, ExifTags
|
|
from math import sqrt
|
|
from pathlib import Path
|
|
|
|
def largest_ratio_box(ratio, img):
|
|
""" Return a center rectangle box respecting the ratio inside the image.
|
|
|
|
:param ratio:
|
|
:param img: the img (from PIL.Image)
|
|
:return: (left, upper, right, lower)
|
|
"""
|
|
try:
|
|
ratio[0]
|
|
except TypeError:
|
|
r = ratio
|
|
else:
|
|
r = ratio[0]/ratio[1]
|
|
|
|
img_ratio = img.size[0] / img.size[1]
|
|
if img_ratio > r:
|
|
return (int(img.size[0]/2-r*img.size[1]/2),
|
|
0,
|
|
int(img.size[0]/2+r*img.size[1]/2),
|
|
img.size[1])
|
|
else:
|
|
return (0,
|
|
int(img.size[1]/2-img.size[0]/(r*2)),
|
|
img.size[0],
|
|
int(img.size[1]/2+img.size[0]/(r*2)))
|
|
|
|
def auto_rotate_exif(img):
|
|
""" Rotate the img corresponding to its exifdatas"""
|
|
for orientation in ExifTags.TAGS.keys():
|
|
if ExifTags.TAGS[orientation] == 'Orientation':
|
|
break
|
|
exif = dict(img._getexif().items())
|
|
|
|
if exif[orientation] == 3:
|
|
return img.rotate(180, expand=True)
|
|
elif exif[orientation] == 6:
|
|
return img.rotate(270, expand=True)
|
|
elif exif[orientation] == 8:
|
|
return img.rotate(90, expand=True)
|
|
else:
|
|
return img
|
|
|
|
def resize_to(img, megapixel=4):
|
|
""" Resize the image to an image with total_pixel number of pixels
|
|
|
|
:param img: the image
|
|
:param megapixel: number of mega pixels
|
|
"""
|
|
pixels = megapixel * 10**6
|
|
org_ratio = img.size[0]/img.size[1]
|
|
new_height = sqrt(pixels/org_ratio)
|
|
new_width = org_ratio*new_height
|
|
return img.resize((int(new_width), int(new_height)))
|
|
|
|
def fit_to(img, ratio, megapixel=4):
|
|
""" auto_rotate then crop largest_ratio_box then resize_to
|
|
if ration = 0, the image is not cropped
|
|
"""
|
|
try:
|
|
rot = auto_rotate_exif(img)
|
|
except (AttributeError, KeyError):
|
|
rot = img
|
|
if ratio == 0:
|
|
cropped = rot
|
|
else:
|
|
cropped = rot.crop(largest_ratio_box(ratio, rot))
|
|
return resize_to(cropped, megapixel)
|
|
|
|
def cut_save(src, dest, ratio=0, megapixel=1):
|
|
"""
|
|
if no ratio is given, the image is not cropped
|
|
"""
|
|
img = Image.open(src)
|
|
dest_filename = dest / rename(src, ratio)
|
|
if not dest_filename.exists():
|
|
print(f"Processing {dest_filename}")
|
|
dest_filename.parent.mkdir(parents=True, exist_ok=True)
|
|
out = fit_to(img, ratio, megapixel)
|
|
out.save(dest_filename)
|
|
else:
|
|
print(f"{dest_filename} exists skipping")
|
|
return dest_filename
|
|
|
|
def rename(src_filename, ratio):
|
|
p_src = Path(src_filename)
|
|
path = p_src.parent
|
|
filename = p_src.stem
|
|
ext = p_src.suffix
|
|
return path / (filename + f"_{int(ratio[0])}by{int(ratio[1])}" + ext)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
img = Image.open("DSCN0119.JPG")
|
|
filename = img.filename.split(".")[0]
|
|
print(filename)
|
|
print("img.size -> ", img.size)
|
|
img = auto_rotate_exif(img)
|
|
ratio = (1, 1)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|
|
|
|
ratio = (2, 1)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|
|
|
|
ratio = (1, 2)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|
|
|
|
print("--------------")
|
|
|
|
img = Image.open("IMG_2284.JPG")
|
|
filename = img.filename.split(".")[0]
|
|
print(filename)
|
|
print("img.size -> ", img.size)
|
|
img = auto_rotate_exif(img)
|
|
ratio = (1, 1)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|
|
|
|
ratio = (2, 1)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|
|
|
|
ratio = (1, 2)
|
|
print(ratio)
|
|
cropped = img.crop(largest_ratio_box(ratio, img))
|
|
cropped.save(filename+f"_crop_{ratio[0]}by{ratio[1]}.jpg")
|
|
crop_res = resize_to(cropped, 4)
|
|
crop_res.save(filename+f"_resi_{ratio[0]}by{ratio[1]}.jpg")
|