comparison src/metadata.c @ 1238:947e603a52c6

simplified metadata interface, dropped metadata_read, fixes for older exiv2 versions
author nadvornik
date Sat, 10 Jan 2009 20:40:37 +0000
parents 31f50c1b6a9a
children 30e207ac22e4
comparison
equal deleted inserted replaced
1237:824a1e1775b8 1238:947e603a52c6
323 } 323 }
324 } 324 }
325 325
326 fclose(f); 326 fclose(f);
327 327
328 *keywords = g_list_reverse(list); 328 if (keywords)
329 {
330 *keywords = g_list_reverse(list);
331 }
332 else
333 {
334 string_list_free(list);
335 }
336
329 if (comment_build) 337 if (comment_build)
330 { 338 {
331 if (comment) 339 if (comment)
332 { 340 {
333 gint len; 341 gint len;
418 g_list_free(list); 426 g_list_free(list);
419 427
420 return g_list_reverse(newlist); 428 return g_list_reverse(newlist);
421 } 429 }
422 430
423 431 GList *metadata_read_list(FileData *fd, const gchar *key)
424 static gint metadata_xmp_read(FileData *fd, GList **keywords, gchar **comment)
425 { 432 {
426 ExifData *exif; 433 ExifData *exif;
427 434 GList *list = NULL;
428 exif = exif_read_fd(fd); 435 if (!fd) return NULL;
429 if (!exif) return FALSE; 436
430 437 /* unwritten data overide everything */
431 if (comment) 438 if (fd->modified_xmp)
432 { 439 {
433 gchar *text; 440 list = g_hash_table_lookup(fd->modified_xmp, key);
434 ExifItem *item = exif_get_item(exif, COMMENT_KEY); 441 if (list) return string_list_copy(list);
435 442 }
436 text = exif_item_get_string(item, 0); 443
437 *comment = utf8_validate_or_convert(text); 444 /*
438 g_free(text); 445 Legacy metadata file is the primary source if it exists.
439 } 446 Merging the lists does not make much sense, because the existence of
440 447 legacy metadata file indicates that the other metadata sources are not
441 if (keywords) 448 writable and thus it would not be possible to delete the keywords
442 { 449 that comes from the image file.
443 ExifItem *item; 450 */
444 guint i; 451 if (strcmp(key, KEYWORD_KEY) == 0)
452 {
453 if (metadata_legacy_read(fd, &list, NULL)) return list;
454 }
455
456 if (strcmp(key, COMMENT_KEY) == 0)
457 {
458 gchar *comment = NULL;
459 if (metadata_legacy_read(fd, NULL, &comment)) return g_list_append(NULL, comment);
460 }
461
462 exif = exif_read_fd(fd); /* this is cached, thus inexpensive */
463 if (!exif) return NULL;
464 list = exif_get_metadata(exif, key);
465 exif_free_fd(fd, exif);
466 return list;
467 }
468
469 gchar *metadata_read_string(FileData *fd, const gchar *key)
470 {
471 GList *string_list = metadata_read_list(fd, key);
472 if (string_list)
473 {
474 gchar *str = string_list->data;
475 string_list->data = NULL;
476 string_list_free(string_list);
477 return str;
478 }
479 return NULL;
480 }
481
482 gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value)
483 {
484 gchar *str = metadata_read_string(fd, key);
485
486 if (!str)
487 {
488 return metadata_write_string(fd, key, value);
489 }
490 else
491 {
492 gchar *new_string = g_strconcat(str, value, NULL);
493 gboolean ret = metadata_write_string(fd, key, new_string);
494 g_free(str);
495 g_free(new_string);
496 return ret;
497 }
498 }
499
500 gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values)
501 {
502 GList *list = metadata_read_list(fd, key);
503
504 if (!list)
505 {
506 return metadata_write_list(fd, key, values);
507 }
508 else
509 {
510 gboolean ret;
511 list = g_list_concat(list, string_list_copy(values));
512 list = remove_duplicate_strings_from_list(list);
445 513
446 *keywords = NULL; 514 ret = metadata_write_list(fd, key, list);
447 item = exif_get_item(exif, KEYWORD_KEY); 515 string_list_free(list);
448 for (i = 0; i < exif_item_get_elements(item); i++) 516 return ret;
449 { 517 }
450 gchar *kw = exif_item_get_string(item, i);
451 gchar *utf8_kw;
452
453 if (!kw) break;
454
455 utf8_kw = utf8_validate_or_convert(kw);
456 *keywords = g_list_append(*keywords, (gpointer) utf8_kw);
457 g_free(kw);
458 }
459
460 /* FIXME:
461 * Exiv2 handles Iptc keywords as multiple entries with the
462 * same key, thus exif_get_item returns only the first keyword
463 * and the only way to get all keywords is to iterate through
464 * the item list.
465 */
466 /* Read IPTC keywords only if there are no XMP keywords
467 * IPTC does not have standard charset, thus the encoding may differ
468 * from XMP and keyword merging is not reliable.
469 */
470 if (!*keywords)
471 {
472 for (item = exif_get_first_item(exif);
473 item;
474 item = exif_get_next_item(exif))
475 {
476 guint tag;
477
478 tag = exif_item_get_tag_id(item);
479 if (tag == 0x0019)
480 {
481 gchar *tag_name = exif_item_get_tag_name(item);
482
483 if (strcmp(tag_name, "Iptc.Application2.Keywords") == 0)
484 {
485 gchar *kw;
486 gchar *utf8_kw;
487
488 kw = exif_item_get_data_as_text(item);
489 if (!kw) continue;
490
491 utf8_kw = utf8_validate_or_convert(kw);
492 *keywords = g_list_append(*keywords, (gpointer) utf8_kw);
493 g_free(kw);
494 }
495 g_free(tag_name);
496 }
497 }
498 }
499 }
500
501 exif_free_fd(fd, exif);
502
503 return (comment && *comment) || (keywords && *keywords);
504 }
505
506 gint metadata_read(FileData *fd, GList **keywords, gchar **comment)
507 {
508 GList *keywords_xmp = NULL;
509 GList *keywords_legacy = NULL;
510 gchar *comment_xmp = NULL;
511 gchar *comment_legacy = NULL;
512 gint result_xmp, result_legacy;
513
514 if (!fd) return FALSE;
515
516 result_xmp = metadata_xmp_read(fd, &keywords_xmp, &comment_xmp);
517 result_legacy = metadata_legacy_read(fd, &keywords_legacy, &comment_legacy);
518
519 if (!result_xmp && !result_legacy)
520 {
521 return FALSE;
522 }
523
524 if (keywords)
525 {
526 if (result_xmp && result_legacy)
527 *keywords = g_list_concat(keywords_xmp, keywords_legacy);
528 else
529 *keywords = result_xmp ? keywords_xmp : keywords_legacy;
530
531 *keywords = remove_duplicate_strings_from_list(*keywords);
532 }
533 else
534 {
535 if (result_xmp) string_list_free(keywords_xmp);
536 if (result_legacy) string_list_free(keywords_legacy);
537 }
538
539
540 if (comment)
541 {
542 if (result_xmp && result_legacy && comment_xmp && comment_legacy && *comment_xmp && *comment_legacy)
543 *comment = g_strdup_printf("%s\n%s", comment_xmp, comment_legacy);
544 else
545 *comment = result_xmp ? comment_xmp : comment_legacy;
546 }
547
548 if (result_xmp && (!comment || *comment != comment_xmp)) g_free(comment_xmp);
549 if (result_legacy && (!comment || *comment != comment_legacy)) g_free(comment_legacy);
550
551 // return FALSE in the following cases:
552 // - only looking for a comment and didn't find one
553 // - only looking for keywords and didn't find any
554 // - looking for either a comment or keywords, but found nothing
555 if ((!keywords && comment && !*comment) ||
556 (!comment && keywords && !*keywords) ||
557 ( comment && !*comment && keywords && !*keywords))
558 return FALSE;
559
560 return TRUE;
561 }
562
563 void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append)
564 {
565 gchar *comment = NULL;
566 GList *keywords = NULL;
567 GList *keywords_list = NULL;
568
569 metadata_read(fd, &keywords, &comment);
570
571 if (new_comment)
572 {
573 if (append && comment && *comment)
574 {
575 gchar *tmp = comment;
576
577 comment = g_strconcat(tmp, new_comment, NULL);
578 g_free(tmp);
579 }
580 else
581 {
582 g_free(comment);
583 comment = g_strdup(new_comment);
584 }
585 }
586
587 if (new_keywords)
588 {
589 if (append && keywords && g_list_length(keywords) > 0)
590 {
591 GList *work;
592
593 work = new_keywords;
594 while (work)
595 {
596 gchar *key;
597 GList *p;
598
599 key = work->data;
600 work = work->next;
601
602 p = keywords;
603 while (p && key)
604 {
605 gchar *needle = p->data;
606 p = p->next;
607
608 if (strcmp(needle, key) == 0) key = NULL;
609 }
610
611 if (key) keywords = g_list_append(keywords, g_strdup(key));
612 }
613 keywords_list = keywords;
614 }
615 else
616 {
617 keywords_list = new_keywords;
618 }
619 }
620
621 metadata_write_string(fd, COMMENT_KEY, comment);
622 metadata_write_list(fd, KEYWORD_KEY, keywords);
623
624 string_list_free(keywords);
625 g_free(comment);
626 } 518 }
627 519
628 gboolean find_string_in_list(GList *list, const gchar *string) 520 gboolean find_string_in_list(GList *list, const gchar *string)
629 { 521 {
630 while (list) 522 while (list)
685 577
686 gboolean meta_data_get_keyword_mark(FileData *fd, gint n, gpointer data) 578 gboolean meta_data_get_keyword_mark(FileData *fd, gint n, gpointer data)
687 { 579 {
688 GList *keywords; 580 GList *keywords;
689 gboolean found = FALSE; 581 gboolean found = FALSE;
690 if (metadata_read(fd, &keywords, NULL)) 582 keywords = metadata_read_list(fd, KEYWORD_KEY);
583 if (keywords)
691 { 584 {
692 GList *work = keywords; 585 GList *work = keywords;
693 586
694 while (work) 587 while (work)
695 { 588 {
711 { 604 {
712 GList *keywords = NULL; 605 GList *keywords = NULL;
713 gboolean found = FALSE; 606 gboolean found = FALSE;
714 gboolean changed = FALSE; 607 gboolean changed = FALSE;
715 GList *work; 608 GList *work;
716 metadata_read(fd, &keywords, NULL); 609 keywords = metadata_read_list(fd, KEYWORD_KEY);
717 610
718 work = keywords; 611 work = keywords;
719 612
720 while (work) 613 while (work)
721 { 614 {