Skip to content

Instantly share code, notes, and snippets.

@Gowee
Created February 3, 2024 05:24
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 Gowee/c078343b6058f4acc90e751456e17e38 to your computer and use it in GitHub Desktop.
Save Gowee/c078343b6058f4acc90e751456e17e38 to your computer and use it in GitHub Desktop.
Add a date stamp to photos
#!/usr/bin/env python3
import sys
from PIL import Image, ImageDraw, ImageFont
from PIL.ExifTags import TAGS, GPSTAGS
from datetime import date, datetime, timezone
def calculate_crop_dimensions(image, ratio=3/2):
width, height = image.size
l = width > height # is landscape
if not l:
width, height = height, width
width, height = min(width, height * ratio), min(height, width / ratio)
if not l:
width, height = height, width
return width, height
# if width > height:
# return (width, int(width * 2/3)) # Landscape, crop to 3:2
# else:
# return (int(height * 3/2), height) # Portrait, crop to 2:3
def adjust_orientation(image):
# Check the orientation from Exif data
try:
exif_data = image.getexif()
if exif_data is not None:
orientation = exif_data.get(0x0112, 1)
if orientation == 3:
# Rotate 180 degrees
return 180
elif orientation == 6:
# Rotate 90 degrees clockwise
return 270
elif orientation == 8:
# Rotate 90 degrees counter-clockwise
return 90
except (AttributeError, KeyError, IndexError, TypeError):
print("Error extracting or processing EXIF orientation.")
# Default rotation (0 degrees)
return 0
def extract_timestamp(image):
try:
# Get EXIF information
exif_data = image.getexif()
if exif_data is not None:
print(exif_data)
exif_info = {TAGS[key]: exif_data[key] for key in exif_data.keys() if key in TAGS}
print(exif_info)
if date_taken := exif_info.get('DateTimeOriginal', exif_info.get('DateTime', None)):
# Convert date string to datetime object
date_obj = datetime.strptime(date_taken, '%Y:%m:%d %H:%M:%S')
return date_obj
elif 'GPSInfo' in exif_info:
gps_data = exif_data.get_ifd(next(key for key, value in TAGS.items() if value == "GPSInfo")) #(exif_info['GPSInfo']))
gps_info = {GPSTAGS.get(key, key): value for key, value in gps_data.items()}
date_obj = datetime(*map(int, gps_info['GPSDateStamp'].split(":")), *map(int, gps_info['GPSTimeStamp']), tzinfo=timezone.utc).astimezone()
return date_obj
except Exception as e:
print(f"Error extracting EXIF information: {e}")
raise e
def add_date_watermark(image, font_path='/home/lotus/Downloads/Date-Stamp-Font/Date Stamp Bold.otf'):
# draw = ImageDraw.Draw(image)
date_taken = extract_timestamp(image)
if date_taken:
# Format the date
date_text = date_taken.strftime('%Y.%m.%d %H:%M')
# Determine base point size
r = max(image.height, image.width) * 0.001
# Choose font and size
font_size = 30 * r
font = ImageFont.truetype(font_path, font_size)
# Create a blank image to draw the rotated text
temp_image = Image.new('RGBA', image.size, (0, 0, 0, 0))
temp_draw = ImageDraw.Draw(temp_image)
# Calculate angle based on EXIF orientation
orientation = adjust_orientation(image)
angle = {
0: 0,
90: 270,
180: 180,
270: 90
}.get(orientation, 0)
# Draw text on the temporary image, rotated if needed
temp_draw.text((0, 0), date_text, font=font, fill='#e5711f')
# Calculate text size
text_width, text_height = temp_draw.textlength(date_text, font=font), font_size
print(image.width, image.height, text_width, text_height)
temp_image = temp_image.crop((0, 0, text_width, text_height))
temp_image = temp_image.rotate(angle, expand=True)
#temp_image.show()
# Calculate position for the watermark (right-bottom corner)
# position = (temp_image.width - text_width - 300, temp_image.height - text_height - 300)
dx = 10 * r
dy = 10 * r
if orientation == 90:
position = (dx, image.height - text_width - dy)
elif orientation == 180:
position = (dx, dy)
elif orientation == 270:
position = (image.width - text_height - dx, dy)
else:
position = (image.width - text_width - dx, image.height - text_height - dy)
position = tuple(int(t) for t in position)
# Paste the temporary image onto the original image
image.paste(temp_image, position, temp_image)
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python script.py input_path output_path")
sys.exit(1)
input_path = sys.argv[1]
output_path = sys.argv[2]
# Open the image
image = Image.open(input_path)
# Calculate crop dimensions
crop_dimensions = calculate_crop_dimensions(image)
# print(image.size, calculate_crop_dimensions(image))
dw = image.width - crop_dimensions[0]
dh = image.height - crop_dimensions[1]
# Crop the image
image = image.crop((dw / 2, dh / 2, dw / 2 + crop_dimensions[0], dh / 2 + crop_dimensions[1]))
# image = image.crop((0, 0, crop_dimensions[0], crop_dimensions[1]))
# Add date watermark
add_date_watermark(image)
# Save the result
image.save(output_path, exif=image.info['exif'], quality=95)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment