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 #include <stdio.h>
24 #include <setjmp.h>
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE /* strcasestr() */
28 #endif
29
30 #include <jpeglib.h>
31
32 #include <libtracker-common/tracker-common.h>
33 #include <libtracker-extract/tracker-extract.h>
34 #include <libtracker-sparql/tracker-sparql.h>
35
36 #include "tracker-main.h"
37
38 #define CM_TO_INCH 0.393700787
39
40 #ifdef HAVE_LIBEXIF
41 #define EXIF_NAMESPACE "Exif"
42 #define EXIF_NAMESPACE_LENGTH 4
43 #endif /* HAVE_LIBEXIF */
44
45 #ifdef HAVE_EXEMPI
46 #define XMP_NAMESPACE "http://ns.adobe.com/xap/1.0/\x00"
47 #define XMP_NAMESPACE_LENGTH 29
48 #endif /* HAVE_EXEMPI */
49
50 #ifdef HAVE_LIBIPTCDATA
51 #define PS3_NAMESPACE "Photoshop 3.0\0"
52 #define PS3_NAMESPACE_LENGTH 14
53 #include <libiptcdata/iptc-jpeg.h>
54 #endif /* HAVE_LIBIPTCDATA */
55
56 typedef struct {
57 const gchar *make;
58 const gchar *model;
59 const gchar *title;
60 const gchar *orientation;
61 const gchar *copyright;
62 const gchar *white_balance;
63 const gchar *fnumber;
64 const gchar *flash;
65 const gchar *focal_length;
66 const gchar *artist;
67 const gchar *exposure_time;
68 const gchar *iso_speed_ratings;
69 const gchar *date;
70 const gchar *description;
71 const gchar *metering_mode;
72 const gchar *creator;
73 const gchar *comment;
74 const gchar *city;
75 const gchar *state;
76 const gchar *address;
77 const gchar *country;
78 const gchar *gps_altitude;
79 const gchar *gps_latitude;
80 const gchar *gps_longitude;
81 const gchar *gps_direction;
82 } MergeData;
83
84 struct tej_error_mgr {
85 struct jpeg_error_mgr jpeg;
86 jmp_buf setjmp_buffer;
87 };
88
89 static void
90 extract_jpeg_error_exit (j_common_ptr cinfo)
91 {
92 struct tej_error_mgr *h = (struct tej_error_mgr *) cinfo->err;
93 (*cinfo->err->output_message)(cinfo);
94 longjmp (h->setjmp_buffer, 1);
95 }
96
97 static gboolean
98 guess_dlna_profile (gint width,
99 gint height,
100 const gchar **dlna_profile,
101 const gchar **dlna_mimetype)
102 {
103 const gchar *profile = NULL;
104
105 if (dlna_profile) {
106 *dlna_profile = NULL;
107 }
108
109 if (dlna_mimetype) {
110 *dlna_mimetype = NULL;
111 }
112
113 if (width <= 640 && height <= 480) {
114 profile = "JPEG_SM";
115 } else if (width <= 1024 && height <= 768) {
116 profile = "JPEG_MED";
117 } else if (width <= 4096 && height <= 4096) {
118 profile = "JPEG_LRG";
119 }
120
121 if (profile) {
122 if (dlna_profile) {
123 *dlna_profile = profile;
124 }
125
126 if (dlna_mimetype) {
127 *dlna_mimetype = "image/jpeg";
128 }
129
130 return TRUE;
131 }
132
133 return FALSE;
134 }
135
136 G_MODULE_EXPORT gboolean
137 tracker_extract_get_metadata (TrackerExtractInfo *info)
138 {
139 struct jpeg_decompress_struct cinfo;
140 struct tej_error_mgr tejerr;
141 struct jpeg_marker_struct *marker;
142 TrackerSparqlBuilder *preupdate, *metadata;
143 TrackerXmpData *xd = NULL;
144 TrackerExifData *ed = NULL;
145 TrackerIptcData *id = NULL;
146 MergeData md = { 0 };
147 GFile *file;
148 FILE *f;
149 goffset size;
150 gchar *filename, *uri;
151 gchar *comment = NULL;
152 const gchar *dlna_profile, *dlna_mimetype, *graph;
153 GPtrArray *keywords;
154 gboolean success = TRUE;
155 GString *where;
156 guint i;
157
158 metadata = tracker_extract_info_get_metadata_builder (info);
159 preupdate = tracker_extract_info_get_preupdate_builder (info);
160 graph = tracker_extract_info_get_graph (info);
161
162 file = tracker_extract_info_get_file (info);
163 filename = g_file_get_path (file);
164
165 size = tracker_file_get_size (filename);
166
167 if (size < 18) {
168 g_free (filename);
169 return FALSE;
170 }
171
172 f = tracker_file_open (filename);
173 g_free (filename);
174
175 if (!f) {
176 return FALSE;
177 }
178
179 uri = g_file_get_uri (file);
180
181 tracker_sparql_builder_predicate (metadata, "a");
182 tracker_sparql_builder_object (metadata, "nfo:Image");
183 tracker_sparql_builder_predicate (metadata, "a");
184 tracker_sparql_builder_object (metadata, "nmm:Photo");
185
186 cinfo.err = jpeg_std_error (&tejerr.jpeg);
187 tejerr.jpeg.error_exit = extract_jpeg_error_exit;
188 if (setjmp (tejerr.setjmp_buffer)) {
189 success = FALSE;
190 goto fail;
191 }
192
193 jpeg_create_decompress (&cinfo);
194
195 jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF);
196 jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xFFFF);
197 jpeg_save_markers (&cinfo, JPEG_APP0 + 13, 0xFFFF);
198
199 jpeg_stdio_src (&cinfo, f);
200
201 jpeg_read_header (&cinfo, TRUE);
202
203 /* FIXME? It is possible that there are markers after SOS,
204 * but there shouldn't be. Should we decompress the whole file?
205 *
206 * jpeg_start_decompress(&cinfo);
207 * jpeg_finish_decompress(&cinfo);
208 *
209 * jpeg_calc_output_dimensions(&cinfo);
210 */
211
212 marker = (struct jpeg_marker_struct *) &cinfo.marker_list;
213
214 while (marker) {
215 gchar *str;
216 gsize len;
217 #ifdef HAVE_LIBIPTCDATA
218 gsize offset;
219 guint sublen;
220 #endif /* HAVE_LIBIPTCDATA */
221
222 switch (marker->marker) {
223 case JPEG_COM:
224 g_free (comment);
225 comment = g_strndup ((gchar*) marker->data, marker->data_length);
226 break;
227
228 case JPEG_APP0 + 1:
229 str = (gchar*) marker->data;
230 len = marker->data_length;
231
232 #ifdef HAVE_LIBEXIF
233 if (strncmp (EXIF_NAMESPACE, str, EXIF_NAMESPACE_LENGTH) == 0) {
234 ed = tracker_exif_new ((guchar *) marker->data, len, uri);
235 }
236 #endif /* HAVE_LIBEXIF */
237
238 #ifdef HAVE_EXEMPI
239 if (strncmp (XMP_NAMESPACE, str, XMP_NAMESPACE_LENGTH) == 0) {
240 xd = tracker_xmp_new (str + XMP_NAMESPACE_LENGTH,
241 len - XMP_NAMESPACE_LENGTH,
242 uri);
243 }
244 #endif /* HAVE_EXEMPI */
245
246 break;
247
248 case JPEG_APP0 + 13:
249 str = (gchar*) marker->data;
250 len = marker->data_length;
251 #ifdef HAVE_LIBIPTCDATA
252 if (len > 0 && strncmp (PS3_NAMESPACE, str, PS3_NAMESPACE_LENGTH) == 0) {
253 offset = iptc_jpeg_ps3_find_iptc (str, len, &sublen);
pointer targets in passing argument 1 of 'iptc_jpeg_ps3_find_iptc' differ in signedness
(emitted by gcc)
254 if (offset > 0 && sublen > 0) {
255 id = tracker_iptc_new (str + offset, sublen, uri);
256 }
257 }
258 #endif /* HAVE_LIBIPTCDATA */
259
260 break;
261
262 default:
263 marker = marker->next;
264 continue;
265 }
266
267 marker = marker->next;
268 }
269
270 if (!ed) {
271 ed = g_new0 (TrackerExifData, 1);
272 }
273
274 if (!xd) {
275 xd = g_new0 (TrackerXmpData, 1);
276 }
277
278 if (!id) {
279 id = g_new0 (TrackerIptcData, 1);
280 }
281
282 md.title = tracker_coalesce_strip (4, xd->title, ed->document_name, xd->title2, xd->pdf_title);
283 md.orientation = tracker_coalesce_strip (3, xd->orientation, ed->orientation, id->image_orientation);
284 md.copyright = tracker_coalesce_strip (4, xd->copyright, xd->rights, ed->copyright, id->copyright_notice);
285 md.white_balance = tracker_coalesce_strip (2, xd->white_balance, ed->white_balance);
286 md.fnumber = tracker_coalesce_strip (2, xd->fnumber, ed->fnumber);
287 md.flash = tracker_coalesce_strip (2, xd->flash, ed->flash);
288 md.focal_length = tracker_coalesce_strip (2, xd->focal_length, ed->focal_length);
289 md.artist = tracker_coalesce_strip (3, xd->artist, ed->artist, xd->contributor);
290 md.exposure_time = tracker_coalesce_strip (2, xd->exposure_time, ed->exposure_time);
291 md.iso_speed_ratings = tracker_coalesce_strip (2, xd->iso_speed_ratings, ed->iso_speed_ratings);
292 md.date = tracker_coalesce_strip (5, xd->date, xd->time_original, ed->time, id->date_created, ed->time_original);
293 md.description = tracker_coalesce_strip (2, xd->description, ed->description);
294 md.metering_mode = tracker_coalesce_strip (2, xd->metering_mode, ed->metering_mode);
295 md.city = tracker_coalesce_strip (2, xd->city, id->city);
296 md.state = tracker_coalesce_strip (2, xd->state, id->state);
297 md.address = tracker_coalesce_strip (2, xd->address, id->sublocation);
298 md.country = tracker_coalesce_strip (2, xd->country, id->country_name);
299
300 /* FIXME We are not handling the altitude ref here for xmp */
301 md.gps_altitude = tracker_coalesce_strip (2, xd->gps_altitude, ed->gps_altitude);
302 md.gps_latitude = tracker_coalesce_strip (2, xd->gps_latitude, ed->gps_latitude);
303 md.gps_longitude = tracker_coalesce_strip (2, xd->gps_longitude, ed->gps_longitude);
304 md.gps_direction = tracker_coalesce_strip (2, xd->gps_direction, ed->gps_direction);
305 md.creator = tracker_coalesce_strip (3, xd->creator, id->byline, id->credit);
306 md.comment = tracker_coalesce_strip (2, comment, ed->user_comment);
307 md.make = tracker_coalesce_strip (2, xd->make, ed->make);
308 md.model = tracker_coalesce_strip (2, xd->model, ed->model);
309
310 /* Prioritize on native dimention in all cases */
311 tracker_sparql_builder_predicate (metadata, "nfo:width");
312 tracker_sparql_builder_object_int64 (metadata, cinfo.image_width);
313
314 /* TODO: add ontology and store ed->software */
315
316 tracker_sparql_builder_predicate (metadata, "nfo:height");
317 tracker_sparql_builder_object_int64 (metadata, cinfo.image_height);
318
319 if (guess_dlna_profile (cinfo.image_width, cinfo.image_height, &dlna_profile, &dlna_mimetype)) {
320 tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
321 tracker_sparql_builder_object_string (metadata, dlna_profile);
322 tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
323 tracker_sparql_builder_object_string (metadata, dlna_mimetype);
324 }
325
326 if (id->contact) {
327 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", id->contact);
328
329 tracker_sparql_builder_insert_open (preupdate, NULL);
330 if (graph) {
331 tracker_sparql_builder_graph_open (preupdate, graph);
332 }
333
334 tracker_sparql_builder_subject_iri (preupdate, uri);
335 tracker_sparql_builder_predicate (preupdate, "a");
336 tracker_sparql_builder_object (preupdate, "nco:Contact");
337 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
338 tracker_sparql_builder_object_unvalidated (preupdate, id->contact);
339
340 if (graph) {
341 tracker_sparql_builder_graph_close (preupdate);
342 }
343 tracker_sparql_builder_insert_close (preupdate);
344
345 tracker_sparql_builder_predicate (metadata, "nco:representative");
346 tracker_sparql_builder_object_iri (metadata, uri);
347 g_free (uri);
348 }
349
350 keywords = g_ptr_array_new ();
351
352 if (xd->keywords) {
353 tracker_keywords_parse (keywords, xd->keywords);
354 }
355
356 if (xd->pdf_keywords) {
357 tracker_keywords_parse (keywords, xd->pdf_keywords);
358 }
359
360 if (xd->subject) {
361 tracker_keywords_parse (keywords, xd->subject);
362 }
363
364 if (xd->publisher) {
365 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
366
367 tracker_sparql_builder_insert_open (preupdate, NULL);
368 if (graph) {
369 tracker_sparql_builder_graph_open (preupdate, graph);
370 }
371
372 tracker_sparql_builder_subject_iri (preupdate, uri);
373 tracker_sparql_builder_predicate (preupdate, "a");
374 tracker_sparql_builder_object (preupdate, "nco:Contact");
375 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
376 tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
377
378 if (graph) {
379 tracker_sparql_builder_graph_close (preupdate);
380 }
381 tracker_sparql_builder_insert_close (preupdate);
382
383 tracker_sparql_builder_predicate (metadata, "nco:publisher");
384 tracker_sparql_builder_object_iri (metadata, uri);
385 g_free (uri);
386 }
387
388 if (xd->type) {
389 tracker_sparql_builder_predicate (metadata, "dc:type");
390 tracker_sparql_builder_object_unvalidated (metadata, xd->type);
391 }
392
393 if (xd->rating) {
394 tracker_sparql_builder_predicate (metadata, "nao:numericRating");
395 tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
396 }
397
398 if (xd->format) {
399 tracker_sparql_builder_predicate (metadata, "dc:format");
400 tracker_sparql_builder_object_unvalidated (metadata, xd->format);
401 }
402
403 if (xd->identifier) {
404 tracker_sparql_builder_predicate (metadata, "dc:indentifier");
405 tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
406 }
407
408 if (xd->source) {
409 tracker_sparql_builder_predicate (metadata, "dc:source");
410 tracker_sparql_builder_object_unvalidated (metadata, xd->source);
411 }
412
413 if (xd->language) {
414 tracker_sparql_builder_predicate (metadata, "dc:language");
415 tracker_sparql_builder_object_unvalidated (metadata, xd->language);
416 }
417
418 if (xd->relation) {
419 tracker_sparql_builder_predicate (metadata, "dc:relation");
420 tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
421 }
422
423 if (xd->coverage) {
424 tracker_sparql_builder_predicate (metadata, "dc:coverage");
425 tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
426 }
427
428 if (xd->license) {
429 tracker_sparql_builder_predicate (metadata, "nie:license");
430 tracker_sparql_builder_object_unvalidated (metadata, xd->license);
431 }
432
433 if (xd->regions) {
434 tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
435 }
436
437 if (id->keywords) {
438 tracker_keywords_parse (keywords, id->keywords);
439 }
440
441 where = g_string_new ("");
442
443 for (i = 0; i < keywords->len; i++) {
444 gchar *p, *escaped, *var;
445
446 p = g_ptr_array_index (keywords, i);
447 escaped = tracker_sparql_escape_string (p);
448 var = g_strdup_printf ("tag%d", i + 1);
449
450 /* ensure tag with specified label exists */
451 tracker_sparql_builder_append (preupdate, "INSERT { ");
452
453 if (graph) {
454 tracker_sparql_builder_append (preupdate, "GRAPH <");
455 tracker_sparql_builder_append (preupdate, graph);
456 tracker_sparql_builder_append (preupdate, "> { ");
457 }
458
459 tracker_sparql_builder_append (preupdate,
460 "_:tag a nao:Tag ; nao:prefLabel \"");
461 tracker_sparql_builder_append (preupdate, escaped);
462 tracker_sparql_builder_append (preupdate, "\"");
463
464 if (graph) {
465 tracker_sparql_builder_append (preupdate, " } ");
466 }
467
468 tracker_sparql_builder_append (preupdate, " }\n");
469 tracker_sparql_builder_append (preupdate,
470 "WHERE { FILTER (NOT EXISTS { "
471 "?tag a nao:Tag ; nao:prefLabel \"");
472 tracker_sparql_builder_append (preupdate, escaped);
473 tracker_sparql_builder_append (preupdate,
474 "\" }) }\n");
475
476 /* associate file with tag */
477 tracker_sparql_builder_predicate (metadata, "nao:hasTag");
478 tracker_sparql_builder_object_variable (metadata, var);
479
480 g_string_append_printf (where, "?%s a nao:Tag ; nao:prefLabel \"%s\" .\n", var, escaped);
481
482 g_free (var);
483 g_free (escaped);
484 g_free (p);
485 }
486 g_ptr_array_free (keywords, TRUE);
487
488 tracker_extract_info_set_where_clause (info, where->str);
489 g_string_free (where, TRUE);
490
491 if (md.make || md.model) {
492 gchar *equip_uri;
493
494 equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
495 md.make ? md.make : "",
496 md.model ? md.model : "");
497
498 tracker_sparql_builder_insert_open (preupdate, NULL);
499 if (graph) {
500 tracker_sparql_builder_graph_open (preupdate, graph);
501 }
502
503 tracker_sparql_builder_subject_iri (preupdate, equip_uri);
504 tracker_sparql_builder_predicate (preupdate, "a");
505 tracker_sparql_builder_object (preupdate, "nfo:Equipment");
506
507 if (md.make) {
508 tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
509 tracker_sparql_builder_object_unvalidated (preupdate, md.make);
510 }
511 if (md.model) {
512 tracker_sparql_builder_predicate (preupdate, "nfo:model");
513 tracker_sparql_builder_object_unvalidated (preupdate, md.model);
514 }
515
516 if (graph) {
517 tracker_sparql_builder_graph_close (preupdate);
518 }
519 tracker_sparql_builder_insert_close (preupdate);
520
521 tracker_sparql_builder_predicate (metadata, "nfo:equipment");
522 tracker_sparql_builder_object_iri (metadata, equip_uri);
523 g_free (equip_uri);
524 }
525
526 tracker_guarantee_title_from_file (metadata,
527 "nie:title",
528 md.title,
529 uri,
530 NULL);
531
532 if (md.orientation) {
533 tracker_sparql_builder_predicate (metadata, "nfo:orientation");
534 tracker_sparql_builder_object (metadata, md.orientation);
535 }
536
537 if (md.copyright) {
538 tracker_sparql_builder_predicate (metadata, "nie:copyright");
539 tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
540 }
541
542 if (md.white_balance) {
543 tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
544 tracker_sparql_builder_object (metadata, md.white_balance);
545 }
546
547 if (md.fnumber) {
548 gdouble value;
549
550 value = g_strtod (md.fnumber, NULL);
551 tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
552 tracker_sparql_builder_object_double (metadata, value);
553 }
554
555 if (md.flash) {
556 tracker_sparql_builder_predicate (metadata, "nmm:flash");
557 tracker_sparql_builder_object (metadata, md.flash);
558 }
559
560 if (md.focal_length) {
561 gdouble value;
562
563 value = g_strtod (md.focal_length, NULL);
564 tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
565 tracker_sparql_builder_object_double (metadata, value);
566 }
567
568 if (md.artist) {
569 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
570
571 tracker_sparql_builder_insert_open (preupdate, NULL);
572 if (graph) {
573 tracker_sparql_builder_graph_open (preupdate, graph);
574 }
575
576 tracker_sparql_builder_subject_iri (preupdate, uri);
577 tracker_sparql_builder_predicate (preupdate, "a");
578 tracker_sparql_builder_object (preupdate, "nco:Contact");
579 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
580 tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
581
582 if (graph) {
583 tracker_sparql_builder_graph_close (preupdate);
584 }
585 tracker_sparql_builder_insert_close (preupdate);
586
587 tracker_sparql_builder_predicate (metadata, "nco:contributor");
588 tracker_sparql_builder_object_iri (metadata, uri);
589 g_free (uri);
590 }
591
592 if (md.exposure_time) {
593 gdouble value;
594
595 value = g_strtod (md.exposure_time, NULL);
596 tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
597 tracker_sparql_builder_object_double (metadata, value);
598 }
599
600 if (md.iso_speed_ratings) {
601 gdouble value;
602
603 value = g_strtod (md.iso_speed_ratings, NULL);
604 tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
605 tracker_sparql_builder_object_double (metadata, value);
606 }
607
608 tracker_guarantee_date_from_file_mtime (metadata,
609 "nie:contentCreated",
610 md.date,
611 uri);
612
613 if (md.description) {
614 tracker_sparql_builder_predicate (metadata, "nie:description");
615 tracker_sparql_builder_object_unvalidated (metadata, md.description);
616 }
617
618 if (md.metering_mode) {
619 tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
620 tracker_sparql_builder_object (metadata, md.metering_mode);
621 }
622
623 if (md.creator) {
624 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
625
626 tracker_sparql_builder_insert_open (preupdate, NULL);
627 if (graph) {
628 tracker_sparql_builder_graph_open (preupdate, graph);
629 }
630
631 tracker_sparql_builder_subject_iri (preupdate, uri);
632 tracker_sparql_builder_predicate (preupdate, "a");
633 tracker_sparql_builder_object (preupdate, "nco:Contact");
634 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
635 tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
636
637 if (graph) {
638 tracker_sparql_builder_graph_close (preupdate);
639 }
640 tracker_sparql_builder_insert_close (preupdate);
641
642 /* NOTE: We only have affiliation with
643 * nco:PersonContact and we are using
644 * nco:Contact here.
645 */
646
647 /* if (id->byline_title) { */
648 /* tracker_sparql_builder_insert_open (preupdate, NULL); */
649
650 /* tracker_sparql_builder_subject (preupdate, "_:affiliation_by_line"); */
651 /* tracker_sparql_builder_predicate (preupdate, "a"); */
652 /* tracker_sparql_builder_object (preupdate, "nco:Affiliation"); */
653
654 /* tracker_sparql_builder_predicate (preupdate, "nco:title"); */
655 /* tracker_sparql_builder_object_unvalidated (preupdate, id->byline_title); */
656
657 /* tracker_sparql_builder_insert_close (preupdate); */
658
659 /* tracker_sparql_builder_predicate (preupdate, "a"); */
660 /* tracker_sparql_builder_object (preupdate, "nco:Contact"); */
661 /* tracker_sparql_builder_predicate (preupdate, "nco:hasAffiliation"); */
662 /* tracker_sparql_builder_object (preupdate, "_:affiliation_by_line"); */
663 /* } */
664
665 tracker_sparql_builder_predicate (metadata, "nco:creator");
666 tracker_sparql_builder_object_iri (metadata, uri);
667 g_free (uri);
668 }
669
670 if (md.comment) {
671 tracker_sparql_builder_predicate (metadata, "nie:comment");
672 tracker_sparql_builder_object_unvalidated (metadata, md.comment);
673 }
674
675 if (md.address || md.state || md.country || md.city ||
676 md.gps_altitude || md.gps_latitude || md.gps_longitude) {
677
678 tracker_sparql_builder_predicate (metadata, "slo:location");
679
680 tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */
681 tracker_sparql_builder_predicate (metadata, "a");
682 tracker_sparql_builder_object (metadata, "slo:GeoLocation");
683
684 if (md.address || md.state || md.country || md.city) {
685 gchar *addruri;
686
687 addruri = tracker_sparql_get_uuid_urn ();
688
689 tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
690 tracker_sparql_builder_object_iri (metadata, addruri);
691
692 tracker_sparql_builder_insert_open (preupdate, NULL);
693 if (graph) {
694 tracker_sparql_builder_graph_open (preupdate, graph);
695 }
696
697 tracker_sparql_builder_subject_iri (preupdate, addruri);
698
699 g_free (addruri);
700
701 tracker_sparql_builder_predicate (preupdate, "a");
702 tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
703
704 if (md.address) {
705 tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
706 tracker_sparql_builder_object_unvalidated (preupdate, md.address);
707 }
708
709 if (md.state) {
710 tracker_sparql_builder_predicate (preupdate, "nco:region");
711 tracker_sparql_builder_object_unvalidated (preupdate, md.state);
712 }
713
714 if (md.city) {
715 tracker_sparql_builder_predicate (preupdate, "nco:locality");
716 tracker_sparql_builder_object_unvalidated (preupdate, md.city);
717 }
718
719 if (md.country) {
720 tracker_sparql_builder_predicate (preupdate, "nco:country");
721 tracker_sparql_builder_object_unvalidated (preupdate, md.country);
722 }
723
724 if (graph) {
725 tracker_sparql_builder_graph_close (preupdate);
726 }
727 tracker_sparql_builder_insert_close (preupdate);
728 }
729
730 if (md.gps_altitude) {
731 tracker_sparql_builder_predicate (metadata, "slo:altitude");
732 tracker_sparql_builder_object_unvalidated (metadata, md.gps_altitude);
733 }
734
735 if (md.gps_latitude) {
736 tracker_sparql_builder_predicate (metadata, "slo:latitude");
737 tracker_sparql_builder_object_unvalidated (metadata, md.gps_latitude);
738 }
739
740 if (md.gps_longitude) {
741 tracker_sparql_builder_predicate (metadata, "slo:longitude");
742 tracker_sparql_builder_object_unvalidated (metadata, md.gps_longitude);
743 }
744
745 tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
746 }
747
748 if (md.gps_direction) {
749 tracker_sparql_builder_predicate (metadata, "nfo:heading");
750 tracker_sparql_builder_object_unvalidated (metadata, md.gps_direction);
751 }
752
753 if (cinfo.density_unit != 0 || ed->x_resolution) {
754 gdouble value;
755
756 if (cinfo.density_unit == 0) {
757 if (ed->resolution_unit != 3)
758 value = g_strtod (ed->x_resolution, NULL);
759 else
760 value = g_strtod (ed->x_resolution, NULL) * CM_TO_INCH;
761 } else {
762 if (cinfo.density_unit == 1)
763 value = cinfo.X_density;
764 else
765 value = cinfo.X_density * CM_TO_INCH;
766 }
767
768 tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
769 tracker_sparql_builder_object_double (metadata, value);
770 }
771
772 if (cinfo.density_unit != 0 || ed->y_resolution) {
773 gdouble value;
774
775 if (cinfo.density_unit == 0) {
776 if (ed->resolution_unit != 3)
777 value = g_strtod (ed->y_resolution, NULL);
778 else
779 value = g_strtod (ed->y_resolution, NULL) * CM_TO_INCH;
780 } else {
781 if (cinfo.density_unit == 1)
782 value = cinfo.Y_density;
783 else
784 value = cinfo.Y_density * CM_TO_INCH;
785 }
786
787 tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
788 tracker_sparql_builder_object_double (metadata, value);
789 }
790
791 jpeg_destroy_decompress (&cinfo);
792
793 tracker_exif_free (ed);
794 tracker_xmp_free (xd);
795 tracker_iptc_free (id);
796 g_free (comment);
797
798 fail:
799 tracker_file_close (f, FALSE);
800 g_free (uri);
801
802 return success;
803 }