C++程序  |  913行  |  17.88 KB

/*****************************************************************************/
// Copyright 2006-2012 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_validate.cpp#2 $ */ 
/* $DateTime: 2012/06/14 20:24:41 $ */
/* $Change: 835078 $ */
/* $Author: tknoll $ */

// Process exit codes
// ------------------
//
// As usual, 0 indicates success.
//
// If an exception occurs, the exit code will be equal to:
//
//    DNG SDK error code - 100000 + 100
//
// For example, the error dng_error_memory, which has a DNG SDK error code of
// 100005, is returned as an exit code of 105.
//
// This convention accounts for the fact that the shell truncates process exit
// codes to 8 bits and that the exit code 1 is used by ASAN to signal that a
// memory error occurred (so mapping the first DNG SDK error code to an exit
// code of 1 would not be a good idea).

/*****************************************************************************/

#include "dng_color_space.h"
#include "dng_date_time.h"
#include "dng_exceptions.h"
#include "dng_file_stream.h"
#include "dng_globals.h"
#include "dng_host.h"
#include "dng_ifd.h"
#include "dng_image_writer.h"
#include "dng_info.h"
#include "dng_linearization_info.h"
#include "dng_mosaic_info.h"
#include "dng_negative.h"
#include "dng_preview.h"
#include "dng_render.h"
#include "dng_simple_image.h"
#include "dng_tag_codes.h"
#include "dng_tag_types.h"
#include "dng_tag_values.h"

#if qDNGUseXMP
#include "dng_xmp.h"
#include "dng_xmp_sdk.h"
#endif

/*****************************************************************************/

#if qDNGValidateTarget
		
/*****************************************************************************/

#define kDNGValidateVersion "1.4"
		
/*****************************************************************************/

static bool gFourColorBayer = false;
		
static int32 gMosaicPlane = -1;

static uint32 gPreferredSize = 0;
static uint32 gMinimumSize   = 0;
static uint32 gMaximumSize   = 0;

static uint32 gProxyDNGSize = 0;

static const dng_color_space *gFinalSpace = &dng_space_sRGB::Get ();

static uint32 gFinalPixelType = ttByte;

static dng_string gDumpStage1;
static dng_string gDumpStage2;
static dng_string gDumpStage3;
static dng_string gDumpTIF;
static dng_string gDumpDNG;

/*****************************************************************************/

