/gdata/exif/__init__.py

http://radioappz.googlecode.com/ · Python · 217 lines · 150 code · 18 blank · 49 comment · 4 complexity · b1f9439f014126422f0ff32b34fa592d MD5 · raw file

  1. # -*-*- encoding: utf-8 -*-*-
  2. #
  3. # This is gdata.photos.exif, implementing the exif namespace in gdata
  4. #
  5. # $Id: __init__.py 81 2007-10-03 14:41:42Z havard.gulldahl $
  6. #
  7. # Copyright 2007 H?vard Gulldahl
  8. # Portions copyright 2007 Google Inc.
  9. #
  10. # Licensed under the Apache License, Version 2.0 (the "License");
  11. # you may not use this file except in compliance with the License.
  12. # You may obtain a copy of the License at
  13. #
  14. # http://www.apache.org/licenses/LICENSE-2.0
  15. #
  16. # Unless required by applicable law or agreed to in writing, software
  17. # distributed under the License is distributed on an "AS IS" BASIS,
  18. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. # See the License for the specific language governing permissions and
  20. # limitations under the License.
  21. """This module maps elements from the {EXIF} namespace[1] to GData objects.
  22. These elements describe image data, using exif attributes[2].
  23. Picasa Web Albums uses the exif namespace to represent Exif data encoded
  24. in a photo [3].
  25. Picasa Web Albums uses the following exif elements:
  26. exif:distance
  27. exif:exposure
  28. exif:flash
  29. exif:focallength
  30. exif:fstop
  31. exif:imageUniqueID
  32. exif:iso
  33. exif:make
  34. exif:model
  35. exif:tags
  36. exif:time
  37. [1]: http://schemas.google.com/photos/exif/2007.
  38. [2]: http://en.wikipedia.org/wiki/Exif
  39. [3]: http://code.google.com/apis/picasaweb/reference.html#exif_reference
  40. """
  41. __author__ = u'havard@gulldahl.no'# (H?vard Gulldahl)' #BUG: pydoc chokes on non-ascii chars in __author__
  42. __license__ = 'Apache License v2'
  43. import atom
  44. import gdata
  45. EXIF_NAMESPACE = 'http://schemas.google.com/photos/exif/2007'
  46. class ExifBaseElement(atom.AtomBase):
  47. """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
  48. """ % EXIF_NAMESPACE
  49. _tag = ''
  50. _namespace = EXIF_NAMESPACE
  51. _children = atom.AtomBase._children.copy()
  52. _attributes = atom.AtomBase._attributes.copy()
  53. def __init__(self, name=None, extension_elements=None,
  54. extension_attributes=None, text=None):
  55. self.name = name
  56. self.text = text
  57. self.extension_elements = extension_elements or []
  58. self.extension_attributes = extension_attributes or {}
  59. class Distance(ExifBaseElement):
  60. "(float) The distance to the subject, e.g. 0.0"
  61. _tag = 'distance'
  62. def DistanceFromString(xml_string):
  63. return atom.CreateClassFromXMLString(Distance, xml_string)
  64. class Exposure(ExifBaseElement):
  65. "(float) The exposure time used, e.g. 0.025 or 8.0E4"
  66. _tag = 'exposure'
  67. def ExposureFromString(xml_string):
  68. return atom.CreateClassFromXMLString(Exposure, xml_string)
  69. class Flash(ExifBaseElement):
  70. """(string) Boolean value indicating whether the flash was used.
  71. The .text attribute will either be `true' or `false'
  72. As a convenience, this object's .bool method will return what you want,
  73. so you can say:
  74. flash_used = bool(Flash)
  75. """
  76. _tag = 'flash'
  77. def __bool__(self):
  78. if self.text.lower() in ('true','false'):
  79. return self.text.lower() == 'true'
  80. def FlashFromString(xml_string):
  81. return atom.CreateClassFromXMLString(Flash, xml_string)
  82. class Focallength(ExifBaseElement):
  83. "(float) The focal length used, e.g. 23.7"
  84. _tag = 'focallength'
  85. def FocallengthFromString(xml_string):
  86. return atom.CreateClassFromXMLString(Focallength, xml_string)
  87. class Fstop(ExifBaseElement):
  88. "(float) The fstop value used, e.g. 5.0"
  89. _tag = 'fstop'
  90. def FstopFromString(xml_string):
  91. return atom.CreateClassFromXMLString(Fstop, xml_string)
  92. class ImageUniqueID(ExifBaseElement):
  93. "(string) The unique image ID for the photo. Generated by Google Photo servers"
  94. _tag = 'imageUniqueID'
  95. def ImageUniqueIDFromString(xml_string):
  96. return atom.CreateClassFromXMLString(ImageUniqueID, xml_string)
  97. class Iso(ExifBaseElement):
  98. "(int) The iso equivalent value used, e.g. 200"
  99. _tag = 'iso'
  100. def IsoFromString(xml_string):
  101. return atom.CreateClassFromXMLString(Iso, xml_string)
  102. class Make(ExifBaseElement):
  103. "(string) The make of the camera used, e.g. Fictitious Camera Company"
  104. _tag = 'make'
  105. def MakeFromString(xml_string):
  106. return atom.CreateClassFromXMLString(Make, xml_string)
  107. class Model(ExifBaseElement):
  108. "(string) The model of the camera used,e.g AMAZING-100D"
  109. _tag = 'model'
  110. def ModelFromString(xml_string):
  111. return atom.CreateClassFromXMLString(Model, xml_string)
  112. class Time(ExifBaseElement):
  113. """(int) The date/time the photo was taken, e.g. 1180294337000.
  114. Represented as the number of milliseconds since January 1st, 1970.
  115. The value of this element will always be identical to the value
  116. of the <gphoto:timestamp>.
  117. Look at this object's .isoformat() for a human friendly datetime string:
  118. photo_epoch = Time.text # 1180294337000
  119. photo_isostring = Time.isoformat() # '2007-05-27T19:32:17.000Z'
  120. Alternatively:
  121. photo_datetime = Time.datetime() # (requires python >= 2.3)
  122. """
  123. _tag = 'time'
  124. def isoformat(self):
  125. """(string) Return the timestamp as a ISO 8601 formatted string,
  126. e.g. '2007-05-27T19:32:17.000Z'
  127. """
  128. import time
  129. epoch = float(self.text)/1000
  130. return time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime(epoch))
  131. def datetime(self):
  132. """(datetime.datetime) Return the timestamp as a datetime.datetime object
  133. Requires python 2.3
  134. """
  135. import datetime
  136. epoch = float(self.text)/1000
  137. return datetime.datetime.fromtimestamp(epoch)
  138. def TimeFromString(xml_string):
  139. return atom.CreateClassFromXMLString(Time, xml_string)
  140. class Tags(ExifBaseElement):
  141. """The container for all exif elements.
  142. The <exif:tags> element can appear as a child of a photo entry.
  143. """
  144. _tag = 'tags'
  145. _children = atom.AtomBase._children.copy()
  146. _children['{%s}fstop' % EXIF_NAMESPACE] = ('fstop', Fstop)
  147. _children['{%s}make' % EXIF_NAMESPACE] = ('make', Make)
  148. _children['{%s}model' % EXIF_NAMESPACE] = ('model', Model)
  149. _children['{%s}distance' % EXIF_NAMESPACE] = ('distance', Distance)
  150. _children['{%s}exposure' % EXIF_NAMESPACE] = ('exposure', Exposure)
  151. _children['{%s}flash' % EXIF_NAMESPACE] = ('flash', Flash)
  152. _children['{%s}focallength' % EXIF_NAMESPACE] = ('focallength', Focallength)
  153. _children['{%s}iso' % EXIF_NAMESPACE] = ('iso', Iso)
  154. _children['{%s}time' % EXIF_NAMESPACE] = ('time', Time)
  155. _children['{%s}imageUniqueID' % EXIF_NAMESPACE] = ('imageUniqueID', ImageUniqueID)
  156. def __init__(self, extension_elements=None, extension_attributes=None, text=None):
  157. ExifBaseElement.__init__(self, extension_elements=extension_elements,
  158. extension_attributes=extension_attributes,
  159. text=text)
  160. self.fstop=None
  161. self.make=None
  162. self.model=None
  163. self.distance=None
  164. self.exposure=None
  165. self.flash=None
  166. self.focallength=None
  167. self.iso=None
  168. self.time=None
  169. self.imageUniqueID=None
  170. def TagsFromString(xml_string):
  171. return atom.CreateClassFromXMLString(Tags, xml_string)