218 lines
6.8 KiB
Python
218 lines
6.8 KiB
Python
# -*-*- 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 <gphoto:timestamp>.
|
|
|
|
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 <exif:tags> 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)
|
|
|