photolib/photoapp/image.py

112 lines
3.4 KiB
Python
Raw Normal View History

2018-09-08 15:49:16 -07:00
from datetime import datetime
from PIL import Image, ExifTags
from decimal import Decimal
from hashlib import sha256
import os
import magic
from photoapp.types import Photo, PhotoSet
def get_jpg_info(fpath):
"""
Given the path to a jpg, return a dict describing it
"""
2018-09-09 13:45:26 -07:00
date, gps, dimensions, orientation = get_exif_data(fpath)
2018-09-08 15:49:16 -07:00
2018-09-09 12:05:13 -07:00
if date is None:
import pdb
pdb.set_trace()
raise Exception("fuk")
2018-09-08 15:49:16 -07:00
# gps is set to 0,0 if unavailable
lat, lon = gps or [0, 0]
2018-09-09 12:05:13 -07:00
dimensions = dimensions or (0, 0)
2018-09-08 15:49:16 -07:00
mime = magic.from_file(fpath, mime=True)
2018-09-09 12:05:13 -07:00
size = os.path.getsize(fpath)
2018-09-08 15:49:16 -07:00
2018-09-09 13:45:26 -07:00
photo = Photo(hash=get_hash(fpath), path=fpath, format=mime, size=size,
width=dimensions[0], height=dimensions[1], orientation=orientation)
2018-09-08 15:49:16 -07:00
return PhotoSet(date=date, lat=lat, lon=lon, files=[photo])
def get_mtime(fpath):
return datetime.fromtimestamp(os.stat(fpath).st_mtime)
def get_hash(path):
hasher = sha256()
with open(path, 'rb') as f:
while True:
piece = f.read(1024 * 256)
if not piece:
break
hasher.update(piece)
return hasher.hexdigest()
def get_exif_data(path):
"""
2018-09-09 13:45:26 -07:00
Return a (datetime, (decimal, decimal), (width, height), rotation) tuple describing the photo's exif date and gps coordinates
2018-09-08 15:49:16 -07:00
"""
img = Image.open(path)
2018-09-09 12:05:13 -07:00
2018-09-08 15:49:16 -07:00
datestr = None
gpsinfo = None
dateinfo = None
2018-09-09 13:45:26 -07:00
orientationinfo = 0
2018-09-09 12:05:13 -07:00
sizeinfo = (img.width, img.height)
if img.format in ["JPEG", "PNG", "GIF"]:
if hasattr(img, "_getexif"):
exif_data = img._getexif()
if exif_data:
exif = {
ExifTags.TAGS[k]: v
for k, v in exif_data.items()
if k in ExifTags.TAGS
}
acceptable = ["DateTime", "DateTimeOriginal", "DateTimeDigitized"]
for key in acceptable:
if key in exif:
datestr = exif[key]
continue
if datestr is None:
print(exif.keys())
raise Exception("{} has no DateTime".format(path)) # TODO how often do we hit this
dateinfo = datetime.strptime(datestr, "%Y:%m:%d %H:%M:%S")
2018-09-09 13:45:26 -07:00
orien = exif.get("Orientation")
if orien:
orientationinfo = {0: 0, 8: 1, 3: 2, 6: 3}.get(int(orien), 0)
2018-09-09 12:05:13 -07:00
gps = exif.get("GPSInfo")
if gps:
# see https://gis.stackexchange.com/a/273402
gps_y = round(hms_to_decimal(rational64u_to_hms(gps[2])), 8)
gps_x = round(hms_to_decimal(rational64u_to_hms(gps[4])), 8)
if gps[1] == 'S':
gps_y *= -1
if gps[3] == 'W':
gps_x *= -1
gpsinfo = (gps_y, gps_x)
if dateinfo is None:
dateinfo = get_mtime(path)
2018-09-09 13:45:26 -07:00
return dateinfo, gpsinfo, sizeinfo, orientationinfo
2018-09-08 15:49:16 -07:00
def rational64u_to_hms(values):
return [Decimal(values[0][0]) / Decimal(values[0][1]),
Decimal(values[1][0]) / Decimal(values[1][1]),
Decimal(values[2][0]) / Decimal(values[2][1])]
def hms_to_decimal(values):
return values[0] + values[1] / 60 + values[2] / 3600
2018-09-09 12:05:13 -07:00
def main():
print(get_exif_data("library/2018/9/8/MMwo4hr.jpg"))