Feature/gui
This commit is contained in:
parent
c36ab9b733
commit
1512e8efeb
15 changed files with 2328 additions and 299 deletions
|
@ -1,6 +1,7 @@
|
|||
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
|
||||
import piexif
|
||||
import time
|
||||
from fractions import Fraction
|
||||
|
||||
class ImageProcessor:
|
||||
"""Functions using pillow are in here."""
|
||||
|
@ -38,15 +39,17 @@ class ImageProcessor:
|
|||
resized_image = image.resize((new_size),resample=Image.Resampling.NEAREST)
|
||||
return resized_image
|
||||
|
||||
def add_watermark(self, image, text, font_size_scale = 70):
|
||||
def add_watermark(self, image, text, font_size_percentage):
|
||||
# Still not happy about this function..
|
||||
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
|
||||
font_size = imagewidth * (font_size_percentage / 100)
|
||||
|
||||
try: # Try loading front, if notaviable return unmodified image
|
||||
font = ImageFont.truetype("OpenDyslexic3-Regular.ttf", font_size)
|
||||
except:
|
||||
print("Error loading font for watermark, please ensure font is installed...\n")
|
||||
font = ImageFont.load_default(font_size)
|
||||
except Exception as e:
|
||||
print(f"Error {e}\nloading font for watermark, please ensure font is installed...\n")
|
||||
time.sleep(0.1)
|
||||
return image
|
||||
|
||||
|
@ -55,16 +58,16 @@ class ImageProcessor:
|
|||
y = imageheight - textheight - margin
|
||||
|
||||
# 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))
|
||||
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))
|
||||
drawer.text((x, y), text, font = font, fill = (255, 255, 255))
|
||||
|
||||
return image
|
||||
|
||||
def save_image(self, image, path, file_type, jpg_quality, png_compressing, optimize, exif_data = None):
|
||||
def save_image(self, image, path, file_type, jpg_quality, png_compressing, optimize, exif_data):
|
||||
# partly optimized by chatGPT
|
||||
"""
|
||||
Save an image to the specified path with optional EXIF data and optimization.
|
||||
|
@ -72,7 +75,7 @@ class ImageProcessor:
|
|||
file_type = file_type.lower()
|
||||
save_params = {"optimize": optimize}
|
||||
# Add file-specific parameters
|
||||
if file_type == "jpg":
|
||||
if file_type == "jpg" or "webp":
|
||||
save_params["quality"] = jpg_quality
|
||||
elif file_type == "png":
|
||||
save_params["compress_level"] = png_compressing
|
||||
|
@ -102,21 +105,97 @@ class ExifHandler:
|
|||
"""Build a piexif-compatible EXIF dictionary from user data."""
|
||||
# Mostly made by ChatGPT, some adjustment
|
||||
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.Make: user_data["make"].encode("utf-8"),
|
||||
piexif.ImageIFD.Model: user_data["model"].encode("utf-8"),
|
||||
piexif.ImageIFD.Software: user_data["software"].encode("utf-8"),
|
||||
piexif.ImageIFD.Copyright: user_data["copyright_info"].encode("utf-8"),
|
||||
piexif.ImageIFD.Artist: user_data["artist"].encode("utf-8"),
|
||||
piexif.ImageIFD.ImageDescription: user_data["image_description"].encode("utf-8"),
|
||||
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.UserComment: user_data["user_comment"].encode("utf-8"),
|
||||
piexif.ExifIFD.ISOSpeedRatings: int(user_data["iso"].encode("utf-8")),
|
||||
piexif.ExifIFD.PixelXDimension: imagesize[0],
|
||||
piexif.ExifIFD.PixelYDimension: imagesize[1],
|
||||
}
|
||||
if "date_time_original" in user_data:
|
||||
exif_ifd[piexif.ExifIFD.DateTimeOriginal] = user_data["date_time_original"].encode("utf-8")
|
||||
|
||||
return {"0th": zeroth_ifd, "Exif": exif_ifd}
|
||||
|
||||
def deg_to_dms(self, decimal_coordinate, cardinal_directions):
|
||||
"""
|
||||
This function converts decimal coordinates into the DMS (degrees, minutes and seconds) format.
|
||||
It also determines the cardinal direction of the coordinates.
|
||||
|
||||
:param decimal_coordinate: the decimal coordinates, such as 34.0522
|
||||
:param cardinal_directions: the locations of the decimal coordinate, such as ["S", "N"] or ["W", "E"]
|
||||
:return: degrees, minutes, seconds and compass_direction
|
||||
:rtype: int, int, float, string
|
||||
"""
|
||||
if decimal_coordinate < 0:
|
||||
compass_direction = cardinal_directions[0]
|
||||
elif decimal_coordinate > 0:
|
||||
compass_direction = cardinal_directions[1]
|
||||
else:
|
||||
compass_direction = ""
|
||||
degrees = int(abs(decimal_coordinate))
|
||||
decimal_minutes = (abs(decimal_coordinate) - degrees) * 60
|
||||
minutes = int(decimal_minutes)
|
||||
seconds = Fraction((decimal_minutes - minutes) * 60).limit_denominator(100)
|
||||
return degrees, minutes, seconds, compass_direction
|
||||
|
||||
def dms_to_exif_format(self, dms_degrees, dms_minutes, dms_seconds):
|
||||
"""
|
||||
This function converts DMS (degrees, minutes and seconds) to values that can
|
||||
be used with the EXIF (Exchangeable Image File Format).
|
||||
|
||||
:param dms_degrees: int value for degrees
|
||||
:param dms_minutes: int value for minutes
|
||||
:param dms_seconds: fractions.Fraction value for seconds
|
||||
:return: EXIF values for the provided DMS values
|
||||
:rtype: nested tuple
|
||||
"""
|
||||
exif_format = (
|
||||
(dms_degrees, 1),
|
||||
(dms_minutes, 1),
|
||||
(int(dms_seconds.limit_denominator(100).numerator), int(dms_seconds.limit_denominator(100).denominator))
|
||||
)
|
||||
return exif_format
|
||||
|
||||
def add_geolocation_to_exif(self, exif_data, latitude, longitude):
|
||||
"""
|
||||
https://stackoverflow.com/questions/77015464/adding-exif-gps-data-to-jpg-files-using-python-and-piexif
|
||||
This function adds GPS values to an image using the EXIF format.
|
||||
This fumction calls the functions deg_to_dms and dms_to_exif_format.
|
||||
|
||||
:param image_path: image to add the GPS data to
|
||||
:param latitude: the north–south position coordinate
|
||||
:param longitude: the east–west position coordinate
|
||||
"""
|
||||
# converts the latitude and longitude coordinates to DMS
|
||||
latitude_dms = self.deg_to_dms(latitude, ["S", "N"])
|
||||
longitude_dms = self.deg_to_dms(longitude, ["W", "E"])
|
||||
|
||||
# convert the DMS values to EXIF values
|
||||
exif_latitude = self.dms_to_exif_format(latitude_dms[0], latitude_dms[1], latitude_dms[2])
|
||||
exif_longitude = self.dms_to_exif_format(longitude_dms[0], longitude_dms[1], longitude_dms[2])
|
||||
|
||||
try:
|
||||
# https://exiftool.org/TagNames/GPS.html
|
||||
# Create the GPS EXIF data
|
||||
coordinates = {
|
||||
piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
|
||||
piexif.GPSIFD.GPSLatitude: exif_latitude,
|
||||
piexif.GPSIFD.GPSLatitudeRef: latitude_dms[3],
|
||||
piexif.GPSIFD.GPSLongitude: exif_longitude,
|
||||
piexif.GPSIFD.GPSLongitudeRef: longitude_dms[3]
|
||||
}
|
||||
# Update the EXIF data with the GPS information
|
||||
exif_data["GPS"] = coordinates
|
||||
|
||||
return exif_data
|
||||
except Exception as e:
|
||||
print(f"Error: {str(e)}")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue