|
1 """ |
|
2 The various Exif backends that we have |
|
3 """ |
|
4 |
|
5 from __future__ import with_statement |
|
6 |
|
7 import utils |
|
8 |
|
9 class ExifHandler (object) : |
|
10 """ |
|
11 Our generic interface for Exif data |
|
12 """ |
|
13 |
|
14 def __init__ (self, file) : |
|
15 """ |
|
16 Load Exif data from the given File. |
|
17 """ |
|
18 |
|
19 self.file = file |
|
20 |
|
21 def image_tag (self, tag, default=None) : |
|
22 """ |
|
23 Load and return the human-readable unicode-safe value for the given main image tag. |
|
24 """ |
|
25 |
|
26 abstract |
|
27 |
|
28 def image_tags (self, tags) : |
|
29 """ |
|
30 Load and return the given tags for the main image as a sequence of (tag, value) tuples , following the same |
|
31 rules as image_tag, except there should mainly be only one call to this function, encompassing all the |
|
32 relevant tags. |
|
33 |
|
34 The returned list should omit those values which were not found. |
|
35 """ |
|
36 |
|
37 for tag in tags : |
|
38 # try and fetch value |
|
39 value = self.image_tag(tag) |
|
40 |
|
41 # filter out default not-found |
|
42 if value is not None : |
|
43 yield tag, value |
|
44 |
|
45 try : |
|
46 import pyexiv2 |
|
47 |
|
48 except ImportError : |
|
49 PyExiv2_Handler = None |
|
50 |
|
51 else : |
|
52 class PyExiv2_Handler (ExifHandler) : |
|
53 NAME = 'pyexiv2' |
|
54 |
|
55 def __init__ (self, file) : |
|
56 """ |
|
57 Load as pyexiv2.Image |
|
58 """ |
|
59 |
|
60 # create |
|
61 self.image = pyexiv2.Image(file.path) |
|
62 |
|
63 # load |
|
64 self.image.readMetadata() |
|
65 |
|
66 def image_tag (self, tag, default=None) : |
|
67 try : |
|
68 # XXX: this is wrong |
|
69 return self.image.interpretedExifValue("Exif.Photo.%s" % tag) |
|
70 |
|
71 except (IndexError, KeyError) : |
|
72 return default |
|
73 |
|
74 try : |
|
75 from lib import EXIF |
|
76 |
|
77 except ImportError : |
|
78 EXIF_Handler = None |
|
79 |
|
80 else : |
|
81 class EXIF_Handler (ExifHandler) : |
|
82 NAME = 'EXIFpy' |
|
83 |
|
84 def __init__ (self, file) : |
|
85 """ |
|
86 Load using EXIF.process_file |
|
87 """ |
|
88 |
|
89 with file.open('rb') as fh : |
|
90 self.tags = EXIF.process_file(fh) |
|
91 |
|
92 def image_tag (self, tag, default=None) : |
|
93 # XXX: this is wrong |
|
94 return self.tags.get('Image %s' % (tag, ), default) |
|
95 |
|
96 # ExifHandler implementations to use, in preference order |
|
97 EXIF_HANDLERS = [ |
|
98 # reasonably fast, but requires the native library and extension module |
|
99 PyExiv2_Handler, |
|
100 |
|
101 # pure-python, but very, very slow |
|
102 EXIF_Handler, |
|
103 ] |
|
104 |
|
105 # default ExifHandler to use |
|
106 EXIF_HANDLER = utils.first(EXIF_HANDLERS) |
|
107 |
|
108 # ExifHandler implementations by name |
|
109 EXIF_HANDLERS_BY_NAME = dict((h.NAME, h) for h in EXIF_HANDLERS) |
|
110 |
|
111 def load (config, file) : |
|
112 """ |
|
113 Load Exif data using the configured Exif handler, and return the instance. |
|
114 |
|
115 Returns None if there wasn't any Exif handler available for use. |
|
116 """ |
|
117 |
|
118 if config.exif_handler : |
|
119 # explicit |
|
120 exif_handler = config.exif_handler |
|
121 |
|
122 elif config.exif_handler_name : |
|
123 # by name |
|
124 exif_handler = EXIF_HANDLERS_BY_NAME[config.exif_handler_name] |
|
125 |
|
126 else : |
|
127 # default |
|
128 exif_handler = EXIF_HANDLER |
|
129 |
|
130 if exif_handler : |
|
131 # found one, use it |
|
132 return exif_handler(file) |
|
133 |
|
134 else : |
|
135 # nothing :( |
|
136 return None |
|
137 |