static dng_error_code dng_validate (const char *filename)
	{
	
	printf ("Validating \"%s\"...\n", filename);
	
	try
		{
	
		dng_file_stream stream (filename);
		
		dng_host host;
		
		host.SetPreferredSize (gPreferredSize);
		host.SetMinimumSize   (gMinimumSize  );
		host.SetMaximumSize   (gMaximumSize  );
		
		host.ValidateSizes ();
		
		if (host.MinimumSize ())
			{
			
			host.SetForPreview (true);
			
			gDumpDNG.Clear ();
			
			}
			
		if (gDumpDNG.NotEmpty ())
			{
			
			host.SetSaveDNGVersion (dngVersion_SaveDefault);
			
			host.SetSaveLinearDNG (false);
			
			host.SetKeepOriginalFile (false);
			
			}
			
		// Read into the negative.
		
		AutoPtr<dng_negative> negative;
		
			{
			
			dng_info info;
			
			info.Parse (host, stream);
			
			info.PostParse (host);
			
			if (!info.IsValidDNG ())
				{
				return dng_error_bad_format;
				}
				
			negative.Reset (host.Make_dng_negative ());
			
			negative->Parse (host, stream, info);
			
			negative->PostParse (host, stream, info);
			
				{
				
				dng_timer timer ("Raw image read time");

				negative->ReadStage1Image (host, stream, info);
				
				}
				
			if (info.fMaskIndex != -1)
				{
				
				dng_timer timer ("Transparency mask read time");

				negative->ReadTransparencyMask (host, stream, info);
				
				}
				
			negative->ValidateRawImageDigest (host);
				
			}
					 
		// Option to write stage 1 image.
			
		if (gDumpStage1.NotEmpty ())
			{
			
			dng_file_stream stream2 (gDumpStage1.Get (), true);
			
			const dng_image &stage1 = *negative->Stage1Image ();
			
			dng_image_writer writer;
			
			writer.WriteTIFF (host,
							  stream2,
							  stage1,
							  stage1.Planes () >= 3 ? piRGB 
												    : piBlackIsZero);

			gDumpStage1.Clear ();
			
			}
			
		// Metadata.
			
		negative->SynchronizeMetadata ();
		
		// Four color Bayer option.
		
		if (gFourColorBayer)
			{
			negative->SetFourColorBayer ();
			}
			
		// Build stage 2 image.
		
			{
			
			dng_timer timer ("Linearization time");
			
			negative->BuildStage2Image (host);
						         
			}
					 
		if (gDumpStage2.NotEmpty ())
			{
			
			dng_file_stream stream2 (gDumpStage2.Get (), true);
			
			const dng_image &stage2 = *negative->Stage2Image ();
						
			dng_image_writer writer;
			
			writer.WriteTIFF (host,
							  stream2,
							  stage2,
							  stage2.Planes () >= 3 ? piRGB 
												    : piBlackIsZero);
			
			gDumpStage2.Clear ();
			
			}
			
		// Build stage 3 image.
			
			{
			
			dng_timer timer ("Interpolate time");
		
			negative->BuildStage3Image (host,
									    gMosaicPlane);
							
			}
			
		// Convert to proxy, if requested.
		
		if (gProxyDNGSize)
			{
			
			dng_timer timer ("ConvertToProxy time");
			
			dng_image_writer writer;
			
			negative->ConvertToProxy (host,
									  writer,
									  gProxyDNGSize);
		
			}
			
		// Flatten transparency, if required.
		
		if (negative->NeedFlattenTransparency (host))
			{
			
			dng_timer timer ("FlattenTransparency time");
		
			negative->FlattenTransparency (host);
			
			}
			
		if (gDumpStage3.NotEmpty ())
			{
			
			dng_file_stream stream2 (gDumpStage3.Get (), true);
			
			const dng_image &stage3 = *negative->Stage3Image ();
			
			dng_image_writer writer;
			
			writer.WriteTIFF (host,
							  stream2,
							  stage3,
							  stage3.Planes () >= 3 ? piRGB 
												    : piBlackIsZero);
			
			gDumpStage3.Clear ();
			
			}
			
		// Output DNG file if requested.
			
		if (gDumpDNG.NotEmpty ())
			{
			
			// Build the preview list.
			
			dng_preview_list previewList;
			
			dng_date_time_info dateTimeInfo;
			
			CurrentDateTimeAndZone (dateTimeInfo);
											  
			for (uint32 previewIndex = 0; previewIndex < 2; previewIndex++)
				{
				
				// Skip preview if writing a compresssed main image to save space
				// in this example code.
				
				if (negative->RawJPEGImage () != NULL && previewIndex > 0)
					{
					break;
					}
					
				// Report timing.
			
				dng_timer timer (previewIndex == 0 ? "Build thumbnail time"
												   : "Build preview time");
				
				// Render a preview sized image.
				
				AutoPtr<dng_image> previewImage;
				
					{
					
					dng_render render (host, *negative);
					
					render.SetFinalSpace (negative->IsMonochrome () ? dng_space_GrayGamma22::Get ()
																	: dng_space_sRGB       ::Get ());
					
					render.SetFinalPixelType (ttByte);
					
					render.SetMaximumSize (previewIndex == 0 ? 256 : 1024);
				
					previewImage.Reset (render.Render ());
				
					}
					
				// Don't write the preview if it is same size as thumbnail.
				
				if (previewIndex > 0 &&
					Max_uint32 (previewImage->Bounds ().W (),
								previewImage->Bounds ().H ()) <= 256)
					{
					break;
					}
				
				// If we have compressed JPEG data, create a compressed thumbnail.  Otherwise
				// save a uncompressed thumbnail.
				
				bool useCompressedPreview = (negative->RawJPEGImage () != NULL) ||
											(previewIndex > 0);
				
				AutoPtr<dng_preview> preview (useCompressedPreview ?
											  (dng_preview *) new dng_jpeg_preview :
											  (dng_preview *) new dng_image_preview);
											  
				// Setup up preview info.
									
				preview->fInfo.fApplicationName   .Set ("dng_validate");
				preview->fInfo.fApplicationVersion.Set (kDNGValidateVersion);
				
				preview->fInfo.fSettingsName.Set ("Default");

				preview->fInfo.fColorSpace = previewImage->Planes () == 1 ?
											 previewColorSpace_GrayGamma22 :
											 previewColorSpace_sRGB;
											
				preview->fInfo.fDateTime = dateTimeInfo.Encode_ISO_8601 ();
				
				if (!useCompressedPreview)
					{
					
					dng_image_preview *imagePreview = dynamic_cast<dng_image_preview *> (preview.Get ());
				
					imagePreview->fImage.Reset (previewImage.Release ());
					
					}
					
				else
					{

					dng_jpeg_preview *jpegPreview = dynamic_cast<dng_jpeg_preview *> (preview.Get ());
					
					int32 quality = (previewIndex == 0 ? 8 : 5);

					dng_image_writer writer;
					
					writer.EncodeJPEGPreview (host,
										      *previewImage,
										      *jpegPreview,
											  quality);
										  
					}
		
				previewList.Append (preview);
				
				}
				
			// Write DNG file.
			
			dng_file_stream stream2 (gDumpDNG.Get (), true);
			
				{
				
				dng_timer timer ("Write DNG time");
			
				dng_image_writer writer;
			
				writer.WriteDNG (host,
								 stream2,
								 *negative.Get (),
								 &previewList,
								 dngVersion_Current,
								 false);

				}
				
			gDumpDNG.Clear ();
			
			}
					
		// Output TIF file if requested.
			
		if (gDumpTIF.NotEmpty ())
			{
			
			// Render final image.
				
			dng_render render (host, *negative);
			
			render.SetFinalSpace     (*gFinalSpace   );
			render.SetFinalPixelType (gFinalPixelType);
			
			if (host.MinimumSize ())
				{
				
				dng_point stage3Size = negative->Stage3Image ()->Size ();
				
				render.SetMaximumSize (Max_uint32 (stage3Size.v,
												   stage3Size.h));

				}
			
			AutoPtr<dng_image> finalImage;
			
				{
				
				dng_timer timer ("Render time");
			
				finalImage.Reset (render.Render ());
				
				}
				
			finalImage->Rotate (negative->Orientation ());
			
			// Now that Camera Raw supports non-raw formats, we should
			// not keep any Camera Raw settings in the XMP around when
			// writing rendered files.
			
			#if qDNGUseXMP
			
			if (negative->GetXMP ())
				{

				negative->GetXMP ()->RemoveProperties (XMP_NS_CRS);
				negative->GetXMP ()->RemoveProperties (XMP_NS_CRSS);
				
				}
			
			#endif
			
			// Write TIF file.
			
			dng_file_stream stream2 (gDumpTIF.Get (), true);
			
				{
				
				dng_timer timer ("Write TIFF time");
			
				dng_image_writer writer;
			
				writer.WriteTIFF (host,
								  stream2,
								  *finalImage.Get (),
								  finalImage->Planes () >= 3 ? piRGB 
															 : piBlackIsZero,
								  ccUncompressed,
								  negative.Get (),
								  &render.FinalSpace ());
								  
				}
				
			gDumpTIF.Clear ();
			
			}
					
		}
	
	catch (const dng_exception &except)
		{
		
		return except.ErrorCode ();
		
		}
		
	catch (...)
		{
		
		return dng_error_unknown;
		
		}
		
	printf ("Validation complete\n");
	
	return dng_error_none;

	}

