aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOlivier Tilloy <olivier@tilloy.net>2010-01-19 19:42:25 +0100
committerOlivier Tilloy <olivier@tilloy.net>2010-01-19 19:42:25 +0100
commitbbc8f8cebe280a0bcd295839af23b2156b75eb89 (patch)
treed3aa3e0a3a0df2021179dba7c02b5ba99b9d2c1d /src
parentb7b0316bfddefb2451308f1d4ea4edf35b45ff44 (diff)
downloadpyexiv2-bbc8f8cebe280a0bcd295839af23b2156b75eb89.tar.gz
GPSCoordinate class to match the XMP GPSCoordinate type.
Diffstat (limited to 'src')
-rw-r--r--src/pyexiv2/__init__.py3
-rw-r--r--src/pyexiv2/utils.py109
-rw-r--r--src/pyexiv2/xmp.py14
3 files changed, 124 insertions, 2 deletions
diff --git a/src/pyexiv2/__init__.py b/src/pyexiv2/__init__.py
index 4a4322f..4b83d54 100644
--- a/src/pyexiv2/__init__.py
+++ b/src/pyexiv2/__init__.py
@@ -64,7 +64,8 @@ from pyexiv2.exif import ExifValueError, ExifTag
from pyexiv2.iptc import IptcValueError, IptcTag
from pyexiv2.xmp import XmpValueError, XmpTag
from pyexiv2.utils import FixedOffset, Rational, NotifyingList, \
- undefined_to_string, string_to_undefined
+ undefined_to_string, string_to_undefined, \
+ GPSCoordinate
__version__ = (0, 2, 1)
diff --git a/src/pyexiv2/utils.py b/src/pyexiv2/utils.py
index 02fca1d..09a27c9 100644
--- a/src/pyexiv2/utils.py
+++ b/src/pyexiv2/utils.py
@@ -359,3 +359,112 @@ class NotifyingList(list):
if deleted:
self._notify_listeners()
+
+class GPSCoordinate(object):
+
+ """
+ A class representing GPS coordinates (e.g. a latitude or a longitude).
+
+ Its attributes (degrees, minutes, seconds, direction) are read-only
+ properties.
+ """
+
+ _format_re = \
+ re.compile(r'(?P<degrees>-?\d+),'
+ '(?P<minutes>\d+)(,(?P<seconds>\d+)|\.(?P<fraction>\d+))'
+ '(?P<direction>[NSEW])')
+
+ def __init__(self, degrees, minutes, seconds, direction):
+ """
+ Constructor.
+
+ @param degrees: degrees
+ @type degrees: C{int}
+ @param minutes: minutes
+ @type minutes: C{int}
+ @param seconds: seconds
+ @type seconds: C{int}
+ @param direction: direction ('N', 'S', 'E' or 'W')
+ @type direction: C{str}
+ """
+ if degrees < 0 or degrees > 90:
+ raise ValueError()
+ self._degrees = degrees
+ if minutes < 0 or minutes > 60:
+ raise ValueError()
+ self._minutes = minutes
+ if seconds < 0 or seconds > 60:
+ raise ValueError()
+ self._seconds = seconds
+ if direction not in ('N', 'S', 'E', 'W'):
+ raise ValueError()
+ self._direction = direction
+
+ @property
+ def degrees(self):
+ return self._degrees
+
+ @property
+ def minutes(self):
+ return self._minutes
+
+ @property
+ def seconds(self):
+ return self._seconds
+
+ @property
+ def direction(self):
+ return self._direction
+
+ @staticmethod
+ def from_string(string):
+ """
+ Instantiate a GPSCoordinate from a string formatted as C{DDD,MM,SSk} or
+ C{DDD,MM.mmk} where C{DDD} is a number of degrees, C{MM} is a number of
+ minutes, C{SS} is a number of seconds, C{mm} is a fraction of minutes,
+ and C{k} is a single character C{N}, C{S}, C{E}, or C{W} indicating a
+ direction (north, south, east, west).
+
+ @param string: a string representation of a GPS coordinate
+ @type string: C{str}
+
+ @return: the GPS coordinate parsed
+ @rtype: L{GPSCoordinate}
+
+ @raise ValueError: if the format of the string is invalid
+ """
+ match = GPSCoordinate._format_re.match(string)
+ if match is None:
+ raise ValueError('Invalid format for a GPS coordinate: %s' % string)
+ gd = match.groupdict()
+ fraction = gd['fraction']
+ if fraction is not None:
+ seconds = int(round(int(fraction[:2]) * 0.6))
+ else:
+ seconds = int(gd['seconds'])
+ return GPSCoordinate(int(gd['degrees']), int(gd['minutes']), seconds,
+ gd['direction'])
+
+ def __eq__(self, other):
+ """
+ Compare two GPS coordinates for equality.
+
+ @param other: the GPS coordinate to compare to self for equality
+ @type other: L{GPSCoordinate}
+
+ @return: C{True} if equal, C{False} otherwise
+ @rtype: C{bool}
+ """
+ return (self._degrees == other._degrees) and \
+ (self._minutes == other._minutes) and \
+ (self._seconds == other._seconds) and \
+ (self._direction == other._direction)
+
+ def __str__(self):
+ """
+ Return a string representation of the GPS coordinate conforming to the
+ XMP specification.
+ """
+ return '%d,%d,%d%s' % (self._degrees, self._minutes, self._seconds,
+ self._direction)
+
diff --git a/src/pyexiv2/xmp.py b/src/pyexiv2/xmp.py
index 60fa7aa..7cf82e1 100644
--- a/src/pyexiv2/xmp.py
+++ b/src/pyexiv2/xmp.py
@@ -26,7 +26,7 @@
import libexiv2python
-from pyexiv2.utils import FixedOffset, Rational
+from pyexiv2.utils import FixedOffset, Rational, GPSCoordinate
import datetime
import re
@@ -290,6 +290,12 @@ class XmpTag(object):
# TODO
raise NotImplementedError('XMP conversion for type [%s]' % type)
+ elif type == 'GPSCoordinate':
+ try:
+ return GPSCoordinate.from_string(value)
+ except ValueError:
+ raise XmpValueError(value, type)
+
elif type == 'Integer':
try:
return int(value)
@@ -379,6 +385,12 @@ class XmpTag(object):
else:
raise XmpValueError(value, type)
+ elif type == 'GPSCoordinate':
+ if isinstance(value, GPSCoordinate):
+ return str(value)
+ else:
+ raise XmpValueError(value, type)
+
elif type == 'Integer':
if isinstance(value, (int, long)):
return str(value)