Геотеггинг JPEG с pyexiv2
Я выполняю геотеггинг JPEG-файлов с помощью модуля Pyexiv2 Python, используя код, который я нашел в другом ответе SO (см.: Каков лучший способ геотегирования jpeg-изображений с помощью Python?), И у меня возник вопрос о значении GPSTag.
Код, приведенный в ответе, имеет следующие строки:
exiv_image["Exif.Image.GPSTag"] = 654
exiv_image["Exif.GPSInfo.GPSMapDatum"] = "WGS-84"
exiv_image["Exif.GPSInfo.GPSVersionID"] = '2 0 0 0'
Я просмотрел документацию по Exiv2 и нашел описания GPSTag, GPSMapDatum и GPSVersionID, но все еще не уверен в значении GPSTag.
Из документации написано:
Указатель на GPS Info IFD. В структуре взаимодействия GPS Info IFD, как и в Exif IFD, нет данных изображения.
Это описание на самом деле не объясняет, как определить, какое значение использовать, и я не смог найти лучшего описания GPSTag онлайн.
Итак, мои вопросы:
- Учитывая новое изображение, как вы определяете значение Exif.Image.GPSTag?
- Почему в примере кода используется значение 654 (на этот вопрос может быть дан ответ на первый вопрос)?
Спасибо за вашу помощь.
2 ответа
Лучший способ геотегить фотографии с помощью pyexiv2, безусловно, с моей программой, GottenGeography;-)
Но если серьезно, если вы хотите получить доступ к данным GPS из pyexiv2, этот код выглядит следующим образом:
GPS = 'Exif.GPSInfo.GPS'
try:
self.latitude = dms_to_decimal(
*self.exif[GPS + 'Latitude'].value +
[self.exif[GPS + 'LatitudeRef'].value]
)
self.longitude = dms_to_decimal(
*self.exif[GPS + 'Longitude'].value +
[self.exif[GPS + 'LongitudeRef'].value]
)
except KeyError:
pass
try:
self.altitude = float(self.exif[GPS + 'Altitude'].value)
if int(self.exif[GPS + 'AltitudeRef'].value) > 0:
self.altitude *= -1
except KeyError:
pass
И письмо выглядит так:
self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1'
self.exif[GPS + 'Altitude'] = Fraction(self.altitude)
self.exif[GPS + 'Latitude'] = decimal_to_dms(self.latitude)
self.exif[GPS + 'LatitudeRef'] = 'N' if self.latitude >= 0 else 'S'
self.exif[GPS + 'Longitude'] = decimal_to_dms(self.longitude)
self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W'
self.exif[GPS + 'MapDatum'] = 'WGS-84'
С этими функциями поддержки:
class Fraction(fractions.Fraction):
"""Only create Fractions from floats.
>>> Fraction(0.3)
Fraction(3, 10)
>>> Fraction(1.1)
Fraction(11, 10)
"""
def __new__(cls, value, ignore=None):
"""Should be compatible with Python 2.6, though untested."""
return fractions.Fraction.from_float(value).limit_denominator(99999)
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
"""Convert degrees, minutes, seconds into decimal degrees.
>>> dms_to_decimal(10, 10, 10)
10.169444444444444
>>> dms_to_decimal(8, 9, 10, 'S')
-8.152777777777779
"""
return (-1 if sign[0] in 'SWsw' else 1) * (
float(degrees) +
float(minutes) / 60 +
float(seconds) / 3600
)
def decimal_to_dms(decimal):
"""Convert decimal degrees into degrees, minutes, seconds.
>>> decimal_to_dms(50.445891)
[Fraction(50, 1), Fraction(26, 1), Fraction(113019, 2500)]
>>> decimal_to_dms(-125.976893)
[Fraction(125, 1), Fraction(58, 1), Fraction(92037, 2500)]
"""
remainder, degrees = math.modf(abs(decimal))
remainder, minutes = math.modf(remainder * 60)
return [Fraction(n) for n in (degrees, minutes, remainder * 60)]
Хотя в настоящее время я работаю над альтернативой pyexiv2, которая использует интроспекцию GObject для гораздо более прямого доступа к библиотеке exiv2, называемой GExiv2, и хотела бы получить некоторую обратную связь по ней. И gexiv2, и pyexiv2 являются оболочками вокруг одной и той же библиотеки exiv2, но разница в том, что pyexiv2 - очень большой проект с большим количеством клея, работает только на python и находится на грани отказа *; в то время как gexiv2 легок и проворен, доступен из любого языка программирования и поддерживается в хорошем состоянии благодаря его использованию Shotwell.
Надеюсь это поможет!
* pyexiv2's author, Olivier Tilloy, has asked me for help with maintainership as he no longer has much time
Моя версия, немного длинная...
from fractions import Fraction
import pyexiv2
try:
metadata = pyexiv2.metadata.ImageMetadata(image_file)
metadata.read();
thumb = metadata.exif_thumbnail
try:
latitude = metadata.__getitem__("Exif.GPSInfo.GPSLatitude")
latitudeRef = metadata.__getitem__("Exif.GPSInfo.GPSLatitudeRef")
longitude = metadata.__getitem__("Exif.GPSInfo.GPSLongitude")
longitudeRef = metadata.__getitem__("Exif.GPSInfo.GPSLongitudeRef")
latitude = str(latitude).split("=")[1][1:-1].split(" ");
latitude = map(lambda f: str(float(Fraction(f))), latitude)
latitude = latitude[0] + u"\u00b0" + latitude[1] + "'" + latitude[2] + '"' + " " + str(latitudeRef).split("=")[1][1:-1]
longitude = str(longitude).split("=")[1][1:-1].split(" ");
longitude = map(lambda f: str(float(Fraction(f))), longitude)
longitude = longitude[0] + u"\u00b0" + longitude[1] + "'" + longitude[2] + '"' + " " + str(longitudeRef).split("=")[1][1:-1]
latitude_value = dms_to_decimal(*metadata.__getitem__("Exif.GPSInfo.GPSLatitude").value + [metadata.__getitem__("Exif.GPSInfo.GPSLatitudeRef").value]);
longitude_value = dms_to_decimal(*metadata.__getitem__("Exif.GPSInfo.GPSLongitude").value + [metadata.__getitem__("Exif.GPSInfo.GPSLongitudeRef").value]);
print "--- GPS ---"
print "Coordinates: " + latitude + ", " + longitude
print "Coordinates: " + str(latitude_value) + ", " + str(longitude_value)
print "--- GPS ---"
except Exception, e:
print "No GPS Information!"
#print e
# Check for thumbnail
if(thumb.data == ""):
print "No thumbnail!"
except Exception, e:
print "Error processing image..."
print e;