1 /*
2 * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
3 * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33
34 #include <glib/gstdio.h>
35
36 #include <tiffio.h>
37 #include <libtracker-common/tracker-common.h>
38 #include <libtracker-extract/tracker-extract.h>
39
40 #define CM_TO_INCH 0.393700787
41
42 typedef enum {
43 TAG_TYPE_UNDEFINED = 0,
44 TAG_TYPE_STRING,
45 TAG_TYPE_UINT16,
46 TAG_TYPE_UINT32,
47 TAG_TYPE_DOUBLE,
48 TAG_TYPE_C16_UINT16
49 } TagType;
50
51 typedef struct {
52 const gchar *make;
53 const gchar *model;
54 const gchar *title;
55 const gchar *orientation;
56 const gchar *copyright;
57 const gchar *white_balance;
58 const gchar *fnumber;
59 const gchar *flash;
60 const gchar *focal_length;
61 const gchar *artist;
62 const gchar *exposure_time;
63 const gchar *iso_speed_ratings;
64 const gchar *date;
65 const gchar *description;
66 const gchar *metering_mode;
67 const gchar *creator;
68 const gchar *x_dimension;
69 const gchar *y_dimension;
70 const gchar *city;
71 const gchar *state;
72 const gchar *address;
73 const gchar *country;
74 const gchar *gps_altitude;
75 const gchar *gps_latitude;
76 const gchar *gps_longitude;
77 const gchar *gps_direction;
78 } MergeData;
79
80 typedef struct {
81 gchar *artist;
82 gchar *copyright;
83 gchar *date;
84 gchar *title;
85 gchar *description;
86 gchar *width;
87 gchar *length;
88 gchar *make;
89 gchar *model;
90 gchar *orientation;
91 } TiffData;
92
93 static void
94 tiff_data_free (TiffData *tags)
95 {
96 g_free (tags->artist);
97 g_free (tags->copyright);
98 g_free (tags->date);
99 g_free (tags->title);
100 g_free (tags->description);
101 g_free (tags->width);
102 g_free (tags->length);
103 g_free (tags->make);
104 g_free (tags->model);
105 g_free (tags->orientation);
106 }
107
108 static gchar *
109 get_flash (TIFF *image)
110 {
111 guint16 data = 0;
112
113 if (TIFFGetField (image, EXIFTAG_FLASH, &data)) {
114 switch (data) {
115 case 0x0001:
116 case 0x0009:
117 case 0x000D:
118 case 0x000F:
119 case 0x0019:
120 case 0x001D:
121 case 0x001F:
122 case 0x0041:
123 case 0x0045:
124 case 0x0047:
125 case 0x0049:
126 case 0x004D:
127 case 0x004F:
128 case 0x0059:
129 case 0x005F:
130 case 0x005D:
131 return g_strdup ("nmm:flash-on");
132 default:
133 return g_strdup ("nmm:flash-off");
134 }
135 }
136
137 return NULL;
138 }
139
140 static gchar *
141 get_orientation (TIFF *image)
142 {
143 guint16 data = 0;
144
145 if (TIFFGetField (image, TIFFTAG_ORIENTATION, &data)) {
146 switch (data) {
147 case 0: return g_strdup ("nfo:orientation-top");
148 case 1: return g_strdup ("nfo:orientation-top-mirror");
149 case 2: return g_strdup ("nfo:orientation-bottom");
150 case 3: return g_strdup ("nfo:orientation-bottom-mirror");
151 case 4: return g_strdup ("nfo:orientation-left-mirror");
152 case 5: return g_strdup ("nfo:orientation-right");
153 case 6: return g_strdup ("nfo:orientation-right-mirror");
154 case 7: return g_strdup ("nfo:orientation-left");
155 }
156 }
157
158 return NULL;
159 }
160
161 static gchar *
162 get_metering_mode (TIFF *image)
163 {
164 guint16 data = 0;
165
166 if (TIFFGetField (image, EXIFTAG_METERINGMODE, &data)) {
167 switch (data) {
168 case 1: return g_strdup ("nmm:metering-mode-average");
169 case 2: return g_strdup ("nmm:metering-mode-center-weighted-average");
170 case 3: return g_strdup ("nmm:metering-mode-spot");
171 case 4: return g_strdup ("nmm:metering-mode-multispot");
172 case 5: return g_strdup ("nmm:metering-mode-pattern");
173 case 6: return g_strdup ("nmm:metering-mode-partial");
174 default:
175 return g_strdup ("nmm:metering-mode-other");
176 }
177 }
178
179 return NULL;
180 }
181
182 static gchar *
183 get_white_balance (TIFF *image)
184 {
185 guint16 data = 0;
186
187 if (TIFFGetField (image, EXIFTAG_WHITEBALANCE, &data)) {
188 if (data == 0) {
189 return g_strdup ("nmm:white-balance-auto");
190 } else {
191 return g_strdup ("nmm:white-balance-manual");
192 }
193 }
194
195 return NULL;
196 }
197
198 static gchar *
199 tag_to_string (TIFF *image,
200 guint tag,
201 TagType type)
202 {
203 switch (type) {
204 case TAG_TYPE_STRING: {
205 gchar *data = NULL;
206
207 if (TIFFGetField (image, tag, &data)) {
208 return g_strdup (data);
209 }
210 break;
211 }
212
213 case TAG_TYPE_UINT16: {
214 guint16 data = 0;
215
216 if (TIFFGetField (image, tag, &data)) {
217 return g_strdup_printf ("%i", data);
218 }
219 break;
220 }
221
222 case TAG_TYPE_UINT32: {
223 guint32 data = 0;
224
225 if (TIFFGetField (image, tag, &data)) {
226 return g_strdup_printf ("%i", data);
227 }
228 break;
229 }
230
231 case TAG_TYPE_DOUBLE: {
232 gfloat data = 0;
233
234 if (TIFFGetField (image, tag, &data)) {
235 return g_strdup_printf ("%f", data);
236 }
237 break;
238 }
239
240 case TAG_TYPE_C16_UINT16: {
241 void *data = NULL;
242 guint16 count = 0;
243
244 if (TIFFGetField (image, tag, &count, &data)) {
245 return g_strdup_printf ("%i", * (guint16*) data);
246 }
247 break;
248 }
249
250 default:
251 break;
252 }
253
254 return NULL;
255 }
256
257 G_MODULE_EXPORT gboolean
258 tracker_extract_get_metadata (TrackerExtractInfo *info)
259 {
260 TIFF *image;
261 TrackerXmpData *xd = NULL;
262 TrackerIptcData *id = NULL;
263 TrackerExifData *ed = NULL;
264 MergeData md = { 0 };
265 TiffData td = { 0 };
266 gchar *filename, *uri;
267 gchar *date;
268 glong exif_offset;
269 GPtrArray *keywords;
270 guint i;
271 GFile *file;
272 TrackerSparqlBuilder *metadata, *preupdate;
273 const gchar *graph;
274 GString *where;
275 int fd;
276
277 #ifdef HAVE_LIBIPTCDATA
278 gchar *iptc_offset;
279 guint32 iptc_size;
280 #endif
281
282 #ifdef HAVE_EXEMPI
283 gchar *xmp_offset;
284 guint32 size;
285 #endif /* HAVE_EXEMPI */
286
287 file = tracker_extract_info_get_file (info);
288 filename = g_file_get_path (file);
289
290 preupdate = tracker_extract_info_get_preupdate_builder (info);
291 metadata = tracker_extract_info_get_metadata_builder (info);
292 graph = tracker_extract_info_get_graph (info);
293
294 fd = tracker_file_open_fd (filename);
295
296 if (fd == -1) {
297 g_warning ("Could not open tiff file '%s': %s\n",
298 filename,
299 g_strerror (errno));
300 g_free (filename);
301 return FALSE;
302 }
303
304 if ((image = TIFFFdOpen (fd, filename, "r")) == NULL){
305 g_warning ("Could not open image:'%s'\n", filename);
306 g_free (filename);
307 close (fd);
308 return FALSE;
309 }
310
311 tracker_sparql_builder_predicate (metadata, "a");
312 tracker_sparql_builder_object (metadata, "nfo:Image");
313 tracker_sparql_builder_object (metadata, "nmm:Photo");
314
315 uri = g_file_get_uri (file);
316
317 #ifdef HAVE_LIBIPTCDATA
318 if (TIFFGetField (image,
319 TIFFTAG_RICHTIFFIPTC,
320 &iptc_size,
321 &iptc_offset)) {
322 if (TIFFIsByteSwapped(image) != 0) {
323 TIFFSwabArrayOfLong((uint32*) iptc_offset,
324 (unsigned long) iptc_size);
325 }
326 id = tracker_iptc_new (iptc_offset, 4 * iptc_size, uri);
pointer targets in passing argument 1 of 'tracker_iptc_new' differ in signedness
(emitted by gcc)
327 }
328 #endif /* HAVE_LIBIPTCDATA */
329
330 if (!id) {
331 id = g_new0 (TrackerIptcData, 1);
332 }
333
334 /* FIXME There are problems between XMP data embedded with different tools
335 due to bugs in the original spec (type) */
336 #ifdef HAVE_EXEMPI
337 if (TIFFGetField (image, TIFFTAG_XMLPACKET, &size, &xmp_offset)) {
338 xd = tracker_xmp_new (xmp_offset, size, uri);
339 }
340 #endif /* HAVE_EXEMPI */
341
342 if (!xd) {
343 xd = g_new0 (TrackerXmpData, 1);
344 }
345
346 ed = g_new0 (TrackerExifData, 1);
347
348 /* Get Tiff specifics */
349 td.width = tag_to_string (image, TIFFTAG_IMAGEWIDTH, TAG_TYPE_UINT32);
350 td.length = tag_to_string (image, TIFFTAG_IMAGELENGTH, TAG_TYPE_UINT32);
351 td.artist = tag_to_string (image, TIFFTAG_ARTIST, TAG_TYPE_STRING);
352 td.copyright = tag_to_string (image, TIFFTAG_COPYRIGHT, TAG_TYPE_STRING);
353
354 date = tag_to_string (image, TIFFTAG_DATETIME, TAG_TYPE_STRING);
355 td.date = tracker_date_guess (date);
356 g_free (date);
357
358 td.title = tag_to_string (image, TIFFTAG_DOCUMENTNAME, TAG_TYPE_STRING);
359 td.description = tag_to_string (image, TIFFTAG_IMAGEDESCRIPTION, TAG_TYPE_STRING);
360 td.make = tag_to_string (image, TIFFTAG_MAKE, TAG_TYPE_STRING);
361 td.model = tag_to_string (image, TIFFTAG_MODEL, TAG_TYPE_STRING);
362 td.orientation = get_orientation (image);
363
364 /* Get Exif specifics */
365 if (TIFFGetField (image, TIFFTAG_EXIFIFD, &exif_offset)) {
366 if (TIFFReadEXIFDirectory (image, exif_offset)) {
367 ed->exposure_time = tag_to_string (image, EXIFTAG_EXPOSURETIME, TAG_TYPE_DOUBLE);
368 ed->fnumber = tag_to_string (image, EXIFTAG_FNUMBER, TAG_TYPE_DOUBLE);
369 ed->iso_speed_ratings = tag_to_string (image, EXIFTAG_ISOSPEEDRATINGS, TAG_TYPE_C16_UINT16);
370 date = tag_to_string (image, EXIFTAG_DATETIMEORIGINAL, TAG_TYPE_STRING);
371 ed->time_original = tracker_date_guess (date);
372 g_free (date);
373
374 ed->metering_mode = get_metering_mode (image);
375 ed->flash = get_flash (image);
376 ed->focal_length = tag_to_string (image, EXIFTAG_DATETIMEORIGINAL, TAG_TYPE_DOUBLE);
377 ed->white_balance = get_white_balance (image);
378 /* ed->software = tag_to_string (image, EXIFTAG_SOFTWARE, TAG_TYPE_STRING); */
379 }
380 }
381
382 TIFFClose (image);
383 g_free (filename);
384
385 md.title = tracker_coalesce_strip (5, xd->title, xd->pdf_title, td.title, ed->document_name, xd->title2);
386 md.orientation = tracker_coalesce_strip (4, xd->orientation, td.orientation, ed->orientation, id->image_orientation);
387 md.copyright = tracker_coalesce_strip (4, xd->rights, td.copyright, ed->copyright, id->copyright_notice);
388 md.white_balance = tracker_coalesce_strip (2, xd->white_balance, ed->white_balance);
389 md.fnumber = tracker_coalesce_strip (2, xd->fnumber, ed->fnumber);
390 md.flash = tracker_coalesce_strip (2, xd->flash, ed->flash);
391 md.focal_length = tracker_coalesce_strip (2, xd->focal_length, ed->focal_length);
392 md.artist = tracker_coalesce_strip (4, xd->artist, td.artist, ed->artist, xd->contributor);
393 md.exposure_time = tracker_coalesce_strip (2, xd->exposure_time, ed->exposure_time);
394 md.iso_speed_ratings = tracker_coalesce_strip (2, xd->iso_speed_ratings, ed->iso_speed_ratings);
395 md.date = tracker_coalesce_strip (6, xd->date, xd->time_original, td.date, ed->time, id->date_created, ed->time_original);
396 md.description = tracker_coalesce_strip (3, xd->description, td.description, ed->description);
397 md.metering_mode = tracker_coalesce_strip (2, xd->metering_mode, ed->metering_mode);
398 md.city = tracker_coalesce_strip (2, xd->city, id->city);
399 md.state = tracker_coalesce_strip (2, xd->state, id->state);
400 md.address = tracker_coalesce_strip (2, xd->address, id->sublocation);
401 md.country = tracker_coalesce_strip (2, xd->country, id->country_name);
402
403 /* FIXME We are not handling the altitude ref here for xmp */
404 md.gps_altitude = tracker_coalesce_strip (2, xd->gps_altitude, ed->gps_altitude);
405 md.gps_latitude = tracker_coalesce_strip (2, xd->gps_latitude, ed->gps_latitude);
406 md.gps_longitude = tracker_coalesce_strip (2, xd->gps_longitude, ed->gps_longitude);
407 md.gps_direction = tracker_coalesce_strip (2, xd->gps_direction, ed->gps_direction);
408 md.creator = tracker_coalesce_strip (3, xd->creator, id->byline, id->credit);
409 md.x_dimension = tracker_coalesce_strip (2, td.width, ed->x_dimension);
410 md.y_dimension = tracker_coalesce_strip (2, td.length, ed->y_dimension);
411 md.make = tracker_coalesce_strip (3, xd->make, td.make, ed->make);
412 md.model = tracker_coalesce_strip (3, xd->model, td.model, ed->model);
413
414 keywords = g_ptr_array_new ();
415
416 if (ed->user_comment) {
417 tracker_sparql_builder_predicate (metadata, "nie:comment");
418 tracker_sparql_builder_object_unvalidated (metadata, ed->user_comment);
419 }
420
421 if (md.x_dimension) {
422 tracker_sparql_builder_predicate (metadata, "nfo:width");
423 tracker_sparql_builder_object_unvalidated (metadata, md.x_dimension);
424 }
425
426 if (md.y_dimension) {
427 tracker_sparql_builder_predicate (metadata, "nfo:height");
428 tracker_sparql_builder_object_unvalidated (metadata, md.y_dimension);
429 }
430
431 if (xd->keywords) {
432 tracker_keywords_parse (keywords, xd->keywords);
433 }
434
435 if (xd->pdf_keywords) {
436 tracker_keywords_parse (keywords, xd->pdf_keywords);
437 }
438
439 if (xd->subject) {
440 tracker_keywords_parse (keywords, xd->subject);
441 }
442
443 if (xd->publisher) {
444 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
445
446 tracker_sparql_builder_insert_open (preupdate, NULL);
447 if (graph) {
448 tracker_sparql_builder_graph_open (preupdate, graph);
449 }
450
451 tracker_sparql_builder_subject_iri (preupdate, uri);
452 tracker_sparql_builder_predicate (preupdate, "a");
453 tracker_sparql_builder_object (preupdate, "nco:Contact");
454 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
455 tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
456
457 if (graph) {
458 tracker_sparql_builder_graph_close (preupdate);
459 }
460 tracker_sparql_builder_insert_close (preupdate);
461
462 tracker_sparql_builder_predicate (metadata, "nco:publisher");
463 tracker_sparql_builder_object_iri (metadata, uri);
464 g_free (uri);
465 }
466
467 if (xd->type) {
468 tracker_sparql_builder_predicate (metadata, "dc:type");
469 tracker_sparql_builder_object_unvalidated (metadata, xd->type);
470 }
471
472 if (xd->format) {
473 tracker_sparql_builder_predicate (metadata, "dc:format");
474 tracker_sparql_builder_object_unvalidated (metadata, xd->format);
475 }
476
477 if (xd->identifier) {
478 tracker_sparql_builder_predicate (metadata, "dc:identifier");
479 tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
480 }
481
482 if (xd->source) {
483 tracker_sparql_builder_predicate (metadata, "dc:source");
484 tracker_sparql_builder_object_unvalidated (metadata, xd->source);
485 }
486
487 if (xd->language) {
488 tracker_sparql_builder_predicate (metadata, "dc:language");
489 tracker_sparql_builder_object_unvalidated (metadata, xd->language);
490 }
491
492 if (xd->relation) {
493 tracker_sparql_builder_predicate (metadata, "dc:relation");
494 tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
495 }
496
497 if (xd->coverage) {
498 tracker_sparql_builder_predicate (metadata, "dc:coverage");
499 tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
500 }
501
502 if (xd->rating) {
503 tracker_sparql_builder_predicate (metadata, "nao:numericRating");
504 tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
505 }
506
507 if (xd->license) {
508 tracker_sparql_builder_predicate (metadata, "nie:license");
509 tracker_sparql_builder_object_unvalidated (metadata, xd->license);
510 }
511
512 if (xd->regions) {
513 tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
514 }
515
516 if (md.address || md.state || md.country || md.city ||
517 md.gps_altitude || md.gps_latitude || md.gps_longitude) {
518
519 tracker_sparql_builder_predicate (metadata, "slo:location");
520
521 tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */
522 tracker_sparql_builder_predicate (metadata, "a");
523 tracker_sparql_builder_object (metadata, "slo:GeoLocation");
524
525 if (md.address || md.state || md.country || md.city) {
526 gchar *addruri;
527
528 addruri = tracker_sparql_get_uuid_urn ();
529
530 tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
531 tracker_sparql_builder_object_iri (metadata, addruri);
532
533 tracker_sparql_builder_insert_open (preupdate, NULL);
534 if (graph) {
535 tracker_sparql_builder_graph_open (preupdate, graph);
536 }
537
538 tracker_sparql_builder_subject_iri (preupdate, addruri);
539
540 g_free (addruri);
541
542 tracker_sparql_builder_predicate (preupdate, "a");
543 tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
544
545 if (md.address) {
546 tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
547 tracker_sparql_builder_object_unvalidated (preupdate, md.address);
548 }
549
550 if (md.state) {
551 tracker_sparql_builder_predicate (preupdate, "nco:region");
552 tracker_sparql_builder_object_unvalidated (preupdate, md.state);
553 }
554
555 if (md.city) {
556 tracker_sparql_builder_predicate (preupdate, "nco:locality");
557 tracker_sparql_builder_object_unvalidated (preupdate, md.city);
558 }
559
560 if (md.country) {
561 tracker_sparql_builder_predicate (preupdate, "nco:country");
562 tracker_sparql_builder_object_unvalidated (preupdate, md.country);
563 }
564
565 if (graph) {
566 tracker_sparql_builder_graph_close (preupdate);
567 }
568 tracker_sparql_builder_insert_close (preupdate);
569 }
570
571 if (md.gps_altitude) {
572 tracker_sparql_builder_predicate (metadata, "slo:altitude");
573 tracker_sparql_builder_object_unvalidated (metadata, md.gps_altitude);
574 }
575
576 if (md.gps_latitude) {
577 tracker_sparql_builder_predicate (metadata, "slo:latitude");
578 tracker_sparql_builder_object_unvalidated (metadata, md.gps_latitude);
579 }
580
581 if (md.gps_longitude) {
582 tracker_sparql_builder_predicate (metadata, "slo:longitude");
583 tracker_sparql_builder_object_unvalidated (metadata, md.gps_longitude);
584 }
585
586 tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
587 }
588
589 if (md.gps_direction) {
590 tracker_sparql_builder_predicate (metadata, "nfo:heading");
591 tracker_sparql_builder_object_unvalidated (metadata, md.gps_direction);
592 }
593
594 if (id->contact) {
595 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", id->contact);
596
597 tracker_sparql_builder_insert_open (preupdate, NULL);
598 if (graph) {
599 tracker_sparql_builder_graph_open (preupdate, graph);
600 }
601
602 tracker_sparql_builder_subject_iri (preupdate, uri);
603 tracker_sparql_builder_predicate (preupdate, "a");
604 tracker_sparql_builder_object (preupdate, "nco:Contact");
605 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
606 tracker_sparql_builder_object_unvalidated (preupdate, id->contact);
607
608 if (graph) {
609 tracker_sparql_builder_graph_close (preupdate);
610 }
611 tracker_sparql_builder_insert_close (preupdate);
612
613 tracker_sparql_builder_predicate (metadata, "nco:representative");
614 tracker_sparql_builder_object_iri (metadata, uri);
615 g_free (uri);
616 }
617
618 if (id->keywords) {
619 tracker_keywords_parse (keywords, id->keywords);
620 }
621
622 where = g_string_new ("");
623
624 for (i = 0; i < keywords->len; i++) {
625 gchar *p, *escaped, *var;
626
627 p = g_ptr_array_index (keywords, i);
628 escaped = tracker_sparql_escape_string (p);
629 var = g_strdup_printf ("tag%d", i + 1);
630
631 /* ensure tag with specified label exists */
632 tracker_sparql_builder_append (preupdate, "INSERT { ");
633
634 if (graph) {
635 tracker_sparql_builder_append (preupdate, "GRAPH <");
636 tracker_sparql_builder_append (preupdate, graph);
637 tracker_sparql_builder_append (preupdate, "> { ");
638 }
639
640 tracker_sparql_builder_append (preupdate,
641 "_:tag a nao:Tag ; nao:prefLabel \"");
642 tracker_sparql_builder_append (preupdate, escaped);
643 tracker_sparql_builder_append (preupdate, "\"");
644
645 if (graph) {
646 tracker_sparql_builder_append (preupdate, " } ");
647 }
648
649 tracker_sparql_builder_append (preupdate, " }\n");
650 tracker_sparql_builder_append (preupdate,
651 "WHERE { FILTER (NOT EXISTS { "
652 "?tag a nao:Tag ; nao:prefLabel \"");
653 tracker_sparql_builder_append (preupdate, escaped);
654 tracker_sparql_builder_append (preupdate,
655 "\" }) }\n");
656
657 /* associate file with tag */
658 tracker_sparql_builder_predicate (metadata, "nao:hasTag");
659 tracker_sparql_builder_object_variable (metadata, var);
660
661 g_string_append_printf (where, "?%s a nao:Tag ; nao:prefLabel \"%s\" .\n", var, escaped);
662
663 g_free (var);
664 g_free (escaped);
665 g_free (p);
666 }
667 g_ptr_array_free (keywords, TRUE);
668
669 tracker_extract_info_set_where_clause (info, where->str);
670 g_string_free (where, TRUE);
671
672 if (md.make || md.model) {
673 gchar *equip_uri;
674
675 equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
676 md.make ? md.make : "",
677 md.model ? md.model : "");
678
679 tracker_sparql_builder_insert_open (preupdate, NULL);
680 if (graph) {
681 tracker_sparql_builder_graph_open (preupdate, graph);
682 }
683
684 tracker_sparql_builder_subject_iri (preupdate, equip_uri);
685 tracker_sparql_builder_predicate (preupdate, "a");
686 tracker_sparql_builder_object (preupdate, "nfo:Equipment");
687
688 if (md.make) {
689 tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
690 tracker_sparql_builder_object_unvalidated (preupdate, md.make);
691 }
692 if (md.model) {
693 tracker_sparql_builder_predicate (preupdate, "nfo:model");
694 tracker_sparql_builder_object_unvalidated (preupdate, md.model);
695 }
696
697 if (graph) {
698 tracker_sparql_builder_graph_close (preupdate);
699 }
700 tracker_sparql_builder_insert_close (preupdate);
701
702 tracker_sparql_builder_predicate (metadata, "nfo:equipment");
703 tracker_sparql_builder_object_iri (metadata, equip_uri);
704 g_free (equip_uri);
705 }
706
707 tracker_guarantee_title_from_file (metadata,
708 "nie:title",
709 md.title,
710 uri,
711 NULL);
712
713 if (md.orientation) {
714 tracker_sparql_builder_predicate (metadata, "nfo:orientation");
715 tracker_sparql_builder_object_unvalidated (metadata, md.orientation);
716 }
717
718 if (md.copyright) {
719 tracker_sparql_builder_predicate (metadata, "nie:copyright");
720 tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
721 }
722
723 if (md.white_balance) {
724 tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
725 tracker_sparql_builder_object_unvalidated (metadata, md.white_balance);
726 }
727
728 if (md.fnumber) {
729 tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
730 tracker_sparql_builder_object_unvalidated (metadata, md.fnumber);
731 }
732
733 if (md.flash) {
734 tracker_sparql_builder_predicate (metadata, "nmm:flash");
735 tracker_sparql_builder_object_unvalidated (metadata, md.flash);
736 }
737
738 if (md.focal_length) {
739 tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
740 tracker_sparql_builder_object_unvalidated (metadata, md.focal_length);
741 }
742
743 if (md.artist) {
744 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
745
746 tracker_sparql_builder_insert_open (preupdate, NULL);
747 if (graph) {
748 tracker_sparql_builder_graph_open (preupdate, graph);
749 }
750
751 tracker_sparql_builder_subject_iri (preupdate, uri);
752 tracker_sparql_builder_predicate (preupdate, "a");
753 tracker_sparql_builder_object (preupdate, "nco:Contact");
754 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
755 tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
756
757 if (graph) {
758 tracker_sparql_builder_graph_close (preupdate);
759 }
760 tracker_sparql_builder_insert_close (preupdate);
761
762 tracker_sparql_builder_predicate (metadata, "nco:contributor");
763 tracker_sparql_builder_object_iri (metadata, uri);
764 g_free (uri);
765 }
766
767 if (md.exposure_time) {
768 tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
769 tracker_sparql_builder_object_unvalidated (metadata, md.exposure_time);
770 }
771
772 if (md.iso_speed_ratings) {
773 tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
774 tracker_sparql_builder_object_unvalidated (metadata, md.iso_speed_ratings);
775 }
776
777 tracker_guarantee_date_from_file_mtime (metadata,
778 "nie:contentCreated",
779 md.date,
780 uri);
781
782 if (md.description) {
783 tracker_sparql_builder_predicate (metadata, "nie:description");
784 tracker_sparql_builder_object_unvalidated (metadata, md.description);
785 }
786
787 if (md.metering_mode) {
788 tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
789 tracker_sparql_builder_object_unvalidated (metadata, md.metering_mode);
790 }
791
792 if (md.creator) {
793 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
794
795 tracker_sparql_builder_insert_open (preupdate, NULL);
796 if (graph) {
797 tracker_sparql_builder_graph_open (preupdate, graph);
798 }
799
800 tracker_sparql_builder_subject_iri (preupdate, uri);
801 tracker_sparql_builder_predicate (preupdate, "a");
802 tracker_sparql_builder_object (preupdate, "nco:Contact");
803 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
804 tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
805
806 if (graph) {
807 tracker_sparql_builder_graph_close (preupdate);
808 }
809 tracker_sparql_builder_insert_close (preupdate);
810
811 /* NOTE: We only have affiliation with
812 * nco:PersonContact and we are using
813 * nco:Contact here.
814 */
815
816 /* if (id->byline_title) { */
817 /* tracker_sparql_builder_insert_open (preupdate, NULL); */
818
819 /* tracker_sparql_builder_subject (preupdate, "_:affiliation_by_line"); */
820 /* tracker_sparql_builder_predicate (preupdate, "a"); */
821 /* tracker_sparql_builder_object (preupdate, "nco:Affiliation"); */
822
823 /* tracker_sparql_builder_predicate (preupdate, "nco:title"); */
824 /* tracker_sparql_builder_object_unvalidated (preupdate, id->byline_title); */
825
826 /* tracker_sparql_builder_insert_close (preupdate); */
827
828 /* tracker_sparql_builder_predicate (metadata, "a"); */
829 /* tracker_sparql_builder_object (metadata, "nco:PersonContact"); */
830 /* tracker_sparql_builder_predicate (metadata, "nco:hasAffiliation"); */
831 /* tracker_sparql_builder_object (metadata, "_:affiliation_by_line"); */
832 /* } */
833
834 tracker_sparql_builder_predicate (metadata, "nco:creator");
835 tracker_sparql_builder_object_iri (metadata, uri);
836 g_free (uri);
837 }
838
839 if (ed->x_resolution) {
840 gdouble value;
841
842 value = ed->resolution_unit != 3 ? g_strtod (ed->x_resolution, NULL) : g_strtod (ed->x_resolution, NULL) * CM_TO_INCH;
843 tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
844 tracker_sparql_builder_object_double (metadata, value);
845 }
846
847 if (ed->y_resolution) {
848 gdouble value;
849
850 value = ed->resolution_unit != 3 ? g_strtod (ed->y_resolution, NULL) : g_strtod (ed->y_resolution, NULL) * CM_TO_INCH;
851 tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
852 tracker_sparql_builder_object_double (metadata, value);
853 }
854
855 tiff_data_free (&td);
856 tracker_exif_free (ed);
857 tracker_xmp_free (xd);
858 tracker_iptc_free (id);
859 g_free (uri);
860
861 return TRUE;
862 }