# -*-*- encoding: utf-8 -*-*- # # This is gdata.photos.exif, implementing the exif namespace in gdata # # $Id: __init__.py 81 2007-10-03 14:41:42Z havard.gulldahl $ # # Copyright 2007 Håvard Gulldahl # Portions copyright 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """This module maps elements from the {EXIF} namespace[1] to GData objects. These elements describe image data, using exif attributes[2]. Picasa Web Albums uses the exif namespace to represent Exif data encoded in a photo [3]. Picasa Web Albums uses the following exif elements: exif:distance exif:exposure exif:flash exif:focallength exif:fstop exif:imageUniqueID exif:iso exif:make exif:model exif:tags exif:time [1]: http://schemas.google.com/photos/exif/2007. [2]: http://en.wikipedia.org/wiki/Exif [3]: http://code.google.com/apis/picasaweb/reference.html#exif_reference """ __author__ = u'havard@gulldahl.no'# (Håvard Gulldahl)' #BUG: pydoc chokes on non-ascii chars in __author__ __license__ = 'Apache License v2' import atom import gdata EXIF_NAMESPACE = 'http://schemas.google.com/photos/exif/2007' class ExifBaseElement(atom.AtomBase): """Base class for elements in the EXIF_NAMESPACE (%s). To add new elements, you only need to add the element tag name to self._tag """ % EXIF_NAMESPACE _tag = '' _namespace = EXIF_NAMESPACE _children = atom.AtomBase._children.copy() _attributes = atom.AtomBase._attributes.copy() def __init__(self, name=None, extension_elements=None, extension_attributes=None, text=None): self.name = name self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} class Distance(ExifBaseElement): "(float) The distance to the subject, e.g. 0.0" _tag = 'distance' def DistanceFromString(xml_string): return atom.CreateClassFromXMLString(Distance, xml_string) class Exposure(ExifBaseElement): "(float) The exposure time used, e.g. 0.025 or 8.0E4" _tag = 'exposure' def ExposureFromString(xml_string): return atom.CreateClassFromXMLString(Exposure, xml_string) class Flash(ExifBaseElement): """(string) Boolean value indicating whether the flash was used. The .text attribute will either be `true' or `false' As a convenience, this object's .bool method will return what you want, so you can say: flash_used = bool(Flash) """ _tag = 'flash' def __bool__(self): if self.text.lower() in ('true','false'): return self.text.lower() == 'true' def FlashFromString(xml_string): return atom.CreateClassFromXMLString(Flash, xml_string) class Focallength(ExifBaseElement): "(float) The focal length used, e.g. 23.7" _tag = 'focallength' def FocallengthFromString(xml_string): return atom.CreateClassFromXMLString(Focallength, xml_string) class Fstop(ExifBaseElement): "(float) The fstop value used, e.g. 5.0" _tag = 'fstop' def FstopFromString(xml_string): return atom.CreateClassFromXMLString(Fstop, xml_string) class ImageUniqueID(ExifBaseElement): "(string) The unique image ID for the photo. Generated by Google Photo servers" _tag = 'imageUniqueID' def ImageUniqueIDFromString(xml_string): return atom.CreateClassFromXMLString(ImageUniqueID, xml_string) class Iso(ExifBaseElement): "(int) The iso equivalent value used, e.g. 200" _tag = 'iso' def IsoFromString(xml_string): return atom.CreateClassFromXMLString(Iso, xml_string) class Make(ExifBaseElement): "(string) The make of the camera used, e.g. Fictitious Camera Company" _tag = 'make' def MakeFromString(xml_string): return atom.CreateClassFromXMLString(Make, xml_string) class Model(ExifBaseElement): "(string) The model of the camera used,e.g AMAZING-100D" _tag = 'model' def ModelFromString(xml_string): return atom.CreateClassFromXMLString(Model, xml_string) class Time(ExifBaseElement): """(int) The date/time the photo was taken, e.g. 1180294337000. Represented as the number of milliseconds since January 1st, 1970. The value of this element will always be identical to the value of the . Look at this object's .isoformat() for a human friendly datetime string: photo_epoch = Time.text # 1180294337000 photo_isostring = Time.isoformat() # '2007-05-27T19:32:17.000Z' Alternatively: photo_datetime = Time.datetime() # (requires python >= 2.3) """ _tag = 'time' def isoformat(self): """(string) Return the timestamp as a ISO 8601 formatted string, e.g. '2007-05-27T19:32:17.000Z' """ import time epoch = float(self.text)/1000 return time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime(epoch)) def datetime(self): """(datetime.datetime) Return the timestamp as a datetime.datetime object Requires python 2.3 """ import datetime epoch = float(self.text)/1000 return datetime.datetime.fromtimestamp(epoch) def TimeFromString(xml_string): return atom.CreateClassFromXMLString(Time, xml_string) class Tags(ExifBaseElement): """The container for all exif elements. The element can appear as a child of a photo entry. """ _tag = 'tags' _children = atom.AtomBase._children.copy() _children['{%s}fstop' % EXIF_NAMESPACE] = ('fstop', Fstop) _children['{%s}make' % EXIF_NAMESPACE] = ('make', Make) _children['{%s}model' % EXIF_NAMESPACE] = ('model', Model) _children['{%s}distance' % EXIF_NAMESPACE] = ('distance', Distance) _children['{%s}exposure' % EXIF_NAMESPACE] = ('exposure', Exposure) _children['{%s}flash' % EXIF_NAMESPACE] = ('flash', Flash) _children['{%s}focallength' % EXIF_NAMESPACE] = ('focallength', Focallength) _children['{%s}iso' % EXIF_NAMESPACE] = ('iso', Iso) _children['{%s}time' % EXIF_NAMESPACE] = ('time', Time) _children['{%s}imageUniqueID' % EXIF_NAMESPACE] = ('imageUniqueID', ImageUniqueID) def __init__(self, extension_elements=None, extension_attributes=None, text=None): ExifBaseElement.__init__(self, extension_elements=extension_elements, extension_attributes=extension_attributes, text=text) self.fstop=None self.make=None self.model=None self.distance=None self.exposure=None self.flash=None self.focallength=None self.iso=None self.time=None self.imageUniqueID=None def TagsFromString(xml_string): return atom.CreateClassFromXMLString(Tags, xml_string)