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 
dng_validate(const char * filename)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 
main(int argc,char * argv[])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