photobook/photobook/cropping.py

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")