1 /*****************************************************************************/ 2 // Copyright 2006-2012 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_validate.cpp#2 $ */ 10 /* $DateTime: 2012/06/14 20:24:41 $ */ 11 /* $Change: 835078 $ */ 12 /* $Author: tknoll $ */ 13 14 // Process exit codes 15 // ------------------ 16 // 17 // As usual, 0 indicates success. 18 // 19 // If an exception occurs, the exit code will be equal to: 20 // 21 // DNG SDK error code - 100000 + 100 22 // 23 // For example, the error dng_error_memory, which has a DNG SDK error code of 24 // 100005, is returned as an exit code of 105. 25 // 26 // This convention accounts for the fact that the shell truncates process exit 27 // codes to 8 bits and that the exit code 1 is used by ASAN to signal that a 28 // memory error occurred (so mapping the first DNG SDK error code to an exit 29 // code of 1 would not be a good idea). 30 31 /*****************************************************************************/ 32 33 #include "dng_color_space.h" 34 #include "dng_date_time.h" 35 #include "dng_exceptions.h" 36 #include "dng_file_stream.h" 37 #include "dng_globals.h" 38 #include "dng_host.h" 39 #include "dng_ifd.h" 40 #include "dng_image_writer.h" 41 #include "dng_info.h" 42 #include "dng_linearization_info.h" 43 #include "dng_mosaic_info.h" 44 #include "dng_negative.h" 45 #include "dng_preview.h" 46 #include "dng_render.h" 47 #include "dng_simple_image.h" 48 #include "dng_tag_codes.h" 49 #include "dng_tag_types.h" 50 #include "dng_tag_values.h" 51 52 #if qDNGUseXMP 53 #include "dng_xmp.h" 54 #include "dng_xmp_sdk.h" 55 #endif 56 57 /*****************************************************************************/ 58 59 #if qDNGValidateTarget 60 61 /*****************************************************************************/ 62 63 #define kDNGValidateVersion "1.4" 64 65 /*****************************************************************************/ 66 67 static bool gFourColorBayer = false; 68 69 static int32 gMosaicPlane = -1; 70 71 static uint32 gPreferredSize = 0; 72 static uint32 gMinimumSize = 0; 73 static uint32 gMaximumSize = 0; 74 75 static uint32 gProxyDNGSize = 0; 76 77 static const dng_color_space *gFinalSpace = &dng_space_sRGB::Get (); 78 79 static uint32 gFinalPixelType = ttByte; 80 81 static dng_string gDumpStage1; 82 static dng_string gDumpStage2; 83 static dng_string gDumpStage3; 84 static dng_string gDumpTIF; 85 static dng_string gDumpDNG; 86 87 /*****************************************************************************/ 88 89 static dng_error_code dng_validate (const char *filename) 90 { 91 92 printf ("Validating \"%s\"...\n", filename); 93 94 try 95 { 96 97 dng_file_stream stream (filename); 98 99 dng_host host; 100 101 host.SetPreferredSize (gPreferredSize); 102 host.SetMinimumSize (gMinimumSize ); 103 host.SetMaximumSize (gMaximumSize ); 104 105 host.ValidateSizes (); 106 107 if (host.MinimumSize ()) 108 { 109 110 host.SetForPreview (true); 111 112 gDumpDNG.Clear (); 113 114 } 115 116 if (gDumpDNG.NotEmpty ()) 117 { 118 119 host.SetSaveDNGVersion (dngVersion_SaveDefault); 120 121 host.SetSaveLinearDNG (false); 122 123 host.SetKeepOriginalFile (false); 124 125 } 126 127 // Read into the negative. 128 129 AutoPtr<dng_negative> negative; 130 131 { 132 133 dng_info info; 134 135 info.Parse (host, stream); 136 137 info.PostParse (host); 138 139 if (!info.IsValidDNG ()) 140 { 141 return dng_error_bad_format; 142 } 143 144 negative.Reset (host.Make_dng_negative ()); 145 146 negative->Parse (host, stream, info); 147 148 negative->PostParse (host, stream, info); 149 150 { 151 152 dng_timer timer ("Raw image read time"); 153 154 negative->ReadStage1Image (host, stream, info); 155 156 } 157 158 if (info.fMaskIndex != -1) 159 { 160 161 dng_timer timer ("Transparency mask read time"); 162 163 negative->ReadTransparencyMask (host, stream, info); 164 165 } 166 167 negative->ValidateRawImageDigest (host); 168 169 } 170 171 // Option to write stage 1 image. 172 173 if (gDumpStage1.NotEmpty ()) 174 { 175 176 dng_file_stream stream2 (gDumpStage1.Get (), true); 177 178 const dng_image &stage1 = *negative->Stage1Image (); 179 180 dng_image_writer writer; 181 182 writer.WriteTIFF (host, 183 stream2, 184 stage1, 185 stage1.Planes () >= 3 ? piRGB 186 : piBlackIsZero); 187 188 gDumpStage1.Clear (); 189 190 } 191 192 // Metadata. 193 194 negative->SynchronizeMetadata (); 195 196 // Four color Bayer option. 197 198 if (gFourColorBayer) 199 { 200 negative->SetFourColorBayer (); 201 } 202 203 // Build stage 2 image. 204 205 { 206 207 dng_timer timer ("Linearization time"); 208 209 negative->BuildStage2Image (host); 210 211 } 212 213 if (gDumpStage2.NotEmpty ()) 214 { 215 216 dng_file_stream stream2 (gDumpStage2.Get (), true); 217 218 const dng_image &stage2 = *negative->Stage2Image (); 219 220 dng_image_writer writer; 221 222 writer.WriteTIFF (host, 223 stream2, 224 stage2, 225 stage2.Planes () >= 3 ? piRGB 226 : piBlackIsZero); 227 228 gDumpStage2.Clear (); 229 230 } 231 232 // Build stage 3 image. 233 234 { 235 236 dng_timer timer ("Interpolate time"); 237 238 negative->BuildStage3Image (host, 239 gMosaicPlane); 240 241 } 242 243 // Convert to proxy, if requested. 244 245 if (gProxyDNGSize) 246 { 247 248 dng_timer timer ("ConvertToProxy time"); 249 250 dng_image_writer writer; 251 252 negative->ConvertToProxy (host, 253 writer, 254 gProxyDNGSize); 255 256 } 257 258 // Flatten transparency, if required. 259 260 if (negative->NeedFlattenTransparency (host)) 261 { 262 263 dng_timer timer ("FlattenTransparency time"); 264 265 negative->FlattenTransparency (host); 266 267 } 268 269 if (gDumpStage3.NotEmpty ()) 270 { 271 272 dng_file_stream stream2 (gDumpStage3.Get (), true); 273 274 const dng_image &stage3 = *negative->Stage3Image (); 275 276 dng_image_writer writer; 277 278 writer.WriteTIFF (host, 279 stream2, 280 stage3, 281 stage3.Planes () >= 3 ? piRGB 282 : piBlackIsZero); 283 284 gDumpStage3.Clear (); 285 286 } 287 288 // Output DNG file if requested. 289 290 if (gDumpDNG.NotEmpty ()) 291 { 292 293 // Build the preview list. 294 295 dng_preview_list previewList; 296 297 dng_date_time_info dateTimeInfo; 298 299 CurrentDateTimeAndZone (dateTimeInfo); 300 301 for (uint32 previewIndex = 0; previewIndex < 2; previewIndex++) 302 { 303 304 // Skip preview if writing a compresssed main image to save space 305 // in this example code. 306 307 if (negative->RawJPEGImage () != NULL && previewIndex > 0) 308 { 309 break; 310 } 311 312 // Report timing. 313 314 dng_timer timer (previewIndex == 0 ? "Build thumbnail time" 315 : "Build preview time"); 316 317 // Render a preview sized image. 318 319 AutoPtr<dng_image> previewImage; 320 321 { 322 323 dng_render render (host, *negative); 324 325 render.SetFinalSpace (negative->IsMonochrome () ? dng_space_GrayGamma22::Get () 326 : dng_space_sRGB ::Get ()); 327 328 render.SetFinalPixelType (ttByte); 329 330 render.SetMaximumSize (previewIndex == 0 ? 256 : 1024); 331 332 previewImage.Reset (render.Render ()); 333 334 } 335 336 // Don't write the preview if it is same size as thumbnail. 337 338 if (previewIndex > 0 && 339 Max_uint32 (previewImage->Bounds ().W (), 340 previewImage->Bounds ().H ()) <= 256) 341 { 342 break; 343 } 344 345 // If we have compressed JPEG data, create a compressed thumbnail. Otherwise 346 // save a uncompressed thumbnail. 347 348 bool useCompressedPreview = (negative->RawJPEGImage () != NULL) || 349 (previewIndex > 0); 350 351 AutoPtr<dng_preview> preview (useCompressedPreview ? 352 (dng_preview *) new dng_jpeg_preview : 353 (dng_preview *) new dng_image_preview); 354 355 // Setup up preview info. 356 357 preview->fInfo.fApplicationName .Set ("dng_validate"); 358 preview->fInfo.fApplicationVersion.Set (kDNGValidateVersion); 359 360 preview->fInfo.fSettingsName.Set ("Default"); 361 362 preview->fInfo.fColorSpace = previewImage->Planes () == 1 ? 363 previewColorSpace_GrayGamma22 : 364 previewColorSpace_sRGB; 365 366 preview->fInfo.fDateTime = dateTimeInfo.Encode_ISO_8601 (); 367 368 if (!useCompressedPreview) 369 { 370 371 dng_image_preview *imagePreview = dynamic_cast<dng_image_preview *> (preview.Get ()); 372 373 imagePreview->fImage.Reset (previewImage.Release ()); 374 375 } 376 377 else 378 { 379 380 dng_jpeg_preview *jpegPreview = dynamic_cast<dng_jpeg_preview *> (preview.Get ()); 381 382 int32 quality = (previewIndex == 0 ? 8 : 5); 383 384 dng_image_writer writer; 385 386 writer.EncodeJPEGPreview (host, 387 *previewImage, 388 *jpegPreview, 389 quality); 390 391 } 392 393 previewList.Append (preview); 394 395 } 396 397 // Write DNG file. 398 399 dng_file_stream stream2 (gDumpDNG.Get (), true); 400 401 { 402 403 dng_timer timer ("Write DNG time"); 404 405 dng_image_writer writer; 406 407 writer.WriteDNG (host, 408 stream2, 409 *negative.Get (), 410 &previewList, 411 dngVersion_Current, 412 false); 413 414 } 415 416 gDumpDNG.Clear (); 417 418 } 419 420 // Output TIF file if requested. 421 422 if (gDumpTIF.NotEmpty ()) 423 { 424 425 // Render final image. 426 427 dng_render render (host, *negative); 428 429 render.SetFinalSpace (*gFinalSpace ); 430 render.SetFinalPixelType (gFinalPixelType); 431 432 if (host.MinimumSize ()) 433 { 434 435 dng_point stage3Size = negative->Stage3Image ()->Size (); 436 437 render.SetMaximumSize (Max_uint32 (stage3Size.v, 438 stage3Size.h)); 439 440 } 441 442 AutoPtr<dng_image> finalImage; 443 444 { 445 446 dng_timer timer ("Render time"); 447 448 finalImage.Reset (render.Render ()); 449 450 } 451 452 finalImage->Rotate (negative->Orientation ()); 453 454 // Now that Camera Raw supports non-raw formats, we should 455 // not keep any Camera Raw settings in the XMP around when 456 // writing rendered files. 457 458 #if qDNGUseXMP 459 460 if (negative->GetXMP ()) 461 { 462 463 negative->GetXMP ()->RemoveProperties (XMP_NS_CRS); 464 negative->GetXMP ()->RemoveProperties (XMP_NS_CRSS); 465 466 } 467 468 #endif 469 470 // Write TIF file. 471 472 dng_file_stream stream2 (gDumpTIF.Get (), true); 473 474 { 475 476 dng_timer timer ("Write TIFF time"); 477 478 dng_image_writer writer; 479 480 writer.WriteTIFF (host, 481 stream2, 482 *finalImage.Get (), 483 finalImage->Planes () >= 3 ? piRGB 484 : piBlackIsZero, 485 ccUncompressed, 486 negative.Get (), 487 &render.FinalSpace ()); 488 489 } 490 491 gDumpTIF.Clear (); 492 493 } 494 495 } 496 497 catch (const dng_exception &except) 498 { 499 500 return except.ErrorCode (); 501 502 } 503 504 catch (...) 505 { 506 507 return dng_error_unknown; 508 509 } 510 511 printf ("Validation complete\n"); 512 513 return dng_error_none; 514 515 } 516 517 /*****************************************************************************/ 518 519 int main (int argc, char *argv []) 520 { 521 522 try 523 { 524 525 if (argc == 1) 526 { 527 528 fprintf (stderr, 529 "\n" 530 "dng_validate, version " kDNGValidateVersion " " 531 #if qDNG64Bit 532 "(64-bit)" 533 #else 534 "(32-bit)" 535 #endif 536 "\n" 537 "Copyright 2005-2012 Adobe Systems, Inc.\n" 538 "\n" 539 "Usage: %s [options] file1 file2 ...\n" 540 "\n" 541 "Valid options:\n" 542 "-v Verbose mode\n" 543 "-d <num> Dump line limit (implies -v)\n" 544 "-b4 Use four-color Bayer interpolation\n" 545 "-s <num> Use this sample of multi-sample CFAs\n" 546 "-size <num> Preferred preview image size\n" 547 "-min <num> Minimum preview image size\n" 548 "-max <num> Maximum preview image size\n" 549 "-proxy <num> Target size for proxy DNG\n" 550 "-cs1 Color space: \"sRGB\" (default)\n" 551 "-cs2 Color space: \"Adobe RGB\"\n" 552 "-cs3 Color space: \"ProPhoto RGB\"\n" 553 "-cs4 Color space: \"ColorMatch RGB\"\n" 554 "-cs5 Color space: \"Gray Gamma 1.8\"\n" 555 "-cs6 Color space: \"Gray Gamma 2.2\"\n" 556 "-16 16-bits/channel output\n" 557 "-1 <file> Write stage 1 image to \"<file>.tif\"\n" 558 "-2 <file> Write stage 2 image to \"<file>.tif\"\n" 559 "-3 <file> Write stage 3 image to \"<file>.tif\"\n" 560 "-tif <file> Write TIF image to \"<file>.tif\"\n" 561 "-dng <file> Write DNG image to \"<file>.dng\"\n" 562 "\n", 563 argv [0]); 564 565 return 1; 566 567 } 568 569 int index; 570 571 for (index = 1; index < argc && argv [index] [0] == '-'; index++) 572 { 573 574 dng_string option; 575 576 option.Set (&argv [index] [1]); 577 578 if (option.Matches ("v", true)) 579 { 580 gVerbose = true; 581 } 582 583 else if (option.Matches ("d", true)) 584 { 585 586 gVerbose = true; 587 588 gDumpLineLimit = 0; 589 590 if (index + 1 < argc) 591 { 592 gDumpLineLimit = atoi (argv [++index]); 593 } 594 595 if (!gDumpLineLimit) 596 { 597 fprintf (stderr, "*** Invalid number after -d\n"); 598 return 1; 599 } 600 601 } 602 603 else if (option.Matches ("s", true)) 604 { 605 606 if (index + 1 < argc) 607 { 608 gMosaicPlane = atoi (argv [++index]); 609 } 610 611 else 612 { 613 fprintf (stderr, "*** Missing number after -s\n"); 614 return 1; 615 } 616 617 } 618 619 else if (option.Matches ("b4", true)) 620 { 621 gFourColorBayer = true; 622 } 623 624 else if (option.Matches ("size", true)) 625 { 626 627 if (index + 1 < argc) 628 { 629 gPreferredSize = (uint32) atoi (argv [++index]); 630 } 631 632 else 633 { 634 fprintf (stderr, "*** Missing number after -size\n"); 635 return 1; 636 } 637 638 } 639 640 else if (option.Matches ("min", true)) 641 { 642 643 if (index + 1 < argc) 644 { 645 gMinimumSize = (uint32) atoi (argv [++index]); 646 } 647 648 else 649 { 650 fprintf (stderr, "*** Missing number after -min\n"); 651 return 1; 652 } 653 654 } 655 656 else if (option.Matches ("max", true)) 657 { 658 659 if (index + 1 < argc) 660 { 661 gMaximumSize = (uint32) atoi (argv [++index]); 662 } 663 664 else 665 { 666 fprintf (stderr, "*** Missing number after -max\n"); 667 return 1; 668 } 669 670 } 671 672 else if (option.Matches ("proxy", true)) 673 { 674 675 if (index + 1 < argc) 676 { 677 gProxyDNGSize = (uint32) atoi (argv [++index]); 678 } 679 680 else 681 { 682 fprintf (stderr, "*** Missing number after -proxy\n"); 683 return 1; 684 } 685 686 } 687 688 else if (option.Matches ("cs1", true)) 689 { 690 691 gFinalSpace = &dng_space_sRGB::Get (); 692 693 } 694 695 else if (option.Matches ("cs2", true)) 696 { 697 698 gFinalSpace = &dng_space_AdobeRGB::Get (); 699 700 } 701 702 else if (option.Matches ("cs3", true)) 703 { 704 705 gFinalSpace = &dng_space_ProPhoto::Get (); 706 707 } 708 709 else if (option.Matches ("cs4", true)) 710 { 711 712 gFinalSpace = &dng_space_ColorMatch::Get (); 713 714 } 715 716 else if (option.Matches ("cs5", true)) 717 { 718 719 gFinalSpace = &dng_space_GrayGamma18::Get (); 720 721 } 722 723 else if (option.Matches ("cs6", true)) 724 { 725 726 gFinalSpace = &dng_space_GrayGamma22::Get (); 727 728 } 729 730 else if (option.Matches ("16")) 731 { 732 733 gFinalPixelType = ttShort; 734 735 } 736 737 else if (option.Matches ("1")) 738 { 739 740 gDumpStage1.Clear (); 741 742 if (index + 1 < argc) 743 { 744 gDumpStage1.Set (argv [++index]); 745 } 746 747 if (gDumpStage1.IsEmpty () || gDumpStage1.StartsWith ("-")) 748 { 749 fprintf (stderr, "*** Missing file name after -1\n"); 750 return 1; 751 } 752 753 if (!gDumpStage1.EndsWith (".tif")) 754 { 755 gDumpStage1.Append (".tif"); 756 } 757 758 } 759 760 else if (option.Matches ("2")) 761 { 762 763 gDumpStage2.Clear (); 764 765 if (index + 1 < argc) 766 { 767 gDumpStage2.Set (argv [++index]); 768 } 769 770 if (gDumpStage2.IsEmpty () || gDumpStage2.StartsWith ("-")) 771 { 772 fprintf (stderr, "*** Missing file name after -2\n"); 773 return 1; 774 } 775 776 if (!gDumpStage2.EndsWith (".tif")) 777 { 778 gDumpStage2.Append (".tif"); 779 } 780 781 } 782 783 else if (option.Matches ("3")) 784 { 785 786 gDumpStage3.Clear (); 787 788 if (index + 1 < argc) 789 { 790 gDumpStage3.Set (argv [++index]); 791 } 792 793 if (gDumpStage3.IsEmpty () || gDumpStage3.StartsWith ("-")) 794 { 795 fprintf (stderr, "*** Missing file name after -3\n"); 796 return 1; 797 } 798 799 if (!gDumpStage3.EndsWith (".tif")) 800 { 801 gDumpStage3.Append (".tif"); 802 } 803 804 } 805 806 else if (option.Matches ("tif", true)) 807 { 808 809 gDumpTIF.Clear (); 810 811 if (index + 1 < argc) 812 { 813 gDumpTIF.Set (argv [++index]); 814 } 815 816 if (gDumpTIF.IsEmpty () || gDumpTIF.StartsWith ("-")) 817 { 818 fprintf (stderr, "*** Missing file name after -tif\n"); 819 return 1; 820 } 821 822 if (!gDumpTIF.EndsWith (".tif")) 823 { 824 gDumpTIF.Append (".tif"); 825 } 826 827 } 828 829 else if (option.Matches ("dng", true)) 830 { 831 832 gDumpDNG.Clear (); 833 834 if (index + 1 < argc) 835 { 836 gDumpDNG.Set (argv [++index]); 837 } 838 839 if (gDumpDNG.IsEmpty () || gDumpDNG.StartsWith ("-")) 840 { 841 fprintf (stderr, "*** Missing file name after -dng\n"); 842 return 1; 843 } 844 845 if (!gDumpDNG.EndsWith (".dng")) 846 { 847 gDumpDNG.Append (".dng"); 848 } 849 850 } 851 852 else 853 { 854 fprintf (stderr, "*** Unknown option \"-%s\"\n", option.Get ()); 855 return 1; 856 } 857 858 } 859 860 if (index == argc) 861 { 862 fprintf (stderr, "*** No file specified\n"); 863 return 1; 864 } 865 866 #if qDNGUseXMP 867 868 dng_xmp_sdk::InitializeSDK (); 869 870 #endif 871 872 int result = 0; 873 874 while (index < argc) 875 { 876 877 dng_error_code error_code = dng_validate (argv [index++]); 878 if (error_code != dng_error_none) 879 { 880 881 result = error_code - dng_error_unknown + 100; 882 883 } 884 885 } 886 887 #if qDNGUseXMP 888 889 dng_xmp_sdk::TerminateSDK (); 890 891 #endif 892 893 return result; 894 895 } 896 897 catch (...) 898 { 899 900 } 901 902 fprintf (stderr, "*** Exception thrown in main routine\n"); 903 904 return 1; 905 906 } 907 908 /*****************************************************************************/ 909 910 #endif 911 912 /*****************************************************************************/ 913