diff options
Diffstat (limited to 'src/plugins/exiv2_extractor.cc')
-rw-r--r-- | src/plugins/exiv2_extractor.cc | 879 |
1 files changed, 708 insertions, 171 deletions
diff --git a/src/plugins/exiv2_extractor.cc b/src/plugins/exiv2_extractor.cc index c3bd91a..8cd7f20 100644 --- a/src/plugins/exiv2_extractor.cc +++ b/src/plugins/exiv2_extractor.cc | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * This program is free software; you can redistribute it and/or | 3 | * This program is free software; you can redistribute it and/or |
4 | * modify it under the terms of the GNU General Public License | 4 | * modify it under the terms of the GNU General Public License |
5 | * as published by the Free Software Foundation; either version 2 | 5 | * as published by the Free Software Foundation; either version 3 |
6 | * of the License, or (at your option) any later version. | 6 | * of the License, or (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
@@ -14,74 +14,588 @@ | |||
14 | * along with this program; if not, write to the Free Software | 14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
16 | */ | 16 | */ |
17 | /*! | 17 | /** |
18 | @file exiv2_extractor.cc | 18 | * @file plugins/exiv2_extractor.cc |
19 | @brief libextractor plugin for Exif using exiv2 | 19 | * @brief libextractor plugin for Exif using exiv2 |
20 | @version $Rev$ | 20 | * @author Andreas Huggel (ahu) |
21 | @author Andreas Huggel (ahu) | 21 | * @author Christian Grothoff |
22 | <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> | 22 | */ |
23 | @date 30-Jun-05, ahu: created; 15-Dec-09, cg: updated | 23 | #include "platform.h" |
24 | */ | 24 | #include "extractor.h" |
25 | |||
26 | #include <iostream> | 25 | #include <iostream> |
27 | #include <iomanip> | 26 | #include <iomanip> |
28 | #include <cassert> | 27 | #include <cassert> |
29 | #include <cstring> | 28 | #include <cstring> |
30 | #include <math.h> | 29 | #include <math.h> |
31 | |||
32 | #include "platform.h" | ||
33 | #include "extractor.h" | ||
34 | |||
35 | #include <exiv2/exif.hpp> | 30 | #include <exiv2/exif.hpp> |
31 | #include <exiv2/error.hpp> | ||
36 | #include <exiv2/image.hpp> | 32 | #include <exiv2/image.hpp> |
37 | #include <exiv2/futils.hpp> | 33 | #include <exiv2/futils.hpp> |
38 | 34 | ||
35 | /** | ||
36 | * Should we suppress exiv2 warnings? | ||
37 | */ | ||
39 | #define SUPPRESS_WARNINGS 1 | 38 | #define SUPPRESS_WARNINGS 1 |
40 | 39 | ||
41 | #define ADD(s, type) do { if (0!=proc(proc_cls, "exiv2", type, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1)) return 1; } while (0) | ||
42 | 40 | ||
43 | static int | 41 | /** |
44 | addExiv2Tag(const Exiv2::ExifData& exifData, | 42 | * Implementation of EXIV2's BasicIO interface based |
45 | const std::string& key, | 43 | * on the 'struct EXTRACTOR_ExtractContext. |
46 | enum EXTRACTOR_MetaType type, | 44 | */ |
47 | EXTRACTOR_MetaDataProcessor proc, | 45 | class ExtractorIO:Exiv2::BasicIo |
48 | void *proc_cls) | ||
49 | { | 46 | { |
50 | const char * str; | 47 | private: |
51 | 48 | ||
52 | Exiv2::ExifKey ek(key); | 49 | /** |
53 | Exiv2::ExifData::const_iterator md = exifData.findKey(ek); | 50 | * Extract context we are using. |
54 | if (md != exifData.end()) { | 51 | */ |
55 | std::string ccstr = Exiv2::toString(*md); | 52 | struct EXTRACTOR_ExtractContext *ec; |
56 | str = ccstr.c_str(); | 53 | |
57 | while ( (strlen(str) > 0) && isspace((unsigned char) str[0])) str++; | 54 | public: |
58 | if (strlen(str) > 0) | 55 | |
59 | ADD (str, type); | 56 | /** |
60 | md++; | 57 | * Constructor. |
58 | * | ||
59 | * @param s_ec extract context to wrap | ||
60 | */ | ||
61 | ExtractorIO (struct EXTRACTOR_ExtractContext *s_ec) | ||
62 | { | ||
63 | ec = s_ec; | ||
61 | } | 64 | } |
65 | |||
66 | /** | ||
67 | * Destructor. | ||
68 | */ | ||
69 | virtual ~ExtractorIO () | ||
70 | { | ||
71 | /* nothing to do */ | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * Open stream. | ||
76 | * | ||
77 | * @return 0 (always successful) | ||
78 | */ | ||
79 | virtual int open (); | ||
80 | |||
81 | /** | ||
82 | * Close stream. | ||
83 | * | ||
84 | * @return 0 (always successful) | ||
85 | */ | ||
86 | virtual int close (); | ||
87 | |||
88 | /** | ||
89 | * Read up to 'rcount' bytes into a buffer | ||
90 | * | ||
91 | * @param rcount number of bytes to read | ||
92 | * @return buffer with data read, empty buffer (!) on failure (!) | ||
93 | */ | ||
94 | virtual Exiv2::DataBuf read (long rcount); | ||
95 | |||
96 | /** | ||
97 | * Read up to 'rcount' bytes into 'buf'. | ||
98 | * | ||
99 | * @param buf buffer to fill | ||
100 | * @param rcount size of 'buf' | ||
101 | * @return number of bytes read successfully, 0 on failure (!) | ||
102 | */ | ||
103 | virtual long read (Exiv2::byte *buf, | ||
104 | long rcount); | ||
105 | |||
106 | /** | ||
107 | * Read a single character. | ||
108 | * | ||
109 | * @return the character | ||
110 | * @throw exception on errors | ||
111 | */ | ||
112 | virtual int getb (); | ||
113 | |||
114 | /** | ||
115 | * Write to stream. | ||
116 | * | ||
117 | * @param data data to write | ||
118 | * @param wcount how many bytes to write | ||
119 | * @return -1 (always fails) | ||
120 | */ | ||
121 | virtual long write (const Exiv2::byte *data, | ||
122 | long wcount); | ||
123 | |||
124 | /** | ||
125 | * Write to stream. | ||
126 | * | ||
127 | * @param src stream to copy | ||
128 | * @return -1 (always fails) | ||
129 | */ | ||
130 | virtual long write (Exiv2::BasicIo &src); | ||
131 | |||
132 | /** | ||
133 | * Write a single byte. | ||
134 | * | ||
135 | * @param data byte to write | ||
136 | * @return -1 (always fails) | ||
137 | */ | ||
138 | virtual int putb (Exiv2::byte data); | ||
139 | |||
140 | /** | ||
141 | * Not supported. | ||
142 | * | ||
143 | * @throws error | ||
144 | */ | ||
145 | virtual void transfer (Exiv2::BasicIo& src); | ||
146 | |||
147 | /** | ||
148 | * Seek to the given offset. | ||
149 | * | ||
150 | * @param offset desired offset | ||
151 | * @parma pos offset is relative to where? | ||
152 | * @return -1 on failure, 0 on success | ||
153 | */ | ||
154 | virtual int seek (long offset, | ||
155 | Exiv2::BasicIo::Position pos); | ||
156 | |||
157 | /** | ||
158 | * Not supported. | ||
159 | * | ||
160 | * @throws error | ||
161 | */ | ||
162 | virtual Exiv2::byte* mmap (bool isWritable); | ||
163 | |||
164 | /** | ||
165 | * Not supported. | ||
166 | * | ||
167 | * @return -1 (error) | ||
168 | */ | ||
169 | virtual int munmap (); | ||
170 | |||
171 | /** | ||
172 | * Return our current offset in the file. | ||
173 | * | ||
174 | * @return -1 on error | ||
175 | */ | ||
176 | virtual long int tell (void) const; | ||
177 | |||
178 | /** | ||
179 | * Return overall size of the file. | ||
180 | * | ||
181 | * @return -1 on error | ||
182 | */ | ||
183 | virtual long int size (void) const; | ||
184 | |||
185 | /** | ||
186 | * Check if file is open. | ||
187 | * | ||
188 | * @return true (always). | ||
189 | */ | ||
190 | virtual bool isopen () const; | ||
191 | |||
192 | /** | ||
193 | * Check if this file source is in error mode. | ||
194 | * | ||
195 | * @return 0 (always all is fine). | ||
196 | */ | ||
197 | virtual int error () const; | ||
198 | |||
199 | /** | ||
200 | * Check if current position of the file is at the end | ||
201 | * | ||
202 | * @return true if at EOF, false if not. | ||
203 | */ | ||
204 | virtual bool eof () const; | ||
205 | |||
206 | /** | ||
207 | * Not supported. | ||
208 | * | ||
209 | * @throws error | ||
210 | */ | ||
211 | virtual std::string path () const; | ||
212 | |||
213 | #ifdef EXV_UNICODE_PATH | ||
214 | /** | ||
215 | * Not supported. | ||
216 | * | ||
217 | * @throws error | ||
218 | */ | ||
219 | virtual std::wstring wpath () const; | ||
220 | #endif | ||
221 | |||
222 | /** | ||
223 | * Not supported. | ||
224 | * | ||
225 | * @throws error | ||
226 | */ | ||
227 | virtual Exiv2::BasicIo::AutoPtr temporary () const; | ||
228 | |||
229 | }; | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Open stream. | ||
234 | * | ||
235 | * @return 0 (always successful) | ||
236 | */ | ||
237 | int | ||
238 | ExtractorIO::open () | ||
239 | { | ||
62 | return 0; | 240 | return 0; |
63 | } | 241 | } |
64 | 242 | ||
243 | /** | ||
244 | * Close stream. | ||
245 | * | ||
246 | * @return 0 (always successful) | ||
247 | */ | ||
248 | int | ||
249 | ExtractorIO::close () | ||
250 | { | ||
251 | return 0; | ||
252 | } | ||
65 | 253 | ||
66 | static int | 254 | |
67 | addIptcData(const Exiv2::IptcData& iptcData, | 255 | /** |
68 | const std::string& key, | 256 | * Read up to 'rcount' bytes into a buffer |
69 | enum EXTRACTOR_MetaType type, | 257 | * |
70 | EXTRACTOR_MetaDataProcessor proc, | 258 | * @param rcount number of bytes to read |
71 | void *proc_cls) | 259 | * @return buffer with data read, empty buffer (!) on failure (!) |
260 | */ | ||
261 | Exiv2::DataBuf | ||
262 | ExtractorIO::read (long rcount) | ||
72 | { | 263 | { |
73 | const char * str; | 264 | void *data; |
265 | ssize_t ret; | ||
266 | |||
267 | if (-1 == (ret = ec->read (ec->cls, &data, rcount))) | ||
268 | return Exiv2::DataBuf (NULL, 0); | ||
269 | return Exiv2::DataBuf ((const Exiv2::byte *) data, ret); | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Read up to 'rcount' bytes into 'buf'. | ||
275 | * | ||
276 | * @param buf buffer to fill | ||
277 | * @param rcount size of 'buf' | ||
278 | * @return number of bytes read successfully, 0 on failure (!) | ||
279 | */ | ||
280 | long | ||
281 | ExtractorIO::read (Exiv2::byte *buf, | ||
282 | long rcount) | ||
283 | { | ||
284 | void *data; | ||
285 | ssize_t ret; | ||
74 | 286 | ||
75 | Exiv2::IptcKey ek(key); | 287 | if (-1 == (ret = ec->read (ec->cls, &data, rcount))) |
76 | Exiv2::IptcData::const_iterator md = iptcData.findKey(ek); | 288 | return 0; |
77 | while (md != iptcData.end()) | 289 | memcpy (buf, data, ret); |
290 | return ret; | ||
291 | } | ||
292 | |||
293 | |||
294 | /** | ||
295 | * Read a single character. | ||
296 | * | ||
297 | * @return the character | ||
298 | * @throw exception on errors | ||
299 | */ | ||
300 | int | ||
301 | ExtractorIO::getb () | ||
302 | { | ||
303 | void *data; | ||
304 | char *r; | ||
305 | |||
306 | if (1 != ec->read (ec->cls, &data, 1)) | ||
307 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
308 | r = (char *) data; | ||
309 | return *r; | ||
310 | } | ||
311 | |||
312 | |||
313 | /** | ||
314 | * Write to stream. | ||
315 | * | ||
316 | * @param data data to write | ||
317 | * @param wcount how many bytes to write | ||
318 | * @return -1 (always fails) | ||
319 | */ | ||
320 | long | ||
321 | ExtractorIO::write (const Exiv2::byte *data, | ||
322 | long wcount) | ||
323 | { | ||
324 | return -1; | ||
325 | } | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Write to stream. | ||
330 | * | ||
331 | * @param src stream to copy | ||
332 | * @return -1 (always fails) | ||
333 | */ | ||
334 | long | ||
335 | ExtractorIO::write (Exiv2::BasicIo &src) | ||
336 | { | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | |||
341 | /** | ||
342 | * Write a single byte. | ||
343 | * | ||
344 | * @param data byte to write | ||
345 | * @return -1 (always fails) | ||
346 | */ | ||
347 | int | ||
348 | ExtractorIO::putb (Exiv2::byte data) | ||
349 | { | ||
350 | return -1; | ||
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Not supported. | ||
356 | * | ||
357 | * @throws error | ||
358 | */ | ||
359 | void | ||
360 | ExtractorIO::transfer (Exiv2::BasicIo& src) | ||
361 | { | ||
362 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
363 | } | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Seek to the given offset. | ||
368 | * | ||
369 | * @param offset desired offset | ||
370 | * @parma pos offset is relative to where? | ||
371 | * @return -1 on failure, 0 on success | ||
372 | */ | ||
373 | int | ||
374 | ExtractorIO::seek (long offset, | ||
375 | Exiv2::BasicIo::Position pos) | ||
376 | { | ||
377 | int rel; | ||
378 | |||
379 | switch (pos) | ||
78 | { | 380 | { |
79 | if (0 != strcmp (Exiv2::toString(md->key()).c_str(), key.c_str())) | 381 | case beg: // Exiv2::BasicIo::beg: |
382 | rel = SEEK_SET; | ||
383 | break; | ||
384 | case cur: | ||
385 | rel = SEEK_CUR; | ||
386 | break; | ||
387 | case end: | ||
388 | rel = SEEK_END; | ||
389 | break; | ||
390 | default: | ||
391 | abort (); | ||
392 | } | ||
393 | if (-1 == ec->seek (ec->cls, offset, rel)) | ||
394 | return -1; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Not supported. | ||
401 | * | ||
402 | * @throws error | ||
403 | */ | ||
404 | Exiv2::byte * | ||
405 | ExtractorIO::mmap (bool isWritable) | ||
406 | { | ||
407 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
408 | } | ||
409 | |||
410 | |||
411 | /** | ||
412 | * Not supported. | ||
413 | * | ||
414 | * @return -1 error | ||
415 | */ | ||
416 | int | ||
417 | ExtractorIO::munmap () | ||
418 | { | ||
419 | return -1; | ||
420 | } | ||
421 | |||
422 | |||
423 | /** | ||
424 | * Return our current offset in the file. | ||
425 | * | ||
426 | * @return -1 on error | ||
427 | */ | ||
428 | long int | ||
429 | ExtractorIO::tell (void) const | ||
430 | { | ||
431 | return (long) ec->seek (ec->cls, 0, SEEK_CUR); | ||
432 | } | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Return overall size of the file. | ||
437 | * | ||
438 | * @return -1 on error | ||
439 | */ | ||
440 | long int | ||
441 | ExtractorIO::size (void) const | ||
442 | { | ||
443 | return (long) ec->get_size (ec->cls); | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * Check if file is open. | ||
449 | * | ||
450 | * @return true (always). | ||
451 | */ | ||
452 | bool | ||
453 | ExtractorIO::isopen () const | ||
454 | { | ||
455 | return true; | ||
456 | } | ||
457 | |||
458 | |||
459 | /** | ||
460 | * Check if this file source is in error mode. | ||
461 | * | ||
462 | * @return 0 (always all is fine). | ||
463 | */ | ||
464 | int | ||
465 | ExtractorIO::error () const | ||
466 | { | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | |||
471 | /** | ||
472 | * Check if current position of the file is at the end | ||
473 | * | ||
474 | * @return true if at EOF, false if not. | ||
475 | */ | ||
476 | bool | ||
477 | ExtractorIO::eof () const | ||
478 | { | ||
479 | return size () == tell (); | ||
480 | } | ||
481 | |||
482 | |||
483 | /** | ||
484 | * Not supported. | ||
485 | * | ||
486 | * @throws error | ||
487 | */ | ||
488 | std::string | ||
489 | ExtractorIO::path () const | ||
490 | { | ||
491 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
492 | } | ||
493 | |||
494 | |||
495 | #ifdef EXV_UNICODE_PATH | ||
496 | /** | ||
497 | * Not supported. | ||
498 | * | ||
499 | * @throws error | ||
500 | */ | ||
501 | std::string | ||
502 | ExtractorIO::wpath () const | ||
503 | { | ||
504 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
505 | } | ||
506 | #endif | ||
507 | |||
508 | |||
509 | /** | ||
510 | * Not supported. | ||
511 | * | ||
512 | * @throws error | ||
513 | */ | ||
514 | Exiv2::BasicIo::AutoPtr | ||
515 | ExtractorIO::temporary () const | ||
516 | { | ||
517 | throw Exiv2::BasicError<char> (42 /* error code */); | ||
518 | } | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Pass the given UTF-8 string to the 'proc' callback using | ||
523 | * the given type. Uses 'return 1' if 'proc' returns non-0. | ||
524 | * | ||
525 | * @param s 0-terminated UTF8 string value with the meta data | ||
526 | * @param type libextractor type for the meta data | ||
527 | */ | ||
528 | #define ADD(s, type) do { if (0 != proc (proc_cls, "exiv2", type, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen (s) + 1)) return 1; } while (0) | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Try to find a given key in the exifData and if a value is | ||
533 | * found, pass it to 'proc'. | ||
534 | * | ||
535 | * @param exifData metadata set to inspect | ||
536 | * @param key key to lookup in exifData | ||
537 | * @param type extractor type to use | ||
538 | * @param proc function to call with results | ||
539 | * @param proc_cls closurer for proc | ||
540 | * @return 0 to continue extracting, 1 to abort | ||
541 | */ | ||
542 | static int | ||
543 | addExiv2Tag (const Exiv2::ExifData& exifData, | ||
544 | const std::string& key, | ||
545 | enum EXTRACTOR_MetaType type, | ||
546 | EXTRACTOR_MetaDataProcessor proc, | ||
547 | void *proc_cls) | ||
548 | { | ||
549 | const char *str; | ||
550 | Exiv2::ExifKey ek (key); | ||
551 | Exiv2::ExifData::const_iterator md = exifData.findKey (ek); | ||
552 | |||
553 | if (exifData.end () == md) | ||
554 | return 0; /* not found */ | ||
555 | std::string ccstr = Exiv2::toString(*md); | ||
556 | str = ccstr.c_str(); | ||
557 | /* skip over whitespace */ | ||
558 | while ( (strlen (str) > 0) && isspace ((unsigned char) str[0])) | ||
559 | str++; | ||
560 | if (strlen (str) > 0) | ||
561 | ADD (str, type); | ||
562 | md++; | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * Try to find a given key in the iptcData and if a value is | ||
569 | * found, pass it to 'proc'. | ||
570 | * | ||
571 | * @param ipctData metadata set to inspect | ||
572 | * @param key key to lookup in exifData | ||
573 | * @param type extractor type to use | ||
574 | * @param proc function to call with results | ||
575 | * @param proc_cls closurer for proc | ||
576 | * @return 0 to continue extracting, 1 to abort | ||
577 | */ | ||
578 | static int | ||
579 | addIptcData (const Exiv2::IptcData& iptcData, | ||
580 | const std::string& key, | ||
581 | enum EXTRACTOR_MetaType type, | ||
582 | EXTRACTOR_MetaDataProcessor proc, | ||
583 | void *proc_cls) | ||
584 | { | ||
585 | const char *str; | ||
586 | Exiv2::IptcKey ek (key); | ||
587 | Exiv2::IptcData::const_iterator md = iptcData.findKey (ek); | ||
588 | |||
589 | while (iptcData.end () != md) | ||
590 | { | ||
591 | if (0 != strcmp (Exiv2::toString (md->key ()).c_str (), key.c_str ())) | ||
80 | break; | 592 | break; |
81 | std::string ccstr = Exiv2::toString(*md); | 593 | std::string ccstr = Exiv2::toString (*md); |
82 | str = ccstr.c_str(); | 594 | str = ccstr.c_str (); |
83 | while ( (strlen(str) > 0) && isspace( (unsigned char) str[0])) str++; | 595 | /* skip over whitespace */ |
84 | if (strlen(str) > 0) | 596 | while ((strlen (str) > 0) && isspace ((unsigned char) str[0])) |
597 | str++; | ||
598 | if (strlen (str) > 0) | ||
85 | ADD (str, type); | 599 | ADD (str, type); |
86 | md++; | 600 | md++; |
87 | } | 601 | } |
@@ -89,6 +603,17 @@ addIptcData(const Exiv2::IptcData& iptcData, | |||
89 | } | 603 | } |
90 | 604 | ||
91 | 605 | ||
606 | /** | ||
607 | * Try to find a given key in the xmpData and if a value is | ||
608 | * found, pass it to 'proc'. | ||
609 | * | ||
610 | * @param xmpData metadata set to inspect | ||
611 | * @param key key to lookup in exifData | ||
612 | * @param type extractor type to use | ||
613 | * @param proc function to call with results | ||
614 | * @param proc_cls closurer for proc | ||
615 | * @return 0 to continue extracting, 1 to abort | ||
616 | */ | ||
92 | static int | 617 | static int |
93 | addXmpData(const Exiv2::XmpData& xmpData, | 618 | addXmpData(const Exiv2::XmpData& xmpData, |
94 | const std::string& key, | 619 | const std::string& key, |
@@ -97,149 +622,163 @@ addXmpData(const Exiv2::XmpData& xmpData, | |||
97 | void *proc_cls) | 622 | void *proc_cls) |
98 | { | 623 | { |
99 | const char * str; | 624 | const char * str; |
100 | 625 | Exiv2::XmpKey ek (key); | |
101 | Exiv2::XmpKey ek(key); | 626 | Exiv2::XmpData::const_iterator md = xmpData.findKey (ek); |
102 | Exiv2::XmpData::const_iterator md = xmpData.findKey(ek); | 627 | |
103 | while (md != xmpData.end()) | 628 | while (xmpData.end () != md) |
104 | { | 629 | { |
105 | if (0 != strcmp (Exiv2::toString(md->key()).c_str(), key.c_str())) | 630 | if (0 != strcmp (Exiv2::toString (md->key ()).c_str (), key.c_str ())) |
106 | break; | 631 | break; |
107 | std::string ccstr = Exiv2::toString(*md); | 632 | std::string ccstr = Exiv2::toString (*md); |
108 | str = ccstr.c_str(); | 633 | str = ccstr.c_str (); |
109 | while ( (strlen(str) > 0) && isspace( (unsigned char) str[0])) str++; | 634 | while ( (strlen (str) > 0) && isspace ((unsigned char) str[0])) str++; |
110 | if (strlen(str) > 0) | 635 | if (strlen (str) > 0) |
111 | ADD (str, type); | 636 | ADD (str, type); |
112 | md++; | 637 | md++; |
113 | } | 638 | } |
114 | return 0; | 639 | return 0; |
115 | } | 640 | } |
116 | 641 | ||
117 | #define ADDEXIV(s,t) do { if (0 != addExiv2Tag (exifData, s, t, proc, proc_cls)) return 1; } while (0) | ||
118 | #define ADDIPTC(s,t) do { if (0 != addIptcData (iptcData, s, t, proc, proc_cls)) return 1; } while (0) | ||
119 | #define ADDXMP(s,t) do { if (0 != addXmpData (xmpData, s, t, proc, proc_cls)) return 1; } while (0) | ||
120 | 642 | ||
643 | /** | ||
644 | * Call 'addExiv2Tag' for the given key-type combination. | ||
645 | * Uses 'return' if addExiv2Tag returns non-0. | ||
646 | * | ||
647 | * @param s key to lookup | ||
648 | * @param type libextractor type to use for the meta data found under the given key | ||
649 | */ | ||
650 | #define ADDEXIV(s,t) do { if (0 != addExiv2Tag (exifData, s, t, ec->proc, ec->cls)) return; } while (0) | ||
121 | 651 | ||
122 | extern "C" { | 652 | |
123 | 653 | /** | |
124 | int | 654 | * Call 'addIptcData' for the given key-type combination. |
125 | EXTRACTOR_exiv2_extract (const char *data, | 655 | * Uses 'return' if addIptcData returns non-0. |
126 | size_t size, | 656 | * |
127 | EXTRACTOR_MetaDataProcessor proc, | 657 | * @param s key to lookup |
128 | void *proc_cls, | 658 | * @param type libextractor type to use for the meta data found under the given key |
129 | const char *options) | 659 | */ |
130 | { | 660 | #define ADDIPTC(s,t) do { if (0 != addIptcData (iptcData, s, t, ec->proc, ec->cls)) return; } while (0) |
131 | try | 661 | |
132 | { | 662 | |
133 | Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open( (Exiv2::byte*) data, | 663 | /** |
134 | size); | 664 | * Call 'addXmpData' for the given key-type combination. |
135 | if (image.get() == 0) | 665 | * Uses 'return' if addXmpData returns non-0. |
136 | return 0; | 666 | * |
137 | image->readMetadata(); | 667 | * @param s key to lookup |
138 | Exiv2::ExifData &exifData = image->exifData(); | 668 | * @param type libextractor type to use for the meta data found under the given key |
139 | if (!exifData.empty()) | 669 | */ |
140 | { | 670 | #define ADDXMP(s,t) do { if (0 != addXmpData (xmpData, s, t, ec->proc, ec->cls)) return; } while (0) |
141 | Exiv2::ExifData::const_iterator md; | 671 | |
142 | 672 | ||
143 | /* FIXME: this should be a loop over data, | 673 | /** |
144 | not a looooong block of code */ | 674 | * Main entry method for the 'exiv2' extraction plugin. |
145 | ADDEXIV ("Exif.Image.Copyright", EXTRACTOR_METATYPE_COPYRIGHT); | 675 | * |
146 | ADDEXIV ("Exif.Photo.UserComment", EXTRACTOR_METATYPE_COMMENT); | 676 | * @param ec extraction context provided to the plugin |
147 | ADDEXIV ("Exif.GPSInfo.GPSLatitudeRef", EXTRACTOR_METATYPE_GPS_LATITUDE_REF); | 677 | */ |
148 | ADDEXIV ("Exif.GPSInfo.GPSLatitude", EXTRACTOR_METATYPE_GPS_LATITUDE); | 678 | extern "C" void |
149 | ADDEXIV ("Exif.GPSInfo.GPSLongitudeRef", EXTRACTOR_METATYPE_GPS_LONGITUDE_REF); | 679 | EXTRACTOR_exiv2_extract_method (struct EXTRACTOR_ExtractContext *ec) |
150 | ADDEXIV ("Exif.GPSInfo.GPSLongitude", EXTRACTOR_METATYPE_GPS_LONGITUDE); | 680 | { |
151 | ADDEXIV ("Exif.Image.Make", EXTRACTOR_METATYPE_CAMERA_MAKE); | 681 | try |
152 | ADDEXIV ("Exif.Image.Model", EXTRACTOR_METATYPE_CAMERA_MODEL); | 682 | { |
153 | ADDEXIV ("Exif.Image.Orientation", EXTRACTOR_METATYPE_ORIENTATION); | 683 | std::auto_ptr<Exiv2::BasicIo> eio = new ExtractorIO (ec); |
154 | ADDEXIV ("Exif.Photo.DateTimeOriginal", EXTRACTOR_METATYPE_CREATION_DATE); | 684 | Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open (eio); |
155 | ADDEXIV ("Exif.Photo.ExposureBiasValue", EXTRACTOR_METATYPE_EXPOSURE_BIAS); | 685 | if (0 == image.get ()) |
156 | ADDEXIV ("Exif.Photo.Flash", EXTRACTOR_METATYPE_FLASH); | 686 | return; |
157 | ADDEXIV ("Exif.CanonSi.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); | 687 | image->readMetadata (); |
158 | ADDEXIV ("Exif.Panasonic.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); | 688 | Exiv2::ExifData &exifData = image->exifData (); |
159 | ADDEXIV ("Exif.Olympus.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); | 689 | if (! exifData.empty ()) |
160 | ADDEXIV ("Exif.Photo.FocalLength", EXTRACTOR_METATYPE_FOCAL_LENGTH); | 690 | { |
161 | ADDEXIV ("Exif.Photo.FocalLengthIn35mmFilm", EXTRACTOR_METATYPE_FOCAL_LENGTH_35MM); | 691 | ADDEXIV ("Exif.Image.Copyright", EXTRACTOR_METATYPE_COPYRIGHT); |
162 | ADDEXIV ("Exif.Photo.ISOSpeedRatings", EXTRACTOR_METATYPE_ISO_SPEED); | 692 | ADDEXIV ("Exif.Photo.UserComment", EXTRACTOR_METATYPE_COMMENT); |
163 | ADDEXIV ("Exif.CanonSi.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); | 693 | ADDEXIV ("Exif.GPSInfo.GPSLatitudeRef", EXTRACTOR_METATYPE_GPS_LATITUDE_REF); |
164 | ADDEXIV ("Exif.Nikon1.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); | 694 | ADDEXIV ("Exif.GPSInfo.GPSLatitude", EXTRACTOR_METATYPE_GPS_LATITUDE); |
165 | ADDEXIV ("Exif.Nikon2.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); | 695 | ADDEXIV ("Exif.GPSInfo.GPSLongitudeRef", EXTRACTOR_METATYPE_GPS_LONGITUDE_REF); |
166 | ADDEXIV ("Exif.Nikon3.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); | 696 | ADDEXIV ("Exif.GPSInfo.GPSLongitude", EXTRACTOR_METATYPE_GPS_LONGITUDE); |
167 | ADDEXIV ("Exif.Photo.ExposureProgram", EXTRACTOR_METATYPE_EXPOSURE_MODE); | 697 | ADDEXIV ("Exif.Image.Make", EXTRACTOR_METATYPE_CAMERA_MAKE); |
168 | ADDEXIV ("Exif.CanonCs.ExposureProgram", EXTRACTOR_METATYPE_EXPOSURE_MODE); | 698 | ADDEXIV ("Exif.Image.Model", EXTRACTOR_METATYPE_CAMERA_MODEL); |
169 | ADDEXIV ("Exif.Photo.MeteringMode", EXTRACTOR_METATYPE_METERING_MODE); | 699 | ADDEXIV ("Exif.Image.Orientation", EXTRACTOR_METATYPE_ORIENTATION); |
170 | ADDEXIV ("Exif.CanonCs.Macro", EXTRACTOR_METATYPE_MACRO_MODE); | 700 | ADDEXIV ("Exif.Photo.DateTimeOriginal", EXTRACTOR_METATYPE_CREATION_DATE); |
171 | ADDEXIV ("Exif.Fujifilm.Macro", EXTRACTOR_METATYPE_MACRO_MODE); | 701 | ADDEXIV ("Exif.Photo.ExposureBiasValue", EXTRACTOR_METATYPE_EXPOSURE_BIAS); |
172 | ADDEXIV ("Exif.Olympus.Macro", EXTRACTOR_METATYPE_MACRO_MODE); | 702 | ADDEXIV ("Exif.Photo.Flash", EXTRACTOR_METATYPE_FLASH); |
173 | ADDEXIV ("Exif.Panasonic.Macro", EXTRACTOR_METATYPE_MACRO_MODE); | 703 | ADDEXIV ("Exif.CanonSi.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); |
174 | ADDEXIV ("Exif.CanonCs.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 704 | ADDEXIV ("Exif.Panasonic.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); |
175 | ADDEXIV ("Exif.Fujifilm.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 705 | ADDEXIV ("Exif.Olympus.FlashBias", EXTRACTOR_METATYPE_FLASH_BIAS); |
176 | ADDEXIV ("Exif.Sigma.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 706 | ADDEXIV ("Exif.Photo.FocalLength", EXTRACTOR_METATYPE_FOCAL_LENGTH); |
177 | ADDEXIV ("Exif.Nikon1.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 707 | ADDEXIV ("Exif.Photo.FocalLengthIn35mmFilm", EXTRACTOR_METATYPE_FOCAL_LENGTH_35MM); |
178 | ADDEXIV ("Exif.Nikon2.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 708 | ADDEXIV ("Exif.Photo.ISOSpeedRatings", EXTRACTOR_METATYPE_ISO_SPEED); |
179 | ADDEXIV ("Exif.Nikon3.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 709 | ADDEXIV ("Exif.CanonSi.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); |
180 | ADDEXIV ("Exif.Olympus.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 710 | ADDEXIV ("Exif.Nikon1.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); |
181 | ADDEXIV ("Exif.Panasonic.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | 711 | ADDEXIV ("Exif.Nikon2.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); |
182 | ADDEXIV ("Exif.CanonSi.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 712 | ADDEXIV ("Exif.Nikon3.ISOSpeed", EXTRACTOR_METATYPE_ISO_SPEED); |
183 | ADDEXIV ("Exif.Fujifilm.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 713 | ADDEXIV ("Exif.Photo.ExposureProgram", EXTRACTOR_METATYPE_EXPOSURE_MODE); |
184 | ADDEXIV ("Exif.Sigma.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 714 | ADDEXIV ("Exif.CanonCs.ExposureProgram", EXTRACTOR_METATYPE_EXPOSURE_MODE); |
185 | ADDEXIV ("Exif.Nikon1.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 715 | ADDEXIV ("Exif.Photo.MeteringMode", EXTRACTOR_METATYPE_METERING_MODE); |
186 | ADDEXIV ("Exif.Nikon2.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 716 | ADDEXIV ("Exif.CanonCs.Macro", EXTRACTOR_METATYPE_MACRO_MODE); |
187 | ADDEXIV ("Exif.Nikon3.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 717 | ADDEXIV ("Exif.Fujifilm.Macro", EXTRACTOR_METATYPE_MACRO_MODE); |
188 | ADDEXIV ("Exif.Olympus.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 718 | ADDEXIV ("Exif.Olympus.Macro", EXTRACTOR_METATYPE_MACRO_MODE); |
189 | ADDEXIV ("Exif.Panasonic.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | 719 | ADDEXIV ("Exif.Panasonic.Macro", EXTRACTOR_METATYPE_MACRO_MODE); |
190 | 720 | ADDEXIV ("Exif.CanonCs.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | |
191 | ADDEXIV ("Exif.Photo.FNumber", EXTRACTOR_METATYPE_APERTURE); | 721 | ADDEXIV ("Exif.Fujifilm.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); |
192 | md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ApertureValue")); | 722 | ADDEXIV ("Exif.Sigma.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); |
193 | if (md != exifData.end()) { | 723 | ADDEXIV ("Exif.Nikon1.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); |
724 | ADDEXIV ("Exif.Nikon2.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | ||
725 | ADDEXIV ("Exif.Nikon3.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | ||
726 | ADDEXIV ("Exif.Olympus.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | ||
727 | ADDEXIV ("Exif.Panasonic.Quality", EXTRACTOR_METATYPE_IMAGE_QUALITY); | ||
728 | ADDEXIV ("Exif.CanonSi.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
729 | ADDEXIV ("Exif.Fujifilm.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
730 | ADDEXIV ("Exif.Sigma.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
731 | ADDEXIV ("Exif.Nikon1.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
732 | ADDEXIV ("Exif.Nikon2.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
733 | ADDEXIV ("Exif.Nikon3.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
734 | ADDEXIV ("Exif.Olympus.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
735 | ADDEXIV ("Exif.Panasonic.WhiteBalance", EXTRACTOR_METATYPE_WHITE_BALANCE); | ||
736 | ADDEXIV ("Exif.Photo.FNumber", EXTRACTOR_METATYPE_APERTURE); | ||
737 | ADDEXIV ("Exif.Photo.ExposureTime", EXTRACTOR_METATYPE_EXPOSURE); | ||
738 | |||
739 | #if FIXME | ||
740 | /* FIXME: the 'ADD' macro below won't work as we don't have 'proc' and 'proc_cls' in | ||
741 | this scope... */ | ||
742 | Exiv2::ExifData::const_iterator md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ApertureValue")); | ||
743 | if (exifData.end() != md) | ||
744 | { | ||
194 | std::ostringstream os; | 745 | std::ostringstream os; |
195 | os << std::fixed << std::setprecision(1) | 746 | os << std::fixed << std::setprecision(1) |
196 | << "F" << exp(log(2.0) * md->toFloat() / 2); | 747 | << "F" << exp(log(2.0) * md->toFloat() / 2); |
197 | ADD (os.str().c_str(), EXTRACTOR_METATYPE_APERTURE); | 748 | ADD (os.str().c_str(), EXTRACTOR_METATYPE_APERTURE); |
198 | } | 749 | } |
199 | 750 | ||
200 | ADDEXIV ("Exif.Photo.ExposureTime", EXTRACTOR_METATYPE_EXPOSURE); | 751 | md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ShutterSpeedValue")); |
201 | md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ShutterSpeedValue")); | 752 | if (exifData.end() != md) |
202 | if (md != exifData.end()) { | 753 | { |
203 | double tmp = exp(log(2.0) * md->toFloat()) + 0.5; | 754 | double tmp = exp(log(2.0) * md->toFloat()) + 0.5; |
204 | std::ostringstream os; | 755 | std::ostringstream os; |
205 | if (tmp > 1) { | 756 | if (tmp > 1) |
206 | os << "1/" << static_cast<long>(tmp) << " s"; | 757 | { |
207 | } | 758 | os << "1/" << static_cast<long>(tmp) << " s"; |
208 | else { | 759 | } |
209 | os << static_cast<long>(1/tmp) << " s"; | 760 | else |
210 | } | 761 | { |
762 | os << static_cast<long>(1/tmp) << " s"; | ||
763 | } | ||
211 | ADD (os.str().c_str(), EXTRACTOR_METATYPE_EXPOSURE); | 764 | ADD (os.str().c_str(), EXTRACTOR_METATYPE_EXPOSURE); |
212 | } | 765 | } |
213 | 766 | #endif | |
214 | /* this can sometimes be wrong (corrupt exiv2 data?). | 767 | } |
215 | Either way, we should get the data directly from | 768 | |
216 | the specific file format parser (i.e. jpeg, tiff). */ | 769 | Exiv2::IptcData &iptcData = image->iptcData(); |
217 | // Exif Resolution | 770 | if (! iptcData.empty()) |
218 | unsigned long xdim = 0; | 771 | { |
219 | unsigned long ydim = 0; | ||
220 | md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); | ||
221 | if (md != exifData.end()) xdim = md->toLong(); | ||
222 | md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); | ||
223 | if (md != exifData.end()) ydim = md->toLong(); | ||
224 | if ( (xdim != 0) && (ydim != 0)) | ||
225 | { | ||
226 | std::ostringstream os; | ||
227 | os << xdim << "x" << ydim; | ||
228 | ADD (os.str().c_str(), EXTRACTOR_METATYPE_IMAGE_DIMENSIONS); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | Exiv2::IptcData &iptcData = image->iptcData(); | ||
233 | if (! iptcData.empty()) { | ||
234 | ADDIPTC ("Iptc.Application2.Keywords", EXTRACTOR_METATYPE_KEYWORDS); | 772 | ADDIPTC ("Iptc.Application2.Keywords", EXTRACTOR_METATYPE_KEYWORDS); |
235 | ADDIPTC ("Iptc.Application2.City", EXTRACTOR_METATYPE_LOCATION_CITY); | 773 | ADDIPTC ("Iptc.Application2.City", EXTRACTOR_METATYPE_LOCATION_CITY); |
236 | ADDIPTC ("Iptc.Application2.SubLocation", EXTRACTOR_METATYPE_LOCATION_SUBLOCATION); | 774 | ADDIPTC ("Iptc.Application2.SubLocation", EXTRACTOR_METATYPE_LOCATION_SUBLOCATION); |
237 | ADDIPTC ("Iptc.Application2.CountryName", EXTRACTOR_METATYPE_LOCATION_COUNTRY); | 775 | ADDIPTC ("Iptc.Application2.CountryName", EXTRACTOR_METATYPE_LOCATION_COUNTRY); |
238 | ADDIPTC ("Xmp.photoshop.Country", EXTRACTOR_METATYPE_RATING); | 776 | ADDIPTC ("Xmp.photoshop.Country", EXTRACTOR_METATYPE_RATING); |
239 | } | 777 | } |
240 | 778 | ||
241 | Exiv2::XmpData &xmpData = image->xmpData(); | 779 | Exiv2::XmpData &xmpData = image->xmpData(); |
242 | if (! xmpData.empty()) { | 780 | if (! xmpData.empty()) |
781 | { | ||
243 | ADDXMP ("Xmp.photoshop.City", EXTRACTOR_METATYPE_LOCATION_CITY); | 782 | ADDXMP ("Xmp.photoshop.City", EXTRACTOR_METATYPE_LOCATION_CITY); |
244 | ADDXMP ("Xmp.xmp.Rating", EXTRACTOR_METATYPE_RATING); | 783 | ADDXMP ("Xmp.xmp.Rating", EXTRACTOR_METATYPE_RATING); |
245 | ADDXMP ("Xmp.MicrosoftPhoto.Rating", EXTRACTOR_METATYPE_RATING); | 784 | ADDXMP ("Xmp.MicrosoftPhoto.Rating", EXTRACTOR_METATYPE_RATING); |
@@ -248,14 +787,12 @@ extern "C" { | |||
248 | ADDXMP ("Xmp.lr.hierarchicalSubject", EXTRACTOR_METATYPE_SUBJECT); | 787 | ADDXMP ("Xmp.lr.hierarchicalSubject", EXTRACTOR_METATYPE_SUBJECT); |
249 | } | 788 | } |
250 | } | 789 | } |
251 | catch (const Exiv2::AnyError& e) { | 790 | catch (const Exiv2::AnyError& e) |
791 | { | ||
252 | #ifndef SUPPRESS_WARNINGS | 792 | #ifndef SUPPRESS_WARNINGS |
253 | std::cout << "Caught Exiv2 exception '" << e << "'\n"; | 793 | std::cout << "Caught Exiv2 exception '" << e << "'\n"; |
254 | #endif | 794 | #endif |
255 | } | 795 | } |
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | |||
261 | } | 796 | } |
797 | |||
798 | /* end of exiv2_extractor.cc */ | ||