1 /*****************************************************************************/ 2 // Copyright 2006-2008 Adobe Systems Incorporated 3 // All Rights Reserved. 4 // 5 // NOTICE: Adobe permits you to use, modify, and distribute this file in 6 // accordance with the terms of the Adobe license agreement accompanying it. 7 /*****************************************************************************/ 8 9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp.cpp#1 $ */ 10 /* $DateTime: 2012/05/30 13:28:51 $ */ 11 /* $Change: 832332 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 #if qDNGUseXMP 16 17 #include "dng_xmp.h" 18 19 #include "dng_assertions.h" 20 #include "dng_date_time.h" 21 #include "dng_exceptions.h" 22 #include "dng_exif.h" 23 #include "dng_image_writer.h" 24 #include "dng_iptc.h" 25 #include "dng_negative.h" 26 #include "dng_string.h" 27 #include "dng_string_list.h" 28 #include "dng_utils.h" 29 #include "dng_xmp_sdk.h" 30 31 /*****************************************************************************/ 32 33 dng_xmp::dng_xmp (dng_memory_allocator &allocator) 34 35 : fAllocator (allocator) 36 37 , fSDK (NULL) 38 39 { 40 41 fSDK = new dng_xmp_sdk (); 42 43 if (!fSDK) 44 { 45 ThrowMemoryFull (); 46 } 47 48 } 49 50 /*****************************************************************************/ 51 52 dng_xmp::dng_xmp (const dng_xmp &xmp) 53 54 : fAllocator (xmp.fAllocator) 55 56 , fSDK (NULL) 57 58 { 59 60 fSDK = new dng_xmp_sdk (*xmp.fSDK); 61 62 if (!fSDK) 63 { 64 ThrowMemoryFull (); 65 } 66 67 } 68 69 /*****************************************************************************/ 70 71 dng_xmp::~dng_xmp () 72 { 73 74 if (fSDK) 75 { 76 77 delete fSDK; 78 79 } 80 81 } 82 83 /*****************************************************************************/ 84 85 dng_xmp * dng_xmp::Clone () const 86 { 87 88 dng_xmp *result = new dng_xmp (*this); 89 90 if (!result) 91 { 92 ThrowMemoryFull (); 93 } 94 95 return result; 96 97 } 98 99 /*****************************************************************************/ 100 101 void dng_xmp::TrimDecimal (char *s) 102 { 103 104 uint32 len = (uint32) strlen (s); 105 106 while (len > 0) 107 { 108 109 if (s [len - 1] == '0') 110 s [--len] = 0; 111 112 else 113 break; 114 115 } 116 117 if (len > 0) 118 { 119 120 if (s [len - 1] == '.') 121 s [--len] = 0; 122 123 } 124 125 } 126 127 /*****************************************************************************/ 128 129 dng_string dng_xmp::EncodeFingerprint (const dng_fingerprint &f, 130 bool allowInvalid) 131 { 132 133 dng_string result; 134 135 if (f.IsValid () || allowInvalid) 136 { 137 138 char s [dng_fingerprint::kDNGFingerprintSize * 2 + 1]; 139 140 f.ToUtf8HexString (s); 141 142 result.Set (s); 143 144 } 145 146 return result; 147 148 } 149 150 /*****************************************************************************/ 151 152 dng_fingerprint dng_xmp::DecodeFingerprint (const dng_string &s) 153 { 154 155 dng_fingerprint result; 156 157 if (s.Length () == 32) 158 result.FromUtf8HexString (s.Get ()); 159 160 return result; 161 162 } 163 164 /*****************************************************************************/ 165 166 dng_string dng_xmp::EncodeGPSVersion (uint32 version) 167 { 168 169 dng_string result; 170 171 if (version) 172 { 173 174 uint8 b0 = (uint8) (version >> 24); 175 uint8 b1 = (uint8) (version >> 16); 176 uint8 b2 = (uint8) (version >> 8); 177 uint8 b3 = (uint8) (version ); 178 179 if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9) 180 { 181 182 char s [32]; 183 184 sprintf (s, 185 "%u.%u.%u.%u", 186 (unsigned) b0, 187 (unsigned) b1, 188 (unsigned) b2, 189 (unsigned) b3); 190 191 result.Set (s); 192 193 } 194 195 } 196 197 return result; 198 199 } 200 201 /*****************************************************************************/ 202 203 uint32 dng_xmp::DecodeGPSVersion (const dng_string &s) 204 { 205 206 uint32 result = 0; 207 208 if (s.Length () == 7) 209 { 210 211 unsigned b0 = 0; 212 unsigned b1 = 0; 213 unsigned b2 = 0; 214 unsigned b3 = 0; 215 216 if (sscanf (s.Get (), 217 "%u.%u.%u.%u", 218 &b0, 219 &b1, 220 &b2, 221 &b3) == 4) 222 { 223 224 result = (b0 << 24) | 225 (b1 << 16) | 226 (b2 << 8) | 227 (b3 ); 228 229 } 230 231 } 232 233 return result; 234 235 } 236 237 /*****************************************************************************/ 238 239 dng_string dng_xmp::EncodeGPSCoordinate (const dng_string &ref, 240 const dng_urational *coord) 241 { 242 243 dng_string result; 244 245 if (ref.Length () == 1 && coord [0].IsValid () && 246 coord [1].IsValid ()) 247 { 248 249 char refChar = ForceUppercase (ref.Get () [0]); 250 251 if (refChar == 'N' || 252 refChar == 'S' || 253 refChar == 'E' || 254 refChar == 'W') 255 { 256 257 char s [256]; 258 259 // Use the seconds case if all three values are 260 // integers. 261 262 if (coord [0].d == 1 && 263 coord [1].d == 1 && 264 coord [2].d == 1) 265 { 266 267 sprintf (s, 268 "%u,%u,%u%c", 269 (unsigned) coord [0].n, 270 (unsigned) coord [1].n, 271 (unsigned) coord [2].n, 272 refChar); 273 274 } 275 276 // Else we need to use the fractional minutes case. 277 278 else 279 { 280 281 // Find value minutes. 282 283 real64 x = coord [0].As_real64 () * 60.0 + 284 coord [1].As_real64 () + 285 coord [2].As_real64 () * (1.0 / 60.0); 286 287 // Round to fractional four decimal places. 288 289 uint32 y = Round_uint32 (x * 10000.0); 290 291 // Split into degrees and minutes. 292 293 uint32 d = y / (60 * 10000); 294 uint32 m = y % (60 * 10000); 295 296 char min [32]; 297 298 sprintf (min, "%.4f", m * (1.0 / 10000.0)); 299 300 TrimDecimal (min); 301 302 sprintf (s, 303 "%u,%s%c", 304 (unsigned) d, 305 min, 306 refChar); 307 308 } 309 310 result.Set (s); 311 312 } 313 314 } 315 316 return result; 317 318 } 319 320 /*****************************************************************************/ 321 322 void dng_xmp::DecodeGPSCoordinate (const dng_string &s, 323 dng_string &ref, 324 dng_urational *coord) 325 { 326 327 ref.Clear (); 328 329 coord [0].Clear (); 330 coord [1].Clear (); 331 coord [2].Clear (); 332 333 if (s.Length () > 1) 334 { 335 336 char refChar = ForceUppercase (s.Get () [s.Length () - 1]); 337 338 if (refChar == 'N' || 339 refChar == 'S' || 340 refChar == 'E' || 341 refChar == 'W') 342 { 343 344 dng_string ss (s); 345 346 ss.Truncate (ss.Length () - 1); 347 348 ss.NormalizeAsCommaSeparatedNumbers(); 349 350 int degrees = 0; 351 352 real64 minutes = 0.0; 353 real64 seconds = 0.0; 354 355 int count = sscanf (ss.Get (), 356 "%d,%lf,%lf", 357 °rees, 358 &minutes, 359 &seconds); 360 361 if (count < 1) 362 { 363 return; 364 } 365 366 // The degree, minute, second values should always be positive. 367 368 if (degrees < 0 || minutes < 0 || seconds < 0) 369 { 370 return; 371 } 372 373 coord [0] = dng_urational ((uint32) degrees, 1); 374 375 if (count <= 2) 376 { 377 coord [1].Set_real64 (minutes, 10000); 378 coord [2] = dng_urational (0, 1); 379 } 380 else 381 { 382 coord [1].Set_real64 (minutes, 1); 383 coord [2].Set_real64 (seconds, 100); 384 } 385 386 char r [2]; 387 388 r [0] = refChar; 389 r [1] = 0; 390 391 ref.Set (r); 392 393 } 394 395 } 396 397 } 398 399 /*****************************************************************************/ 400 401 dng_string dng_xmp::EncodeGPSDateTime (const dng_string &dateStamp, 402 const dng_urational *timeStamp) 403 { 404 405 dng_string result; 406 407 if (timeStamp [0].IsValid () && 408 timeStamp [1].IsValid () && 409 timeStamp [2].IsValid ()) 410 { 411 412 char s [256]; 413 414 char sec [32]; 415 416 sprintf (sec, 417 "%09.6f", 418 timeStamp [2].As_real64 ()); 419 420 TrimDecimal (sec); 421 422 int year = 0; 423 int month = 0; 424 int day = 0; 425 426 if (dateStamp.NotEmpty ()) 427 { 428 429 sscanf (dateStamp.Get (), 430 "%d:%d:%d", 431 &year, 432 &month, 433 &day); 434 435 } 436 437 if (year >= 1 && year <= 9999 && 438 month >= 1 && month <= 12 && 439 day >= 1 && day <= 31) 440 { 441 442 sprintf (s, 443 "%04d-%02d-%02dT%02u:%02u:%sZ", 444 year, 445 month, 446 day, 447 (unsigned) Round_uint32 (timeStamp [0].As_real64 ()), 448 (unsigned) Round_uint32 (timeStamp [1].As_real64 ()), 449 sec); 450 451 } 452 453 else 454 { 455 456 sprintf (s, 457 "%02u:%02u:%sZ", 458 (unsigned) Round_uint32 (timeStamp [0].As_real64 ()), 459 (unsigned) Round_uint32 (timeStamp [1].As_real64 ()), 460 sec); 461 462 } 463 464 result.Set (s); 465 466 } 467 468 return result; 469 470 } 471 472 /*****************************************************************************/ 473 474 void dng_xmp::DecodeGPSDateTime (const dng_string &s, 475 dng_string &dateStamp, 476 dng_urational *timeStamp) 477 { 478 479 dateStamp.Clear (); 480 481 timeStamp [0].Clear (); 482 timeStamp [1].Clear (); 483 timeStamp [2].Clear (); 484 485 if (s.NotEmpty ()) 486 { 487 488 unsigned year = 0; 489 unsigned month = 0; 490 unsigned day = 0; 491 unsigned hour = 0; 492 unsigned minute = 0; 493 494 double second = 0.0; 495 496 if (sscanf (s.Get (), 497 "%u-%u-%uT%u:%u:%lf", 498 &year, 499 &month, 500 &day, 501 &hour, 502 &minute, 503 &second) == 6) 504 { 505 506 if (year >= 1 && year <= 9999 && 507 month >= 1 && month <= 12 && 508 day >= 1 && day <= 31 ) 509 { 510 511 char ss [64]; 512 513 sprintf (ss, 514 "%04u:%02u:%02u", 515 year, 516 month, 517 day); 518 519 dateStamp.Set (ss); 520 521 } 522 523 } 524 525 else if (sscanf (s.Get (), 526 "%u:%u:%lf", 527 &hour, 528 &minute, 529 &second) != 3) 530 { 531 532 return; 533 534 } 535 536 timeStamp [0] = dng_urational ((uint32) hour , 1); 537 timeStamp [1] = dng_urational ((uint32) minute, 1); 538 539 timeStamp [2].Set_real64 (second, 1000); 540 541 } 542 543 } 544 545 /*****************************************************************************/ 546 547 void dng_xmp::Parse (dng_host &host, 548 const void *buffer, 549 uint32 count) 550 { 551 552 fSDK->Parse (host, 553 (const char *) buffer, 554 count); 555 556 } 557 558 /*****************************************************************************/ 559 560 dng_memory_block * dng_xmp::Serialize (bool asPacket, 561 uint32 targetBytes, 562 uint32 padBytes, 563 bool forJPEG, 564 bool compact) const 565 { 566 567 return fSDK->Serialize (fAllocator, 568 asPacket, 569 targetBytes, 570 padBytes, 571 forJPEG, 572 compact); 573 574 } 575 576 /*****************************************************************************/ 577 578 void dng_xmp::PackageForJPEG (AutoPtr<dng_memory_block> &stdBlock, 579 AutoPtr<dng_memory_block> &extBlock, 580 dng_string &extDigest) const 581 { 582 583 fSDK->PackageForJPEG (fAllocator, 584 stdBlock, 585 extBlock, 586 extDigest); 587 588 } 589 590 /*****************************************************************************/ 591 592 void dng_xmp::MergeFromJPEG (const dng_xmp &xmp) 593 { 594 595 fSDK->MergeFromJPEG (xmp.fSDK); 596 597 } 598 599 /*****************************************************************************/ 600 601 bool dng_xmp::HasMeta () const 602 { 603 604 return fSDK->HasMeta (); 605 606 } 607 608 /*****************************************************************************/ 609 610 void * dng_xmp::GetPrivateMeta () 611 { 612 613 return fSDK->GetPrivateMeta (); 614 615 } 616 617 /*****************************************************************************/ 618 619 bool dng_xmp::Exists (const char *ns, 620 const char *path) const 621 { 622 623 return fSDK->Exists (ns, path); 624 625 } 626 627 /*****************************************************************************/ 628 629 bool dng_xmp::HasNameSpace (const char *ns) const 630 { 631 632 return fSDK->HasNameSpace (ns); 633 634 } 635 636 /*****************************************************************************/ 637 638 bool dng_xmp::IteratePaths (IteratePathsCallback *callback, 639 void *callbackData, 640 const char *ns, 641 const char *path) 642 { 643 644 return fSDK->IteratePaths (callback, callbackData, ns, path); 645 646 } 647 648 /*****************************************************************************/ 649 650 void dng_xmp::Remove (const char *ns, 651 const char *path) 652 { 653 654 fSDK->Remove (ns, path); 655 656 } 657 658 /*****************************************************************************/ 659 660 void dng_xmp::RemoveProperties (const char *ns) 661 { 662 663 fSDK->RemoveProperties (ns); 664 665 } 666 667 /*****************************************************************************/ 668 669 void dng_xmp::RemoveEmptyStringOrArray (const char *ns, 670 const char *path) 671 { 672 673 if (path == NULL || path [0] == 0) 674 { 675 return; 676 } 677 678 if (fSDK->IsEmptyString (ns, path) || 679 fSDK->IsEmptyArray (ns, path)) 680 { 681 682 Remove (ns, path); 683 684 } 685 686 } 687 688 /*****************************************************************************/ 689 690 static bool RemoveEmptyStringsAndArraysCallback (const char *ns, 691 const char *path, 692 void *callbackData) 693 { 694 695 dng_xmp *xmp = (dng_xmp *) callbackData; 696 697 xmp->RemoveEmptyStringOrArray (ns, path); 698 699 return true; 700 701 } 702 703 /*****************************************************************************/ 704 705 void dng_xmp::RemoveEmptyStringsAndArrays (const char *ns) 706 { 707 708 IteratePaths (RemoveEmptyStringsAndArraysCallback, 709 (void *) this, 710 ns, 711 NULL); 712 713 } 714 715 /*****************************************************************************/ 716 717 void dng_xmp::Set (const char *ns, 718 const char *path, 719 const char *text) 720 { 721 722 fSDK->Set (ns, path, text); 723 724 } 725 726 /*****************************************************************************/ 727 728 bool dng_xmp::GetString (const char *ns, 729 const char *path, 730 dng_string &s) const 731 { 732 733 return fSDK->GetString (ns, path, s); 734 735 } 736 737 /*****************************************************************************/ 738 739 void dng_xmp::SetString (const char *ns, 740 const char *path, 741 const dng_string &s) 742 { 743 744 fSDK->SetString (ns, path, s); 745 746 } 747 748 /*****************************************************************************/ 749 750 bool dng_xmp::SyncString (const char *ns, 751 const char *path, 752 dng_string &s, 753 uint32 options) 754 { 755 756 bool isDefault = s.IsEmpty (); 757 758 // Sync 1: Force XMP to match non-XMP. 759 760 if (options & ignoreXMP) 761 { 762 763 if (isDefault || (options & removeXMP)) 764 { 765 766 Remove (ns, path); 767 768 } 769 770 else 771 { 772 773 SetString (ns, path, s); 774 775 } 776 777 return false; 778 779 } 780 781 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 782 783 if ((options & preferNonXMP) && !isDefault) 784 { 785 786 if (options & removeXMP) 787 { 788 789 Remove (ns, path); 790 791 } 792 793 else 794 { 795 796 SetString (ns, path, s); 797 798 } 799 800 return false; 801 802 } 803 804 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 805 806 if ((options & preferXMP) || isDefault) 807 { 808 809 if (GetString (ns, path, s)) 810 { 811 812 if (options & removeXMP) 813 { 814 815 Remove (ns, path); 816 817 } 818 819 return true; 820 821 } 822 823 } 824 825 // Sync 4: From non-XMP to XMP. 826 827 if (options & removeXMP) 828 { 829 830 Remove (ns, path); 831 832 } 833 834 else if (!isDefault) 835 { 836 837 SetString (ns, path, s); 838 839 } 840 841 return false; 842 843 } 844 845 /*****************************************************************************/ 846 847 bool dng_xmp::GetStringList (const char *ns, 848 const char *path, 849 dng_string_list &list) const 850 { 851 852 return fSDK->GetStringList (ns, path, list); 853 854 } 855 856 /*****************************************************************************/ 857 858 void dng_xmp::SetStringList (const char *ns, 859 const char *path, 860 const dng_string_list &list, 861 bool isBag) 862 { 863 864 fSDK->SetStringList (ns, path, list, isBag); 865 866 } 867 868 /*****************************************************************************/ 869 870 void dng_xmp::SyncStringList (const char *ns, 871 const char *path, 872 dng_string_list &list, 873 bool isBag, 874 uint32 options) 875 { 876 877 bool isDefault = (list.Count () == 0); 878 879 // First make sure the XMP is not badly formatted, since 880 // this breaks some Photoshop logic. 881 882 ValidateStringList (ns, path); 883 884 // Sync 1: Force XMP to match non-XMP. 885 886 if (options & ignoreXMP) 887 { 888 889 if (isDefault) 890 { 891 892 Remove (ns, path); 893 894 } 895 896 else 897 { 898 899 SetStringList (ns, path, list, isBag); 900 901 } 902 903 return; 904 905 } 906 907 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 908 909 if ((options & preferNonXMP) && !isDefault) 910 { 911 912 SetStringList (ns, path, list, isBag); 913 914 return; 915 916 } 917 918 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 919 920 if ((options & preferXMP) || isDefault) 921 { 922 923 if (GetStringList (ns, path, list)) 924 { 925 926 return; 927 928 } 929 930 } 931 932 // Sync 4: From non-XMP to XMP. 933 934 if (!isDefault) 935 { 936 937 SetStringList (ns, path, list, isBag); 938 939 } 940 941 } 942 943 /*****************************************************************************/ 944 945 void dng_xmp::SetStructField (const char *ns, 946 const char *path, 947 const char *fieldNS, 948 const char *fieldName, 949 const dng_string &s) 950 { 951 952 dng_string ss (s); 953 954 ss.SetLineEndings ('\n'); 955 956 ss.StripLowASCII (); 957 958 fSDK->SetStructField (ns, path, fieldNS, fieldName, ss.Get ()); 959 960 } 961 962 /*****************************************************************************/ 963 964 void dng_xmp::SetStructField (const char *ns, 965 const char *path, 966 const char *fieldNS, 967 const char *fieldName, 968 const char *s) 969 { 970 971 fSDK->SetStructField (ns, path, fieldNS, fieldName, s); 972 973 } 974 975 /*****************************************************************************/ 976 977 void dng_xmp::DeleteStructField (const char *ns, 978 const char *path, 979 const char *fieldNS, 980 const char *fieldName) 981 { 982 983 fSDK->DeleteStructField (ns, path, fieldNS, fieldName); 984 985 } 986 987 /*****************************************************************************/ 988 989 bool dng_xmp::GetStructField (const char *ns, 990 const char *path, 991 const char *fieldNS, 992 const char *fieldName, 993 dng_string &s) const 994 { 995 996 return fSDK->GetStructField (ns, path, fieldNS, fieldName, s); 997 998 } 999 1000 /*****************************************************************************/ 1001 1002 void dng_xmp::SetAltLangDefault (const char *ns, 1003 const char *path, 1004 const dng_string &s) 1005 { 1006 1007 fSDK->SetAltLangDefault (ns, path, s); 1008 1009 } 1010 1011 /*****************************************************************************/ 1012 1013 bool dng_xmp::GetAltLangDefault (const char *ns, 1014 const char *path, 1015 dng_string &s) const 1016 { 1017 1018 return fSDK->GetAltLangDefault (ns, path, s); 1019 1020 } 1021 1022 /*****************************************************************************/ 1023 1024 bool dng_xmp::SyncAltLangDefault (const char *ns, 1025 const char *path, 1026 dng_string &s, 1027 uint32 options) 1028 { 1029 1030 bool isDefault = s.IsEmpty (); 1031 1032 // Sync 1: Force XMP to match non-XMP. 1033 1034 if (options & ignoreXMP) 1035 { 1036 1037 if (isDefault) 1038 { 1039 1040 Remove (ns, path); 1041 1042 } 1043 1044 else 1045 { 1046 1047 SetAltLangDefault (ns, path, s); 1048 1049 } 1050 1051 return false; 1052 1053 } 1054 1055 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 1056 1057 if ((options & preferNonXMP) && !isDefault) 1058 { 1059 1060 SetAltLangDefault (ns, path, s); 1061 1062 return false; 1063 1064 } 1065 1066 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 1067 1068 if ((options & preferXMP) || isDefault) 1069 { 1070 1071 if (GetAltLangDefault (ns, path, s)) 1072 { 1073 1074 return true; 1075 1076 } 1077 1078 } 1079 1080 // Sync 4: From non-XMP to XMP. 1081 1082 if (!isDefault) 1083 { 1084 1085 SetAltLangDefault (ns, path, s); 1086 1087 } 1088 1089 return false; 1090 1091 } 1092 1093 /*****************************************************************************/ 1094 1095 bool dng_xmp::GetBoolean (const char *ns, 1096 const char *path, 1097 bool &x) const 1098 { 1099 1100 dng_string s; 1101 1102 if (GetString (ns, path, s)) 1103 { 1104 1105 if (s.Matches ("True")) 1106 { 1107 1108 x = true; 1109 1110 return true; 1111 1112 } 1113 1114 if (s.Matches ("False")) 1115 { 1116 1117 x = false; 1118 1119 return true; 1120 1121 } 1122 1123 } 1124 1125 return false; 1126 1127 } 1128 1129 /*****************************************************************************/ 1130 1131 void dng_xmp::SetBoolean (const char *ns, 1132 const char *path, 1133 bool x) 1134 { 1135 1136 Set (ns, path, x ? "True" : "False"); 1137 1138 } 1139 1140 /*****************************************************************************/ 1141 1142 bool dng_xmp::Get_int32 (const char *ns, 1143 const char *path, 1144 int32 &x) const 1145 { 1146 1147 dng_string s; 1148 1149 if (GetString (ns, path, s)) 1150 { 1151 1152 if (s.NotEmpty ()) 1153 { 1154 1155 int y = 0; 1156 1157 if (sscanf (s.Get (), "%d", &y) == 1) 1158 { 1159 1160 x = y; 1161 1162 return true; 1163 1164 } 1165 1166 } 1167 1168 } 1169 1170 return false; 1171 1172 } 1173 1174 /*****************************************************************************/ 1175 1176 void dng_xmp::Set_int32 (const char *ns, 1177 const char *path, 1178 int32 x, 1179 bool usePlus) 1180 { 1181 1182 char s [64]; 1183 1184 if (x > 0 && usePlus) 1185 { 1186 sprintf (s, "+%d", (int) x); 1187 } 1188 else 1189 { 1190 sprintf (s, "%d", (int) x); 1191 } 1192 1193 Set (ns, path, s); 1194 1195 } 1196 1197 /*****************************************************************************/ 1198 1199 bool dng_xmp::Get_uint32 (const char *ns, 1200 const char *path, 1201 uint32 &x) const 1202 { 1203 1204 dng_string s; 1205 1206 if (GetString (ns, path, s)) 1207 { 1208 1209 if (s.NotEmpty ()) 1210 { 1211 1212 unsigned y = 0; 1213 1214 if (sscanf (s.Get (), "%u", &y) == 1) 1215 { 1216 1217 x = y; 1218 1219 return true; 1220 1221 } 1222 1223 } 1224 1225 } 1226 1227 return false; 1228 1229 } 1230 1231 /*****************************************************************************/ 1232 1233 void dng_xmp::Set_uint32 (const char *ns, 1234 const char *path, 1235 uint32 x) 1236 { 1237 1238 char s [64]; 1239 1240 sprintf (s, 1241 "%u", 1242 (unsigned) x); 1243 1244 Set (ns, path, s); 1245 1246 } 1247 1248 /*****************************************************************************/ 1249 1250 void dng_xmp::Sync_uint32 (const char *ns, 1251 const char *path, 1252 uint32 &x, 1253 bool isDefault, 1254 uint32 options) 1255 { 1256 1257 // Sync 1: Force XMP to match non-XMP. 1258 1259 if (options & ignoreXMP) 1260 { 1261 1262 if (isDefault || (options & removeXMP)) 1263 { 1264 1265 Remove (ns, path); 1266 1267 } 1268 1269 else 1270 { 1271 1272 Set_uint32 (ns, path, x); 1273 1274 } 1275 1276 return; 1277 1278 } 1279 1280 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 1281 1282 if ((options & preferNonXMP) && !isDefault) 1283 { 1284 1285 if (options & removeXMP) 1286 { 1287 1288 Remove (ns, path); 1289 1290 } 1291 1292 else 1293 { 1294 1295 Set_uint32 (ns, path, x); 1296 1297 } 1298 1299 return; 1300 1301 } 1302 1303 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 1304 1305 if ((options & preferXMP) || isDefault) 1306 { 1307 1308 if (Get_uint32 (ns, path, x)) 1309 { 1310 1311 if (options & removeXMP) 1312 { 1313 1314 Remove (ns, path); 1315 1316 } 1317 1318 return; 1319 1320 } 1321 1322 } 1323 1324 // Sync 4: From non-XMP to XMP. 1325 1326 if (options & removeXMP) 1327 { 1328 1329 Remove (ns, path); 1330 1331 } 1332 1333 else if (!isDefault) 1334 { 1335 1336 Set_uint32 (ns, path, x); 1337 1338 } 1339 1340 } 1341 1342 /*****************************************************************************/ 1343 1344 void dng_xmp::Sync_uint32_array (const char *ns, 1345 const char *path, 1346 uint32 *data, 1347 uint32 &count, 1348 uint32 maxCount, 1349 uint32 options) 1350 { 1351 1352 dng_string_list list; 1353 1354 for (uint32 j = 0; j < count; j++) 1355 { 1356 1357 char s [32]; 1358 1359 sprintf (s, "%u", (unsigned) data [j]); 1360 1361 dng_string ss; 1362 1363 ss.Set (s); 1364 1365 list.Append (ss); 1366 1367 } 1368 1369 SyncStringList (ns, 1370 path, 1371 list, 1372 false, 1373 options); 1374 1375 count = 0; 1376 1377 for (uint32 k = 0; k < maxCount; k++) 1378 { 1379 1380 data [k] = 0; 1381 1382 if (k < list.Count ()) 1383 { 1384 1385 unsigned x = 0; 1386 1387 if (sscanf (list [k].Get (), "%u", &x) == 1) 1388 { 1389 1390 data [count++] = x; 1391 1392 } 1393 1394 } 1395 1396 } 1397 1398 } 1399 1400 /*****************************************************************************/ 1401 1402 bool dng_xmp::Get_real64 (const char *ns, 1403 const char *path, 1404 real64 &x) const 1405 { 1406 1407 dng_string s; 1408 1409 if (GetString (ns, path, s)) 1410 { 1411 1412 if (s.NotEmpty ()) 1413 { 1414 1415 double y = 0; 1416 1417 if (sscanf (s.Get (), "%lf", &y) == 1) 1418 { 1419 1420 x = y; 1421 1422 return true; 1423 1424 } 1425 1426 } 1427 1428 } 1429 1430 return false; 1431 1432 } 1433 1434 /*****************************************************************************/ 1435 1436 void dng_xmp::Set_real64 (const char *ns, 1437 const char *path, 1438 real64 x, 1439 uint32 places, 1440 bool trim, 1441 bool usePlus) 1442 { 1443 1444 char s [64]; 1445 1446 if (x > 0.0 && usePlus) 1447 { 1448 sprintf (s, "+%0.*f", (unsigned) places, (double) x); 1449 } 1450 else 1451 { 1452 sprintf (s, "%0.*f", (unsigned) places, (double) x); 1453 } 1454 1455 if (trim) 1456 { 1457 1458 while (s [strlen (s) - 1] == '0') 1459 { 1460 s [strlen (s) - 1] = 0; 1461 } 1462 1463 if (s [strlen (s) - 1] == '.') 1464 { 1465 s [strlen (s) - 1] = 0; 1466 } 1467 1468 } 1469 1470 Set (ns, path, s); 1471 1472 } 1473 1474 /*****************************************************************************/ 1475 1476 bool dng_xmp::Get_urational (const char *ns, 1477 const char *path, 1478 dng_urational &r) const 1479 { 1480 1481 dng_string s; 1482 1483 if (GetString (ns, path, s)) 1484 { 1485 1486 if (s.NotEmpty ()) 1487 { 1488 1489 unsigned n = 0; 1490 unsigned d = 0; 1491 1492 if (sscanf (s.Get (), "%u/%u", &n, &d) == 2) 1493 { 1494 1495 if (d != 0) 1496 { 1497 1498 r = dng_urational (n, d); 1499 1500 return true; 1501 1502 } 1503 1504 } 1505 1506 } 1507 1508 } 1509 1510 return false; 1511 1512 } 1513 1514 /*****************************************************************************/ 1515 1516 void dng_xmp::Set_urational (const char *ns, 1517 const char *path, 1518 const dng_urational &r) 1519 { 1520 1521 char s [64]; 1522 1523 sprintf (s, 1524 "%u/%u", 1525 (unsigned) r.n, 1526 (unsigned) r.d); 1527 1528 Set (ns, path, s); 1529 1530 } 1531 1532 /*****************************************************************************/ 1533 1534 void dng_xmp::Sync_urational (const char *ns, 1535 const char *path, 1536 dng_urational &r, 1537 uint32 options) 1538 { 1539 1540 bool isDefault = r.NotValid (); 1541 1542 // Sync 1: Force XMP to match non-XMP. 1543 1544 if (options & ignoreXMP) 1545 { 1546 1547 if (isDefault || (options & removeXMP)) 1548 { 1549 1550 Remove (ns, path); 1551 1552 } 1553 1554 else 1555 { 1556 1557 Set_urational (ns, path, r); 1558 1559 } 1560 1561 return; 1562 1563 } 1564 1565 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 1566 1567 if ((options & preferNonXMP) && !isDefault) 1568 { 1569 1570 if (options & removeXMP) 1571 { 1572 1573 Remove (ns, path); 1574 1575 } 1576 1577 else 1578 { 1579 1580 Set_urational (ns, path, r); 1581 1582 } 1583 1584 return; 1585 1586 } 1587 1588 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 1589 1590 if ((options & preferXMP) || isDefault) 1591 { 1592 1593 if (Get_urational (ns, path, r)) 1594 { 1595 1596 if (options & removeXMP) 1597 { 1598 1599 Remove (ns, path); 1600 1601 } 1602 1603 return; 1604 1605 } 1606 1607 } 1608 1609 // Sync 4: From non-XMP to XMP. 1610 1611 if (options & removeXMP) 1612 { 1613 1614 Remove (ns, path); 1615 1616 } 1617 1618 else if (!isDefault) 1619 { 1620 1621 Set_urational (ns, path, r); 1622 1623 } 1624 1625 } 1626 1627 /*****************************************************************************/ 1628 1629 bool dng_xmp::Get_srational (const char *ns, 1630 const char *path, 1631 dng_srational &r) const 1632 { 1633 1634 dng_string s; 1635 1636 if (GetString (ns, path, s)) 1637 { 1638 1639 if (s.NotEmpty ()) 1640 { 1641 1642 int n = 0; 1643 int d = 0; 1644 1645 if (sscanf (s.Get (), "%d/%d", &n, &d) == 2) 1646 { 1647 1648 if (d != 0) 1649 { 1650 1651 r = dng_srational (n, d); 1652 1653 return true; 1654 1655 } 1656 1657 } 1658 1659 } 1660 1661 } 1662 1663 return false; 1664 1665 } 1666 1667 /*****************************************************************************/ 1668 1669 void dng_xmp::Set_srational (const char *ns, 1670 const char *path, 1671 const dng_srational &r) 1672 { 1673 1674 char s [64]; 1675 1676 sprintf (s, 1677 "%d/%d", 1678 (int) r.n, 1679 (int) r.d); 1680 1681 Set (ns, path, s); 1682 1683 } 1684 1685 /*****************************************************************************/ 1686 1687 void dng_xmp::Sync_srational (const char *ns, 1688 const char *path, 1689 dng_srational &r, 1690 uint32 options) 1691 { 1692 1693 bool isDefault = r.NotValid (); 1694 1695 // Sync 1: Force XMP to match non-XMP. 1696 1697 if (options & ignoreXMP) 1698 { 1699 1700 if (isDefault || (options & removeXMP)) 1701 { 1702 1703 Remove (ns, path); 1704 1705 } 1706 1707 else 1708 { 1709 1710 Set_srational (ns, path, r); 1711 1712 } 1713 1714 return; 1715 1716 } 1717 1718 // Sync 2: From non-XMP to XMP if non-XMP is prefered. 1719 1720 if ((options & preferNonXMP) && !isDefault) 1721 { 1722 1723 if (options & removeXMP) 1724 { 1725 1726 Remove (ns, path); 1727 1728 } 1729 1730 else 1731 { 1732 1733 Set_srational (ns, path, r); 1734 1735 } 1736 1737 return; 1738 1739 } 1740 1741 // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP. 1742 1743 if ((options & preferXMP) || isDefault) 1744 { 1745 1746 if (Get_srational (ns, path, r)) 1747 { 1748 1749 if (options & removeXMP) 1750 { 1751 1752 Remove (ns, path); 1753 1754 } 1755 1756 return; 1757 1758 } 1759 1760 } 1761 1762 // Sync 4: From non-XMP to XMP. 1763 1764 if (options & removeXMP) 1765 { 1766 1767 Remove (ns, path); 1768 1769 } 1770 1771 else if (!isDefault) 1772 { 1773 1774 Set_srational (ns, path, r); 1775 1776 } 1777 1778 } 1779 1780 /*****************************************************************************/ 1781 1782 bool dng_xmp::GetFingerprint (const char *ns, 1783 const char *path, 1784 dng_fingerprint &print) const 1785 { 1786 1787 dng_string s; 1788 1789 if (GetString (ns, path, s)) 1790 { 1791 1792 dng_fingerprint temp = DecodeFingerprint (s); 1793 1794 if (temp.IsValid ()) 1795 { 1796 1797 print = temp; 1798 1799 return true; 1800 1801 } 1802 1803 } 1804 1805 return false; 1806 1807 } 1808 1809 /******************************************************************************/ 1810 1811 void dng_xmp::SetFingerprint (const char *ns, 1812 const char *tag, 1813 const dng_fingerprint &print, 1814 bool allowInvalid) 1815 { 1816 1817 dng_string s = EncodeFingerprint (print, allowInvalid); 1818 1819 if (s.IsEmpty ()) 1820 { 1821 1822 Remove (ns, tag); 1823 1824 } 1825 1826 else 1827 { 1828 1829 SetString (ns, tag, s); 1830 1831 } 1832 1833 } 1834 1835 /******************************************************************************/ 1836 1837 void dng_xmp::SetVersion2to4 (const char *ns, 1838 const char *path, 1839 uint32 version) 1840 { 1841 1842 char buf [32]; 1843 1844 if (version & 0x000000ff) 1845 { 1846 1847 // x.x.x.x 1848 1849 sprintf (buf, 1850 "%u.%u.%u.%u", 1851 (unsigned) ((version >> 24) & 0xff), 1852 (unsigned) ((version >> 16) & 0xff), 1853 (unsigned) ((version >> 8) & 0xff), 1854 (unsigned) ((version ) & 0xff)); 1855 1856 } 1857 1858 else if (version & 0x0000ff00) 1859 { 1860 1861 // x.x.x 1862 1863 sprintf (buf, 1864 "%u.%u.%u", 1865 (unsigned) ((version >> 24) & 0xff), 1866 (unsigned) ((version >> 16) & 0xff), 1867 (unsigned) ((version >> 8) & 0xff)); 1868 1869 } 1870 1871 else 1872 { 1873 1874 // x.x 1875 1876 sprintf (buf, 1877 "%u.%u", 1878 (unsigned) ((version >> 24) & 0xff), 1879 (unsigned) ((version >> 16) & 0xff)); 1880 1881 } 1882 1883 Set (ns, path, buf); 1884 1885 } 1886 1887 /******************************************************************************/ 1888 1889 dng_fingerprint dng_xmp::GetIPTCDigest () const 1890 { 1891 1892 dng_fingerprint digest; 1893 1894 if (GetFingerprint (XMP_NS_PHOTOSHOP, 1895 "LegacyIPTCDigest", 1896 digest)) 1897 { 1898 1899 return digest; 1900 1901 } 1902 1903 return dng_fingerprint (); 1904 1905 } 1906 1907 /******************************************************************************/ 1908 1909 void dng_xmp::SetIPTCDigest (dng_fingerprint &digest) 1910 { 1911 1912 SetFingerprint (XMP_NS_PHOTOSHOP, 1913 "LegacyIPTCDigest", 1914 digest); 1915 1916 } 1917 1918 /******************************************************************************/ 1919 1920 void dng_xmp::ClearIPTCDigest () 1921 { 1922 1923 Remove (XMP_NS_PHOTOSHOP, "LegacyIPTCDigest"); 1924 1925 } 1926 1927 /*****************************************************************************/ 1928 1929 void dng_xmp::SyncIPTC (dng_iptc &iptc, 1930 uint32 options) 1931 { 1932 1933 SyncAltLangDefault (XMP_NS_DC, 1934 "title", 1935 iptc.fTitle, 1936 options); 1937 1938 SyncString (XMP_NS_PHOTOSHOP, 1939 "Category", 1940 iptc.fCategory, 1941 options); 1942 1943 { 1944 1945 uint32 x = 0xFFFFFFFF; 1946 1947 if (iptc.fUrgency >= 0) 1948 { 1949 1950 x = (uint32) iptc.fUrgency; 1951 1952 } 1953 1954 Sync_uint32 (XMP_NS_PHOTOSHOP, 1955 "Urgency", 1956 x, 1957 x == 0xFFFFFFFF, 1958 options); 1959 1960 if (x <= 9) 1961 { 1962 1963 iptc.fUrgency = (int32) x; 1964 1965 } 1966 1967 } 1968 1969 SyncStringList (XMP_NS_PHOTOSHOP, 1970 "SupplementalCategories", 1971 iptc.fSupplementalCategories, 1972 true, 1973 options); 1974 1975 SyncStringList (XMP_NS_PHOTOSHOP, 1976 "Keywords", 1977 iptc.fKeywords, 1978 true, 1979 options); 1980 1981 SyncString (XMP_NS_PHOTOSHOP, 1982 "Instructions", 1983 iptc.fInstructions, 1984 options); 1985 1986 { 1987 1988 dng_string s = iptc.fDateTimeCreated.Encode_ISO_8601 (); 1989 1990 if (SyncString (XMP_NS_PHOTOSHOP, 1991 "DateCreated", 1992 s, 1993 options)) 1994 { 1995 1996 iptc.fDateTimeCreated.Decode_ISO_8601 (s.Get ()); 1997 1998 } 1999 2000 } 2001 2002 { 2003 2004 dng_string s = iptc.fDigitalCreationDateTime.Encode_ISO_8601 (); 2005 2006 if (SyncString (XMP_NS_EXIF, 2007 "DateTimeDigitized", 2008 s, 2009 options)) 2010 { 2011 2012 iptc.fDigitalCreationDateTime.Decode_ISO_8601 (s.Get ()); 2013 2014 } 2015 2016 } 2017 2018 SyncStringList (XMP_NS_DC, 2019 "creator", 2020 iptc.fAuthors, 2021 false, 2022 options); 2023 2024 SyncString (XMP_NS_PHOTOSHOP, 2025 "AuthorsPosition", 2026 iptc.fAuthorsPosition, 2027 options); 2028 2029 SyncString (XMP_NS_PHOTOSHOP, 2030 "City", 2031 iptc.fCity, 2032 options); 2033 2034 SyncString (XMP_NS_PHOTOSHOP, 2035 "State", 2036 iptc.fState, 2037 options); 2038 2039 SyncString (XMP_NS_PHOTOSHOP, 2040 "Country", 2041 iptc.fCountry, 2042 options); 2043 2044 SyncString (XMP_NS_IPTC, 2045 "CountryCode", 2046 iptc.fCountryCode, 2047 options); 2048 2049 SyncString (XMP_NS_IPTC, 2050 "Location", 2051 iptc.fLocation, 2052 options); 2053 2054 SyncString (XMP_NS_PHOTOSHOP, 2055 "TransmissionReference", 2056 iptc.fTransmissionReference, 2057 options); 2058 2059 SyncString (XMP_NS_PHOTOSHOP, 2060 "Headline", 2061 iptc.fHeadline, 2062 options); 2063 2064 SyncString (XMP_NS_PHOTOSHOP, 2065 "Credit", 2066 iptc.fCredit, 2067 options); 2068 2069 SyncString (XMP_NS_PHOTOSHOP, 2070 "Source", 2071 iptc.fSource, 2072 options); 2073 2074 SyncAltLangDefault (XMP_NS_DC, 2075 "rights", 2076 iptc.fCopyrightNotice, 2077 options); 2078 2079 SyncAltLangDefault (XMP_NS_DC, 2080 "description", 2081 iptc.fDescription, 2082 options); 2083 2084 SyncString (XMP_NS_PHOTOSHOP, 2085 "CaptionWriter", 2086 iptc.fDescriptionWriter, 2087 options); 2088 2089 } 2090 2091 /*****************************************************************************/ 2092 2093 void dng_xmp::IngestIPTC (dng_metadata &metadata, 2094 bool xmpIsNewer) 2095 { 2096 2097 if (metadata.IPTCLength ()) 2098 { 2099 2100 // Parse the IPTC block. 2101 2102 dng_iptc iptc; 2103 2104 iptc.Parse (metadata.IPTCData (), 2105 metadata.IPTCLength (), 2106 metadata.IPTCOffset ()); 2107 2108 // Compute fingerprint of IPTC data both ways, including and 2109 // excluding the padding data. 2110 2111 dng_fingerprint iptcDigest1 = metadata.IPTCDigest (true ); 2112 dng_fingerprint iptcDigest2 = metadata.IPTCDigest (false); 2113 2114 // See if there is an IPTC fingerprint stored in the XMP. 2115 2116 dng_fingerprint xmpDigest = GetIPTCDigest (); 2117 2118 if (xmpDigest.IsValid ()) 2119 { 2120 2121 // If they match, the XMP was already synced with this 2122 // IPTC block, and we should not resync since it might 2123 // overwrite changes in the XMP data. 2124 2125 if (iptcDigest1 == xmpDigest) 2126 { 2127 2128 return; 2129 2130 } 2131 2132 // If it matches the incorrectly computed digest, skip 2133 // the sync, but fix the digest in the XMP. 2134 2135 if (iptcDigest2 == xmpDigest) 2136 { 2137 2138 SetIPTCDigest (iptcDigest1); 2139 2140 return; 2141 2142 } 2143 2144 // Else the IPTC has changed, so force an update. 2145 2146 xmpIsNewer = false; 2147 2148 } 2149 2150 else 2151 { 2152 2153 // There is no IPTC digest. Previously we would 2154 // prefer the IPTC in this case, but the MWG suggests 2155 // that we prefer the XMP in this case. 2156 2157 xmpIsNewer = true; 2158 2159 } 2160 2161 // Remember the fingerprint of the IPTC we are syncing with. 2162 2163 SetIPTCDigest (iptcDigest1); 2164 2165 // Find the sync options. 2166 2167 uint32 options = xmpIsNewer ? preferXMP 2168 : preferNonXMP; 2169 2170 // Synchronize the fields. 2171 2172 SyncIPTC (iptc, options); 2173 2174 } 2175 2176 // After the IPTC data is moved to XMP, we don't need it anymore. 2177 2178 metadata.ClearIPTC (); 2179 2180 } 2181 2182 /*****************************************************************************/ 2183 2184 void dng_xmp::RebuildIPTC (dng_metadata &metadata, 2185 dng_memory_allocator &allocator, 2186 bool padForTIFF) 2187 { 2188 2189 // If there is no XMP, then there is no IPTC. 2190 2191 if (!fSDK->HasMeta ()) 2192 { 2193 return; 2194 } 2195 2196 // Extract the legacy IPTC fields from the XMP data. 2197 2198 dng_iptc iptc; 2199 2200 SyncIPTC (iptc, preferXMP); 2201 2202 // Build legacy IPTC record 2203 2204 if (iptc.NotEmpty ()) 2205 { 2206 2207 AutoPtr<dng_memory_block> block (iptc.Spool (allocator, 2208 padForTIFF)); 2209 2210 metadata.SetIPTC (block); 2211 2212 } 2213 2214 } 2215 2216 /*****************************************************************************/ 2217 2218 void dng_xmp::SyncFlash (uint32 &flashState, 2219 uint32 &flashMask, 2220 uint32 options) 2221 { 2222 2223 bool isDefault = (flashState == 0xFFFFFFFF); 2224 2225 if ((options & ignoreXMP) || !isDefault) 2226 { 2227 2228 Remove (XMP_NS_EXIF, "Flash"); 2229 2230 } 2231 2232 if (!isDefault) 2233 { 2234 2235 fSDK->SetStructField (XMP_NS_EXIF, 2236 "Flash", 2237 XMP_NS_EXIF, 2238 "Fired", 2239 (flashState & 0x1) ? "True" : "False"); 2240 2241 if (((flashMask >> 1) & 3) == 3) 2242 { 2243 2244 char s [8]; 2245 2246 sprintf (s, "%u", (unsigned) ((flashState >> 1) & 3)); 2247 2248 fSDK->SetStructField (XMP_NS_EXIF, 2249 "Flash", 2250 XMP_NS_EXIF, 2251 "Return", 2252 s); 2253 2254 } 2255 2256 if (((flashMask >> 3) & 3) == 3) 2257 { 2258 2259 char s [8]; 2260 2261 sprintf (s, "%u", (unsigned) ((flashState >> 3) & 3)); 2262 2263 fSDK->SetStructField (XMP_NS_EXIF, 2264 "Flash", 2265 XMP_NS_EXIF, 2266 "Mode", 2267 s); 2268 2269 } 2270 2271 if ((flashMask & (1 << 5)) != 0) 2272 { 2273 2274 fSDK->SetStructField (XMP_NS_EXIF, 2275 "Flash", 2276 XMP_NS_EXIF, 2277 "Function", 2278 (flashState & (1 << 5)) ? "True" : "False"); 2279 2280 } 2281 2282 if ((flashMask & (1 << 6)) != 0) 2283 { 2284 2285 fSDK->SetStructField (XMP_NS_EXIF, 2286 "Flash", 2287 XMP_NS_EXIF, 2288 "RedEyeMode", 2289 (flashState & (1 << 6)) ? "True" : "False"); 2290 2291 } 2292 2293 } 2294 2295 else if (fSDK->Exists (XMP_NS_EXIF, "Flash")) 2296 { 2297 2298 dng_string s; 2299 2300 if (fSDK->GetStructField (XMP_NS_EXIF, 2301 "Flash", 2302 XMP_NS_EXIF, 2303 "Fired", 2304 s)) 2305 { 2306 2307 flashState = 0; 2308 flashMask = 1; 2309 2310 if (s.Matches ("True")) 2311 { 2312 flashState |= 1; 2313 } 2314 2315 if (fSDK->GetStructField (XMP_NS_EXIF, 2316 "Flash", 2317 XMP_NS_EXIF, 2318 "Return", 2319 s)) 2320 { 2321 2322 unsigned x = 0; 2323 2324 if (sscanf (s.Get (), "%u", &x) == 1 && x <= 3) 2325 { 2326 2327 flashState |= x << 1; 2328 flashMask |= 3 << 1; 2329 2330 } 2331 2332 } 2333 2334 if (fSDK->GetStructField (XMP_NS_EXIF, 2335 "Flash", 2336 XMP_NS_EXIF, 2337 "Mode", 2338 s)) 2339 { 2340 2341 unsigned x = 0; 2342 2343 if (sscanf (s.Get (), "%u", &x) == 1 && x <= 3) 2344 { 2345 2346 flashState |= x << 3; 2347 flashMask |= 3 << 3; 2348 2349 } 2350 2351 } 2352 2353 if (fSDK->GetStructField (XMP_NS_EXIF, 2354 "Flash", 2355 XMP_NS_EXIF, 2356 "Function", 2357 s)) 2358 { 2359 2360 flashMask |= 1 << 5; 2361 2362 if (s.Matches ("True")) 2363 { 2364 flashState |= 1 << 5; 2365 } 2366 2367 } 2368 2369 if (fSDK->GetStructField (XMP_NS_EXIF, 2370 "Flash", 2371 XMP_NS_EXIF, 2372 "RedEyeMode", 2373 s)) 2374 { 2375 2376 flashMask |= 1 << 6; 2377 2378 if (s.Matches ("True")) 2379 { 2380 flashState |= 1 << 6; 2381 } 2382 2383 } 2384 2385 } 2386 2387 } 2388 2389 } 2390 2391 /*****************************************************************************/ 2392 2393 void dng_xmp::SyncExif (dng_exif &exif, 2394 const dng_exif *originalExif, 2395 bool doingUpdateFromXMP, 2396 bool removeFromXMP) 2397 { 2398 2399 DNG_ASSERT (!doingUpdateFromXMP || originalExif, 2400 "Must have original EXIF if doingUpdateFromXMP"); 2401 2402 // Default synchronization options for the read-only fields. 2403 2404 uint32 readOnly = doingUpdateFromXMP ? ignoreXMP 2405 : preferNonXMP; 2406 2407 // Option for removable fields. 2408 2409 uint32 removable = removeFromXMP ? removeXMP 2410 : 0; 2411 2412 // Make: 2413 2414 SyncString (XMP_NS_TIFF, 2415 "Make", 2416 exif.fMake, 2417 readOnly + removable); 2418 2419 // Model: 2420 2421 SyncString (XMP_NS_TIFF, 2422 "Model", 2423 exif.fModel, 2424 readOnly + removable); 2425 2426 // Exif version number: 2427 2428 { 2429 2430 dng_string exifVersion; 2431 2432 if (exif.fExifVersion) 2433 { 2434 2435 unsigned b0 = ((exif.fExifVersion >> 24) & 0x0FF) - '0'; 2436 unsigned b1 = ((exif.fExifVersion >> 16) & 0x0FF) - '0'; 2437 unsigned b2 = ((exif.fExifVersion >> 8) & 0x0FF) - '0'; 2438 unsigned b3 = ((exif.fExifVersion ) & 0x0FF) - '0'; 2439 2440 if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9) 2441 { 2442 2443 char s [5]; 2444 2445 sprintf (s, 2446 "%1u%1u%1u%1u", 2447 b0, 2448 b1, 2449 b2, 2450 b3); 2451 2452 exifVersion.Set (s); 2453 2454 } 2455 2456 } 2457 2458 SyncString (XMP_NS_EXIF, 2459 "ExifVersion", 2460 exifVersion, 2461 readOnly); 2462 2463 if (exifVersion.NotEmpty ()) 2464 { 2465 2466 unsigned b0; 2467 unsigned b1; 2468 unsigned b2; 2469 unsigned b3; 2470 2471 if (sscanf (exifVersion.Get (), 2472 "%1u%1u%1u%1u", 2473 &b0, 2474 &b1, 2475 &b2, 2476 &b3) == 4) 2477 { 2478 2479 if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9) 2480 { 2481 2482 b0 += '0'; 2483 b1 += '0'; 2484 b2 += '0'; 2485 b3 += '0'; 2486 2487 exif.fExifVersion = (b0 << 24) | 2488 (b1 << 16) | 2489 (b2 << 8) | 2490 (b3 ); 2491 2492 } 2493 2494 } 2495 2496 } 2497 2498 // Provide default value for ExifVersion. 2499 2500 if (!exif.fExifVersion) 2501 { 2502 2503 exif.fExifVersion = DNG_CHAR4 ('0','2','2','1'); 2504 2505 Set (XMP_NS_EXIF, 2506 "ExifVersion", 2507 "0221"); 2508 2509 } 2510 2511 if (removeFromXMP) 2512 { 2513 2514 Remove (XMP_NS_EXIF, "ExifVersion"); 2515 2516 } 2517 2518 } 2519 2520 // ExposureTime / ShutterSpeedValue: 2521 2522 { 2523 2524 // Process twice in case XMP contains only one of the 2525 // two fields. 2526 2527 for (uint32 pass = 0; pass < 2; pass++) 2528 { 2529 2530 dng_urational et = exif.fExposureTime; 2531 2532 Sync_urational (XMP_NS_EXIF, 2533 "ExposureTime", 2534 et, 2535 readOnly); 2536 2537 if (et.IsValid ()) 2538 { 2539 2540 exif.SetExposureTime (et.As_real64 (), false); 2541 2542 } 2543 2544 dng_srational ss = exif.fShutterSpeedValue; 2545 2546 Sync_srational (XMP_NS_EXIF, 2547 "ShutterSpeedValue", 2548 ss, 2549 readOnly); 2550 2551 if (ss.IsValid ()) 2552 { 2553 2554 exif.SetShutterSpeedValue (ss.As_real64 ()); 2555 2556 } 2557 2558 } 2559 2560 if (removeFromXMP) 2561 { 2562 2563 Remove (XMP_NS_EXIF, "ExposureTime"); 2564 2565 Remove (XMP_NS_EXIF, "ShutterSpeedValue"); 2566 2567 } 2568 2569 } 2570 2571 // FNumber / ApertureValue: 2572 2573 { 2574 2575 for (uint32 pass = 0; pass < 2; pass++) 2576 { 2577 2578 dng_urational fs = exif.fFNumber; 2579 2580 Sync_urational (XMP_NS_EXIF, 2581 "FNumber", 2582 fs, 2583 readOnly); 2584 2585 if (fs.IsValid ()) 2586 { 2587 2588 exif.SetFNumber (fs.As_real64 ()); 2589 2590 } 2591 2592 dng_urational av = exif.fApertureValue; 2593 2594 Sync_urational (XMP_NS_EXIF, 2595 "ApertureValue", 2596 av, 2597 readOnly); 2598 2599 if (av.IsValid ()) 2600 { 2601 2602 exif.SetApertureValue (av.As_real64 ()); 2603 2604 } 2605 2606 } 2607 2608 if (removeFromXMP) 2609 { 2610 2611 Remove (XMP_NS_EXIF, "FNumber"); 2612 2613 Remove (XMP_NS_EXIF, "ApertureValue"); 2614 2615 } 2616 2617 } 2618 2619 // Exposure program: 2620 2621 Sync_uint32 (XMP_NS_EXIF, 2622 "ExposureProgram", 2623 exif.fExposureProgram, 2624 exif.fExposureProgram == 0xFFFFFFFF, 2625 readOnly + removable); 2626 2627 // ISO Speed Ratings: 2628 2629 { 2630 2631 uint32 isoSpeedRatingsCount = 0; 2632 2633 uint32 isoSpeedRatingsOptions = readOnly; 2634 2635 uint32 oldISOSpeedRatings [3]; 2636 2637 memcpy (oldISOSpeedRatings, 2638 exif.fISOSpeedRatings, 2639 sizeof (oldISOSpeedRatings)); 2640 2641 bool checkXMPForHigherISO = false; 2642 2643 for (uint32 j = 0; j < 3; j++) 2644 { 2645 2646 // Special case: the EXIF 2.2x standard represents ISO speed ratings with 2647 // 2 bytes, which cannot hold ISO speed ratings above 65535 (e.g., 2648 // 102400). If the EXIF ISO speed rating value is 65535, prefer the XMP 2649 // ISOSpeedRatings tag value. 2650 2651 if (exif.fISOSpeedRatings [j] == 65535) 2652 { 2653 2654 isoSpeedRatingsOptions = preferXMP; 2655 2656 checkXMPForHigherISO = true; 2657 2658 isoSpeedRatingsCount = 0; 2659 2660 break; 2661 2662 } 2663 2664 else if (exif.fISOSpeedRatings [j] == 0) 2665 { 2666 break; 2667 } 2668 2669 isoSpeedRatingsCount++; 2670 2671 } 2672 2673 Sync_uint32_array (XMP_NS_EXIF, 2674 "ISOSpeedRatings", 2675 exif.fISOSpeedRatings, 2676 isoSpeedRatingsCount, 2677 3, 2678 isoSpeedRatingsOptions); 2679 2680 // If the EXIF ISO was 65535 and we failed to find anything meaningful in the 2681 // XMP, then we fall back to the EXIF ISO. 2682 2683 if (checkXMPForHigherISO && (isoSpeedRatingsCount == 0)) 2684 { 2685 2686 memcpy (exif.fISOSpeedRatings, 2687 oldISOSpeedRatings, 2688 sizeof (oldISOSpeedRatings)); 2689 2690 } 2691 2692 // Only remove the ISO tag if there are not ratings over 65535. 2693 2694 if (removeFromXMP) 2695 { 2696 2697 bool hasHighISO = false; 2698 2699 for (uint32 j = 0; j < 3; j++) 2700 { 2701 2702 if (exif.fISOSpeedRatings [j] == 0) 2703 { 2704 break; 2705 } 2706 2707 hasHighISO = hasHighISO || (exif.fISOSpeedRatings [j] > 65535); 2708 2709 } 2710 2711 if (!hasHighISO) 2712 { 2713 2714 Remove (XMP_NS_EXIF, "ISOSpeedRatings"); 2715 2716 } 2717 2718 } 2719 2720 } 2721 2722 // SensitivityType: 2723 2724 Sync_uint32 (XMP_NS_EXIF, 2725 "SensitivityType", 2726 exif.fSensitivityType, 2727 exif.fSensitivityType == stUnknown, 2728 readOnly + removable); 2729 2730 // StandardOutputSensitivity: 2731 2732 Sync_uint32 (XMP_NS_EXIF, 2733 "StandardOutputSensitivity", 2734 exif.fStandardOutputSensitivity, 2735 exif.fStandardOutputSensitivity == 0, 2736 readOnly + removable); 2737 2738 // RecommendedExposureIndex: 2739 2740 Sync_uint32 (XMP_NS_EXIF, 2741 "RecommendedExposureIndex", 2742 exif.fRecommendedExposureIndex, 2743 exif.fRecommendedExposureIndex == 0, 2744 readOnly + removable); 2745 2746 // ISOSpeed: 2747 2748 Sync_uint32 (XMP_NS_EXIF, 2749 "ISOSpeed", 2750 exif.fISOSpeed, 2751 exif.fISOSpeed == 0, 2752 readOnly + removable); 2753 2754 // ISOSpeedLatitudeyyy: 2755 2756 Sync_uint32 (XMP_NS_EXIF, 2757 "ISOSpeedLatitudeyyy", 2758 exif.fISOSpeedLatitudeyyy, 2759 exif.fISOSpeedLatitudeyyy == 0, 2760 readOnly + removable); 2761 2762 // ISOSpeedLatitudezzz: 2763 2764 Sync_uint32 (XMP_NS_EXIF, 2765 "ISOSpeedLatitudezzz", 2766 exif.fISOSpeedLatitudezzz, 2767 exif.fISOSpeedLatitudezzz == 0, 2768 readOnly + removable); 2769 2770 // ExposureIndex: 2771 2772 Sync_urational (XMP_NS_EXIF, 2773 "ExposureIndex", 2774 exif.fExposureIndex, 2775 readOnly + removable); 2776 2777 // Brightness Value: 2778 2779 Sync_srational (XMP_NS_EXIF, 2780 "BrightnessValue", 2781 exif.fBrightnessValue, 2782 readOnly + removable); 2783 2784 // Exposure Bias: 2785 2786 Sync_srational (XMP_NS_EXIF, 2787 "ExposureBiasValue", 2788 exif.fExposureBiasValue, 2789 readOnly + removable); 2790 2791 // Max Aperture: 2792 2793 Sync_urational (XMP_NS_EXIF, 2794 "MaxApertureValue", 2795 exif.fMaxApertureValue, 2796 readOnly + removable); 2797 2798 // Subject Distance: 2799 2800 Sync_urational (XMP_NS_EXIF, 2801 "SubjectDistance", 2802 exif.fSubjectDistance, 2803 readOnly + removable); 2804 2805 // Metering Mode: 2806 2807 Sync_uint32 (XMP_NS_EXIF, 2808 "MeteringMode", 2809 exif.fMeteringMode, 2810 exif.fMeteringMode == 0xFFFFFFFF, 2811 readOnly + removable); 2812 2813 // Light Source: 2814 2815 Sync_uint32 (XMP_NS_EXIF, 2816 "LightSource", 2817 exif.fLightSource, 2818 exif.fLightSource > 0x0FFFF, 2819 readOnly + removable); 2820 2821 // Flash State: 2822 2823 SyncFlash (exif.fFlash, 2824 exif.fFlashMask, 2825 readOnly); 2826 2827 if (removeFromXMP) 2828 { 2829 Remove (XMP_NS_EXIF, "Flash"); 2830 } 2831 2832 // Focal Length: 2833 2834 Sync_urational (XMP_NS_EXIF, 2835 "FocalLength", 2836 exif.fFocalLength, 2837 readOnly + removable); 2838 2839 // Sensing Method. 2840 2841 Sync_uint32 (XMP_NS_EXIF, 2842 "SensingMethod", 2843 exif.fSensingMethod, 2844 exif.fSensingMethod > 0x0FFFF, 2845 readOnly + removable); 2846 2847 // File Source. 2848 2849 Sync_uint32 (XMP_NS_EXIF, 2850 "FileSource", 2851 exif.fFileSource, 2852 exif.fFileSource > 0x0FF, 2853 readOnly + removable); 2854 2855 // Scene Type. 2856 2857 Sync_uint32 (XMP_NS_EXIF, 2858 "SceneType", 2859 exif.fSceneType, 2860 exif.fSceneType > 0x0FF, 2861 readOnly + removable); 2862 2863 // Focal Length in 35mm Film: 2864 2865 Sync_uint32 (XMP_NS_EXIF, 2866 "FocalLengthIn35mmFilm", 2867 exif.fFocalLengthIn35mmFilm, 2868 exif.fFocalLengthIn35mmFilm == 0, 2869 readOnly + removable); 2870 2871 // Custom Rendered: 2872 2873 Sync_uint32 (XMP_NS_EXIF, 2874 "CustomRendered", 2875 exif.fCustomRendered, 2876 exif.fCustomRendered > 0x0FFFF, 2877 readOnly + removable); 2878 2879 // Exposure Mode: 2880 2881 Sync_uint32 (XMP_NS_EXIF, 2882 "ExposureMode", 2883 exif.fExposureMode, 2884 exif.fExposureMode > 0x0FFFF, 2885 readOnly + removable); 2886 2887 // White Balance: 2888 2889 Sync_uint32 (XMP_NS_EXIF, 2890 "WhiteBalance", 2891 exif.fWhiteBalance, 2892 exif.fWhiteBalance > 0x0FFFF, 2893 readOnly + removable); 2894 2895 // Scene Capture Type: 2896 2897 Sync_uint32 (XMP_NS_EXIF, 2898 "SceneCaptureType", 2899 exif.fSceneCaptureType, 2900 exif.fSceneCaptureType > 0x0FFFF, 2901 readOnly + removable); 2902 2903 // Gain Control: 2904 2905 Sync_uint32 (XMP_NS_EXIF, 2906 "GainControl", 2907 exif.fGainControl, 2908 exif.fGainControl > 0x0FFFF, 2909 readOnly + removable); 2910 2911 // Contrast: 2912 2913 Sync_uint32 (XMP_NS_EXIF, 2914 "Contrast", 2915 exif.fContrast, 2916 exif.fContrast > 0x0FFFF, 2917 readOnly + removable); 2918 2919 // Saturation: 2920 2921 Sync_uint32 (XMP_NS_EXIF, 2922 "Saturation", 2923 exif.fSaturation, 2924 exif.fSaturation > 0x0FFFF, 2925 readOnly + removable); 2926 2927 // Sharpness: 2928 2929 Sync_uint32 (XMP_NS_EXIF, 2930 "Sharpness", 2931 exif.fSharpness, 2932 exif.fSharpness > 0x0FFFF, 2933 readOnly + removable); 2934 2935 // Subject Distance Range: 2936 2937 Sync_uint32 (XMP_NS_EXIF, 2938 "SubjectDistanceRange", 2939 exif.fSubjectDistanceRange, 2940 exif.fSubjectDistanceRange > 0x0FFFF, 2941 readOnly + removable); 2942 2943 // Subject Area: 2944 2945 Sync_uint32_array (XMP_NS_EXIF, 2946 "SubjectArea", 2947 exif.fSubjectArea, 2948 exif.fSubjectAreaCount, 2949 sizeof (exif.fSubjectArea ) / 2950 sizeof (exif.fSubjectArea [0]), 2951 readOnly); 2952 2953 if (removeFromXMP) 2954 { 2955 Remove (XMP_NS_EXIF, "SubjectArea"); 2956 } 2957 2958 // Digital Zoom Ratio: 2959 2960 Sync_urational (XMP_NS_EXIF, 2961 "DigitalZoomRatio", 2962 exif.fDigitalZoomRatio, 2963 readOnly + removable); 2964 2965 // Focal Plane Resolution: 2966 2967 Sync_urational (XMP_NS_EXIF, 2968 "FocalPlaneXResolution", 2969 exif.fFocalPlaneXResolution, 2970 readOnly + removable); 2971 2972 Sync_urational (XMP_NS_EXIF, 2973 "FocalPlaneYResolution", 2974 exif.fFocalPlaneYResolution, 2975 readOnly + removable); 2976 2977 Sync_uint32 (XMP_NS_EXIF, 2978 "FocalPlaneResolutionUnit", 2979 exif.fFocalPlaneResolutionUnit, 2980 exif.fFocalPlaneResolutionUnit > 0x0FFFF, 2981 readOnly + removable); 2982 2983 // ImageDescription: (XMP is is always preferred) 2984 2985 if (fSDK->GetAltLangDefault (XMP_NS_DC, 2986 "description", 2987 exif.fImageDescription)) 2988 2989 { 2990 2991 } 2992 2993 else if (doingUpdateFromXMP) 2994 { 2995 2996 exif.fImageDescription.Clear (); 2997 2998 if (originalExif->fImageDescription.NotEmpty ()) 2999 { 3000 3001 fSDK->SetAltLangDefault (XMP_NS_DC, 3002 "description", 3003 dng_string ()); 3004 3005 } 3006 3007 } 3008 3009 else if (exif.fImageDescription.NotEmpty ()) 3010 { 3011 3012 fSDK->SetAltLangDefault (XMP_NS_DC, 3013 "description", 3014 exif.fImageDescription); 3015 3016 } 3017 3018 // Artist: (XMP is is always preferred) 3019 3020 { 3021 3022 dng_string_list xmpList; 3023 3024 if (fSDK->GetStringList (XMP_NS_DC, 3025 "creator", 3026 xmpList)) 3027 { 3028 3029 exif.fArtist.Clear (); 3030 3031 if (xmpList.Count () > 0) 3032 { 3033 3034 uint32 j; 3035 3036 uint32 bufferSize = xmpList.Count () * 4 + 1; 3037 3038 for (j = 0; j < xmpList.Count (); j++) 3039 { 3040 3041 bufferSize += xmpList [j].Length () * 2; 3042 3043 } 3044 3045 dng_memory_data temp (bufferSize); 3046 3047 char *t = temp.Buffer_char (); 3048 3049 for (j = 0; j < xmpList.Count (); j++) 3050 { 3051 3052 const char *s = xmpList [j].Get (); 3053 3054 bool needQuotes = xmpList [j].Contains ("; ") || 3055 s [0] == '\"'; 3056 3057 if (needQuotes) 3058 { 3059 *(t++) = '\"'; 3060 } 3061 3062 while (s [0] != 0) 3063 { 3064 3065 if (s [0] == '\"' && needQuotes) 3066 { 3067 *(t++) = '\"'; 3068 } 3069 3070 *(t++) = *(s++); 3071 3072 } 3073 3074 if (needQuotes) 3075 { 3076 *(t++) = '\"'; 3077 } 3078 3079 if (j != xmpList.Count () - 1) 3080 { 3081 *(t++) = ';'; 3082 *(t++) = ' '; 3083 } 3084 else 3085 { 3086 *t = 0; 3087 } 3088 3089 } 3090 3091 exif.fArtist.Set (temp.Buffer_char ()); 3092 3093 } 3094 3095 } 3096 3097 else if (doingUpdateFromXMP) 3098 { 3099 3100 exif.fArtist.Clear (); 3101 3102 if (originalExif->fArtist.NotEmpty ()) 3103 { 3104 3105 dng_string_list fakeList; 3106 3107 fakeList.Append (dng_string ()); 3108 3109 SetStringList (XMP_NS_DC, 3110 "creator", 3111 fakeList, 3112 false); 3113 3114 } 3115 3116 } 3117 3118 else if (exif.fArtist.NotEmpty ()) 3119 { 3120 3121 dng_string_list newList; 3122 3123 dng_memory_data temp (exif.fArtist.Length () + 1); 3124 3125 const char *s = exif.fArtist.Get (); 3126 3127 char *t = temp.Buffer_char (); 3128 3129 bool first = true; 3130 3131 bool quoted = false; 3132 3133 bool valid = true; 3134 3135 while (s [0] != 0 && valid) 3136 { 3137 3138 if (first) 3139 { 3140 3141 if (s [0] == '\"') 3142 { 3143 3144 quoted = true; 3145 3146 s++; 3147 3148 } 3149 3150 } 3151 3152 first = false; 3153 3154 if (quoted) 3155 { 3156 3157 if (s [0] == '\"' && 3158 s [1] == '\"') 3159 { 3160 3161 s+= 2; 3162 3163 *(t++) = '\"'; 3164 3165 } 3166 3167 else if (s [0] == '\"') 3168 { 3169 3170 s++; 3171 3172 quoted = false; 3173 3174 valid = valid && ((s [0] == 0) || ((s [0] == ';' && s [1] == ' '))); 3175 3176 } 3177 3178 else 3179 { 3180 3181 *(t++) = *(s++); 3182 3183 } 3184 3185 } 3186 3187 else if (s [0] == ';' && 3188 s [1] == ' ') 3189 { 3190 3191 s += 2; 3192 3193 t [0] = 0; 3194 3195 dng_string ss; 3196 3197 ss.Set (temp.Buffer_char ()); 3198 3199 newList.Append (ss); 3200 3201 t = temp.Buffer_char (); 3202 3203 first = true; 3204 3205 } 3206 3207 else 3208 { 3209 3210 *(t++) = *(s++); 3211 3212 } 3213 3214 } 3215 3216 if (quoted) 3217 { 3218 3219 valid = false; 3220 3221 } 3222 3223 if (valid) 3224 { 3225 3226 if (t != temp.Buffer_char ()) 3227 { 3228 3229 t [0] = 0; 3230 3231 dng_string ss; 3232 3233 ss.Set (temp.Buffer_char ()); 3234 3235 newList.Append (ss); 3236 3237 } 3238 3239 } 3240 3241 else 3242 { 3243 3244 newList.Clear (); 3245 3246 newList.Append (exif.fArtist); 3247 3248 } 3249 3250 SetStringList (XMP_NS_DC, 3251 "creator", 3252 newList, 3253 false); 3254 3255 } 3256 3257 } 3258 3259 // Software: (XMP is is always preferred) 3260 3261 if (fSDK->GetString (XMP_NS_XAP, 3262 "CreatorTool", 3263 exif.fSoftware)) 3264 3265 { 3266 3267 } 3268 3269 else if (doingUpdateFromXMP) 3270 { 3271 3272 exif.fSoftware.Clear (); 3273 3274 if (originalExif->fSoftware.NotEmpty ()) 3275 { 3276 3277 fSDK->SetString (XMP_NS_XAP, 3278 "CreatorTool", 3279 dng_string ()); 3280 3281 } 3282 3283 } 3284 3285 else if (exif.fSoftware.NotEmpty ()) 3286 { 3287 3288 fSDK->SetString (XMP_NS_XAP, 3289 "CreatorTool", 3290 exif.fSoftware); 3291 3292 } 3293 3294 // Copyright: (XMP is is always preferred) 3295 3296 if (fSDK->GetAltLangDefault (XMP_NS_DC, 3297 "rights", 3298 exif.fCopyright)) 3299 3300 { 3301 3302 } 3303 3304 else if (doingUpdateFromXMP) 3305 { 3306 3307 exif.fCopyright.Clear (); 3308 3309 if (originalExif->fCopyright.NotEmpty ()) 3310 { 3311 3312 fSDK->SetAltLangDefault (XMP_NS_DC, 3313 "rights", 3314 dng_string ()); 3315 3316 } 3317 3318 } 3319 3320 else if (exif.fCopyright.NotEmpty ()) 3321 { 3322 3323 fSDK->SetAltLangDefault (XMP_NS_DC, 3324 "rights", 3325 exif.fCopyright); 3326 3327 } 3328 3329 // Camera serial number private tag: 3330 3331 SyncString (XMP_NS_AUX, 3332 "SerialNumber", 3333 exif.fCameraSerialNumber, 3334 readOnly); 3335 3336 // Lens Info: 3337 3338 { 3339 3340 dng_string s; 3341 3342 if (exif.fLensInfo [0].IsValid ()) 3343 { 3344 3345 char ss [256]; 3346 3347 sprintf (ss, 3348 "%u/%u %u/%u %u/%u %u/%u", 3349 (unsigned) exif.fLensInfo [0].n, 3350 (unsigned) exif.fLensInfo [0].d, 3351 (unsigned) exif.fLensInfo [1].n, 3352 (unsigned) exif.fLensInfo [1].d, 3353 (unsigned) exif.fLensInfo [2].n, 3354 (unsigned) exif.fLensInfo [2].d, 3355 (unsigned) exif.fLensInfo [3].n, 3356 (unsigned) exif.fLensInfo [3].d); 3357 3358 s.Set (ss); 3359 3360 } 3361 3362 SyncString (XMP_NS_AUX, 3363 "LensInfo", 3364 s, 3365 readOnly); 3366 3367 if (s.NotEmpty ()) 3368 { 3369 3370 unsigned n [4]; 3371 unsigned d [4]; 3372 3373 if (sscanf (s.Get (), 3374 "%u/%u %u/%u %u/%u %u/%u", 3375 &n [0], 3376 &d [0], 3377 &n [1], 3378 &d [1], 3379 &n [2], 3380 &d [2], 3381 &n [3], 3382 &d [3]) == 8) 3383 { 3384 3385 for (uint32 j = 0; j < 4; j++) 3386 { 3387 3388 exif.fLensInfo [j] = dng_urational (n [j], d [j]); 3389 3390 } 3391 3392 } 3393 3394 3395 } 3396 3397 } 3398 3399 // Lens name: 3400 3401 { 3402 3403 // EXIF lens names are sometimes missing or wrong (esp. when non-OEM lenses 3404 // are used). So prefer the value from XMP. 3405 3406 SyncString (XMP_NS_AUX, 3407 "Lens", 3408 exif.fLensName, 3409 preferXMP); 3410 3411 // Generate default lens name from lens info if required. 3412 // Ignore names names that end in "f/0.0" due to third party bug. 3413 3414 if ((exif.fLensName.IsEmpty () || 3415 exif.fLensName.EndsWith ("f/0.0")) && exif.fLensInfo [0].IsValid ()) 3416 { 3417 3418 char s [256]; 3419 3420 real64 minFL = exif.fLensInfo [0].As_real64 (); 3421 real64 maxFL = exif.fLensInfo [1].As_real64 (); 3422 3423 // The f-stop numbers are optional. 3424 3425 if (exif.fLensInfo [2].IsValid ()) 3426 { 3427 3428 real64 minFS = exif.fLensInfo [2].As_real64 (); 3429 real64 maxFS = exif.fLensInfo [3].As_real64 (); 3430 3431 if (minFL == maxFL) 3432 sprintf (s, "%.1f mm f/%.1f", minFL, minFS); 3433 3434 else if (minFS == maxFS) 3435 sprintf (s, "%.1f-%.1f mm f/%.1f", minFL, maxFL, minFS); 3436 3437 else 3438 sprintf (s, "%.1f-%.1f mm f/%.1f-%.1f", minFL, maxFL, minFS, maxFS); 3439 3440 } 3441 3442 else 3443 { 3444 3445 if (minFL == maxFL) 3446 sprintf (s, "%.1f mm", minFL); 3447 3448 else 3449 sprintf (s, "%.1f-%.1f mm", minFL, maxFL); 3450 3451 } 3452 3453 exif.fLensName.Set (s); 3454 3455 SetString (XMP_NS_AUX, 3456 "Lens", 3457 exif.fLensName); 3458 3459 } 3460 3461 } 3462 3463 // Lens ID: 3464 3465 SyncString (XMP_NS_AUX, 3466 "LensID", 3467 exif.fLensID, 3468 readOnly); 3469 3470 // Lens Make: 3471 3472 SyncString (XMP_NS_EXIF, 3473 "LensMake", 3474 exif.fLensMake, 3475 readOnly + removable); 3476 3477 // Lens Serial Number: 3478 3479 SyncString (XMP_NS_AUX, 3480 "LensSerialNumber", 3481 exif.fLensSerialNumber, 3482 readOnly); 3483 3484 // Image Number: 3485 3486 Sync_uint32 (XMP_NS_AUX, 3487 "ImageNumber", 3488 exif.fImageNumber, 3489 exif.fImageNumber == 0xFFFFFFFF, 3490 readOnly); 3491 3492 // User Comment: 3493 3494 if (exif.fUserComment.NotEmpty ()) 3495 { 3496 3497 fSDK->SetAltLangDefault (XMP_NS_EXIF, 3498 "UserComment", 3499 exif.fUserComment); 3500 3501 } 3502 3503 else 3504 { 3505 3506 (void) fSDK->GetAltLangDefault (XMP_NS_EXIF, 3507 "UserComment", 3508 exif.fUserComment); 3509 3510 } 3511 3512 if (removeFromXMP) 3513 { 3514 Remove (XMP_NS_EXIF, "UserComment"); 3515 } 3516 3517 // Approximate focus distance: 3518 3519 SyncApproximateFocusDistance (exif, 3520 readOnly); 3521 3522 // Flash Compensation: 3523 3524 Sync_srational (XMP_NS_AUX, 3525 "FlashCompensation", 3526 exif.fFlashCompensation, 3527 readOnly); 3528 3529 // Owner Name: (allow XMP updates) 3530 3531 SyncString (XMP_NS_AUX, 3532 "OwnerName", 3533 exif.fOwnerName, 3534 preferXMP); 3535 3536 // Firmware: 3537 3538 SyncString (XMP_NS_AUX, 3539 "Firmware", 3540 exif.fFirmware, 3541 readOnly); 3542 3543 // Image Unique ID: 3544 3545 { 3546 3547 dng_string s = EncodeFingerprint (exif.fImageUniqueID); 3548 3549 SyncString (XMP_NS_EXIF, 3550 "ImageUniqueID", 3551 s, 3552 readOnly + removable); 3553 3554 exif.fImageUniqueID = DecodeFingerprint (s); 3555 3556 } 3557 3558 // Allow EXIF GPS to be updated via updates from XMP. 3559 3560 if (doingUpdateFromXMP) 3561 { 3562 3563 // Require that at least one basic GPS field exist in the 3564 // XMP before overrriding the EXIF GPS fields. 3565 3566 if (Exists (XMP_NS_EXIF, "GPSVersionID" ) || 3567 Exists (XMP_NS_EXIF, "GPSLatitude" ) || 3568 Exists (XMP_NS_EXIF, "GPSLongitude" ) || 3569 Exists (XMP_NS_EXIF, "GPSAltitude" ) || 3570 Exists (XMP_NS_EXIF, "GPSTimeStamp" ) || 3571 Exists (XMP_NS_EXIF, "GPSProcessingMethod")) 3572 { 3573 3574 // Clear out the GPS info from the EXIF so it will 3575 // replaced by the GPS info from the XMP. 3576 3577 dng_exif blankExif; 3578 3579 exif.CopyGPSFrom (blankExif); 3580 3581 } 3582 3583 } 3584 3585 // GPS Version ID: 3586 3587 { 3588 3589 dng_string s = EncodeGPSVersion (exif.fGPSVersionID); 3590 3591 if (SyncString (XMP_NS_EXIF, 3592 "GPSVersionID", 3593 s, 3594 preferNonXMP + removable)) 3595 { 3596 3597 exif.fGPSVersionID = DecodeGPSVersion (s); 3598 3599 } 3600 3601 } 3602 3603 // GPS Latitude: 3604 3605 { 3606 3607 dng_string s = EncodeGPSCoordinate (exif.fGPSLatitudeRef, 3608 exif.fGPSLatitude); 3609 3610 if (SyncString (XMP_NS_EXIF, 3611 "GPSLatitude", 3612 s, 3613 preferNonXMP + removable)) 3614 { 3615 3616 DecodeGPSCoordinate (s, 3617 exif.fGPSLatitudeRef, 3618 exif.fGPSLatitude); 3619 3620 } 3621 3622 } 3623 3624 // GPS Longitude: 3625 3626 { 3627 3628 dng_string s = EncodeGPSCoordinate (exif.fGPSLongitudeRef, 3629 exif.fGPSLongitude); 3630 3631 if (SyncString (XMP_NS_EXIF, 3632 "GPSLongitude", 3633 s, 3634 preferNonXMP + removable)) 3635 { 3636 3637 DecodeGPSCoordinate (s, 3638 exif.fGPSLongitudeRef, 3639 exif.fGPSLongitude); 3640 3641 } 3642 3643 } 3644 3645 // Handle simple case of incorrectly written GPS altitude where someone didn't understand the GPSAltitudeRef and assumed the GPSAltitude RATIONAL is signed. 3646 // Only handle this case as we do not want to misinterpret e.g. a fixed point representation of very high GPS altitudes. 3647 3648 uint32 &altitudeRef = exif.fGPSAltitudeRef; 3649 dng_urational &altitude = exif.fGPSAltitude; 3650 3651 if (altitude.IsValid () && 3652 (altitudeRef == 0 || altitudeRef == 0xFFFFFFFF)) // If the file contains a "below sea level" altitudeRef, assume the writing software is working according to the spec. 3653 { 3654 3655 if ((altitude.n & (1U << 31)) && 3656 altitude.d < 7) // As the denominator increases, large numerator values become possibly valid distances. Pick a limit on the conservative side (approx 33e6m) to prevent misinterpretation. 3657 // Noting that the normal case for this mistake has a denominator of 1 3658 { 3659 3660 altitude.n = ~altitude.n + 1; 3661 altitudeRef = 1; 3662 3663 } 3664 3665 } 3666 3667 // GPS Altitude Reference: 3668 3669 Sync_uint32 (XMP_NS_EXIF, 3670 "GPSAltitudeRef", 3671 altitudeRef, 3672 altitudeRef == 0xFFFFFFFF, 3673 preferNonXMP + removable); 3674 3675 // GPS Altitude: 3676 3677 Sync_urational (XMP_NS_EXIF, 3678 "GPSAltitude", 3679 altitude, 3680 preferNonXMP + removable); 3681 3682 // GPS Date/Time: 3683 3684 { 3685 3686 dng_string s = EncodeGPSDateTime (exif.fGPSDateStamp, 3687 exif.fGPSTimeStamp); 3688 3689 if (SyncString (XMP_NS_EXIF, 3690 "GPSTimeStamp", 3691 s, 3692 preferNonXMP + removable)) 3693 { 3694 3695 DecodeGPSDateTime (s, 3696 exif.fGPSDateStamp, 3697 exif.fGPSTimeStamp); 3698 3699 } 3700 3701 } 3702 3703 // GPS Satellites: 3704 3705 SyncString (XMP_NS_EXIF, 3706 "GPSSatellites", 3707 exif.fGPSSatellites, 3708 preferNonXMP + removable); 3709 3710 // GPS Status: 3711 3712 SyncString (XMP_NS_EXIF, 3713 "GPSStatus", 3714 exif.fGPSStatus, 3715 preferNonXMP + removable); 3716 3717 // GPS Measure Mode: 3718 3719 SyncString (XMP_NS_EXIF, 3720 "GPSMeasureMode", 3721 exif.fGPSMeasureMode, 3722 preferNonXMP + removable); 3723 3724 // GPS DOP: 3725 3726 Sync_urational (XMP_NS_EXIF, 3727 "GPSDOP", 3728 exif.fGPSDOP, 3729 preferNonXMP + removable); 3730 3731 // GPS Speed Reference: 3732 3733 SyncString (XMP_NS_EXIF, 3734 "GPSSpeedRef", 3735 exif.fGPSSpeedRef, 3736 preferNonXMP + removable); 3737 3738 // GPS Speed: 3739 3740 Sync_urational (XMP_NS_EXIF, 3741 "GPSSpeed", 3742 exif.fGPSSpeed, 3743 preferNonXMP + removable); 3744 3745 // GPS Track Reference: 3746 3747 SyncString (XMP_NS_EXIF, 3748 "GPSTrackRef", 3749 exif.fGPSTrackRef, 3750 preferNonXMP + removable); 3751 3752 // GPS Track: 3753 3754 Sync_urational (XMP_NS_EXIF, 3755 "GPSTrack", 3756 exif.fGPSTrack, 3757 preferNonXMP + removable); 3758 3759 // GPS Image Direction Reference: 3760 3761 SyncString (XMP_NS_EXIF, 3762 "GPSImgDirectionRef", 3763 exif.fGPSImgDirectionRef, 3764 preferNonXMP + removable); 3765 3766 // GPS Image Direction: 3767 3768 Sync_urational (XMP_NS_EXIF, 3769 "GPSImgDirection", 3770 exif.fGPSImgDirection, 3771 preferNonXMP + removable); 3772 3773 // GPS Map Datum: 3774 3775 SyncString (XMP_NS_EXIF, 3776 "GPSMapDatum", 3777 exif.fGPSMapDatum, 3778 preferNonXMP + removable); 3779 3780 // GPS Destination Latitude: 3781 3782 { 3783 3784 dng_string s = EncodeGPSCoordinate (exif.fGPSDestLatitudeRef, 3785 exif.fGPSDestLatitude); 3786 3787 if (SyncString (XMP_NS_EXIF, 3788 "GPSDestLatitude", 3789 s, 3790 preferNonXMP + removable)) 3791 { 3792 3793 DecodeGPSCoordinate (s, 3794 exif.fGPSDestLatitudeRef, 3795 exif.fGPSDestLatitude); 3796 3797 } 3798 3799 } 3800 3801 // GPS Destination Longitude: 3802 3803 { 3804 3805 dng_string s = EncodeGPSCoordinate (exif.fGPSDestLongitudeRef, 3806 exif.fGPSDestLongitude); 3807 3808 if (SyncString (XMP_NS_EXIF, 3809 "GPSDestLongitude", 3810 s, 3811 preferNonXMP + removable)) 3812 { 3813 3814 DecodeGPSCoordinate (s, 3815 exif.fGPSDestLongitudeRef, 3816 exif.fGPSDestLongitude); 3817 3818 } 3819 3820 } 3821 3822 // GPS Destination Bearing Reference: 3823 3824 SyncString (XMP_NS_EXIF, 3825 "GPSDestBearingRef", 3826 exif.fGPSDestBearingRef, 3827 preferNonXMP + removable); 3828 3829 // GPS Destination Bearing: 3830 3831 Sync_urational (XMP_NS_EXIF, 3832 "GPSDestBearing", 3833 exif.fGPSDestBearing, 3834 preferNonXMP + removable); 3835 3836 // GPS Destination Distance Reference: 3837 3838 SyncString (XMP_NS_EXIF, 3839 "GPSDestDistanceRef", 3840 exif.fGPSDestDistanceRef, 3841 preferNonXMP + removable); 3842 3843 // GPS Destination Distance: 3844 3845 Sync_urational (XMP_NS_EXIF, 3846 "GPSDestDistance", 3847 exif.fGPSDestDistance, 3848 preferNonXMP + removable); 3849 3850 // GPS Processing Method: 3851 3852 SyncString (XMP_NS_EXIF, 3853 "GPSProcessingMethod", 3854 exif.fGPSProcessingMethod, 3855 preferNonXMP + removable); 3856 3857 // GPS Area Information: 3858 3859 SyncString (XMP_NS_EXIF, 3860 "GPSAreaInformation", 3861 exif.fGPSAreaInformation, 3862 preferNonXMP + removable); 3863 3864 // GPS Differential: 3865 3866 Sync_uint32 (XMP_NS_EXIF, 3867 "GPSDifferential", 3868 exif.fGPSDifferential, 3869 exif.fGPSDifferential == 0xFFFFFFFF, 3870 preferNonXMP + removable); 3871 3872 // GPS Horizontal Positioning Error: 3873 3874 Sync_urational (XMP_NS_EXIF, 3875 "GPSHPositioningError", 3876 exif.fGPSHPositioningError, 3877 preferNonXMP + removable); 3878 3879 // Sync date/times. 3880 3881 UpdateExifDates (exif, removeFromXMP); 3882 3883 // We are syncing EXIF and XMP, but we are not updating the 3884 // NativeDigest tags. It is better to just delete them than leave 3885 // the stale values around. 3886 3887 Remove (XMP_NS_EXIF, "NativeDigest"); 3888 Remove (XMP_NS_TIFF, "NativeDigest"); 3889 3890 } 3891 3892 /*****************************************************************************/ 3893 3894 void dng_xmp::SyncApproximateFocusDistance (dng_exif &exif, 3895 const uint32 readOnly) 3896 { 3897 3898 Sync_urational (XMP_NS_AUX, 3899 "ApproximateFocusDistance", 3900 exif.fApproxFocusDistance, 3901 readOnly); 3902 3903 } 3904 3905 /******************************************************************************/ 3906 3907 void dng_xmp::ValidateStringList (const char *ns, 3908 const char *path) 3909 { 3910 3911 fSDK->ValidateStringList (ns, path); 3912 3913 } 3914 3915 /******************************************************************************/ 3916 3917 void dng_xmp::ValidateMetadata () 3918 { 3919 3920 // The following values should be arrays, but are not always. So 3921 // fix them up because Photoshop sometimes has problems parsing invalid 3922 // tags. 3923 3924 ValidateStringList (XMP_NS_DC, "creator"); 3925 3926 ValidateStringList (XMP_NS_PHOTOSHOP, "Keywords"); 3927 ValidateStringList (XMP_NS_PHOTOSHOP, "SupplementalCategories"); 3928 3929 } 3930 3931 /******************************************************************************/ 3932 3933 bool dng_xmp::DateTimeIsDateOnly (const char *ns, 3934 const char *path) 3935 { 3936 3937 dng_string s; 3938 3939 if (GetString (ns, path, s)) 3940 { 3941 3942 uint32 len = s.Length (); 3943 3944 if (len) 3945 { 3946 3947 for (uint32 j = 0; j < len; j++) 3948 { 3949 3950 if (s.Get () [j] == 'T') 3951 { 3952 3953 return false; 3954 3955 } 3956 3957 } 3958 3959 return true; 3960 3961 } 3962 3963 } 3964 3965 return false; 3966 3967 } 3968 3969 /******************************************************************************/ 3970 3971 void dng_xmp::UpdateExifDates (dng_exif &exif, 3972 bool removeFromXMP) 3973 { 3974 3975 // For the following three date/time fields, we always prefer XMP to 3976 // the EXIF values. This is to allow the user to correct the date/times 3977 // via changes in a sidecar XMP file, without modifying the original 3978 // raw file. 3979 3980 // Kludge: The Nikon D4 is writing date only date/times into XMP, so 3981 // prefer the EXIF values if the XMP only contains a date. 3982 3983 // Modification Date/Time: 3984 // exif.fDateTime 3985 // kXMP_NS_XMP:"ModifyDate" & kXMP_NS_TIFF:"DateTime" are aliased 3986 3987 { 3988 3989 dng_string s = exif.fDateTime.Encode_ISO_8601 (); 3990 3991 bool dateOnly = DateTimeIsDateOnly (XMP_NS_TIFF, "DateTime"); 3992 3993 SyncString (XMP_NS_TIFF, 3994 "DateTime", 3995 s, 3996 dateOnly ? preferNonXMP : preferXMP); 3997 3998 if (s.NotEmpty ()) 3999 { 4000 4001 exif.fDateTime.Decode_ISO_8601 (s.Get ()); 4002 4003 // Round trip again in case we need to add a fake time zone. 4004 4005 s = exif.fDateTime.Encode_ISO_8601 (); 4006 4007 SetString (XMP_NS_TIFF, 4008 "DateTime", 4009 s); 4010 4011 } 4012 4013 } 4014 4015 // Original Date/Time: 4016 // exif.fDateTimeOriginal 4017 // IPTC: DateCreated 4018 // XMP_NS_EXIF:"DateTimeOriginal" & XMP_NS_PHOTOSHOP:"DateCreated" 4019 // Adobe has decided to keep the two XMP fields separate. 4020 4021 { 4022 4023 dng_string s = exif.fDateTimeOriginal.Encode_ISO_8601 (); 4024 4025 bool dateOnly = DateTimeIsDateOnly (XMP_NS_EXIF, "DateTimeOriginal"); 4026 4027 SyncString (XMP_NS_EXIF, 4028 "DateTimeOriginal", 4029 s, 4030 dateOnly ? preferNonXMP : preferXMP); 4031 4032 if (s.NotEmpty ()) 4033 { 4034 4035 exif.fDateTimeOriginal.Decode_ISO_8601 (s.Get ()); 4036 4037 // Round trip again in case we need to add a fake time zone. 4038 4039 s = exif.fDateTimeOriginal.Encode_ISO_8601 (); 4040 4041 SetString (XMP_NS_EXIF, 4042 "DateTimeOriginal", 4043 s); 4044 4045 } 4046 4047 // Sync the IPTC value to the EXIF value if only the EXIF 4048 // value exists. 4049 4050 if (s.NotEmpty () && !Exists (XMP_NS_PHOTOSHOP, "DateCreated")) 4051 { 4052 4053 SetString (XMP_NS_PHOTOSHOP, "DateCreated", s); 4054 4055 } 4056 4057 if (removeFromXMP) 4058 { 4059 4060 Remove (XMP_NS_EXIF, "DateTimeOriginal"); 4061 4062 } 4063 4064 } 4065 4066 // Date Time Digitized: 4067 // XMP_NS_EXIF:"DateTimeDigitized" & kXMP_NS_XMP:"CreateDate" are aliased 4068 4069 { 4070 4071 dng_string s = exif.fDateTimeDigitized.Encode_ISO_8601 (); 4072 4073 bool dateOnly = DateTimeIsDateOnly (XMP_NS_EXIF, "DateTimeDigitized"); 4074 4075 SyncString (XMP_NS_EXIF, 4076 "DateTimeDigitized", 4077 s, 4078 dateOnly ? preferNonXMP : preferXMP); 4079 4080 if (s.NotEmpty ()) 4081 { 4082 4083 exif.fDateTimeDigitized.Decode_ISO_8601 (s.Get ()); 4084 4085 // Round trip again in case we need to add a fake time zone. 4086 4087 s = exif.fDateTimeDigitized.Encode_ISO_8601 (); 4088 4089 SetString (XMP_NS_EXIF, 4090 "DateTimeDigitized", 4091 s); 4092 4093 } 4094 4095 } 4096 4097 } 4098 4099 /******************************************************************************/ 4100 4101 void dng_xmp::UpdateDateTime (const dng_date_time_info &dt) 4102 { 4103 4104 dng_string s = dt.Encode_ISO_8601 (); 4105 4106 SetString (XMP_NS_TIFF, 4107 "DateTime", 4108 s); 4109 4110 } 4111 4112 /******************************************************************************/ 4113 4114 void dng_xmp::UpdateMetadataDate (const dng_date_time_info &dt) 4115 { 4116 4117 dng_string s = dt.Encode_ISO_8601 (); 4118 4119 SetString (XMP_NS_XAP, 4120 "MetadataDate", 4121 s); 4122 4123 } 4124 4125 /*****************************************************************************/ 4126 4127 bool dng_xmp::HasOrientation () const 4128 { 4129 4130 uint32 x = 0; 4131 4132 if (Get_uint32 (XMP_NS_TIFF, 4133 "Orientation", 4134 x)) 4135 { 4136 4137 return (x >= 1) && (x <= 8); 4138 4139 } 4140 4141 return false; 4142 4143 } 4144 4145 /*****************************************************************************/ 4146 4147 dng_orientation dng_xmp::GetOrientation () const 4148 { 4149 4150 dng_orientation result; 4151 4152 uint32 x = 0; 4153 4154 if (Get_uint32 (XMP_NS_TIFF, 4155 "Orientation", 4156 x)) 4157 { 4158 4159 if ((x >= 1) && (x <= 8)) 4160 { 4161 4162 result.SetTIFF (x); 4163 4164 } 4165 4166 } 4167 4168 return result; 4169 4170 } 4171 4172 /******************************************************************************/ 4173 4174 void dng_xmp::ClearOrientation () 4175 { 4176 4177 fSDK->Remove (XMP_NS_TIFF, "Orientation"); 4178 4179 } 4180 4181 /******************************************************************************/ 4182 4183 void dng_xmp::SetOrientation (const dng_orientation &orientation) 4184 { 4185 4186 Set_uint32 (XMP_NS_TIFF, 4187 "Orientation", 4188 orientation.GetTIFF ()); 4189 4190 } 4191 4192 /*****************************************************************************/ 4193 4194 void dng_xmp::SyncOrientation (dng_negative &negative, 4195 bool xmpIsMaster) 4196 { 4197 4198 SyncOrientation (negative.Metadata (), xmpIsMaster); 4199 4200 } 4201 4202 /*****************************************************************************/ 4203 4204 void dng_xmp::SyncOrientation (dng_metadata &metadata, 4205 bool xmpIsMaster) 4206 { 4207 4208 // See if XMP contains the orientation. 4209 4210 bool xmpHasOrientation = HasOrientation (); 4211 4212 // See if XMP is the master value. 4213 4214 if (xmpHasOrientation && (xmpIsMaster || !metadata.HasBaseOrientation ())) 4215 { 4216 4217 metadata.SetBaseOrientation (GetOrientation ()); 4218 4219 } 4220 4221 else 4222 { 4223 4224 SetOrientation (metadata.BaseOrientation ()); 4225 4226 } 4227 4228 } 4229 4230 /******************************************************************************/ 4231 4232 void dng_xmp::ClearImageInfo () 4233 { 4234 4235 Remove (XMP_NS_TIFF, "ImageWidth" ); 4236 Remove (XMP_NS_TIFF, "ImageLength"); 4237 4238 Remove (XMP_NS_EXIF, "PixelXDimension"); 4239 Remove (XMP_NS_EXIF, "PixelYDimension"); 4240 4241 Remove (XMP_NS_TIFF, "BitsPerSample"); 4242 4243 Remove (XMP_NS_TIFF, "Compression"); 4244 4245 Remove (XMP_NS_TIFF, "PhotometricInterpretation"); 4246 4247 // "Orientation" is handled separately. 4248 4249 Remove (XMP_NS_TIFF, "SamplesPerPixel"); 4250 4251 Remove (XMP_NS_TIFF, "PlanarConfiguration"); 4252 4253 Remove (XMP_NS_TIFF, "XResolution"); 4254 Remove (XMP_NS_TIFF, "YResolution"); 4255 4256 Remove (XMP_NS_TIFF, "ResolutionUnit"); 4257 4258 Remove (XMP_NS_PHOTOSHOP, "ColorMode" ); 4259 Remove (XMP_NS_PHOTOSHOP, "ICCProfile"); 4260 4261 } 4262 4263 /******************************************************************************/ 4264 4265 void dng_xmp::SetImageSize (const dng_point &size) 4266 { 4267 4268 Set_uint32 (XMP_NS_TIFF, "ImageWidth" , size.h); 4269 Set_uint32 (XMP_NS_TIFF, "ImageLength", size.v); 4270 4271 // Mirror these values to the EXIF tags. 4272 4273 Set_uint32 (XMP_NS_EXIF, "PixelXDimension" , size.h); 4274 Set_uint32 (XMP_NS_EXIF, "PixelYDimension" , size.v); 4275 4276 } 4277 4278 /******************************************************************************/ 4279 4280 void dng_xmp::SetSampleInfo (uint32 samplesPerPixel, 4281 uint32 bitsPerSample) 4282 { 4283 4284 Set_uint32 (XMP_NS_TIFF, "SamplesPerPixel", samplesPerPixel); 4285 4286 char s [32]; 4287 4288 sprintf (s, "%u", (unsigned) bitsPerSample); 4289 4290 dng_string ss; 4291 4292 ss.Set (s); 4293 4294 dng_string_list list; 4295 4296 for (uint32 j = 0; j < samplesPerPixel; j++) 4297 { 4298 list.Append (ss); 4299 } 4300 4301 SetStringList (XMP_NS_TIFF, "BitsPerSample", list, false); 4302 4303 } 4304 4305 /******************************************************************************/ 4306 4307 void dng_xmp::SetPhotometricInterpretation (uint32 pi) 4308 { 4309 4310 Set_uint32 (XMP_NS_TIFF, "PhotometricInterpretation", pi); 4311 4312 } 4313 4314 /******************************************************************************/ 4315 4316 void dng_xmp::SetResolution (const dng_resolution &res) 4317 { 4318 4319 Set_urational (XMP_NS_TIFF, "XResolution", res.fXResolution); 4320 Set_urational (XMP_NS_TIFF, "YResolution", res.fYResolution); 4321 4322 Set_uint32 (XMP_NS_TIFF, "ResolutionUnit", res.fResolutionUnit); 4323 4324 } 4325 4326 /*****************************************************************************/ 4327 4328 void dng_xmp::ComposeArrayItemPath (const char *ns, 4329 const char *arrayName, 4330 int32 itemNumber, 4331 dng_string &s) const 4332 { 4333 4334 fSDK->ComposeArrayItemPath (ns, arrayName, itemNumber, s); 4335 4336 } 4337 4338 /*****************************************************************************/ 4339 4340 void dng_xmp::ComposeStructFieldPath (const char *ns, 4341 const char *structName, 4342 const char *fieldNS, 4343 const char *fieldName, 4344 dng_string &s) const 4345 { 4346 4347 fSDK->ComposeStructFieldPath (ns, structName, fieldNS, fieldName, s); 4348 4349 } 4350 4351 /*****************************************************************************/ 4352 4353 int32 dng_xmp::CountArrayItems (const char *ns, 4354 const char *path) const 4355 { 4356 4357 return fSDK->CountArrayItems (ns, path); 4358 4359 } 4360 4361 /*****************************************************************************/ 4362 4363 void dng_xmp::AppendArrayItem (const char *ns, 4364 const char *arrayName, 4365 const char *itemValue, 4366 bool isBag, 4367 bool propIsStruct) 4368 { 4369 4370 fSDK->AppendArrayItem (ns, 4371 arrayName, 4372 itemValue, 4373 isBag, 4374 propIsStruct); 4375 } 4376 4377 /*****************************************************************************/ 4378 4379 #if qDNGXMPDocOps 4380 4381 /*****************************************************************************/ 4382 4383 void dng_xmp::DocOpsOpenXMP (const char *srcMIMI) 4384 { 4385 4386 fSDK->DocOpsOpenXMP (srcMIMI); 4387 4388 } 4389 4390 /*****************************************************************************/ 4391 4392 void dng_xmp::DocOpsPrepareForSave (const char *srcMIMI, 4393 const char *dstMIMI, 4394 bool newPath) 4395 { 4396 4397 fSDK->DocOpsPrepareForSave (srcMIMI, 4398 dstMIMI, 4399 newPath); 4400 4401 } 4402 4403 /*****************************************************************************/ 4404 4405 void dng_xmp::DocOpsUpdateMetadata (const char *srcMIMI) 4406 { 4407 4408 fSDK->DocOpsUpdateMetadata (srcMIMI); 4409 4410 } 4411 4412 /*****************************************************************************/ 4413 4414 #endif 4415 4416 #endif 4417 /*****************************************************************************/ 4418