/*****************************************************************************/

int main (int argc, char *argv [])
	{
	
	try
		{

		if (argc == 1)
			{

			fprintf (stderr,
					 "\n"
					 "dng_validate, version " kDNGValidateVersion " "
					 #if qDNG64Bit
					 "(64-bit)"
					 #else
					 "(32-bit)"
					 #endif
					 "\n"
					 "Copyright 2005-2012 Adobe Systems, Inc.\n"
					 "\n"
					 "Usage:  %s [options] file1 file2 ...\n"
					 "\n"
					 "Valid options:\n"
					 "-v            Verbose mode\n"
					 "-d <num>      Dump line limit (implies -v)\n"
					 "-b4           Use four-color Bayer interpolation\n"
					 "-s <num>      Use this sample of multi-sample CFAs\n"
					 "-size <num>   Preferred preview image size\n"
					 "-min <num>    Minimum preview image size\n"
					 "-max <num>    Maximum preview image size\n" 
					 "-proxy <num>  Target size for proxy DNG\n"
					 "-cs1          Color space: \"sRGB\" (default)\n"
					 "-cs2          Color space: \"Adobe RGB\"\n"
					 "-cs3          Color space: \"ProPhoto RGB\"\n"
					 "-cs4          Color space: \"ColorMatch RGB\"\n"
					 "-cs5          Color space: \"Gray Gamma 1.8\"\n"
					 "-cs6          Color space: \"Gray Gamma 2.2\"\n"
					 "-16           16-bits/channel output\n"
					 "-1 <file>     Write stage 1 image to \"<file>.tif\"\n"
					 "-2 <file>     Write stage 2 image to \"<file>.tif\"\n"
					 "-3 <file>     Write stage 3 image to \"<file>.tif\"\n"
					 "-tif <file>   Write TIF image to \"<file>.tif\"\n"
					 "-dng <file>   Write DNG image to \"<file>.dng\"\n"
					 "\n",
					 argv [0]);
					 
			return 1;
			
			}
			
		int index;
		
		for (index = 1; index < argc && argv [index] [0] == '-'; index++)
			{
			
			dng_string option;
			
			option.Set (&argv [index] [1]);
			
			if (option.Matches ("v", true))
				{
				gVerbose = true;
				}
				
			else if (option.Matches ("d", true))
				{
					
				gVerbose = true;
				
				gDumpLineLimit = 0;
				
				if (index + 1 < argc)
					{
					gDumpLineLimit = atoi (argv [++index]);
					}
					
				if (!gDumpLineLimit)
					{
					fprintf (stderr, "*** Invalid number after -d\n");
					return 1;
					}
					
				}
				
			else if (option.Matches ("s", true))
				{
				
				if (index + 1 < argc)
					{
					gMosaicPlane = atoi (argv [++index]);
					}
					
				else
					{
					fprintf (stderr, "*** Missing number after -s\n");
					return 1;
					}
					
				}
					
			else if (option.Matches ("b4", true))
				{
				gFourColorBayer = true;
				}
					
			else if (option.Matches ("size", true))
				{
				
				if (index + 1 < argc)
					{
					gPreferredSize = (uint32) atoi (argv [++index]);
					}
					
				else
					{
					fprintf (stderr, "*** Missing number after -size\n");
					return 1;
					}
					
				}
					
			else if (option.Matches ("min", true))
				{
				
				if (index + 1 < argc)
					{
					gMinimumSize = (uint32) atoi (argv [++index]);
					}
					
				else
					{
					fprintf (stderr, "*** Missing number after -min\n");
					return 1;
					}
					
				}
					
			else if (option.Matches ("max", true))
				{
				
				if (index + 1 < argc)
					{
					gMaximumSize = (uint32) atoi (argv [++index]);
					}
					
				else
					{
					fprintf (stderr, "*** Missing number after -max\n");
					return 1;
					}
					
				}
					
			else if (option.Matches ("proxy", true))
				{
				
				if (index + 1 < argc)
					{
					gProxyDNGSize = (uint32) atoi (argv [++index]);
					}
					
				else
					{
					fprintf (stderr, "*** Missing number after -proxy\n");
					return 1;
					}

				}
					
			else if (option.Matches ("cs1", true))
				{
				
				gFinalSpace = &dng_space_sRGB::Get ();
				
				}
					
			else if (option.Matches ("cs2", true))
				{
				
				gFinalSpace = &dng_space_AdobeRGB::Get ();
				
				}
					
			else if (option.Matches ("cs3", true))
				{
				
				gFinalSpace = &dng_space_ProPhoto::Get ();
				
				}
					
			else if (option.Matches ("cs4", true))
				{
				
				gFinalSpace = &dng_space_ColorMatch::Get ();
				
				}
					
			else if (option.Matches ("cs5", true))
				{
				
				gFinalSpace = &dng_space_GrayGamma18::Get ();
				
				}
					
			else if (option.Matches ("cs6", true))
				{
				
				gFinalSpace = &dng_space_GrayGamma22::Get ();
				
				}
					
			else if (option.Matches ("16"))
				{
				
				gFinalPixelType = ttShort;
				
				}
					
			else if (option.Matches ("1"))
				{
				
				gDumpStage1.Clear ();
				
				if (index + 1 < argc)
					{
					gDumpStage1.Set (argv [++index]);
					}
					
				if (gDumpStage1.IsEmpty () || gDumpStage1.StartsWith ("-"))
					{
					fprintf (stderr, "*** Missing file name after -1\n");
					return 1;
					}
				
				if (!gDumpStage1.EndsWith (".tif"))
					{
					gDumpStage1.Append (".tif");
					}
				
				}
					
			else if (option.Matches ("2"))
				{
				
				gDumpStage2.Clear ();
				
				if (index + 1 < argc)
					{
					gDumpStage2.Set (argv [++index]);
					}
					
				if (gDumpStage2.IsEmpty () || gDumpStage2.StartsWith ("-"))
					{
					fprintf (stderr, "*** Missing file name after -2\n");
					return 1;
					}
				
				if (!gDumpStage2.EndsWith (".tif"))
					{
					gDumpStage2.Append (".tif");
					}
				
				}
					
			else if (option.Matches ("3"))
				{
				
				gDumpStage3.Clear ();
				
				if (index + 1 < argc)
					{
					gDumpStage3.Set (argv [++index]);
					}
					
				if (gDumpStage3.IsEmpty () || gDumpStage3.StartsWith ("-"))
					{
					fprintf (stderr, "*** Missing file name after -3\n");
					return 1;
					}
				
				if (!gDumpStage3.EndsWith (".tif"))
					{
					gDumpStage3.Append (".tif");
					}
				
				}
				
			else if (option.Matches ("tif", true))
				{
				
				gDumpTIF.Clear ();
				
				if (index + 1 < argc)
					{
					gDumpTIF.Set (argv [++index]);
					}
					
				if (gDumpTIF.IsEmpty () || gDumpTIF.StartsWith ("-"))
					{
					fprintf (stderr, "*** Missing file name after -tif\n");
					return 1;
					}
				
				if (!gDumpTIF.EndsWith (".tif"))
					{
					gDumpTIF.Append (".tif");
					}
				
				}
				
			else if (option.Matches ("dng", true))
				{
				
				gDumpDNG.Clear ();
				
				if (index + 1 < argc)
					{
					gDumpDNG.Set (argv [++index]);
					}
					
				if (gDumpDNG.IsEmpty () || gDumpDNG.StartsWith ("-"))
					{
					fprintf (stderr, "*** Missing file name after -dng\n");
					return 1;
					}
				
				if (!gDumpDNG.EndsWith (".dng"))
					{
					gDumpDNG.Append (".dng");
					}
				
				}
				
			else
				{
				fprintf (stderr, "*** Unknown option \"-%s\"\n", option.Get ());
				return 1;
				}
				
			}
					
		if (index == argc)
			{
			fprintf (stderr, "*** No file specified\n");
			return 1;
			}
		
		#if qDNGUseXMP
			
		dng_xmp_sdk::InitializeSDK ();
		
		#endif
			
		int result = 0;
		
		while (index < argc)
			{
			
			dng_error_code error_code = dng_validate (argv [index++]);
			if (error_code != dng_error_none)
				{
				
				result = error_code - dng_error_unknown + 100;
				
				}
			
			}
		
		#if qDNGUseXMP
		
		dng_xmp_sdk::TerminateSDK ();
		
		#endif
			
		return result;
		
		}
		
	catch (...)
		{
		
		}
		
	fprintf (stderr, "*** Exception thrown in main routine\n");
	
	return 1;
	
	}
	
/*****************************************************************************/

#endif
	
/*****************************************************************************/