2024-12-17 11:25:44 +00:00
|
|
|
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
|
|
|
|
import piexif
|
2024-12-27 20:55:20 +00:00
|
|
|
import time
|
2024-12-17 11:25:44 +00:00
|
|
|
|
|
|
|
class ImageProcessor:
|
|
|
|
"""Functions using pillow are in here."""
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def open_image(self, path):
|
|
|
|
"""Open an image from path, returns image object."""
|
|
|
|
return Image.open(path)
|
|
|
|
|
|
|
|
def get_image_size(self, image):
|
|
|
|
"""Simply get image size."""
|
|
|
|
return image.size
|
|
|
|
|
|
|
|
def grayscale(self, image):
|
|
|
|
"""Change to grayscale"""
|
|
|
|
return image.convert("L")
|
|
|
|
|
|
|
|
def change_contrast(self, image, change):
|
|
|
|
enhancer = ImageEnhance.Contrast(image)
|
|
|
|
new_img = enhancer.enhance(1 + (change/100))
|
|
|
|
return new_img
|
|
|
|
|
|
|
|
def change_brightness(self, image, change):
|
|
|
|
enhancer = ImageEnhance.Brightness(image)
|
|
|
|
new_img = enhancer.enhance(1 + (change/100))
|
|
|
|
return new_img
|
|
|
|
|
|
|
|
def resize_image(self, image, percent, resample = True):
|
|
|
|
"""Resize an image by giving a percent."""
|
|
|
|
new_size = tuple(int(x * (percent / 100)) for x in image.size)
|
|
|
|
if resample:
|
|
|
|
resized_image = image.resize(new_size)
|
|
|
|
else:
|
|
|
|
resized_image = image.resize((new_size),resample=Image.Resampling.NEAREST)
|
|
|
|
return resized_image
|
|
|
|
|
|
|
|
def add_watermark(self, image, text, font_size_scale = 70):
|
|
|
|
drawer = ImageDraw.Draw(image)
|
|
|
|
imagewidth, imageheight = image.size
|
|
|
|
margin = (imageheight / 100 ) * 2 # margin dynamic, 2% of image size
|
|
|
|
font_size = imagewidth / font_size_scale # Scaling the font size
|
2024-12-27 20:55:20 +00:00
|
|
|
try: # Try loading front, if notaviable return unmodified image
|
2024-12-17 11:25:44 +00:00
|
|
|
font = ImageFont.truetype("OpenDyslexic3-Regular.ttf", font_size)
|
|
|
|
except:
|
2024-12-27 20:55:20 +00:00
|
|
|
print("Error loading font for watermark, please ensure font is installed...\n")
|
2024-12-28 10:51:18 +00:00
|
|
|
time.sleep(0.1)
|
2024-12-27 20:55:20 +00:00
|
|
|
return image
|
2024-12-17 11:25:44 +00:00
|
|
|
|
|
|
|
c, w, textwidth, textheight, = drawer.textbbox(xy = (0, 0), text = text, font = font) # Getting text size, only need the last two values
|
|
|
|
x = imagewidth - textwidth - margin
|
|
|
|
y = imageheight - textheight - margin
|
2024-12-28 10:51:18 +00:00
|
|
|
|
|
|
|
# thin border
|
|
|
|
drawer.text((x-1, y), text, font=font, fill=(64, 64, 64))
|
|
|
|
drawer.text((x+1, y), text, font=font, fill=(64, 64, 64))
|
|
|
|
drawer.text((x, y-1), text, font=font, fill=(64, 64, 64))
|
|
|
|
drawer.text((x, y+1), text, font=font, fill=(64, 64, 64))
|
|
|
|
# Adding text in the desired color
|
|
|
|
drawer.text((x, y), text, font = font, fill=(255, 255, 255))
|
2024-12-17 11:25:44 +00:00
|
|
|
|
|
|
|
return image
|
|
|
|
|
2024-12-27 20:55:20 +00:00
|
|
|
def save_image(self, image, path, file_type, jpg_quality, png_compressing, optimize, exif_data = None):
|
|
|
|
# partly optimized by chatGPT
|
|
|
|
"""
|
|
|
|
Save an image to the specified path with optional EXIF data and optimization.
|
|
|
|
"""
|
|
|
|
file_type = file_type.lower()
|
|
|
|
save_params = {"optimize": optimize}
|
|
|
|
# Add file-specific parameters
|
|
|
|
if file_type == "jpg":
|
|
|
|
save_params["quality"] = jpg_quality
|
|
|
|
elif file_type == "png":
|
|
|
|
save_params["compress_level"] = png_compressing
|
|
|
|
elif file_type not in ["webp", "jpg", "png"]:
|
|
|
|
input(f"Type: {file_type} is not supported. Press Enter to continue...")
|
|
|
|
return
|
|
|
|
# Add EXIF data if available
|
|
|
|
if exif_data is not None:
|
|
|
|
save_params["exif"] = piexif.dump(exif_data)
|
|
|
|
if file_type == "webp":
|
|
|
|
print("File format webp does not support all exif features, some information might get lost...\n")
|
|
|
|
time.sleep(0.1)
|
|
|
|
try:
|
|
|
|
image.save(f"{path}.{file_type}", **save_params)
|
|
|
|
except Exception as e:
|
|
|
|
print(f"Failed to save image: {e}")
|
2024-12-17 11:25:44 +00:00
|
|
|
|
|
|
|
class ExifHandler:
|
|
|
|
"""Function using piexif are here."""
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_exif_info(self, image):
|
|
|
|
return(piexif.load(image.info['exif']))
|
|
|
|
|
|
|
|
def build_exif_dict(self, user_data, imagesize):
|
|
|
|
"""Build a piexif-compatible EXIF dictionary from user data."""
|
2024-12-27 20:55:20 +00:00
|
|
|
# Mostly made by ChatGPT, some adjustment
|
2024-12-17 11:25:44 +00:00
|
|
|
zeroth_ifd = {
|
|
|
|
piexif.ImageIFD.Make: user_data["make"],
|
|
|
|
piexif.ImageIFD.Model: user_data["model"],
|
|
|
|
piexif.ImageIFD.Software: user_data["software"],
|
|
|
|
piexif.ImageIFD.Copyright: user_data["copyright_info"],
|
|
|
|
piexif.ImageIFD.Artist: user_data["artist"],
|
|
|
|
piexif.ImageIFD.ImageDescription: user_data["image_description"],
|
|
|
|
piexif.ImageIFD.XResolution: (72, 1),
|
|
|
|
piexif.ImageIFD.YResolution: (72, 1),
|
|
|
|
}
|
|
|
|
exif_ifd = {
|
|
|
|
piexif.ExifIFD.UserComment: user_data["user_comment"],
|
|
|
|
piexif.ExifIFD.ISOSpeedRatings: int(user_data["iso"]),
|
|
|
|
piexif.ExifIFD.PixelXDimension: imagesize[0],
|
|
|
|
piexif.ExifIFD.PixelYDimension: imagesize[1],
|
|
|
|
}
|
2024-12-27 20:55:20 +00:00
|
|
|
if "date_time_original" in user_data:
|
|
|
|
exif_ifd[piexif.ExifIFD.DateTimeOriginal] = user_data["date_time_original"].encode("utf-8")
|
2024-12-17 11:25:44 +00:00
|
|
|
return {"0th": zeroth_ifd, "Exif": exif_ifd}
|