1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836: 837: 838: 839: 840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880: 881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: 892: 893: 894: 895: 896: 897: 898: 899: 900: 901: 902: 903: 904: 905: 906: 907: 908: 909: 910: 911: 912: 913: 914: 915: 916: 917: 918: 919: 920: 921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936: 937: 938: 939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954: 955: 956: 957: 958: 959: 960: 961: 962: 963: 964: 965: 966: 967: 968: 969: 970: 971: 972: 973: 974: 975: 976: 977: 978: 979: 980: 981: 982: 983: 984: 985: 986: 987: 988: 989: 990: 991: 992: 993: 994: 995: 996: 997: 998: 999: 1000: 1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033: 1034: 1035: 1036: 1037: 1038: 1039: 1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059: 1060: 1061: 1062: 1063: 1064: 1065: 1066: 1067: 1068: 1069: 1070: 1071: 1072: 1073: 1074: 1075: 1076: 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: 1090: 1091: 1092: 1093: 1094: 1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119: 1120: 1121: 1122: 1123:
<?php
$plugin_is_filter = 9 | CLASS_PLUGIN;
$plugin_description = gettext('Extracts <em>XMP</em> metadata from images and <code>XMP</code> sidecar files.');
$plugin_author = "Stephen Billard (sbillard)";
$plugin_category = gettext('Media');
$option_interface = 'xmpMetadata';
zp_register_filter('album_instantiate', 'xmpMetadata::album_instantiate');
zp_register_filter('new_album', 'xmpMetadata::new_album');
zp_register_filter('album_refresh', 'xmpMetadata::new_album');
zp_register_filter('image_instantiate', 'xmpMetadata::image_instantiate');
zp_register_filter('image_metadata', 'xmpMetadata::new_image');
zp_register_filter('upload_filetypes', 'xmpMetadata::sidecars');
zp_register_filter('save_album_utilities_data', 'xmpMetadata::putXMP');
zp_register_filter('edit_album_utilities', 'xmpMetadata::create');
zp_register_filter('save_image_utilities_data', 'xmpMetadata::putXMP');
zp_register_filter('edit_image_utilities', 'xmpMetadata::create');
zp_register_filter('bulk_image_actions', 'xmpMetadata::bulkActions');
zp_register_filter('bulk_album_actions', 'xmpMetadata::bulkActions');
require_once(dirname(dirname(__FILE__)) . '/exif/exif.php');
define('XMP_EXTENSION', strtolower(getOption('xmpMetadata_suffix')));
class xmpMetadata {
private static $XML_trans = array(
'€' => '€',
'‚' => '‚',
'ƒ' => 'ƒ',
'„' => '„',
'…' => '…',
'†' => '†',
'‡' => '‡',
'ˆ' => 'ˆ',
'‰' => '‰',
'Š' => 'Š',
'‹' => '‹',
'Œ' => 'Œ',
'Ž' => 'Ž',
'‘' => '‘',
'’' => '’',
'“' => '“',
'”' => '”',
'•' => '•',
'–' => '–',
'—' => '—',
'˜' => '˜',
'™' => '™',
'š' => 'š',
'›' => '›',
'œ' => 'œ',
'ž' => 'ž',
'Ÿ' => 'Ÿ',
'¡' => '¡',
'¢' => '¢',
'£' => '£',
'¤' => '¤',
'¥' => '¥',
'¦' => '¦',
'§' => '§',
'¨' => '¨',
'©' => '©',
'ª' => 'ª',
'«' => '«',
'¬' => '¬',
'­' => '',
'®' => '®',
'¯' => '¯',
'°' => '°',
'±' => '±',
'²' => '²',
'³' => '³',
'´' => '´',
'µ' => 'µ',
'¶' => '¶',
'·' => '·',
'¸' => '¸',
'¹' => '¹',
'º' => 'º',
'»' => '»',
'¼' => '¼',
'½' => '½',
'¾' => '¾',
'¿' => '¿',
'À' => 'À',
'Á' => 'Á',
'Â' => 'Â',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Å' => 'Å',
'Æ' => 'Æ',
'Ç' => 'Ç',
'È' => 'È',
'É' => 'É',
'Ê' => 'Ê',
'Ë' => 'Ë',
'Ì' => 'Ì',
'Í' => 'Í',
'Î' => 'Î',
'Ï' => 'Ï',
'Ð' => 'Ð',
'Ñ' => 'Ñ',
'Ò' => 'Ò',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Õ' => 'Õ',
'Ö' => 'Ö',
'×' => '×',
'Ø' => 'Ø',
'Ù' => 'Ù',
'Ú' => 'Ú',
'Û' => 'Û',
'Ü' => 'Ü',
'Ý' => 'Ý',
'Þ' => 'Þ',
'ß' => 'ß',
'à' => 'à',
'á' => 'á',
'â' => 'â',
'ã' => 'ã',
'ä' => 'ä',
'å' => 'å',
'æ' => 'æ',
'ç' => 'ç',
'è' => 'è',
'é' => 'é',
'ê' => 'ê',
'ë' => 'ë',
'ì' => 'ì',
'í' => 'í',
'î' => 'î',
'ï' => 'ï',
'ð' => 'ð',
'ñ' => 'ñ',
'ò' => 'ò',
'ó' => 'ó',
'ô' => 'ô',
'õ' => 'õ',
'ö' => 'ö',
'÷' => '÷',
'ø' => 'ø',
'ù' => 'ù',
'ú' => 'ú',
'û' => 'û',
'ü' => 'ü',
'ý' => 'ý',
'þ' => 'þ',
'ÿ' => 'ÿ',
'Ā' => 'Ā',
'ā' => 'ā',
'Ă' => 'Ă',
'ă' => 'ă',
'Ą' => 'Ą',
'ą' => 'ą',
'Ć' => 'Ć',
'ć' => 'ć',
'Ĉ' => 'Ĉ',
'ĉ' => 'ĉ',
'Ċ' => 'Ċ',
'ċ' => 'ċ',
'Č' => 'Č',
'č' => 'č',
'Ď' => 'Ď',
'ď' => 'ď',
'Đ' => 'Đ',
'đ' => 'đ',
'Ē' => 'Ē',
'ē' => 'ē',
'Ĕ' => 'Ĕ',
'ĕ' => 'ĕ',
'Ė' => 'Ė',
'ė' => 'ė',
'Ę' => 'Ę',
'ę' => 'ę',
'Ě' => 'Ě',
'ě' => 'ě',
'Ĝ' => 'Ĝ',
'ĝ' => 'ĝ',
'Ğ' => 'Ğ',
'ğ' => 'ğ',
'Ġ' => 'Ġ',
'ġ' => 'ġ',
'Ģ' => 'Ģ',
'ģ' => 'ģ',
'Ĥ' => 'Ĥ',
'ĥ' => 'ĥ',
'Ħ' => 'Ħ',
'ħ' => 'ħ',
'Ĩ' => 'Ĩ',
'ĩ' => 'ĩ',
'Ī' => 'Ī',
'ī' => 'ī',
'Ĭ' => 'Ĭ',
'ĭ' => 'ĭ',
'Į' => 'Į',
'į' => 'į',
'İ' => 'İ',
'ı' => 'ı',
'IJ' => 'IJ',
'ij' => 'ij',
'Ĵ' => 'Ĵ',
'ĵ' => 'ĵ',
'Ķ' => 'Ķ',
'ķ' => 'ķ',
'ĸ' => 'ĸ',
'Ĺ' => 'Ĺ',
'ĺ' => 'ĺ',
'Ļ' => 'Ļ',
'ļ' => 'ļ',
'Ľ' => 'Ľ',
'ľ' => 'ľ',
'Ŀ' => 'Ŀ',
'ŀ' => 'ŀ',
'Ł' => 'Ł',
'ł' => 'ł',
'Ń' => 'Ń',
'ń' => 'ń',
'Ņ' => 'Ņ',
'ņ' => 'ņ',
'Ň' => 'Ň',
'ň' => 'ň',
'ʼn' => 'ʼn',
'Ŋ' => 'Ŋ',
'ŋ' => 'ŋ',
'Ō' => 'Ō',
'ō' => 'ō',
'Ŏ' => 'Ŏ',
'ŏ' => 'ŏ',
'Ő' => 'Ő',
'ő' => 'ő',
'Œ' => 'Œ',
'œ' => 'œ',
'Ŕ' => 'Ŕ',
'ŕ' => 'ŕ',
'Ŗ' => 'Ŗ',
'ŗ' => 'ŗ',
'Ř' => 'Ř',
'ř' => 'ř',
'Ś' => 'Ś',
'ś' => 'ś',
'Ŝ' => 'Ŝ',
'ŝ' => 'ŝ',
'"' => '"',
'Ş' => 'Ş',
'ş' => 'ş',
'Š' => 'Š',
'š' => 'š',
'Ţ' => 'Ţ',
'ţ' => 'ţ',
'Ť' => 'Ť',
'ť' => 'ť',
'Ŧ' => 'Ŧ',
'ŧ' => 'ŧ',
'Ũ' => 'Ũ',
'ũ' => 'ũ',
'Ū' => 'Ū',
'ū' => 'ū',
'Ŭ' => 'Ŭ',
'ŭ' => 'ŭ',
'Ů' => 'Ů',
'ů' => 'ů',
'Ű' => 'Ű',
'ű' => 'ű',
'Ų' => 'Ų',
'ų' => 'ų',
'Ŵ' => 'Ŵ',
'ŵ' => 'ŵ',
'Ŷ' => 'Ŷ',
'ŷ' => 'ŷ',
'Ź' => 'Ź',
'ź' => 'ź',
'Ż' => 'Ż',
'ż' => 'ż',
'Ž' => 'Ž',
'ž' => 'ž',
'ſ' => 'ſ',
'&' => '&',
''' => '\'',
'ƒ' => 'ƒ',
'Ʒ' => 'Ʒ',
'DŽ' => 'DŽ',
'Dž' => 'Dž',
'dž' => 'dž',
'LJ' => 'LJ',
'Lj' => 'Lj',
'lj' => 'lj',
'NJ' => 'NJ',
'Nj' => 'Nj',
'nj' => 'nj',
'Ǟ' => 'Ǟ',
'ǟ' => 'ǟ',
'Ǥ' => 'Ǥ',
'ǥ' => 'ǥ',
'Ǧ' => 'Ǧ',
'ǧ' => 'ǧ',
'Ǩ' => 'Ǩ',
'ǩ' => 'ǩ',
'Ǯ' => 'Ǯ',
'ǯ' => 'ǯ',
'DZ' => 'DZ',
'dz' => 'dz',
'Ǵ' => 'Ǵ',
'ǵ' => 'ǵ',
'Ǻ' => 'Ǻ',
'ǻ' => 'ǻ',
'Ǽ' => 'Ǽ',
'ǽ' => 'ǽ',
'Ǿ' => 'Ǿ',
'ǿ' => 'ǿ',
'<' => '<',
'>' => '>',
'ɼ' => 'ɼ',
'fi' => 'fi',
'fl' => 'fl',
'ʒ' => 'ʒ',
'˘' => '˘',
'˙' => '˙',
'˚' => '˚',
'˛' => '˛',
'˜' => '˜',
'˝' => '˝',
'Ḃ' => 'Ḃ',
'ḃ' => 'ḃ',
'Ḋ' => 'Ḋ',
'ḋ' => 'ḋ',
'Ḑ' => 'Ḑ',
'ḑ' => 'ḑ',
'Ḟ' => 'Ḟ',
'ḟ' => 'ḟ',
'Ḱ' => 'Ḱ',
'ḱ' => 'ḱ',
'Ṁ' => 'Ṁ',
'ṁ' => 'ṁ',
'Ṗ' => 'Ṗ',
'ṗ' => 'ṗ',
'Ṡ' => 'Ṡ',
'ṡ' => 'ṡ',
'Ṫ' => 'Ṫ',
'ṫ' => 'ṫ',
'Ẁ' => 'Ẁ',
'ẁ' => 'ẁ',
'Ẃ' => 'Ẃ',
'ẃ' => 'ẃ',
'Ẅ' => 'Ẅ',
'ẅ' => 'ẅ',
'Ỳ' => 'Ỳ',
'ỳ' => 'ỳ',
'―' => '―',
'‣' => '‣',
'‼' => '‼',
'‾' => '‾',
'⁄' => '⁄',
'ⁿ' => 'ⁿ',
'₣' => '₣',
'₤' => '₤',
'₧' => '₧',
'℅' => '℅',
'№' => '№',
'⅛' => '⅛',
'⅜' => '⅜',
'⅝' => '⅝',
'⅞' => '⅞',
'←' => '←',
'↑' => '↑',
'→' => '→',
'↓' => '↓',
'∂' => '∂',
'∆' => '∆',
'∏' => '∏',
'∑' => '∑',
'∙' => '∙',
'√' => '√',
'∞' => '∞',
'∟' => '∟',
'∩' => '∩',
'∫' => '∫',
'≈' => '≈',
'≠' => '≠',
'≡' => '≡',
'≤' => '≤',
'≥' => '≥',
'^' => '^',
'♀' => '♀',
'♂' => '♂',
'♠' => '♠',
'♣' => '♣',
'♥' => '♥',
'♦' => '♦',
'♩' => '♩',
'♪' => '♪',
'♬' => '♬',
'♭' => '♭',
'♯' => '♯',
'&498;' => 'Dz',
'Æ' => 'Æ',
'Á' => 'Á',
'Â' => 'Â',
'À' => 'À',
'Å' => 'Å',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Ç' => 'Ç',
'‡' => '‡',
'Ð' => 'Ð',
'É' => 'É',
'Ê' => 'Ê',
'È' => 'È',
'Ë' => 'Ë',
'Í' => 'Í',
'Î' => 'Î',
'Ì' => 'Ì',
'Ï' => 'Ï',
'Ñ' => 'Ñ',
'Œ' => 'Œ',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Ò' => 'Ò',
'Ø' => 'Ø',
'Õ' => 'Õ',
'Ö' => 'Ö',
'Þ' => 'Þ',
'Ú' => 'Ú',
'Û' => 'Û',
'Ù' => 'Ù',
'Ü' => 'Ü',
'Ý' => 'Ý',
'Ÿ' => 'Ÿ',
'á' => 'á',
'â' => 'â',
'´' => '´',
'æ' => 'æ',
'à' => 'à',
'&' => '&',
'å' => 'å',
'ã' => 'ã',
'ä' => 'ä',
'¦' => '¦',
'ç' => 'ç',
'¸' => '¸',
'¢' => '¢',
'♣' => '♣',
'©' => '©',
'¤' => '¤',
'†' => '†',
'↓' => '↓',
'&dbquo;' => '„',
'°' => '°',
'♦' => '♦',
'÷' => '÷',
'é' => 'é',
'ê' => 'ê',
'è' => 'è',
'ð' => 'ð',
'ë' => 'ë',
'€' => '€',
'½' => '½',
'¼' => '¼',
'¾' => '¾',
'>' => '>',
'♥' => '♥',
'í' => 'í',
'î' => 'î',
'¡' => '¡',
'ì' => 'ì',
'¿' => '¿',
'ï' => 'ï',
'«' => '«',
'←' => '←',
'“' => '“',
'‹' => '‹',
'‘' => '‘',
'<' => '<',
'¯' => '¯',
'—' => '—',
'µ' => 'µ',
'·' => '·',
'–' => '–',
'¬' => '¬',
'ñ' => 'ñ',
'ó' => 'ó',
'ô' => 'ô',
'œ' => 'œ',
'ò' => 'ò',
'‾' => '‾',
'ª' => 'ª',
'º' => 'º',
'ø' => 'ø',
'õ' => 'õ',
'ö' => 'ö',
'¶' => '¶',
'‰' => '‰',
'±' => '±',
'£' => '£',
'"' => '"',
'»' => '»',
'→' => '→',
'”' => '”',
'®' => '®',
'›' => '›',
'’' => '’',
'‚' => '‚',
'§' => '§',
'­' => '',
'♠' => '♠',
'¹' => '¹',
'²' => '²',
'³' => '³',
'ß' => 'ß',
'þ' => 'þ',
'&tilde' => '˜',
'˜' => '˜',
'×' => '×',
'™' => '™',
'ú' => 'ú',
'↑' => '↑',
'û' => 'û',
'ù' => 'ù',
'¨' => '¨',
'ü' => 'ü',
'ý' => 'ý',
'¥' => '¥',
'ÿ' => 'ÿ'
);
function __construct() {
setOptionDefault('xmpMetadata_suffix', 'xmp');
}
function getOptionsSupported() {
global $_zp_supported_images, $_zp_extra_filetypes;
$list = $_zp_supported_images;
foreach (array('gif', 'wbmp') as $suffix) {
$key = array_search($suffix, $list);
if ($key !== false)
unset($list[$key]);
}
sortArray($list);
$types = array();
foreach ($_zp_extra_filetypes as $suffix => $type) {
if ($type == 'Video')
$types[] = $suffix;
}
sortArray($types);
$list = array_merge($list, $types);
$listi = array();
foreach ($list as $suffix) {
$listi[$suffix] = 'xmpMetadata_examine_images_' . $suffix;
}
return array(gettext('Sidecar file extension') => array('key' => 'xmpMetadata_suffix', 'type' => OPTION_TYPE_TEXTBOX,
'desc' => gettext('The plugin will look for files with <em>image_name.extension</em> and extract XMP metadata from them into the <em>image_name</em> record.')),
gettext('Process extensions') => array('key' => 'xmpMetadata_examine_imagefile', 'type' => OPTION_TYPE_CHECKBOX_UL,
'checkboxes' => $listi,
'desc' => gettext('If no sidecar file exists and the extension is enabled, the plugin will search within that type <em>image</em> file for an <code>XMP</code> block. <strong>Warning</strong> do not set this option unless you require it. Searching image files can be computationally intensive.'))
);
}
function handleOption($option, $currentValue) {
}
private static function extract($xmpdata) {
$desiredtags = array(
'EXIFLensType' => '<aux:Lens>',
'EXIFLensInfo' => '<aux:LensInfo>',
'EXIFArtist' => '<dc:creator>',
'IPTCCopyright' => '<dc:rights>',
'IPTCImageCaption' => '<dc:description>',
'IPTCObjectName' => '<dc:title>',
'IPTCKeywords' => '<dc:subject>',
'EXIFExposureTime' => '<exif:ExposureTime>',
'EXIFFNumber' => '<exif:FNumber>',
'EXIFAperatureValue' => '<exif:ApertureValue>',
'EXIFExposureProgram' => '<exif:ExposureProgram>',
'EXIFISOSpeedRatings' => '<exif:ISOSpeedRatings>',
'EXIFDateTimeOriginal' => '<exif:DateTimeOriginal>',
'EXIFExposureBiasValue' => '<exif:ExposureBiasValue>',
'EXIFGPSLatitude' => '<exif:GPSLatitude>',
'EXIFGPSLongitude' => '<exif:GPSLongitude>',
'EXIFGPSAltitude' => '<exif:GPSAltitude>',
'EXIFGPSAltituedRef' => '<exif:GPSAltitudeRef>',
'EXIFMeteringMode' => '<exif:MeteringMode>',
'EXIFFocalLength' => '<exif:FocalLength>',
'EXIFContrast' => '<exif:Contrast>',
'EXIFSharpness' => '<exif:Sharpness>',
'EXIFExposureTime' => '<exif:ShutterSpeedValue>',
'EXIFSaturation' => '<exif:Saturation>',
'EXIFWhiteBalance' => '<exif:WhiteBalance>',
'IPTCLocationCode' => '<Iptc4xmpCore:CountryCode>',
'IPTCSubLocation' => '<Iptc4xmpCore:Location>',
'rating' => '<MicrosoftPhoto:Rating>',
'IPTCSource' => '<photoshop:Source>',
'IPTCCity' => '<photoshop:City>',
'IPTCState' => '<photoshop:State>',
'IPTCLocationName' => '<photoshop:Country>',
'IPTCImageHeadline' => '<photoshop:Headline>',
'IPTCImageCredit' => '<photoshop:Credit>',
'EXIFMake' => '<tiff:Make>',
'EXIFModel' => '<tiff:Model>',
'EXIFOrientation' => '<tiff:Orientation>',
'EXIFImageWidth' => '<tiff:ImageWidth>',
'EXIFImageHeight' => '<tiff:ImageLength>',
'owner' => '<zp:Owner>',
'thumb' => '<zp:Thumbnail>',
'watermark' => '<zp:Watermark>',
'watermark_use' => '<zp:Watermark_use>',
'watermark_thumb' => '<zp:Watermark_thumb>',
'custom_data' => '<zp:CustomData',
'codeblock' => '<zp:Codeblock>'
);
$xmp_parsed = array();
while (!empty($xmpdata)) {
$s = strpos($xmpdata, '<');
$e = strpos($xmpdata, '>', $s);
$tag = substr($xmpdata, $s, $e - $s + 1);
$xmpdata = substr($xmpdata, $e + 1);
$key = array_search($tag, $desiredtags);
if ($key !== false) {
$close = str_replace('<', '</', $tag);
$e = strpos($xmpdata, $close);
$meta = trim(substr($xmpdata, 0, $e));
$xmpdata = substr($xmpdata, $e + strlen($close));
if (strpos($meta, '<') === false) {
$xmp_parsed[$key] = self::decode($meta);
} else {
$elements = array();
while (!empty($meta)) {
$s = strpos($meta, '<');
$e = strpos($meta, '>', $s);
$tag = substr($meta, $s, $e - $s + 1);
$meta = substr($meta, $e + 1);
if (strpos($tag, 'rdf:li') !== false) {
$e = strpos($meta, '</rdf:li>');
$elements[] = self::decode(trim(substr($meta, 0, $e)));
$meta = substr($meta, $e + 9);
}
}
$xmp_parsed[$key] = $elements;
}
} else {
if (strpos($tag, '<rdf:Description') !== false) {
$meta = substr($tag, 17);
while (preg_match('/^[a-zA-z0-9_]+\:[a-zA-z0-9_]+\=".*"/', $meta, $element)) {
$item = $element[0];
$meta = trim(substr($meta, strlen($item)));
$i = strpos($item, '=');
$tag = '<' . substr($item, 0, $i) . '>';
$v = self::decode(trim(substr($item, $i + 2, -1)));
$key = array_search($tag, $desiredtags);
if ($key !== false) {
$xmp_parsed[$key] = $v;
}
}
}
}
}
return ($xmp_parsed);
}
private static function to_string($meta) {
if (is_array($meta)) {
$meta = implode(',', $meta);
}
return trim($meta);
}
static function album_instantiate($album) {
$album->sidecars[XMP_EXTENSION] = XMP_EXTENSION;
return $album;
}
static function new_album($album) {
$metadata_path = dirname($album->localpath) . '/' . basename($album->localpath) . '*';
$files = safe_glob($metadata_path);
if (count($files) > 0) {
foreach ($files as $file) {
if (strtolower(getSuffix($file)) == XMP_EXTENSION) {
$source = file_get_contents($file);
$metadata = self::extract($source);
if (array_key_exists('IPTCImageCaption', $metadata)) {
$album->setDesc(self::to_string($metadata['IPTCImageCaption']));
}
if (array_key_exists('IPTCImageHeadline', $metadata)) {
$album->setTitle(self::to_string($metadata['IPTCImageHeadline']));
}
if (array_key_exists('IPTCLocationName', $metadata)) {
$album->setLocation(self::to_string($metadata['IPTCLocationName']));
}
if (array_key_exists('IPTCKeywords', $metadata)) {
$tags = $metadata['IPTCKeywords'];
if (!is_array($tags)) {
$tags = explode(',', $tags);
}
$album->setTags($tags);
}
if (array_key_exists('EXIFDateTimeOriginal', $metadata)) {
$album->setDateTime($metadata['EXIFDateTimeOriginal']);
}
if (array_key_exists('thumb', $metadata)) {
$album->setThumb($metadata['thumb']);
}
if (array_key_exists('owner', $metadata)) {
$album->setOwner($metadata['owner']);
}
if (array_key_exists('custom_data', $metadata)) {
$album->setCustomData($metadata['custom_data']);
}
if (array_key_exists('codeblock', $metadata)) {
$album->setCodeblock($metadata['codeblock']);
}
if (array_key_exists('watermark', $metadata)) {
$album->setWatermark($metadata['watermark']);
}
if (array_key_exists('watermark_thumb', $metadata)) {
$album->setWatermarkThumb($metadata['watermark_thumb']);
}
if (array_key_exists('rating', $metadata)) {
$v = min(getoption('rating_stars_count'), $metadata['rating']) * min(1, getOption('rating_split_stars'));
$album->set('total_value', $v);
$album->set('rating', $v);
$album->set('total_votes', 1);
}
$album->save();
break;
}
}
return $album;
}
}
private static function extractXMP($f) {
if (preg_match('~<.*?xmpmeta~', $f, $m)) {
$open = $m[0];
$close = str_replace('<', '</', $open);
$j = strpos($f, $open);
if ($j !== false) {
$k = strpos($f, $close, $j + 4);
$meta = substr($f, $j, $k + 14 - $j);
$l = 0;
return $meta;
}
}
return false;
}
private static function rationalNum($element) {
$n = explode('/', $element);
$v = sprintf('%f', $n[0] / $n[1]);
for ($i = strlen($v) - 1; $i > 1; $i--) {
if ($v[$i] != '0')
break;
}
if ($v[$i] == '.')
$i--;
return substr($v, 0, $i + 1);
}
private static function encode($str) {
return strtr($str, array_flip(self::$XML_trans));
}
private static function decode($str) {
return strtr($str, self::$XML_trans);
}
static function image_instantiate($image) {
$image->sidecars[XMP_EXTENSION] = XMP_EXTENSION;
return $image;
}
static function new_image($image) {
global $_zp_exifvars;
$source = '';
$metadata_path = '';
$files = safe_glob(substr($image->localpath, 0, strrpos($image->localpath, '.')) . '.*');
if (count($files) > 0) {
foreach ($files as $file) {
if (strtolower(getSuffix($file)) == XMP_EXTENSION) {
$metadata_path = $file;
break;
}
}
}
if (!empty($metadata_path)) {
$source = self::extractXMP(file_get_contents($metadata_path));
} else if (getOption('xmpMetadata_examine_images_' . strtolower(substr(strrchr($image->localpath, "."), 1)))) {
$f = file_get_contents($image->localpath);
$l = filesize($image->localpath);
$abort = 0;
$i = 0;
while ($i < $l && $abort < 200 && !$source) {
$tag = bin2hex(substr($f, $i, 2));
$size = hexdec(bin2hex(substr($f, $i + 2, 2)));
switch ($tag) {
case 'ffe1':
case 'ffe2':
case 'fffe':
case 'ffe0':
$source = self::extractXMP($f);
$i = $i + $size + 2;
$abort = 0;
break;
default:
if ($f[$i] == '<') {
$source = self::extractXMP($f);
}
$i = $i + 1;
$abort++;
break;
}
}
}
if (!empty($source)) {
$metadata = self::extract($source);
$hasmetadata = 0;
if(count($metadata) > 0) {
$hasmetadata = 1;
}
$image->set('hasMetadata', $hasmetadata);
foreach ($metadata as $field => $element) {
if (array_key_exists($field, $_zp_exifvars)) {
if (!$_zp_exifvars[$field][5]) {
continue;
}
}
$v = self::to_string($element);
switch ($field) {
case 'EXIFDateTimeOriginal':
$image->setDateTime($element);
break;
case 'IPTCImageCaption':
$image->setDesc($v);
break;
case 'IPTCCity':
$image->setCity($v);
break;
case 'IPTCState':
$image->setState($v);
break;
case 'IPTCLocationName':
$image->setCountry($v);
break;
case 'IPTCSubLocation':
$image->setLocation($v);
break;
case 'EXIFExposureTime':
$v = formatExposure(self::rationalNum($element));
break;
case 'EXIFFocalLength':
$v = self::rationalNum($element) . ' mm';
break;
case 'EXIFAperatureValue':
case 'EXIFFNumber':
$v = 'f/' . self::rationalNum($element);
break;
case 'EXIFExposureBiasValue':
case 'EXIFGPSAltitude':
$v = self::rationalNum($element);
break;
case 'EXIFGPSLatitude':
case 'EXIFGPSLongitude':
$ref = substr($element, -1, 1);
$image->set($field . 'Ref', $ref);
$element = substr($element, 0, -1);
$n = explode(',', $element);
if (count($n) == 3) {
$v = $n[0] + ($n[1] + ($n[2] / 60) / 60);
} else {
$v = $n[0] + $n[1] / 60;
}
break;
case 'rating':
$v = min(getoption('rating_stars_count'), $v) * min(1, getOption('rating_split_stars'));
$image->set('total_value', $v);
$image->set('total_votes', 1);
break;
case 'watermark':
case 'watermark_use':
case 'custom_data':
case 'codeblock':
case 'owner':
$image->set($field, $v);
break;
case 'IPTCKeywords':
if (!is_array($element)) {
$element = explode(',', $element);
}
$image->setTags($element);
break;
}
if (array_key_exists($field, $_zp_exifvars)) {
$image->set($field, $v);
}
}
$image->save();
}
return $image;
}
static function sidecars($types) {
$types[] = XMP_EXTENSION;
return $types;
}
static function putXMP($object, $prefix) {
if (isset($_POST['xmpMedadataPut_' . $prefix])) {
self::publish($object);
}
return $object;
}
static function publish($object) {
$desiredtags = array('copyright' => '<dc:rights>',
'desc' => '<dc:description>',
'title' => '<dc:title>',
'tags' => '<dc:subject>',
'location' => '<Iptc4xmpCore:Location>',
'city' => '<photoshop:City>',
'state' => '<photoshop:State>',
'country' => '<photoshop:Country>',
'title' => '<photoshop:Headline>',
'credit' => '<photoshop:Credit>',
'thumb' => '<zp:Thumbnail>',
'owner' => '<zp:Owner>',
'watermark' => '<zp:Watermark>',
'watermark_use' => '<zp:Watermark_use>',
'watermark_thumb' => '<zp:Watermark_thumb>',
'custom_data' => '<zp:CustomData>',
'codeblock' => '<zp:Codeblock>',
'date' => '<exif:DateTimeOriginal>',
'rating' => '<MicrosoftPhoto:Rating>'
);
$process = array('dc', 'Iptc4xmpCore', 'photoshop', 'xap');
if (isAlbumClass($object)) {
$file = rtrim($object->localpath, '/');
$file .= '.xmp';
} else {
$file = stripSuffix($object->localpath) . '.xmp';
}
@chmod($file, 0777);
$f = fopen($file, 'w');
fwrite($f, '<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2-c020 1.124078, Tue Sep 11 2007 23:21:40 ">' . "\n");
fwrite($f, ' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' . "\n");
$last_element = $special = $output = false;
foreach ($desiredtags as $field => $elementXML) {
$elementXML = substr($elementXML, 1, -1);
if ($last_element != $elementXML) {
if ($output) {
fwrite($f, ' </rdf:Description>' . "\n");
fwrite($f, ' <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">' . "\n");
}
$last_element = $elementXML;
$output = false;
}
$v = self::encode($object->get($field));
$tag = $elementXML;
switch ($elementXML) {
case 'dc:creator':
$special = 'rdf:Seq';
$tag = 'rdf:li';
if ($v) {
fwrite($f, " <$elementXML>\n");
fwrite($f, " <$special>\n");
fwrite($f, " <$tag>$v</$tag>\n");
fwrite($f, " </$special>\n");
fwrite($f, " </$elementXML>\n");
$output = true;
}
break;
case 'dc:rights':
case 'xapRights:UsageTerms':
$special = 'rdf:Alt';
$tag = 'rdf:li';
if ($v) {
fwrite($f, " <$elementXML>\n");
fwrite($f, " <$special>\n");
fwrite($f, " <$tag>$v</$tag>\n");
fwrite($f, " </$special>\n");
fwrite($f, " </$elementXML>\n");
$output = true;
}
break;
case 'dc:subject':
$tags = $object->getTags();
if (!empty($tags)) {
fwrite($f, " <$elementXML>\n");
fwrite($f, " <rdf:Bag>\n");
foreach ($tags as $tag) {
fwrite($f, " <rdf:li>" . self::encode($tag) . "</rdf:li>\n");
}
fwrite($f, " </rdf:Bag>\n");
fwrite($f, " </$elementXML>\n");
$output = true;
}
break;
default:
if ($v) {
fwrite($f, " <$tag>$v</$tag>\n");
$output = true;
}
break;
}
}
fwrite($f, ' </rdf:Description>' . "\n");
fwrite($f, ' </rdf:RDF>' . "\n");
fwrite($f, '</x:xmpmeta>' . "\n");
fclose($f);
clearstatcache();
@chmod($file, FILE_MOD);
return gettext('Metadata exported');
}
static function create($html, $object, $prefix) {
if ($html)
$html .= '<hr />';
$html .= '<label><input type="checkbox" name="xmpMedadataPut_' . $prefix . '" value="1" /> ' . gettext('Export metadata info to XMP sidecar.') . '</label>';
return $html;
}
static function bulkActions($actions) {
return array_merge($actions, array(gettext('Export Metadata') => 'xmpMetadataPublish'));
}
}
?>