Home | History | Annotate | Download | only in source
      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_negative.cpp#3 $ */
     10 /* $DateTime: 2012/06/14 20:24:41 $ */
     11 /* $Change: 835078 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_negative.h"
     17 
     18 #include "dng_1d_table.h"
     19 #include "dng_abort_sniffer.h"
     20 #include "dng_area_task.h"
     21 #include "dng_assertions.h"
     22 #include "dng_bottlenecks.h"
     23 #include "dng_camera_profile.h"
     24 #include "dng_color_space.h"
     25 #include "dng_color_spec.h"
     26 #include "dng_exceptions.h"
     27 #include "dng_globals.h"
     28 #include "dng_host.h"
     29 #include "dng_image.h"
     30 #include "dng_image_writer.h"
     31 #include "dng_info.h"
     32 #include "dng_jpeg_image.h"
     33 #include "dng_linearization_info.h"
     34 #include "dng_memory.h"
     35 #include "dng_memory_stream.h"
     36 #include "dng_misc_opcodes.h"
     37 #include "dng_mosaic_info.h"
     38 #include "dng_preview.h"
     39 #include "dng_resample.h"
     40 #include "dng_safe_arithmetic.h"
     41 #include "dng_simple_image.h"
     42 #include "dng_tag_codes.h"
     43 #include "dng_tag_values.h"
     44 #include "dng_tile_iterator.h"
     45 #include "dng_utils.h"
     46 
     47 #if qDNGUseXMP
     48 #include "dng_xmp.h"
     49 #endif
     50 
     51 /*****************************************************************************/
     52 
     53 dng_noise_profile::dng_noise_profile ()
     54 
     55 	:	fNoiseFunctions ()
     56 
     57 	{
     58 
     59 	}
     60 
     61 /*****************************************************************************/
     62 
     63 dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions)
     64 
     65 	:	fNoiseFunctions (functions)
     66 
     67 	{
     68 
     69 	}
     70 
     71 /*****************************************************************************/
     72 
     73 bool dng_noise_profile::IsValid () const
     74 	{
     75 
     76 	if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes)
     77 		{
     78 		return false;
     79 		}
     80 
     81 	for (uint32 plane = 0; plane < NumFunctions (); plane++)
     82 		{
     83 
     84 		if (!NoiseFunction (plane).IsValid ())
     85 			{
     86 			return false;
     87 			}
     88 
     89 		}
     90 
     91 	return true;
     92 
     93 	}
     94 
     95 /*****************************************************************************/
     96 
     97 bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const
     98 	{
     99 
    100 	if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ()))
    101 		{
    102 		return false;
    103 		}
    104 
    105 	return IsValid ();
    106 
    107 	}
    108 
    109 /*****************************************************************************/
    110 
    111 const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const
    112 	{
    113 
    114 	if (NumFunctions () == 1)
    115 		{
    116 		return fNoiseFunctions.front ();
    117 		}
    118 
    119 	DNG_REQUIRE (plane < NumFunctions (),
    120 				 "Bad plane index argument for NoiseFunction ().");
    121 
    122 	return fNoiseFunctions [plane];
    123 
    124 	}
    125 
    126 /*****************************************************************************/
    127 
    128 uint32 dng_noise_profile::NumFunctions () const
    129 	{
    130 	return (uint32) fNoiseFunctions.size ();
    131 	}
    132 
    133 /*****************************************************************************/
    134 
    135 dng_metadata::dng_metadata (dng_host &host)
    136 
    137 	:	fHasBaseOrientation 		(false)
    138 	,	fBaseOrientation    		()
    139 	,	fIsMakerNoteSafe			(false)
    140 	,	fMakerNote					()
    141 	,	fExif			    		(host.Make_dng_exif ())
    142 	,	fOriginalExif				()
    143 	,	fIPTCBlock          		()
    144 	,	fIPTCOffset					(kDNGStreamInvalidOffset)
    145 
    146 	#if qDNGUseXMP
    147 
    148 	,	fXMP			    		(host.Make_dng_xmp ())
    149 
    150 	#endif
    151 
    152 	,	fEmbeddedXMPDigest       	()
    153 	,	fXMPinSidecar	    		(false)
    154 	,	fXMPisNewer		    		(false)
    155 	,	fSourceMIMI					()
    156 
    157 	{
    158 	}
    159 
    160 /*****************************************************************************/
    161 
    162 dng_metadata::~dng_metadata ()
    163 	{
    164 	}
    165 
    166 /******************************************************************************/
    167 
    168 template< class T >
    169 T * CloneAutoPtr (const AutoPtr< T > &ptr)
    170 	{
    171 
    172 	return ptr.Get () ? ptr->Clone () : NULL;
    173 
    174 	}
    175 
    176 /******************************************************************************/
    177 
    178 template< class T, typename U >
    179 T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u)
    180 	{
    181 
    182 	return ptr.Get () ? ptr->Clone (u) : NULL;
    183 
    184 	}
    185 
    186 /******************************************************************************/
    187 
    188 dng_metadata::dng_metadata (const dng_metadata &rhs,
    189 							dng_memory_allocator &allocator)
    190 
    191 	:	fHasBaseOrientation 		(rhs.fHasBaseOrientation)
    192 	,	fBaseOrientation    		(rhs.fBaseOrientation)
    193 	,	fIsMakerNoteSafe			(rhs.fIsMakerNoteSafe)
    194 	,	fMakerNote					(CloneAutoPtr (rhs.fMakerNote, allocator))
    195 	,	fExif			    		(CloneAutoPtr (rhs.fExif))
    196 	,	fOriginalExif				(CloneAutoPtr (rhs.fOriginalExif))
    197 	,	fIPTCBlock          		(CloneAutoPtr (rhs.fIPTCBlock, allocator))
    198 	,	fIPTCOffset					(rhs.fIPTCOffset)
    199 
    200 	#if qDNGUseXMP
    201 
    202 	,	fXMP			    		(CloneAutoPtr (rhs.fXMP))
    203 
    204 	#endif
    205 
    206 	,	fEmbeddedXMPDigest       	(rhs.fEmbeddedXMPDigest)
    207 	,	fXMPinSidecar	    		(rhs.fXMPinSidecar)
    208 	,	fXMPisNewer		    		(rhs.fXMPisNewer)
    209 	,	fSourceMIMI					(rhs.fSourceMIMI)
    210 
    211 	{
    212 
    213 	}
    214 
    215 /******************************************************************************/
    216 
    217 dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const
    218 	{
    219 
    220 	return new dng_metadata (*this, allocator);
    221 
    222 	}
    223 
    224 /******************************************************************************/
    225 
    226 void dng_metadata::SetBaseOrientation (const dng_orientation &orientation)
    227 	{
    228 
    229 	fHasBaseOrientation = true;
    230 
    231 	fBaseOrientation = orientation;
    232 
    233 	}
    234 
    235 /******************************************************************************/
    236 
    237 void dng_metadata::ApplyOrientation (const dng_orientation &orientation)
    238 	{
    239 
    240 	fBaseOrientation += orientation;
    241 
    242 	#if qDNGUseXMP
    243 
    244 	fXMP->SetOrientation (fBaseOrientation);
    245 
    246 	#endif
    247 
    248 	}
    249 
    250 /*****************************************************************************/
    251 
    252 void dng_metadata::ResetExif (dng_exif * newExif)
    253 	{
    254 
    255 	fExif.Reset (newExif);
    256 
    257 	}
    258 
    259 /******************************************************************************/
    260 
    261 dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator,
    262 												 const dng_resolution *resolution,
    263 												 bool includeIPTC,
    264 												 const dng_jpeg_preview *thumbnail) const
    265 	{
    266 
    267 	dng_memory_stream stream (allocator);
    268 
    269 		{
    270 
    271 		// Create the main IFD
    272 
    273 		dng_tiff_directory mainIFD;
    274 
    275 		// Optionally include the resolution tags.
    276 
    277 		dng_resolution res;
    278 
    279 		if (resolution)
    280 			{
    281 			res = *resolution;
    282 			}
    283 
    284 		tag_urational tagXResolution (tcXResolution, res.fXResolution);
    285 		tag_urational tagYResolution (tcYResolution, res.fYResolution);
    286 
    287 		tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
    288 
    289 		if (resolution)
    290 			{
    291 			mainIFD.Add (&tagXResolution   );
    292 			mainIFD.Add (&tagYResolution   );
    293 			mainIFD.Add (&tagResolutionUnit);
    294 			}
    295 
    296 		// Optionally include IPTC block.
    297 
    298 		tag_iptc tagIPTC (IPTCData   (),
    299 						  IPTCLength ());
    300 
    301 		if (includeIPTC && tagIPTC.Count ())
    302 			{
    303 			mainIFD.Add (&tagIPTC);
    304 			}
    305 
    306 		// Exif tags.
    307 
    308 		exif_tag_set exifSet (mainIFD,
    309 							  *GetExif (),
    310 							  IsMakerNoteSafe (),
    311 							  MakerNoteData   (),
    312 							  MakerNoteLength (),
    313 							  false);
    314 
    315 		// Figure out the Exif IFD offset.
    316 
    317 		uint32 exifOffset = 8 + mainIFD.Size ();
    318 
    319 		exifSet.Locate (exifOffset);
    320 
    321 		// Thumbnail IFD (if any).
    322 
    323 		dng_tiff_directory thumbIFD;
    324 
    325 		tag_uint16 thumbCompression (tcCompression, ccOldJPEG);
    326 
    327 		tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1));
    328 		tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1));
    329 
    330 		tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch);
    331 
    332 		tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat      , 0);
    333 		tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0);
    334 
    335 		if (thumbnail)
    336 			{
    337 
    338 			thumbIFD.Add (&thumbCompression);
    339 
    340 			thumbIFD.Add (&thumbXResolution);
    341 			thumbIFD.Add (&thumbYResolution);
    342 			thumbIFD.Add (&thumbResolutionUnit);
    343 
    344 			thumbIFD.Add (&thumbDataOffset);
    345 			thumbIFD.Add (&thumbDataLength);
    346 
    347 			thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ());
    348 
    349 			uint32 thumbOffset = exifOffset + exifSet.Size ();
    350 
    351 			mainIFD.SetChained (thumbOffset);
    352 
    353 			thumbDataOffset.Set (thumbOffset + thumbIFD.Size ());
    354 
    355 			}
    356 
    357 		// Don't write anything unless the main IFD has some tags.
    358 
    359 		if (mainIFD.Size () != 0)
    360 			{
    361 
    362 			// Write TIFF Header.
    363 
    364 			stream.SetWritePosition (0);
    365 
    366 			stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
    367 
    368 			stream.Put_uint16 (42);
    369 
    370 			stream.Put_uint32 (8);
    371 
    372 			// Write the IFDs.
    373 
    374 			mainIFD.Put (stream);
    375 
    376 			exifSet.Put (stream);
    377 
    378 			if (thumbnail)
    379 				{
    380 
    381 				thumbIFD.Put (stream);
    382 
    383 				stream.Put (thumbnail->fCompressedData->Buffer      (),
    384 							thumbnail->fCompressedData->LogicalSize ());
    385 
    386 				}
    387 
    388 			// Trim the file to this length.
    389 
    390 			stream.Flush ();
    391 
    392 			stream.SetLength (stream.Position ());
    393 
    394 			}
    395 
    396 		}
    397 
    398 	return stream.AsMemoryBlock (allocator);
    399 
    400 	}
    401 
    402 /******************************************************************************/
    403 
    404 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
    405 	{
    406 
    407 	fIPTCBlock.Reset (block.Release ());
    408 
    409 	fIPTCOffset = offset;
    410 
    411 	}
    412 
    413 /******************************************************************************/
    414 
    415 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block)
    416 	{
    417 
    418 	SetIPTC (block, kDNGStreamInvalidOffset);
    419 
    420 	}
    421 
    422 /******************************************************************************/
    423 
    424 void dng_metadata::ClearIPTC ()
    425 	{
    426 
    427 	fIPTCBlock.Reset ();
    428 
    429 	fIPTCOffset = kDNGStreamInvalidOffset;
    430 
    431 	}
    432 
    433 /*****************************************************************************/
    434 
    435 const void * dng_metadata::IPTCData () const
    436 	{
    437 
    438 	if (fIPTCBlock.Get ())
    439 		{
    440 
    441 		return fIPTCBlock->Buffer ();
    442 
    443 		}
    444 
    445 	return NULL;
    446 
    447 	}
    448 
    449 /*****************************************************************************/
    450 
    451 uint32 dng_metadata::IPTCLength () const
    452 	{
    453 
    454 	if (fIPTCBlock.Get ())
    455 		{
    456 
    457 		return fIPTCBlock->LogicalSize ();
    458 
    459 		}
    460 
    461 	return 0;
    462 
    463 	}
    464 
    465 /*****************************************************************************/
    466 
    467 uint64 dng_metadata::IPTCOffset () const
    468 	{
    469 
    470 	if (fIPTCBlock.Get ())
    471 		{
    472 
    473 		return fIPTCOffset;
    474 
    475 		}
    476 
    477 	return kDNGStreamInvalidOffset;
    478 
    479 	}
    480 
    481 /*****************************************************************************/
    482 
    483 dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const
    484 	{
    485 
    486 	if (IPTCLength ())
    487 		{
    488 
    489 		dng_md5_printer printer;
    490 
    491 		const uint8 *data = (const uint8 *) IPTCData ();
    492 
    493 		uint32 count = IPTCLength ();
    494 
    495 		// Because of some stupid ways of storing the IPTC data, the IPTC
    496 		// data might be padded with up to three zeros.  The official Adobe
    497 		// logic is to include these zeros in the digest.  However, older
    498 		// versions of the Camera Raw code did not include the padding zeros
    499 		// in the digest, so we support both methods and allow either to
    500 		// match.
    501 
    502 		if (!includePadding)
    503 			{
    504 
    505 			uint32 removed = 0;
    506 
    507 			while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
    508 				{
    509 				removed++;
    510 				count--;
    511 				}
    512 
    513 			}
    514 
    515 		printer.Process (data, count);
    516 
    517 		return printer.Result ();
    518 
    519 		}
    520 
    521 	return dng_fingerprint ();
    522 
    523 	}
    524 
    525 /******************************************************************************/
    526 
    527 #if qDNGUseXMP
    528 
    529 void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator,
    530 								bool padForTIFF)
    531 	{
    532 
    533 	ClearIPTC ();
    534 
    535 	fXMP->RebuildIPTC (*this, allocator, padForTIFF);
    536 
    537 	dng_fingerprint digest = IPTCDigest ();
    538 
    539 	fXMP->SetIPTCDigest (digest);
    540 
    541 	}
    542 
    543 /*****************************************************************************/
    544 
    545 void dng_metadata::ResetXMP (dng_xmp * newXMP)
    546 	{
    547 
    548 	fXMP.Reset (newXMP);
    549 
    550 	}
    551 
    552 /*****************************************************************************/
    553 
    554 void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP,
    555 										 bool inSidecar,
    556 										 bool isNewer )
    557 	{
    558 
    559 	fXMP.Reset (newXMP);
    560 
    561 	fXMPinSidecar = inSidecar;
    562 
    563 	fXMPisNewer = isNewer;
    564 
    565 	}
    566 
    567 /*****************************************************************************/
    568 
    569 bool dng_metadata::SetXMP (dng_host &host,
    570 						   const void *buffer,
    571 					 	   uint32 count,
    572 					 	   bool xmpInSidecar,
    573 					 	   bool xmpIsNewer)
    574 	{
    575 
    576 	bool result = false;
    577 
    578 	try
    579 		{
    580 
    581 		AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ());
    582 
    583 		tempXMP->Parse (host, buffer, count);
    584 
    585 		ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer);
    586 
    587 		result = true;
    588 
    589 		}
    590 
    591 	catch (dng_exception &except)
    592 		{
    593 
    594 		// Don't ignore transient errors.
    595 
    596 		if (host.IsTransientError (except.ErrorCode ()))
    597 			{
    598 
    599 			throw;
    600 
    601 			}
    602 
    603 		// Eat other parsing errors.
    604 
    605 		}
    606 
    607 	catch (...)
    608 		{
    609 
    610 		// Eat unknown parsing exceptions.
    611 
    612 		}
    613 
    614 	return result;
    615 
    616 	}
    617 
    618 /*****************************************************************************/
    619 
    620 void dng_metadata::SetEmbeddedXMP (dng_host &host,
    621 								   const void *buffer,
    622 								   uint32 count)
    623 	{
    624 
    625 	if (SetXMP (host, buffer, count))
    626 		{
    627 
    628 		dng_md5_printer printer;
    629 
    630 		printer.Process (buffer, count);
    631 
    632 		fEmbeddedXMPDigest = printer.Result ();
    633 
    634 		// Remove any sidecar specific tags from embedded XMP.
    635 
    636 		if (fXMP.Get ())
    637 			{
    638 
    639 			fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
    640 			fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
    641 
    642 			}
    643 
    644 		}
    645 
    646 	else
    647 		{
    648 
    649 		fEmbeddedXMPDigest.Clear ();
    650 
    651 		}
    652 
    653 	}
    654 
    655 #endif
    656 
    657 /*****************************************************************************/
    658 
    659 void dng_metadata::SynchronizeMetadata ()
    660 	{
    661 
    662 	if (!fOriginalExif.Get ())
    663 		{
    664 
    665 		fOriginalExif.Reset (fExif->Clone ());
    666 
    667 		}
    668 
    669 	#if qDNGUseXMP
    670 
    671 	fXMP->ValidateMetadata ();
    672 
    673 	fXMP->IngestIPTC (*this, fXMPisNewer);
    674 
    675 	fXMP->SyncExif (*fExif.Get ());
    676 
    677 	fXMP->SyncOrientation (*this, fXMPinSidecar);
    678 
    679 	#endif
    680 
    681 	}
    682 
    683 /*****************************************************************************/
    684 
    685 void dng_metadata::UpdateDateTime (const dng_date_time_info &dt)
    686 	{
    687 
    688 	fExif->UpdateDateTime (dt);
    689 
    690 #if qDNGUseXMP
    691 	fXMP->UpdateDateTime (dt);
    692 #endif
    693 
    694 	}
    695 
    696 /*****************************************************************************/
    697 
    698 void dng_metadata::UpdateDateTimeToNow ()
    699 	{
    700 
    701 	dng_date_time_info dt;
    702 
    703 	CurrentDateTimeAndZone (dt);
    704 
    705 	UpdateDateTime (dt);
    706 
    707 	#if qDNGUseXMP
    708 
    709 	fXMP->UpdateMetadataDate (dt);
    710 
    711 	#endif
    712 
    713 	}
    714 
    715 /*****************************************************************************/
    716 
    717 void dng_metadata::UpdateMetadataDateTimeToNow ()
    718 	{
    719 
    720 	dng_date_time_info dt;
    721 
    722 	CurrentDateTimeAndZone (dt);
    723 
    724 #if qDNGUseXMP
    725 	fXMP->UpdateMetadataDate (dt);
    726 #endif
    727 
    728 	}
    729 
    730 /*****************************************************************************/
    731 
    732 dng_negative::dng_negative (dng_host &host)
    733 
    734 	:	fAllocator						(host.Allocator ())
    735 
    736 	,	fModelName						()
    737 	,	fLocalName						()
    738 	,	fDefaultCropSizeH				()
    739 	,	fDefaultCropSizeV				()
    740 	,	fDefaultCropOriginH				(0, 1)
    741 	,	fDefaultCropOriginV				(0, 1)
    742 	,	fDefaultUserCropT				(0, 1)
    743 	,	fDefaultUserCropL				(0, 1)
    744 	,	fDefaultUserCropB				(1, 1)
    745 	,	fDefaultUserCropR				(1, 1)
    746 	,	fDefaultScaleH					(1, 1)
    747 	,	fDefaultScaleV					(1, 1)
    748 	,	fBestQualityScale				(1, 1)
    749 	,	fOriginalDefaultFinalSize		()
    750 	,	fOriginalBestQualityFinalSize	()
    751 	,	fOriginalDefaultCropSizeH	    ()
    752 	,	fOriginalDefaultCropSizeV	    ()
    753 	,	fRawToFullScaleH				(1.0)
    754 	,	fRawToFullScaleV				(1.0)
    755 	,	fBaselineNoise					(100, 100)
    756 	,	fNoiseReductionApplied			(0, 0)
    757 	,	fNoiseProfile					()
    758 	,	fBaselineExposure				(  0, 100)
    759 	,	fBaselineSharpness				(100, 100)
    760 	,	fChromaBlurRadius				()
    761 	,	fAntiAliasStrength				(100, 100)
    762 	,	fLinearResponseLimit			(100, 100)
    763 	,	fShadowScale					(1, 1)
    764 	,	fColorimetricReference			(crSceneReferred)
    765 	,	fColorChannels					(0)
    766 	,	fAnalogBalance					()
    767 	,	fCameraNeutral					()
    768 	,	fCameraWhiteXY					()
    769 	,	fCameraCalibration1				()
    770 	,	fCameraCalibration2				()
    771 	,	fCameraCalibrationSignature		()
    772 	,	fCameraProfile					()
    773 	,	fAsShotProfileName				()
    774 	,	fRawImageDigest					()
    775 	,	fNewRawImageDigest				()
    776 	,	fRawDataUniqueID				()
    777 	,	fOriginalRawFileName			()
    778 	,	fHasOriginalRawFileData			(false)
    779 	,	fOriginalRawFileData			()
    780 	,	fOriginalRawFileDigest			()
    781 	,	fDNGPrivateData					()
    782 	,	fMetadata						(host)
    783 	,	fLinearizationInfo				()
    784 	,	fMosaicInfo						()
    785 	,	fOpcodeList1					(1)
    786 	,	fOpcodeList2					(2)
    787 	,	fOpcodeList3					(3)
    788 	,	fStage1Image					()
    789 	,	fStage2Image					()
    790 	,	fStage3Image					()
    791 	,	fStage3Gain						(1.0)
    792 	,	fIsPreview						(false)
    793 	,	fIsDamaged						(false)
    794 	,	fRawImageStage					(rawImageStageNone)
    795 	,	fRawImage						()
    796 	,	fRawFloatBitDepth				(0)
    797 	,	fRawJPEGImage					()
    798 	,	fRawJPEGImageDigest				()
    799 	,	fTransparencyMask				()
    800 	,	fRawTransparencyMask			()
    801 	,	fRawTransparencyMaskBitDepth	(0)
    802 	,	fUnflattenedStage3Image			()
    803 
    804 	{
    805 
    806 	}
    807 
    808 /*****************************************************************************/
    809 
    810 dng_negative::~dng_negative ()
    811 	{
    812 
    813 	// Delete any camera profiles owned by this negative.
    814 
    815 	ClearProfiles ();
    816 
    817 	}
    818 
    819 /******************************************************************************/
    820 
    821 void dng_negative::Initialize ()
    822 	{
    823 
    824 	}
    825 
    826 /******************************************************************************/
    827 
    828 dng_negative * dng_negative::Make (dng_host &host)
    829 	{
    830 
    831 	AutoPtr<dng_negative> result (new dng_negative (host));
    832 
    833 	if (!result.Get ())
    834 		{
    835 		ThrowMemoryFull ();
    836 		}
    837 
    838 	result->Initialize ();
    839 
    840 	return result.Release ();
    841 
    842 	}
    843 
    844 /******************************************************************************/
    845 
    846 dng_metadata * dng_negative::CloneInternalMetadata () const
    847 	{
    848 
    849 	return InternalMetadata ().Clone (Allocator ());
    850 
    851 	}
    852 
    853 /******************************************************************************/
    854 
    855 dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const
    856 	{
    857 
    858 	return metadata.BaseOrientation ();
    859 
    860 	}
    861 
    862 /******************************************************************************/
    863 
    864 void dng_negative::SetAnalogBalance (const dng_vector &b)
    865 	{
    866 
    867 	real64 minEntry = b.MinEntry ();
    868 
    869 	if (b.NotEmpty () && minEntry > 0.0)
    870 		{
    871 
    872 		fAnalogBalance = b;
    873 
    874 		fAnalogBalance.Scale (1.0 / minEntry);
    875 
    876 		fAnalogBalance.Round (1000000.0);
    877 
    878 		}
    879 
    880 	else
    881 		{
    882 
    883 		fAnalogBalance.Clear ();
    884 
    885 		}
    886 
    887 	}
    888 
    889 /*****************************************************************************/
    890 
    891 real64 dng_negative::AnalogBalance (uint32 channel) const
    892 	{
    893 
    894 	DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
    895 
    896 	if (channel < fAnalogBalance.Count ())
    897 		{
    898 
    899 		return fAnalogBalance [channel];
    900 
    901 		}
    902 
    903 	return 1.0;
    904 
    905 	}
    906 
    907 /*****************************************************************************/
    908 
    909 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
    910 	{
    911 
    912 	dng_urational result;
    913 
    914 	result.Set_real64 (AnalogBalance (channel), 1000000);
    915 
    916 	return result;
    917 
    918 	}
    919 
    920 /******************************************************************************/
    921 
    922 void dng_negative::SetCameraNeutral (const dng_vector &n)
    923 	{
    924 
    925 	real64 maxEntry = n.MaxEntry ();
    926 
    927 	if (n.NotEmpty () && maxEntry > 0.0)
    928 		{
    929 
    930 		fCameraNeutral = n;
    931 
    932 		fCameraNeutral.Scale (1.0 / maxEntry);
    933 
    934 		fCameraNeutral.Round (1000000.0);
    935 
    936 		}
    937 
    938 	else
    939 		{
    940 
    941 		fCameraNeutral.Clear ();
    942 
    943 		}
    944 
    945 	}
    946 
    947 /*****************************************************************************/
    948 
    949 dng_urational dng_negative::CameraNeutralR (uint32 channel) const
    950 	{
    951 
    952 	dng_urational result;
    953 
    954 	result.Set_real64 (CameraNeutral () [channel], 1000000);
    955 
    956 	return result;
    957 
    958 	}
    959 
    960 /******************************************************************************/
    961 
    962 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
    963 	{
    964 
    965 	if (coord.IsValid ())
    966 		{
    967 
    968 		fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
    969 		fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
    970 
    971 		}
    972 
    973 	else
    974 		{
    975 
    976 		fCameraWhiteXY.Clear ();
    977 
    978 		}
    979 
    980 	}
    981 
    982 /*****************************************************************************/
    983 
    984 const dng_xy_coord & dng_negative::CameraWhiteXY () const
    985 	{
    986 
    987 	DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
    988 
    989 	return fCameraWhiteXY;
    990 
    991 	}
    992 
    993 /*****************************************************************************/
    994 
    995 void dng_negative::GetCameraWhiteXY (dng_urational &x,
    996 							   		 dng_urational &y) const
    997 	{
    998 
    999 	dng_xy_coord coord = CameraWhiteXY ();
   1000 
   1001 	x.Set_real64 (coord.x, 1000000);
   1002 	y.Set_real64 (coord.y, 1000000);
   1003 
   1004 	}
   1005 
   1006 /*****************************************************************************/
   1007 
   1008 void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
   1009 	{
   1010 
   1011 	fCameraCalibration1 = m;
   1012 
   1013 	fCameraCalibration1.Round (10000);
   1014 
   1015 	}
   1016 
   1017 /******************************************************************************/
   1018 
   1019 void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
   1020 	{
   1021 
   1022 	fCameraCalibration2 = m;
   1023 
   1024 	fCameraCalibration2.Round (10000);
   1025 
   1026 	}
   1027 
   1028 /******************************************************************************/
   1029 
   1030 void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
   1031 	{
   1032 
   1033 	// Make sure we have a profile to add.
   1034 
   1035 	if (!profile.Get ())
   1036 		{
   1037 
   1038 		return;
   1039 
   1040 		}
   1041 
   1042 	// We must have some profile name.  Use "embedded" if nothing else.
   1043 
   1044 	if (profile->Name ().IsEmpty ())
   1045 		{
   1046 
   1047 		profile->SetName (kProfileName_Embedded);
   1048 
   1049 		}
   1050 
   1051 	// Special case support for reading older DNG files which did not store
   1052 	// the profile name in the main IFD profile.
   1053 
   1054 	if (fCameraProfile.size ())
   1055 		{
   1056 
   1057 		// See the first profile has a default "embedded" name, and has
   1058 		// the same data as the profile we are adding.
   1059 
   1060 		if (fCameraProfile [0]->NameIsEmbedded () &&
   1061 			fCameraProfile [0]->EqualData (*profile.Get ()))
   1062 			{
   1063 
   1064 			// If the profile we are deleting was read from DNG
   1065 			// then the new profile should be marked as such also.
   1066 
   1067 			if (fCameraProfile [0]->WasReadFromDNG ())
   1068 				{
   1069 
   1070 				profile->SetWasReadFromDNG ();
   1071 
   1072 				}
   1073 
   1074 			// If the profile we are deleting wasn't read from disk then the new
   1075 			// profile should be marked as such also.
   1076 
   1077 			if (!fCameraProfile [0]->WasReadFromDisk ())
   1078 				{
   1079 
   1080 				profile->SetWasReadFromDisk (false);
   1081 
   1082 				}
   1083 
   1084 			// Delete the profile with default name.
   1085 
   1086 			delete fCameraProfile [0];
   1087 
   1088 			fCameraProfile [0] = NULL;
   1089 
   1090 			fCameraProfile.erase (fCameraProfile.begin ());
   1091 
   1092 			}
   1093 
   1094 		}
   1095 
   1096 	// Duplicate detection logic.  We give a preference to last added profile
   1097 	// so the profiles end up in a more consistent order no matter what profiles
   1098 	// happen to be embedded in the DNG.
   1099 
   1100 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
   1101 		{
   1102 
   1103 		// Instead of checking for matching fingerprints, we check that the two
   1104 		// profiles have the same color and have the same name. This allows two
   1105 		// profiles that are identical except for copyright string and embed policy
   1106 		// to be considered duplicates.
   1107 
   1108 		const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) &&
   1109 											fCameraProfile [index]->Name () == profile->Name ());
   1110 
   1111 		if (equalColorAndSameName)
   1112 			{
   1113 
   1114 			// If the profile we are deleting was read from DNG
   1115 			// then the new profile should be marked as such also.
   1116 
   1117 			if (fCameraProfile [index]->WasReadFromDNG ())
   1118 				{
   1119 
   1120 				profile->SetWasReadFromDNG ();
   1121 
   1122 				}
   1123 
   1124 			// If the profile we are deleting wasn't read from disk then the new
   1125 			// profile should be marked as such also.
   1126 
   1127 			if (!fCameraProfile [index]->WasReadFromDisk ())
   1128 				{
   1129 
   1130 				profile->SetWasReadFromDisk (false);
   1131 
   1132 				}
   1133 
   1134 			// Delete the duplicate profile.
   1135 
   1136 			delete fCameraProfile [index];
   1137 
   1138 			fCameraProfile [index] = NULL;
   1139 
   1140 			fCameraProfile.erase (fCameraProfile.begin () + index);
   1141 
   1142 			break;
   1143 
   1144 			}
   1145 
   1146 		}
   1147 
   1148 	// Now add to profile list.
   1149 
   1150 	fCameraProfile.push_back (NULL);
   1151 
   1152 	fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
   1153 
   1154 	}
   1155 
   1156 /******************************************************************************/
   1157 
   1158 void dng_negative::ClearProfiles ()
   1159 	{
   1160 
   1161 	// Delete any camera profiles owned by this negative.
   1162 
   1163 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
   1164 		{
   1165 
   1166 		if (fCameraProfile [index])
   1167 			{
   1168 
   1169 			delete fCameraProfile [index];
   1170 
   1171 			fCameraProfile [index] = NULL;
   1172 
   1173 			}
   1174 
   1175 		}
   1176 
   1177 	// Now empty list.
   1178 
   1179 	fCameraProfile.clear ();
   1180 
   1181 	}
   1182 
   1183 /*****************************************************************************/
   1184 
   1185 void dng_negative::ClearProfiles (bool clearBuiltinMatrixProfiles,
   1186 								  bool clearReadFromDisk)
   1187 	{
   1188 
   1189 	// If neither flag is set, then there's nothing to do.
   1190 
   1191 	if (!clearBuiltinMatrixProfiles &&
   1192 		!clearReadFromDisk)
   1193 		{
   1194 		return;
   1195 		}
   1196 
   1197 	// Delete any camera profiles in this negative that match the specified criteria.
   1198 
   1199 	dng_std_vector<dng_camera_profile *>::iterator iter = fCameraProfile.begin ();
   1200 	dng_std_vector<dng_camera_profile *>::iterator next;
   1201 
   1202 	for (; iter != fCameraProfile.end (); iter = next)
   1203 		{
   1204 
   1205 		dng_camera_profile *profile = *iter;
   1206 
   1207 		// If the profile is invalid (i.e., NULL pointer), or meets one of the
   1208 		// specified criteria, then axe it.
   1209 
   1210 		if (!profile ||
   1211 			(clearBuiltinMatrixProfiles && profile->WasBuiltinMatrix ()) ||
   1212 			(clearReadFromDisk			&& profile->WasReadFromDisk	 ()))
   1213 			{
   1214 
   1215 			delete profile;
   1216 
   1217 			next = fCameraProfile.erase (iter);
   1218 
   1219 			}
   1220 
   1221 		// Otherwise, just advance to the next element.
   1222 
   1223 		else
   1224 			{
   1225 
   1226 			next = iter + 1;
   1227 
   1228 			}
   1229 
   1230 		}
   1231 
   1232 	}
   1233 
   1234 /******************************************************************************/
   1235 
   1236 uint32 dng_negative::ProfileCount () const
   1237 	{
   1238 
   1239 	return (uint32) fCameraProfile.size ();
   1240 
   1241 	}
   1242 
   1243 /******************************************************************************/
   1244 
   1245 const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
   1246 	{
   1247 
   1248 	DNG_ASSERT (index < ProfileCount (),
   1249 				"Invalid index for ProfileByIndex");
   1250 
   1251 	return *fCameraProfile [index];
   1252 
   1253 	}
   1254 
   1255 /*****************************************************************************/
   1256 
   1257 const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
   1258 													  bool useDefaultIfNoMatch) const
   1259 	{
   1260 
   1261 	uint32 index;
   1262 
   1263 	// If this negative does not have any profiles, we are not going to
   1264 	// find a match.
   1265 
   1266 	uint32 profileCount = ProfileCount ();
   1267 
   1268 	if (profileCount == 0)
   1269 		{
   1270 		return NULL;
   1271 		}
   1272 
   1273 	// If we have both a profile name and fingerprint, try matching both.
   1274 
   1275 	if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
   1276 		{
   1277 
   1278 		for (index = 0; index < profileCount; index++)
   1279 			{
   1280 
   1281 			const dng_camera_profile &profile = ProfileByIndex (index);
   1282 
   1283 			if (id.Name        () == profile.Name        () &&
   1284 				id.Fingerprint () == profile.Fingerprint ())
   1285 				{
   1286 
   1287 				return &profile;
   1288 
   1289 				}
   1290 
   1291 			}
   1292 
   1293 		}
   1294 
   1295 	// If we have a name, try matching that.
   1296 
   1297 	if (id.Name ().NotEmpty ())
   1298 		{
   1299 
   1300 		for (index = 0; index < profileCount; index++)
   1301 			{
   1302 
   1303 			const dng_camera_profile &profile = ProfileByIndex (index);
   1304 
   1305 			if (id.Name () == profile.Name ())
   1306 				{
   1307 
   1308 				return &profile;
   1309 
   1310 				}
   1311 
   1312 			}
   1313 
   1314 		}
   1315 
   1316 	// If we have a valid fingerprint, try matching that.
   1317 
   1318 	if (id.Fingerprint ().IsValid ())
   1319 		{
   1320 
   1321 		for (index = 0; index < profileCount; index++)
   1322 			{
   1323 
   1324 			const dng_camera_profile &profile = ProfileByIndex (index);
   1325 
   1326 			if (id.Fingerprint () == profile.Fingerprint ())
   1327 				{
   1328 
   1329 				return &profile;
   1330 
   1331 				}
   1332 
   1333 			}
   1334 
   1335 		}
   1336 
   1337 	// Try "upgrading" profile name versions.
   1338 
   1339 	if (id.Name ().NotEmpty ())
   1340 		{
   1341 
   1342 		dng_string baseName;
   1343 		int32      version;
   1344 
   1345 		SplitCameraProfileName (id.Name (),
   1346 								baseName,
   1347 								version);
   1348 
   1349 		int32 bestIndex   = -1;
   1350 		int32 bestVersion = 0;
   1351 
   1352 		for (index = 0; index < profileCount; index++)
   1353 			{
   1354 
   1355 			const dng_camera_profile &profile = ProfileByIndex (index);
   1356 
   1357 			if (profile.Name ().StartsWith (baseName.Get ()))
   1358 				{
   1359 
   1360 				dng_string testBaseName;
   1361 				int32      testVersion;
   1362 
   1363 				SplitCameraProfileName (profile.Name (),
   1364 										testBaseName,
   1365 										testVersion);
   1366 
   1367 				if (bestIndex == -1 || testVersion > bestVersion)
   1368 					{
   1369 
   1370 					bestIndex   = index;
   1371 					bestVersion = testVersion;
   1372 
   1373 					}
   1374 
   1375 				}
   1376 
   1377 			}
   1378 
   1379 		if (bestIndex != -1)
   1380 			{
   1381 
   1382 			return &ProfileByIndex (bestIndex);
   1383 
   1384 			}
   1385 
   1386 		}
   1387 
   1388 	// Did not find a match any way.  See if we should return a default value.
   1389 
   1390 	if (useDefaultIfNoMatch)
   1391 		{
   1392 
   1393 		return &ProfileByIndex (0);
   1394 
   1395 		}
   1396 
   1397 	// Found nothing.
   1398 
   1399 	return NULL;
   1400 
   1401 	}
   1402 
   1403 /*****************************************************************************/
   1404 
   1405 const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed
   1406 										(const dng_metadata & /* metadata */) const
   1407 	{
   1408 
   1409 	uint32 index;
   1410 
   1411 	uint32 count = ProfileCount ();
   1412 
   1413 	if (count == 0)
   1414 		{
   1415 
   1416 		return NULL;
   1417 
   1418 		}
   1419 
   1420 	// First try to look for the first profile that was already in the DNG
   1421 	// when we read it.
   1422 
   1423 	for (index = 0; index < count; index++)
   1424 		{
   1425 
   1426 		const dng_camera_profile &profile (ProfileByIndex (index));
   1427 
   1428 		if (profile.WasReadFromDNG ())
   1429 			{
   1430 
   1431 			return &profile;
   1432 
   1433 			}
   1434 
   1435 		}
   1436 
   1437 	// Next we look for the first profile that is legal to embed.
   1438 
   1439 	for (index = 0; index < count; index++)
   1440 		{
   1441 
   1442 		const dng_camera_profile &profile (ProfileByIndex (index));
   1443 
   1444 		if (profile.IsLegalToEmbed ())
   1445 			{
   1446 
   1447 			return &profile;
   1448 
   1449 			}
   1450 
   1451 		}
   1452 
   1453 	// Else just return the first profile.
   1454 
   1455 	return fCameraProfile [0];
   1456 
   1457 	}
   1458 
   1459 /*****************************************************************************/
   1460 
   1461 dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
   1462 	{
   1463 
   1464 	dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
   1465 
   1466 	if (!spec)
   1467 		{
   1468 		ThrowMemoryFull ();
   1469 		}
   1470 
   1471 	return spec;
   1472 
   1473 	}
   1474 
   1475 /*****************************************************************************/
   1476 
   1477 dng_fingerprint dng_negative::FindImageDigest (dng_host &host,
   1478 											   const dng_image &image) const
   1479 	{
   1480 
   1481 	dng_md5_printer printer;
   1482 
   1483 	dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (),
   1484 		 image.PixelType (), pcInterleaved, NULL);
   1485 
   1486 	// Sometimes we expand 8-bit data to 16-bit data while reading or
   1487 	// writing, so always compute the digest of 8-bit data as 16-bits.
   1488 
   1489 	if (buffer.fPixelType == ttByte)
   1490 		{
   1491 		buffer.fPixelType = ttShort;
   1492 		buffer.fPixelSize = 2;
   1493 		}
   1494 
   1495 	const uint32 kBufferRows = 16;
   1496 
   1497 	uint32 bufferBytes = 0;
   1498 
   1499 	if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) ||
   1500 		 !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes))
   1501 		{
   1502 
   1503 		ThrowMemoryFull("Arithmetic overflow computing buffer size.");
   1504 
   1505 		}
   1506 
   1507 	AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
   1508 
   1509 	buffer.fData = bufferData->Buffer ();
   1510 
   1511 	dng_rect area;
   1512 
   1513 	dng_tile_iterator iter (dng_point (kBufferRows,
   1514 									   image.Width ()),
   1515 							image.Bounds ());
   1516 
   1517 	while (iter.GetOneTile (area))
   1518 		{
   1519 
   1520 		host.SniffForAbort ();
   1521 
   1522 		buffer.fArea = area;
   1523 
   1524 		image.Get (buffer);
   1525 
   1526 		uint32 count = buffer.fArea.H () *
   1527 					   buffer.fRowStep *
   1528 					   buffer.fPixelSize;
   1529 
   1530 		#if qDNGBigEndian
   1531 
   1532 		// We need to use the same byte order to compute
   1533 		// the digest, no matter the native order.  Little-endian
   1534 		// is more common now, so use that.
   1535 
   1536 		switch (buffer.fPixelSize)
   1537 			{
   1538 
   1539 			case 1:
   1540 				break;
   1541 
   1542 			case 2:
   1543 				{
   1544 				DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
   1545 				break;
   1546 				}
   1547 
   1548 			case 4:
   1549 				{
   1550 				DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
   1551 				break;
   1552 				}
   1553 
   1554 			default:
   1555 				{
   1556 				DNG_REPORT ("Unexpected pixel size");
   1557 				break;
   1558 				}
   1559 
   1560 			}
   1561 
   1562 		#endif
   1563 
   1564 		printer.Process (buffer.fData,
   1565 						 count);
   1566 
   1567 		}
   1568 
   1569 	return printer.Result ();
   1570 
   1571 	}
   1572 
   1573 /*****************************************************************************/
   1574 
   1575 void dng_negative::FindRawImageDigest (dng_host &host) const
   1576 	{
   1577 
   1578 	if (fRawImageDigest.IsNull ())
   1579 		{
   1580 
   1581 		// Since we are adding the floating point and transparency support
   1582 		// in DNG 1.4, and there are no legacy floating point or transparent
   1583 		// DNGs, switch to using the more MP friendly algorithm to compute
   1584 		// the digest for these images.
   1585 
   1586 		if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ())
   1587 			{
   1588 
   1589 			FindNewRawImageDigest (host);
   1590 
   1591 			fRawImageDigest = fNewRawImageDigest;
   1592 
   1593 			}
   1594 
   1595 		else
   1596 			{
   1597 
   1598 			#if qDNGValidate
   1599 
   1600 			dng_timer timeScope ("FindRawImageDigest time");
   1601 
   1602 			#endif
   1603 
   1604 			fRawImageDigest = FindImageDigest (host, RawImage ());
   1605 
   1606 			}
   1607 
   1608 		}
   1609 
   1610 	}
   1611 
   1612 /*****************************************************************************/
   1613 
   1614 class dng_find_new_raw_image_digest_task : public dng_area_task
   1615 	{
   1616 
   1617 	private:
   1618 
   1619 		enum
   1620 			{
   1621 			kTileSize = 256
   1622 			};
   1623 
   1624 		const dng_image &fImage;
   1625 
   1626 		uint32 fPixelType;
   1627 		uint32 fPixelSize;
   1628 
   1629 		uint32 fTilesAcross;
   1630 		uint32 fTilesDown;
   1631 
   1632 		uint32 fTileCount;
   1633 
   1634 		AutoArray<dng_fingerprint> fTileHash;
   1635 
   1636 		AutoPtr<dng_memory_block> fBufferData [kMaxMPThreads];
   1637 
   1638 	public:
   1639 
   1640 		dng_find_new_raw_image_digest_task (const dng_image &image,
   1641 											uint32 pixelType)
   1642 
   1643 			:	fImage       (image)
   1644 			,	fPixelType   (pixelType)
   1645 			,	fPixelSize	 (TagTypeSize (pixelType))
   1646 			,	fTilesAcross (0)
   1647 			,	fTilesDown   (0)
   1648 			,	fTileCount   (0)
   1649 			,	fTileHash    ()
   1650 
   1651 			{
   1652 
   1653 			fMinTaskArea = 1;
   1654 
   1655 			fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()),
   1656 								   Min_int32 (kTileSize, fImage.Bounds ().W ()));
   1657 
   1658 			fMaxTileSize = fUnitCell;
   1659 
   1660 			}
   1661 
   1662 		virtual void Start (uint32 threadCount,
   1663 							const dng_point &tileSize,
   1664 							dng_memory_allocator *allocator,
   1665 							dng_abort_sniffer * /* sniffer */)
   1666 			{
   1667 
   1668 			if (tileSize != fUnitCell)
   1669 				{
   1670 				ThrowProgramError ();
   1671 				}
   1672 
   1673 			fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h;
   1674 			fTilesDown   = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v;
   1675 
   1676 			fTileCount = fTilesAcross * fTilesDown;
   1677 
   1678 			fTileHash.Reset (fTileCount);
   1679 
   1680 			const uint32 bufferSize =
   1681 				ComputeBufferSize(fPixelType, tileSize, fImage.Planes(),
   1682 								  padNone);
   1683 
   1684 			for (uint32 index = 0; index < threadCount; index++)
   1685 				{
   1686 
   1687 				fBufferData [index].Reset (allocator->Allocate (bufferSize));
   1688 
   1689 				}
   1690 
   1691 			}
   1692 
   1693 		virtual void Process (uint32 threadIndex,
   1694 							  const dng_rect &tile,
   1695 							  dng_abort_sniffer * /* sniffer */)
   1696 			{
   1697 
   1698 			int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h;
   1699 			int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v;
   1700 
   1701 			DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h &&
   1702 						tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v,
   1703 						"Bad tile origin");
   1704 
   1705 			uint32 tileIndex = rowIndex * fTilesAcross + colIndex;
   1706 
   1707 			dng_pixel_buffer buffer (tile, 0, fImage.Planes (),
   1708 				 fPixelType, pcPlanar,
   1709 				 fBufferData [threadIndex]->Buffer ());
   1710 
   1711 			fImage.Get (buffer);
   1712 
   1713 			uint32 count = buffer.fPlaneStep *
   1714 						   buffer.fPlanes *
   1715 						   buffer.fPixelSize;
   1716 
   1717 			#if qDNGBigEndian
   1718 
   1719 			// We need to use the same byte order to compute
   1720 			// the digest, no matter the native order.  Little-endian
   1721 			// is more common now, so use that.
   1722 
   1723 			switch (buffer.fPixelSize)
   1724 				{
   1725 
   1726 				case 1:
   1727 					break;
   1728 
   1729 				case 2:
   1730 					{
   1731 					DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
   1732 					break;
   1733 					}
   1734 
   1735 				case 4:
   1736 					{
   1737 					DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
   1738 					break;
   1739 					}
   1740 
   1741 				default:
   1742 					{
   1743 					DNG_REPORT ("Unexpected pixel size");
   1744 					break;
   1745 					}
   1746 
   1747 				}
   1748 
   1749 			#endif
   1750 
   1751 			dng_md5_printer printer;
   1752 
   1753 			printer.Process (buffer.fData, count);
   1754 
   1755 			fTileHash [tileIndex] = printer.Result ();
   1756 
   1757 			}
   1758 
   1759 		dng_fingerprint Result ()
   1760 			{
   1761 
   1762 			dng_md5_printer printer;
   1763 
   1764 			for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++)
   1765 				{
   1766 
   1767 				printer.Process (fTileHash [tileIndex] . data, 16);
   1768 
   1769 				}
   1770 
   1771 			return printer.Result ();
   1772 
   1773 			}
   1774 
   1775 	};
   1776 
   1777 /*****************************************************************************/
   1778 
   1779 void dng_negative::FindNewRawImageDigest (dng_host &host) const
   1780 	{
   1781 
   1782 	if (fNewRawImageDigest.IsNull ())
   1783 		{
   1784 
   1785 		#if qDNGValidate
   1786 
   1787 		dng_timer timeScope ("FindNewRawImageDigest time");
   1788 
   1789 		#endif
   1790 
   1791 		// Find fast digest of the raw image.
   1792 
   1793 			{
   1794 
   1795 			const dng_image &rawImage = RawImage ();
   1796 
   1797 			// Find pixel type that will be saved in the file.  When saving DNGs, we convert
   1798 			// some 16-bit data to 8-bit data, so we need to do the matching logic here.
   1799 
   1800 			uint32 rawPixelType = rawImage.PixelType ();
   1801 
   1802 			if (rawPixelType == ttShort)
   1803 				{
   1804 
   1805 				// See if we are using a linearization table with <= 256 entries, in which
   1806 				// case the useful data will all fit within 8-bits.
   1807 
   1808 				const dng_linearization_info *rangeInfo = GetLinearizationInfo ();
   1809 
   1810 				if (rangeInfo)
   1811 					{
   1812 
   1813 					if (rangeInfo->fLinearizationTable.Get ())
   1814 						{
   1815 
   1816 						uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
   1817 
   1818 						if (entries <= 256)
   1819 							{
   1820 
   1821 							rawPixelType = ttByte;
   1822 
   1823 							}
   1824 
   1825 						}
   1826 
   1827 					}
   1828 
   1829 				}
   1830 
   1831 			// Find the fast digest on the raw image.
   1832 
   1833 			dng_find_new_raw_image_digest_task task (rawImage, rawPixelType);
   1834 
   1835 			host.PerformAreaTask (task, rawImage.Bounds ());
   1836 
   1837 			fNewRawImageDigest = task.Result ();
   1838 
   1839 			}
   1840 
   1841 		// If there is a transparancy mask, we need to include that in the
   1842 		// digest also.
   1843 
   1844 		if (RawTransparencyMask () != NULL)
   1845 			{
   1846 
   1847 			// Find the fast digest on the raw mask.
   1848 
   1849 			dng_fingerprint maskDigest;
   1850 
   1851 				{
   1852 
   1853 				dng_find_new_raw_image_digest_task task (*RawTransparencyMask (),
   1854 														 RawTransparencyMask ()->PixelType ());
   1855 
   1856 				host.PerformAreaTask (task, RawTransparencyMask ()->Bounds ());
   1857 
   1858 				maskDigest = task.Result ();
   1859 
   1860 				}
   1861 
   1862 			// Combine the two digests into a single digest.
   1863 
   1864 			dng_md5_printer printer;
   1865 
   1866 			printer.Process (fNewRawImageDigest.data, 16);
   1867 
   1868 			printer.Process (maskDigest.data, 16);
   1869 
   1870 			fNewRawImageDigest = printer.Result ();
   1871 
   1872 			}
   1873 
   1874 		}
   1875 
   1876 	}
   1877 
   1878 /*****************************************************************************/
   1879 
   1880 void dng_negative::ValidateRawImageDigest (dng_host &host)
   1881 	{
   1882 
   1883 	if (Stage1Image () && !IsPreview () && (fRawImageDigest   .IsValid () ||
   1884 										    fNewRawImageDigest.IsValid ()))
   1885 		{
   1886 
   1887 		bool isNewDigest = fNewRawImageDigest.IsValid ();
   1888 
   1889 		dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest
   1890 												 : fRawImageDigest;
   1891 
   1892 		// For lossy compressed JPEG images, we need to compare the stored
   1893 		// digest to the digest computed from the compressed data, since
   1894 		// decompressing lossy JPEG data is itself a lossy process.
   1895 
   1896 		if (RawJPEGImageDigest ().IsValid () || RawJPEGImage ())
   1897 			{
   1898 
   1899 			// Compute the raw JPEG image digest if we have not done so
   1900 			// already.
   1901 
   1902 			FindRawJPEGImageDigest (host);
   1903 
   1904 			if (rawDigest != RawJPEGImageDigest ())
   1905 				{
   1906 
   1907 				#if qDNGValidate
   1908 
   1909 				ReportError ("RawImageDigest does not match raw jpeg image");
   1910 
   1911 				#else
   1912 
   1913 				SetIsDamaged (true);
   1914 
   1915 				#endif
   1916 
   1917 				}
   1918 
   1919 			}
   1920 
   1921 		// Else we can compare the stored digest to the image in memory.
   1922 
   1923 		else
   1924 			{
   1925 
   1926 			dng_fingerprint oldDigest = rawDigest;
   1927 
   1928 			try
   1929 				{
   1930 
   1931 				rawDigest.Clear ();
   1932 
   1933 				if (isNewDigest)
   1934 					{
   1935 
   1936 					FindNewRawImageDigest (host);
   1937 
   1938 					}
   1939 
   1940 				else
   1941 					{
   1942 
   1943 					FindRawImageDigest (host);
   1944 
   1945 					}
   1946 
   1947 				}
   1948 
   1949 			catch (...)
   1950 				{
   1951 
   1952 				rawDigest = oldDigest;
   1953 
   1954 				throw;
   1955 
   1956 				}
   1957 
   1958 			if (oldDigest != rawDigest)
   1959 				{
   1960 
   1961 				#if qDNGValidate
   1962 
   1963 				if (isNewDigest)
   1964 					{
   1965 					ReportError ("NewRawImageDigest does not match raw image");
   1966 					}
   1967 				else
   1968 					{
   1969 					ReportError ("RawImageDigest does not match raw image");
   1970 					}
   1971 
   1972 				SetIsDamaged (true);
   1973 
   1974 				#else
   1975 
   1976 				if (!isNewDigest)
   1977 					{
   1978 
   1979 					// Note that Lightroom 1.4 Windows had a bug that corrupts the
   1980 					// first four bytes of the RawImageDigest tag.  So if the last
   1981 					// twelve bytes match, this is very likely the result of the
   1982 					// bug, and not an actual corrupt file.  So don't report this
   1983 					// to the user--just fix it.
   1984 
   1985 						{
   1986 
   1987 						bool matchLast12 = true;
   1988 
   1989 						for (uint32 j = 4; j < 16; j++)
   1990 							{
   1991 							matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
   1992 							}
   1993 
   1994 						if (matchLast12)
   1995 							{
   1996 							return;
   1997 							}
   1998 
   1999 						}
   2000 
   2001 					// Sometimes Lightroom 1.4 would corrupt more than the first four
   2002 					// bytes, but for all those files that I have seen so far the
   2003 					// resulting first four bytes are 0x08 0x00 0x00 0x00.
   2004 
   2005 					if (oldDigest.data [0] == 0x08 &&
   2006 						oldDigest.data [1] == 0x00 &&
   2007 						oldDigest.data [2] == 0x00 &&
   2008 						oldDigest.data [3] == 0x00)
   2009 						{
   2010 						return;
   2011 						}
   2012 
   2013 					}
   2014 
   2015 				SetIsDamaged (true);
   2016 
   2017 				#endif
   2018 
   2019 				}
   2020 
   2021 			}
   2022 
   2023 		}
   2024 
   2025 	}
   2026 
   2027 /*****************************************************************************/
   2028 
   2029 // If the raw data unique ID is missing, compute one based on a MD5 hash of
   2030 // the raw image hash and the model name, plus other commonly changed
   2031 // data that can affect rendering.
   2032 
   2033 void dng_negative::FindRawDataUniqueID (dng_host &host) const
   2034 	{
   2035 
   2036 	if (fRawDataUniqueID.IsNull ())
   2037 		{
   2038 
   2039 		dng_md5_printer_stream printer;
   2040 
   2041 		// If we have a raw jpeg image, it is much faster to
   2042 		// use its digest as part of the unique ID since
   2043 		// the data size is much smaller.  We cannot use it
   2044 		// if there a transparency mask, since that is not
   2045 		// included in the RawJPEGImageDigest.
   2046 
   2047 		if (RawJPEGImage () && !RawTransparencyMask ())
   2048 			{
   2049 
   2050 			FindRawJPEGImageDigest (host);
   2051 
   2052 			printer.Put (fRawJPEGImageDigest.data, 16);
   2053 
   2054 			}
   2055 
   2056 		// Include the new raw image digest in the unique ID.
   2057 
   2058 		else
   2059 			{
   2060 
   2061 			FindNewRawImageDigest (host);
   2062 
   2063 			printer.Put (fNewRawImageDigest.data, 16);
   2064 
   2065 			}
   2066 
   2067 		// Include model name.
   2068 
   2069 		printer.Put (ModelName ().Get    (),
   2070 					 ModelName ().Length ());
   2071 
   2072 		// Include default crop area, since DNG Recover Edges can modify
   2073 		// these values and they affect rendering.
   2074 
   2075 		printer.Put_uint32 (fDefaultCropSizeH.n);
   2076 		printer.Put_uint32 (fDefaultCropSizeH.d);
   2077 
   2078 		printer.Put_uint32 (fDefaultCropSizeV.n);
   2079 		printer.Put_uint32 (fDefaultCropSizeV.d);
   2080 
   2081 		printer.Put_uint32 (fDefaultCropOriginH.n);
   2082 		printer.Put_uint32 (fDefaultCropOriginH.d);
   2083 
   2084 		printer.Put_uint32 (fDefaultCropOriginV.n);
   2085 		printer.Put_uint32 (fDefaultCropOriginV.d);
   2086 
   2087 		// Include default user crop.
   2088 
   2089 		printer.Put_uint32 (fDefaultUserCropT.n);
   2090 		printer.Put_uint32 (fDefaultUserCropT.d);
   2091 
   2092 		printer.Put_uint32 (fDefaultUserCropL.n);
   2093 		printer.Put_uint32 (fDefaultUserCropL.d);
   2094 
   2095 		printer.Put_uint32 (fDefaultUserCropB.n);
   2096 		printer.Put_uint32 (fDefaultUserCropB.d);
   2097 
   2098 		printer.Put_uint32 (fDefaultUserCropR.n);
   2099 		printer.Put_uint32 (fDefaultUserCropR.d);
   2100 
   2101 		// Include opcode lists, since lens correction utilities can modify
   2102 		// these values and they affect rendering.
   2103 
   2104 		fOpcodeList1.FingerprintToStream (printer);
   2105 		fOpcodeList2.FingerprintToStream (printer);
   2106 		fOpcodeList3.FingerprintToStream (printer);
   2107 
   2108 		fRawDataUniqueID = printer.Result ();
   2109 
   2110 		}
   2111 
   2112 	}
   2113 
   2114 /******************************************************************************/
   2115 
   2116 // Forces recomputation of RawDataUniqueID, useful to call
   2117 // after modifying the opcode lists, etc.
   2118 
   2119 void dng_negative::RecomputeRawDataUniqueID (dng_host &host)
   2120 	{
   2121 
   2122 	fRawDataUniqueID.Clear ();
   2123 
   2124 	FindRawDataUniqueID (host);
   2125 
   2126 	}
   2127 
   2128 /******************************************************************************/
   2129 
   2130 void dng_negative::FindOriginalRawFileDigest () const
   2131 	{
   2132 
   2133 	if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
   2134 		{
   2135 
   2136 		dng_md5_printer printer;
   2137 
   2138 		printer.Process (fOriginalRawFileData->Buffer      (),
   2139 						 fOriginalRawFileData->LogicalSize ());
   2140 
   2141 		fOriginalRawFileDigest = printer.Result ();
   2142 
   2143 		}
   2144 
   2145 	}
   2146 
   2147 /*****************************************************************************/
   2148 
   2149 void dng_negative::ValidateOriginalRawFileDigest ()
   2150 	{
   2151 
   2152 	if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
   2153 		{
   2154 
   2155 		dng_fingerprint oldDigest = fOriginalRawFileDigest;
   2156 
   2157 		try
   2158 			{
   2159 
   2160 			fOriginalRawFileDigest.Clear ();
   2161 
   2162 			FindOriginalRawFileDigest ();
   2163 
   2164 			}
   2165 
   2166 		catch (...)
   2167 			{
   2168 
   2169 			fOriginalRawFileDigest = oldDigest;
   2170 
   2171 			throw;
   2172 
   2173 			}
   2174 
   2175 		if (oldDigest != fOriginalRawFileDigest)
   2176 			{
   2177 
   2178 			#if qDNGValidate
   2179 
   2180 			ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
   2181 
   2182 			#else
   2183 
   2184 			SetIsDamaged (true);
   2185 
   2186 			#endif
   2187 
   2188 			// Don't "repair" the original image data digest.  Once it is
   2189 			// bad, it stays bad.  The user cannot tell by looking at the image
   2190 			// whether the damage is acceptable and can be ignored in the
   2191 			// future.
   2192 
   2193 			fOriginalRawFileDigest = oldDigest;
   2194 
   2195 			}
   2196 
   2197 		}
   2198 
   2199 	}
   2200 
   2201 /******************************************************************************/
   2202 
   2203 dng_rect dng_negative::DefaultCropArea () const
   2204 	{
   2205 
   2206 	// First compute the area using simple rounding.
   2207 
   2208 	dng_rect result;
   2209 
   2210 	result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH);
   2211 	result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV);
   2212 
   2213 	result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH);
   2214 	result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV);
   2215 
   2216 	// Sometimes the simple rounding causes the resulting default crop
   2217 	// area to slide off the scaled image area.  So we force this not
   2218 	// to happen.  We only do this if the image is not stubbed.
   2219 
   2220 	const dng_image *image = Stage3Image ();
   2221 
   2222 	if (image)
   2223 		{
   2224 
   2225 		dng_point imageSize = image->Size ();
   2226 
   2227 		if (result.r > imageSize.h)
   2228 			{
   2229 			result.l -= result.r - imageSize.h;
   2230 			result.r  = imageSize.h;
   2231 			}
   2232 
   2233 		if (result.b > imageSize.v)
   2234 			{
   2235 			result.t -= result.b - imageSize.v;
   2236 			result.b  = imageSize.v;
   2237 			}
   2238 
   2239 		}
   2240 
   2241 	return result;
   2242 
   2243 	}
   2244 
   2245 /*****************************************************************************/
   2246 
   2247 real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const
   2248 	{
   2249 
   2250 	real64 total = BaselineExposure ();
   2251 
   2252 	const dng_camera_profile *profile = ProfileByID (profileID);
   2253 
   2254 	if (profile)
   2255 		{
   2256 
   2257 		real64 offset = profile->BaselineExposureOffset ().As_real64 ();
   2258 
   2259 		total += offset;
   2260 
   2261 		}
   2262 
   2263 	return total;
   2264 
   2265 	}
   2266 
   2267 /******************************************************************************/
   2268 
   2269 void dng_negative::SetShadowScale (const dng_urational &scale)
   2270 	{
   2271 
   2272 	if (scale.d > 0)
   2273 		{
   2274 
   2275 		real64 s = scale.As_real64 ();
   2276 
   2277 		if (s > 0.0 && s <= 1.0)
   2278 			{
   2279 
   2280 			fShadowScale = scale;
   2281 
   2282 			}
   2283 
   2284 		}
   2285 
   2286 	}
   2287 
   2288 /******************************************************************************/
   2289 
   2290 void dng_negative::SetActiveArea (const dng_rect &area)
   2291 	{
   2292 
   2293 	NeedLinearizationInfo ();
   2294 
   2295 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2296 
   2297 	info.fActiveArea = area;
   2298 
   2299 	}
   2300 
   2301 /******************************************************************************/
   2302 
   2303 void dng_negative::SetMaskedAreas (uint32 count,
   2304 							 	   const dng_rect *area)
   2305 	{
   2306 
   2307 	DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
   2308 
   2309 	NeedLinearizationInfo ();
   2310 
   2311 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2312 
   2313 	info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
   2314 
   2315 	for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
   2316 		{
   2317 
   2318 		info.fMaskedArea [index] = area [index];
   2319 
   2320 		}
   2321 
   2322 	}
   2323 
   2324 /*****************************************************************************/
   2325 
   2326 void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
   2327 	{
   2328 
   2329 	NeedLinearizationInfo ();
   2330 
   2331 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2332 
   2333 	info.fLinearizationTable.Reset (curve.Release ());
   2334 
   2335 	}
   2336 
   2337 /*****************************************************************************/
   2338 
   2339 void dng_negative::SetBlackLevel (real64 black,
   2340 								  int32 plane)
   2341 	{
   2342 
   2343 	NeedLinearizationInfo ();
   2344 
   2345 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2346 
   2347 	info.fBlackLevelRepeatRows = 1;
   2348 	info.fBlackLevelRepeatCols = 1;
   2349 
   2350 	if (plane < 0)
   2351 		{
   2352 
   2353 		for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
   2354 			{
   2355 
   2356 			info.fBlackLevel [0] [0] [j] = black;
   2357 
   2358 			}
   2359 
   2360 		}
   2361 
   2362 	else
   2363 		{
   2364 
   2365 		info.fBlackLevel [0] [0] [plane] = black;
   2366 
   2367 		}
   2368 
   2369 	info.RoundBlacks ();
   2370 
   2371 	}
   2372 
   2373 /*****************************************************************************/
   2374 
   2375 void dng_negative::SetQuadBlacks (real64 black0,
   2376 						    	  real64 black1,
   2377 						    	  real64 black2,
   2378 						    	  real64 black3,
   2379 								  int32 plane)
   2380 	{
   2381 
   2382 	NeedLinearizationInfo ();
   2383 
   2384 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2385 
   2386 	info.fBlackLevelRepeatRows = 2;
   2387 	info.fBlackLevelRepeatCols = 2;
   2388 
   2389 	if (plane < 0)
   2390 		{
   2391 
   2392 		for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
   2393 			{
   2394 
   2395 			info.fBlackLevel [0] [0] [j] = black0;
   2396 			info.fBlackLevel [0] [1] [j] = black1;
   2397 			info.fBlackLevel [1] [0] [j] = black2;
   2398 			info.fBlackLevel [1] [1] [j] = black3;
   2399 
   2400 			}
   2401 
   2402 		}
   2403 
   2404 	else
   2405 		{
   2406 
   2407 		info.fBlackLevel [0] [0] [plane] = black0;
   2408 		info.fBlackLevel [0] [1] [plane] = black1;
   2409 		info.fBlackLevel [1] [0] [plane] = black2;
   2410 		info.fBlackLevel [1] [1] [plane] = black3;
   2411 
   2412 		}
   2413 
   2414 	info.RoundBlacks ();
   2415 
   2416 	}
   2417 
   2418 /*****************************************************************************/
   2419 
   2420 void dng_negative::SetRowBlacks (const real64 *blacks,
   2421 				   		   		 uint32 count)
   2422 	{
   2423 
   2424 	if (count)
   2425 		{
   2426 
   2427 		NeedLinearizationInfo ();
   2428 
   2429 		dng_linearization_info &info = *fLinearizationInfo.Get ();
   2430 
   2431 		uint32 byteCount = 0;
   2432 
   2433 		if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount))
   2434 			{
   2435 
   2436 			ThrowMemoryFull("Arithmetic overflow computing byte count.");
   2437 
   2438 			}
   2439 
   2440 		info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount));
   2441 
   2442 		DoCopyBytes (blacks,
   2443 					 info.fBlackDeltaV->Buffer (),
   2444 					 byteCount);
   2445 
   2446 		info.RoundBlacks ();
   2447 
   2448 		}
   2449 
   2450 	else if (fLinearizationInfo.Get ())
   2451 		{
   2452 
   2453 		dng_linearization_info &info = *fLinearizationInfo.Get ();
   2454 
   2455 		info.fBlackDeltaV.Reset ();
   2456 
   2457 		}
   2458 
   2459 	}
   2460 
   2461 /*****************************************************************************/
   2462 
   2463 void dng_negative::SetColumnBlacks (const real64 *blacks,
   2464 					  		  	    uint32 count)
   2465 	{
   2466 
   2467 	if (count)
   2468 		{
   2469 
   2470 		NeedLinearizationInfo ();
   2471 
   2472 		dng_linearization_info &info = *fLinearizationInfo.Get ();
   2473 
   2474 		uint32 byteCount = 0;
   2475 
   2476 		if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount))
   2477 			{
   2478 
   2479 			ThrowMemoryFull("Arithmetic overflow computing byte count.");
   2480 
   2481 			}
   2482 
   2483 		info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount));
   2484 
   2485 		DoCopyBytes (blacks,
   2486 					 info.fBlackDeltaH->Buffer (),
   2487 					 byteCount);
   2488 
   2489 		info.RoundBlacks ();
   2490 
   2491 		}
   2492 
   2493 	else if (fLinearizationInfo.Get ())
   2494 		{
   2495 
   2496 		dng_linearization_info &info = *fLinearizationInfo.Get ();
   2497 
   2498 		info.fBlackDeltaH.Reset ();
   2499 
   2500 		}
   2501 
   2502 	}
   2503 
   2504 /*****************************************************************************/
   2505 
   2506 uint32 dng_negative::WhiteLevel (uint32 plane) const
   2507 	{
   2508 
   2509 	if (fLinearizationInfo.Get ())
   2510 		{
   2511 
   2512 		const dng_linearization_info &info = *fLinearizationInfo.Get ();
   2513 
   2514 		return Round_uint32 (info.fWhiteLevel [plane]);
   2515 
   2516 		}
   2517 
   2518 	if (RawImage ().PixelType () == ttFloat)
   2519 		{
   2520 
   2521 		return 1;
   2522 
   2523 		}
   2524 
   2525 	return 0x0FFFF;
   2526 
   2527 	}
   2528 
   2529 /*****************************************************************************/
   2530 
   2531 void dng_negative::SetWhiteLevel (uint32 white,
   2532 							      int32 plane)
   2533 	{
   2534 
   2535 	NeedLinearizationInfo ();
   2536 
   2537 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   2538 
   2539 	if (plane < 0)
   2540 		{
   2541 
   2542 		for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
   2543 			{
   2544 
   2545 			info.fWhiteLevel [j] = (real64) white;
   2546 
   2547 			}
   2548 
   2549 		}
   2550 
   2551 	else
   2552 		{
   2553 
   2554 		info.fWhiteLevel [plane] = (real64) white;
   2555 
   2556 		}
   2557 
   2558 	}
   2559 
   2560 /******************************************************************************/
   2561 
   2562 void dng_negative::SetColorKeys (ColorKeyCode color0,
   2563 						   		 ColorKeyCode color1,
   2564 						   		 ColorKeyCode color2,
   2565 						   		 ColorKeyCode color3)
   2566 	{
   2567 
   2568 	NeedMosaicInfo ();
   2569 
   2570 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2571 
   2572 	info.fCFAPlaneColor [0] = color0;
   2573 	info.fCFAPlaneColor [1] = color1;
   2574 	info.fCFAPlaneColor [2] = color2;
   2575 	info.fCFAPlaneColor [3] = color3;
   2576 
   2577 	}
   2578 
   2579 /******************************************************************************/
   2580 
   2581 void dng_negative::SetBayerMosaic (uint32 phase)
   2582 	{
   2583 
   2584 	NeedMosaicInfo ();
   2585 
   2586 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2587 
   2588 	ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
   2589 	ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
   2590 	ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
   2591 
   2592 	info.fCFAPatternSize = dng_point (2, 2);
   2593 
   2594 	switch (phase)
   2595 		{
   2596 
   2597 		case 0:
   2598 			{
   2599 			info.fCFAPattern [0] [0] = color1;
   2600 			info.fCFAPattern [0] [1] = color0;
   2601 			info.fCFAPattern [1] [0] = color2;
   2602 			info.fCFAPattern [1] [1] = color1;
   2603 			break;
   2604 			}
   2605 
   2606 		case 1:
   2607 			{
   2608 			info.fCFAPattern [0] [0] = color0;
   2609 			info.fCFAPattern [0] [1] = color1;
   2610 			info.fCFAPattern [1] [0] = color1;
   2611 			info.fCFAPattern [1] [1] = color2;
   2612 			break;
   2613 			}
   2614 
   2615 		case 2:
   2616 			{
   2617 			info.fCFAPattern [0] [0] = color2;
   2618 			info.fCFAPattern [0] [1] = color1;
   2619 			info.fCFAPattern [1] [0] = color1;
   2620 			info.fCFAPattern [1] [1] = color0;
   2621 			break;
   2622 			}
   2623 
   2624 		case 3:
   2625 			{
   2626 			info.fCFAPattern [0] [0] = color1;
   2627 			info.fCFAPattern [0] [1] = color2;
   2628 			info.fCFAPattern [1] [0] = color0;
   2629 			info.fCFAPattern [1] [1] = color1;
   2630 			break;
   2631 			}
   2632 
   2633 		}
   2634 
   2635 	info.fColorPlanes = 3;
   2636 
   2637 	info.fCFALayout = 1;
   2638 
   2639 	}
   2640 
   2641 /******************************************************************************/
   2642 
   2643 void dng_negative::SetFujiMosaic (uint32 phase)
   2644 	{
   2645 
   2646 	NeedMosaicInfo ();
   2647 
   2648 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2649 
   2650 	ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
   2651 	ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
   2652 	ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
   2653 
   2654 	info.fCFAPatternSize = dng_point (2, 4);
   2655 
   2656 	switch (phase)
   2657 		{
   2658 
   2659 		case 0:
   2660 			{
   2661 			info.fCFAPattern [0] [0] = color0;
   2662 			info.fCFAPattern [0] [1] = color1;
   2663 			info.fCFAPattern [0] [2] = color2;
   2664 			info.fCFAPattern [0] [3] = color1;
   2665 			info.fCFAPattern [1] [0] = color2;
   2666 			info.fCFAPattern [1] [1] = color1;
   2667 			info.fCFAPattern [1] [2] = color0;
   2668 			info.fCFAPattern [1] [3] = color1;
   2669 			break;
   2670 			}
   2671 
   2672 		case 1:
   2673 			{
   2674 			info.fCFAPattern [0] [0] = color2;
   2675 			info.fCFAPattern [0] [1] = color1;
   2676 			info.fCFAPattern [0] [2] = color0;
   2677 			info.fCFAPattern [0] [3] = color1;
   2678 			info.fCFAPattern [1] [0] = color0;
   2679 			info.fCFAPattern [1] [1] = color1;
   2680 			info.fCFAPattern [1] [2] = color2;
   2681 			info.fCFAPattern [1] [3] = color1;
   2682 			break;
   2683 			}
   2684 
   2685 		}
   2686 
   2687 	info.fColorPlanes = 3;
   2688 
   2689 	info.fCFALayout = 2;
   2690 
   2691 	}
   2692 
   2693 /*****************************************************************************/
   2694 
   2695 void dng_negative::SetFujiMosaic6x6 (uint32 phase)
   2696 	{
   2697 
   2698 	NeedMosaicInfo ();
   2699 
   2700 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2701 
   2702 	ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
   2703 	ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
   2704 	ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
   2705 
   2706 	const uint32 patSize = 6;
   2707 
   2708 	info.fCFAPatternSize = dng_point (patSize, patSize);
   2709 
   2710 	info.fCFAPattern [0] [0] = color1;
   2711 	info.fCFAPattern [0] [1] = color2;
   2712 	info.fCFAPattern [0] [2] = color1;
   2713 	info.fCFAPattern [0] [3] = color1;
   2714 	info.fCFAPattern [0] [4] = color0;
   2715 	info.fCFAPattern [0] [5] = color1;
   2716 
   2717 	info.fCFAPattern [1] [0] = color0;
   2718 	info.fCFAPattern [1] [1] = color1;
   2719 	info.fCFAPattern [1] [2] = color0;
   2720 	info.fCFAPattern [1] [3] = color2;
   2721 	info.fCFAPattern [1] [4] = color1;
   2722 	info.fCFAPattern [1] [5] = color2;
   2723 
   2724 	info.fCFAPattern [2] [0] = color1;
   2725 	info.fCFAPattern [2] [1] = color2;
   2726 	info.fCFAPattern [2] [2] = color1;
   2727 	info.fCFAPattern [2] [3] = color1;
   2728 	info.fCFAPattern [2] [4] = color0;
   2729 	info.fCFAPattern [2] [5] = color1;
   2730 
   2731 	info.fCFAPattern [3] [0] = color1;
   2732 	info.fCFAPattern [3] [1] = color0;
   2733 	info.fCFAPattern [3] [2] = color1;
   2734 	info.fCFAPattern [3] [3] = color1;
   2735 	info.fCFAPattern [3] [4] = color2;
   2736 	info.fCFAPattern [3] [5] = color1;
   2737 
   2738 	info.fCFAPattern [4] [0] = color2;
   2739 	info.fCFAPattern [4] [1] = color1;
   2740 	info.fCFAPattern [4] [2] = color2;
   2741 	info.fCFAPattern [4] [3] = color0;
   2742 	info.fCFAPattern [4] [4] = color1;
   2743 	info.fCFAPattern [4] [5] = color0;
   2744 
   2745 	info.fCFAPattern [5] [0] = color1;
   2746 	info.fCFAPattern [5] [1] = color0;
   2747 	info.fCFAPattern [5] [2] = color1;
   2748 	info.fCFAPattern [5] [3] = color1;
   2749 	info.fCFAPattern [5] [4] = color2;
   2750 	info.fCFAPattern [5] [5] = color1;
   2751 
   2752 	DNG_REQUIRE (phase >= 0 && phase < patSize * patSize,
   2753 				 "Bad phase in SetFujiMosaic6x6.");
   2754 
   2755 	if (phase > 0)
   2756 		{
   2757 
   2758 		dng_mosaic_info temp = info;
   2759 
   2760 		uint32 phaseRow = phase / patSize;
   2761 
   2762 		uint32 phaseCol = phase - (phaseRow * patSize);
   2763 
   2764 		for (uint32 dstRow = 0; dstRow < patSize; dstRow++)
   2765 			{
   2766 
   2767 			uint32 srcRow = (dstRow + phaseRow) % patSize;
   2768 
   2769 			for (uint32 dstCol = 0; dstCol < patSize; dstCol++)
   2770 				{
   2771 
   2772 				uint32 srcCol = (dstCol + phaseCol) % patSize;
   2773 
   2774 				temp.fCFAPattern [dstRow] [dstCol] = info.fCFAPattern [srcRow] [srcCol];
   2775 
   2776 				}
   2777 
   2778 			}
   2779 
   2780 		info = temp;
   2781 
   2782 		}
   2783 
   2784 	info.fColorPlanes = 3;
   2785 
   2786 	info.fCFALayout = 1;
   2787 
   2788 	}
   2789 
   2790 /******************************************************************************/
   2791 
   2792 void dng_negative::SetQuadMosaic (uint32 pattern)
   2793 	{
   2794 
   2795 	// The pattern of the four colors is assumed to be repeat at least every two
   2796 	// columns and eight rows.  The pattern is encoded as a 32-bit integer,
   2797 	// with every two bits encoding a color, in scan order for two columns and
   2798 	// eight rows (lsb is first).  The usual color coding is:
   2799 	//
   2800 	// 0 = Green
   2801 	// 1 = Magenta
   2802 	// 2 = Cyan
   2803 	// 3 = Yellow
   2804 	//
   2805 	// Examples:
   2806 	//
   2807 	//	PowerShot 600 uses 0xe1e4e1e4:
   2808 	//
   2809 	//	  0 1 2 3 4 5
   2810 	//	0 G M G M G M
   2811 	//	1 C Y C Y C Y
   2812 	//	2 M G M G M G
   2813 	//	3 C Y C Y C Y
   2814 	//
   2815 	//	PowerShot A5 uses 0x1e4e1e4e:
   2816 	//
   2817 	//	  0 1 2 3 4 5
   2818 	//	0 C Y C Y C Y
   2819 	//	1 G M G M G M
   2820 	//	2 C Y C Y C Y
   2821 	//	3 M G M G M G
   2822 	//
   2823 	//	PowerShot A50 uses 0x1b4e4b1e:
   2824 	//
   2825 	//	  0 1 2 3 4 5
   2826 	//	0 C Y C Y C Y
   2827 	//	1 M G M G M G
   2828 	//	2 Y C Y C Y C
   2829 	//	3 G M G M G M
   2830 	//	4 C Y C Y C Y
   2831 	//	5 G M G M G M
   2832 	//	6 Y C Y C Y C
   2833 	//	7 M G M G M G
   2834 	//
   2835 	//	PowerShot Pro70 uses 0x1e4b4e1b:
   2836 	//
   2837 	//	  0 1 2 3 4 5
   2838 	//	0 Y C Y C Y C
   2839 	//	1 M G M G M G
   2840 	//	2 C Y C Y C Y
   2841 	//	3 G M G M G M
   2842 	//	4 Y C Y C Y C
   2843 	//	5 G M G M G M
   2844 	//	6 C Y C Y C Y
   2845 	//	7 M G M G M G
   2846 	//
   2847 	//	PowerShots Pro90 and G1 use 0xb4b4b4b4:
   2848 	//
   2849 	//	  0 1 2 3 4 5
   2850 	//	0 G M G M G M
   2851 	//	1 Y C Y C Y C
   2852 
   2853 	NeedMosaicInfo ();
   2854 
   2855 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2856 
   2857 	if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF))
   2858 		{
   2859 		info.fCFAPatternSize = dng_point (8, 2);
   2860 		}
   2861 
   2862 	else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF))
   2863 		{
   2864 		info.fCFAPatternSize = dng_point (4, 2);
   2865 		}
   2866 
   2867 	else
   2868 		{
   2869 		info.fCFAPatternSize = dng_point (2, 2);
   2870 		}
   2871 
   2872 	for (int32 row = 0; row < info.fCFAPatternSize.v; row++)
   2873 		{
   2874 
   2875 		for (int32 col = 0; col < info.fCFAPatternSize.h; col++)
   2876 			{
   2877 
   2878 			uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3;
   2879 
   2880 			info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index];
   2881 
   2882 			}
   2883 
   2884 		}
   2885 
   2886 	info.fColorPlanes = 4;
   2887 
   2888 	info.fCFALayout = 1;
   2889 
   2890 	}
   2891 
   2892 /******************************************************************************/
   2893 
   2894 void dng_negative::SetGreenSplit (uint32 split)
   2895 	{
   2896 
   2897 	NeedMosaicInfo ();
   2898 
   2899 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   2900 
   2901 	info.fBayerGreenSplit = split;
   2902 
   2903 	}
   2904 
   2905 /*****************************************************************************/
   2906 
   2907 void dng_negative::Parse (dng_host &host,
   2908 						  dng_stream &stream,
   2909 						  dng_info &info)
   2910 	{
   2911 
   2912 	// Shared info.
   2913 
   2914 	dng_shared &shared = *(info.fShared.Get ());
   2915 
   2916 	// Find IFD holding the main raw information.
   2917 
   2918 	dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
   2919 
   2920 	// Model name.
   2921 
   2922 	SetModelName (shared.fUniqueCameraModel.Get ());
   2923 
   2924 	// Localized model name.
   2925 
   2926 	SetLocalName (shared.fLocalizedCameraModel.Get ());
   2927 
   2928 	// Base orientation.
   2929 
   2930 		{
   2931 
   2932 		uint32 orientation = info.fIFD [0]->fOrientation;
   2933 
   2934 		if (orientation >= 1 && orientation <= 8)
   2935 			{
   2936 
   2937 			SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
   2938 
   2939 			}
   2940 
   2941 		}
   2942 
   2943 	// Default crop rectangle.
   2944 
   2945 	SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
   2946 					    rawIFD.fDefaultCropSizeV);
   2947 
   2948 	SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
   2949 						  rawIFD.fDefaultCropOriginV);
   2950 
   2951 	// Default user crop rectangle.
   2952 
   2953 	SetDefaultUserCrop (rawIFD.fDefaultUserCropT,
   2954 						rawIFD.fDefaultUserCropL,
   2955 						rawIFD.fDefaultUserCropB,
   2956 						rawIFD.fDefaultUserCropR);
   2957 
   2958 	// Default scale.
   2959 
   2960 	SetDefaultScale (rawIFD.fDefaultScaleH,
   2961 					 rawIFD.fDefaultScaleV);
   2962 
   2963 	// Best quality scale.
   2964 
   2965 	SetBestQualityScale (rawIFD.fBestQualityScale);
   2966 
   2967 	// Baseline noise.
   2968 
   2969 	SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
   2970 
   2971 	// NoiseReductionApplied.
   2972 
   2973 	SetNoiseReductionApplied (shared.fNoiseReductionApplied);
   2974 
   2975 	// NoiseProfile.
   2976 
   2977 	SetNoiseProfile (shared.fNoiseProfile);
   2978 
   2979 	// Baseline exposure.
   2980 
   2981 	SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
   2982 
   2983 	// Baseline sharpness.
   2984 
   2985 	SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
   2986 
   2987 	// Chroma blur radius.
   2988 
   2989 	SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
   2990 
   2991 	// Anti-alias filter strength.
   2992 
   2993 	SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
   2994 
   2995 	// Linear response limit.
   2996 
   2997 	SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
   2998 
   2999 	// Shadow scale.
   3000 
   3001 	SetShadowScale (shared.fShadowScale);
   3002 
   3003 	// Colorimetric reference.
   3004 
   3005 	SetColorimetricReference (shared.fColorimetricReference);
   3006 
   3007 	// Color channels.
   3008 
   3009 	SetColorChannels (shared.fCameraProfile.fColorPlanes);
   3010 
   3011 	// Analog balance.
   3012 
   3013 	if (shared.fAnalogBalance.NotEmpty ())
   3014 		{
   3015 
   3016 		SetAnalogBalance (shared.fAnalogBalance);
   3017 
   3018 		}
   3019 
   3020 	// Camera calibration matrices
   3021 
   3022 	if (shared.fCameraCalibration1.NotEmpty ())
   3023 		{
   3024 
   3025 		SetCameraCalibration1 (shared.fCameraCalibration1);
   3026 
   3027 		}
   3028 
   3029 	if (shared.fCameraCalibration2.NotEmpty ())
   3030 		{
   3031 
   3032 		SetCameraCalibration2 (shared.fCameraCalibration2);
   3033 
   3034 		}
   3035 
   3036 	if (shared.fCameraCalibration1.NotEmpty () ||
   3037 		shared.fCameraCalibration2.NotEmpty ())
   3038 		{
   3039 
   3040 		SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
   3041 
   3042 		}
   3043 
   3044 	// Embedded camera profiles.
   3045 
   3046 	if (shared.fCameraProfile.fColorPlanes > 1)
   3047 		{
   3048 
   3049 		if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
   3050 			{
   3051 
   3052 			// Add profile from main IFD.
   3053 
   3054 				{
   3055 
   3056 				AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
   3057 
   3058 				dng_camera_profile_info &profileInfo = shared.fCameraProfile;
   3059 
   3060 				profile->Parse (stream, profileInfo);
   3061 
   3062 				// The main embedded profile must be valid.
   3063 
   3064 				if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
   3065 					{
   3066 
   3067 					ThrowBadFormat ();
   3068 
   3069 					}
   3070 
   3071 				profile->SetWasReadFromDNG ();
   3072 
   3073 				AddProfile (profile);
   3074 
   3075 				}
   3076 
   3077 			// Extra profiles.
   3078 
   3079 			for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
   3080 				{
   3081 
   3082 				try
   3083 					{
   3084 
   3085 					AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
   3086 
   3087 					dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
   3088 
   3089 					profile->Parse (stream, profileInfo);
   3090 
   3091 					if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
   3092 						{
   3093 
   3094 						ThrowBadFormat ();
   3095 
   3096 						}
   3097 
   3098 					profile->SetWasReadFromDNG ();
   3099 
   3100 					AddProfile (profile);
   3101 
   3102 					}
   3103 
   3104 				catch (dng_exception &except)
   3105 					{
   3106 
   3107 					// Don't ignore transient errors.
   3108 
   3109 					if (host.IsTransientError (except.ErrorCode ()))
   3110 						{
   3111 
   3112 						throw;
   3113 
   3114 						}
   3115 
   3116 					// Eat other parsing errors.
   3117 
   3118 					#if qDNGValidate
   3119 
   3120 					ReportWarning ("Unable to parse extra profile");
   3121 
   3122 					#endif
   3123 
   3124 					}
   3125 
   3126 				}
   3127 
   3128 			}
   3129 
   3130 		// As shot profile name.
   3131 
   3132 		if (shared.fAsShotProfileName.NotEmpty ())
   3133 			{
   3134 
   3135 			SetAsShotProfileName (shared.fAsShotProfileName.Get ());
   3136 
   3137 			}
   3138 
   3139 		}
   3140 
   3141 	// Raw image data digest.
   3142 
   3143 	if (shared.fRawImageDigest.IsValid ())
   3144 		{
   3145 
   3146 		SetRawImageDigest (shared.fRawImageDigest);
   3147 
   3148 		}
   3149 
   3150 	// New raw image data digest.
   3151 
   3152 	if (shared.fNewRawImageDigest.IsValid ())
   3153 		{
   3154 
   3155 		SetNewRawImageDigest (shared.fNewRawImageDigest);
   3156 
   3157 		}
   3158 
   3159 	// Raw data unique ID.
   3160 
   3161 	if (shared.fRawDataUniqueID.IsValid ())
   3162 		{
   3163 
   3164 		SetRawDataUniqueID (shared.fRawDataUniqueID);
   3165 
   3166 		}
   3167 
   3168 	// Original raw file name.
   3169 
   3170 	if (shared.fOriginalRawFileName.NotEmpty ())
   3171 		{
   3172 
   3173 		SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
   3174 
   3175 		}
   3176 
   3177 	// Original raw file data.
   3178 
   3179 	if (shared.fOriginalRawFileDataCount)
   3180 		{
   3181 
   3182 		SetHasOriginalRawFileData (true);
   3183 
   3184 		if (host.KeepOriginalFile ())
   3185 			{
   3186 
   3187 			uint32 count = shared.fOriginalRawFileDataCount;
   3188 
   3189 			AutoPtr<dng_memory_block> block (host.Allocate (count));
   3190 
   3191 			stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
   3192 
   3193 			stream.Get (block->Buffer (), count);
   3194 
   3195 			SetOriginalRawFileData (block);
   3196 
   3197 			SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
   3198 
   3199 			ValidateOriginalRawFileDigest ();
   3200 
   3201 			}
   3202 
   3203 		}
   3204 
   3205 	// DNG private data.
   3206 
   3207 	if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None))
   3208 		{
   3209 
   3210 		uint32 length = shared.fDNGPrivateDataCount;
   3211 
   3212 		AutoPtr<dng_memory_block> block (host.Allocate (length));
   3213 
   3214 		stream.SetReadPosition (shared.fDNGPrivateDataOffset);
   3215 
   3216 		stream.Get (block->Buffer (), length);
   3217 
   3218 		SetPrivateData (block);
   3219 
   3220 		}
   3221 
   3222 	// Hand off EXIF metadata to negative.
   3223 
   3224 	ResetExif (info.fExif.Release ());
   3225 
   3226 	// Parse linearization info.
   3227 
   3228 	NeedLinearizationInfo ();
   3229 
   3230 	fLinearizationInfo.Get ()->Parse (host,
   3231 								      stream,
   3232 								      info);
   3233 
   3234 	// Parse mosaic info.
   3235 
   3236 	if (rawIFD.fPhotometricInterpretation == piCFA)
   3237 		{
   3238 
   3239 		NeedMosaicInfo ();
   3240 
   3241 		fMosaicInfo.Get ()->Parse (host,
   3242 							       stream,
   3243 							       info);
   3244 
   3245 		}
   3246 
   3247 	// Fill in original sizes.
   3248 
   3249 	if (shared.fOriginalDefaultFinalSize.h > 0 &&
   3250 		shared.fOriginalDefaultFinalSize.v > 0)
   3251 		{
   3252 
   3253 		SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize);
   3254 
   3255 		SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize);
   3256 
   3257 		SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1),
   3258 									dng_urational (shared.fOriginalDefaultFinalSize.v, 1));
   3259 
   3260 		}
   3261 
   3262 	if (shared.fOriginalBestQualityFinalSize.h > 0 &&
   3263 		shared.fOriginalBestQualityFinalSize.v > 0)
   3264 		{
   3265 
   3266 		SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize);
   3267 
   3268 		}
   3269 
   3270 	if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 &&
   3271 		shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0)
   3272 		{
   3273 
   3274 		SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH,
   3275 									shared.fOriginalDefaultCropSizeV);
   3276 
   3277 		}
   3278 
   3279 	}
   3280 
   3281 /*****************************************************************************/
   3282 
   3283 void dng_negative::SetDefaultOriginalSizes ()
   3284 	{
   3285 
   3286 	// Fill in original sizes if we don't have them already.
   3287 
   3288 	if (OriginalDefaultFinalSize () == dng_point ())
   3289 		{
   3290 
   3291 		SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (),
   3292 												DefaultFinalWidth  ()));
   3293 
   3294 		}
   3295 
   3296 	if (OriginalBestQualityFinalSize () == dng_point ())
   3297 		{
   3298 
   3299 		SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (),
   3300 													BestQualityFinalWidth  ()));
   3301 
   3302 		}
   3303 
   3304 	if (OriginalDefaultCropSizeH ().NotValid () ||
   3305 		OriginalDefaultCropSizeV ().NotValid ())
   3306 		{
   3307 
   3308 		SetOriginalDefaultCropSize (DefaultCropSizeH (),
   3309 									DefaultCropSizeV ());
   3310 
   3311 		}
   3312 
   3313 	}
   3314 
   3315 /*****************************************************************************/
   3316 
   3317 void dng_negative::PostParse (dng_host &host,
   3318 						  	  dng_stream &stream,
   3319 						  	  dng_info &info)
   3320 	{
   3321 
   3322 	// Shared info.
   3323 
   3324 	dng_shared &shared = *(info.fShared.Get ());
   3325 
   3326 	if (host.NeedsMeta ())
   3327 		{
   3328 
   3329 		// Fill in original sizes if we don't have them already.
   3330 
   3331 		SetDefaultOriginalSizes ();
   3332 
   3333 		// MakerNote.
   3334 
   3335 		if (shared.fMakerNoteCount)
   3336 			{
   3337 
   3338 			// See if we know if the MakerNote is safe or not.
   3339 
   3340 			SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
   3341 
   3342 			// If the MakerNote is safe, preserve it as a MakerNote.
   3343 
   3344 			if (IsMakerNoteSafe ())
   3345 				{
   3346 
   3347 				AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
   3348 
   3349 				stream.SetReadPosition (shared.fMakerNoteOffset);
   3350 
   3351 				stream.Get (block->Buffer (), shared.fMakerNoteCount);
   3352 
   3353 				SetMakerNote (block);
   3354 
   3355 				}
   3356 
   3357 			}
   3358 
   3359 		// IPTC metadata.
   3360 
   3361 		if (shared.fIPTC_NAA_Count)
   3362 			{
   3363 
   3364 			AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
   3365 
   3366 			stream.SetReadPosition (shared.fIPTC_NAA_Offset);
   3367 
   3368 			uint64 iptcOffset = stream.PositionInOriginalFile();
   3369 
   3370 			stream.Get (block->Buffer      (),
   3371 						block->LogicalSize ());
   3372 
   3373 			SetIPTC (block, iptcOffset);
   3374 
   3375 			}
   3376 
   3377 		// XMP metadata.
   3378 
   3379 		#if qDNGUseXMP
   3380 
   3381 		if (shared.fXMPCount)
   3382 			{
   3383 
   3384 			AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount));
   3385 
   3386 			stream.SetReadPosition (shared.fXMPOffset);
   3387 
   3388 			stream.Get (block->Buffer      (),
   3389 						block->LogicalSize ());
   3390 
   3391 			Metadata ().SetEmbeddedXMP (host,
   3392 									    block->Buffer      (),
   3393 									    block->LogicalSize ());
   3394 
   3395 			#if qDNGValidate
   3396 
   3397 			if (!Metadata ().HaveValidEmbeddedXMP ())
   3398 				{
   3399 				ReportError ("The embedded XMP is invalid");
   3400 				}
   3401 
   3402 			#endif
   3403 
   3404 			}
   3405 
   3406 		#endif
   3407 
   3408 		// Color info.
   3409 
   3410 		if (!IsMonochrome ())
   3411 			{
   3412 
   3413 			// If the ColorimetricReference is the ICC profile PCS,
   3414 			// then the data must be already be white balanced to the
   3415 			// ICC profile PCS white point.
   3416 
   3417 			if (ColorimetricReference () == crICCProfilePCS)
   3418 				{
   3419 
   3420 				ClearCameraNeutral ();
   3421 
   3422 				SetCameraWhiteXY (PCStoXY ());
   3423 
   3424 				}
   3425 
   3426 			else
   3427 				{
   3428 
   3429 				// AsShotNeutral.
   3430 
   3431 				if (shared.fAsShotNeutral.Count () == ColorChannels ())
   3432 					{
   3433 
   3434 					SetCameraNeutral (shared.fAsShotNeutral);
   3435 
   3436 					}
   3437 
   3438 				// AsShotWhiteXY.
   3439 
   3440 				if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
   3441 					{
   3442 
   3443 					SetCameraWhiteXY (shared.fAsShotWhiteXY);
   3444 
   3445 					}
   3446 
   3447 				}
   3448 
   3449 			}
   3450 
   3451 		}
   3452 
   3453 	}
   3454 
   3455 /*****************************************************************************/
   3456 
   3457 bool dng_negative::SetFourColorBayer ()
   3458 	{
   3459 
   3460 	if (ColorChannels () != 3)
   3461 		{
   3462 		return false;
   3463 		}
   3464 
   3465 	if (!fMosaicInfo.Get ())
   3466 		{
   3467 		return false;
   3468 		}
   3469 
   3470 	if (!fMosaicInfo.Get ()->SetFourColorBayer ())
   3471 		{
   3472 		return false;
   3473 		}
   3474 
   3475 	SetColorChannels (4);
   3476 
   3477 	if (fCameraNeutral.Count () == 3)
   3478 		{
   3479 
   3480 		dng_vector n (4);
   3481 
   3482 		n [0] = fCameraNeutral [0];
   3483 		n [1] = fCameraNeutral [1];
   3484 		n [2] = fCameraNeutral [2];
   3485 		n [3] = fCameraNeutral [1];
   3486 
   3487 		fCameraNeutral = n;
   3488 
   3489 		}
   3490 
   3491 	fCameraCalibration1.Clear ();
   3492 	fCameraCalibration2.Clear ();
   3493 
   3494 	fCameraCalibrationSignature.Clear ();
   3495 
   3496 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
   3497 		{
   3498 
   3499 		fCameraProfile [index]->SetFourColorBayer ();
   3500 
   3501 		}
   3502 
   3503 	return true;
   3504 
   3505 	}
   3506 
   3507 /*****************************************************************************/
   3508 
   3509 const dng_image & dng_negative::RawImage () const
   3510 	{
   3511 
   3512 	if (fRawImage.Get ())
   3513 		{
   3514 		return *fRawImage.Get ();
   3515 		}
   3516 
   3517 	if (fStage1Image.Get ())
   3518 		{
   3519 		return *fStage1Image.Get ();
   3520 		}
   3521 
   3522 	if (fUnflattenedStage3Image.Get ())
   3523 		{
   3524 		return *fUnflattenedStage3Image.Get ();
   3525 		}
   3526 
   3527 	DNG_ASSERT (fStage3Image.Get (),
   3528 				"dng_negative::RawImage with no raw image");
   3529 
   3530 	return *fStage3Image.Get ();
   3531 
   3532 	}
   3533 
   3534 /*****************************************************************************/
   3535 
   3536 const dng_jpeg_image * dng_negative::RawJPEGImage () const
   3537 	{
   3538 
   3539 	return fRawJPEGImage.Get ();
   3540 
   3541 	}
   3542 
   3543 /*****************************************************************************/
   3544 
   3545 void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage)
   3546 	{
   3547 
   3548 	fRawJPEGImage.Reset (jpegImage.Release ());
   3549 
   3550 	}
   3551 
   3552 /*****************************************************************************/
   3553 
   3554 void dng_negative::ClearRawJPEGImage ()
   3555 	{
   3556 
   3557 	fRawJPEGImage.Reset ();
   3558 
   3559 	}
   3560 
   3561 /*****************************************************************************/
   3562 
   3563 void dng_negative::FindRawJPEGImageDigest (dng_host &host) const
   3564 	{
   3565 
   3566 	if (fRawJPEGImageDigest.IsNull ())
   3567 		{
   3568 
   3569 		if (fRawJPEGImage.Get ())
   3570 			{
   3571 
   3572 			#if qDNGValidate
   3573 
   3574 			dng_timer timer ("FindRawJPEGImageDigest time");
   3575 
   3576 			#endif
   3577 
   3578 			fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host);
   3579 
   3580 			}
   3581 
   3582 		else
   3583 			{
   3584 
   3585 			ThrowProgramError ("No raw JPEG image");
   3586 
   3587 			}
   3588 
   3589 		}
   3590 
   3591 	}
   3592 
   3593 /*****************************************************************************/
   3594 
   3595 void dng_negative::ReadStage1Image (dng_host &host,
   3596 									dng_stream &stream,
   3597 									dng_info &info)
   3598 	{
   3599 
   3600 	// Allocate image we are reading.
   3601 
   3602 	dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
   3603 
   3604 	fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
   3605 											 rawIFD.fSamplesPerPixel,
   3606 											 rawIFD.PixelType ()));
   3607 
   3608 	// See if we should grab the compressed JPEG data.
   3609 
   3610 	AutoPtr<dng_jpeg_image> jpegImage;
   3611 
   3612 	if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 &&
   3613 		!host.PreferredSize () &&
   3614 		!host.ForPreview () &&
   3615 		rawIFD.fCompression == ccLossyJPEG)
   3616 		{
   3617 
   3618 		jpegImage.Reset (new dng_jpeg_image);
   3619 
   3620 		}
   3621 
   3622 	// See if we need to compute the digest of the compressed JPEG data
   3623 	// while reading.
   3624 
   3625 	bool needJPEGDigest = (RawImageDigest    ().IsValid () ||
   3626 						   NewRawImageDigest ().IsValid ()) &&
   3627 						  rawIFD.fCompression == ccLossyJPEG &&
   3628 						  jpegImage.Get () == NULL;
   3629 
   3630 	dng_fingerprint jpegDigest;
   3631 
   3632 	// Read the image.
   3633 
   3634 	rawIFD.ReadImage (host,
   3635 					  stream,
   3636 					  *fStage1Image.Get (),
   3637 					  jpegImage.Get (),
   3638 					  needJPEGDigest ? &jpegDigest : NULL);
   3639 
   3640 	// Remember the raw floating point bit depth, if reading from
   3641 	// a floating point image.
   3642 
   3643 	if (fStage1Image->PixelType () == ttFloat)
   3644 		{
   3645 
   3646 		SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]);
   3647 
   3648 		}
   3649 
   3650 	// Remember the compressed JPEG data if we read it.
   3651 
   3652 	if (jpegImage.Get ())
   3653 		{
   3654 
   3655 		SetRawJPEGImage (jpegImage);
   3656 
   3657 		}
   3658 
   3659 	// Remember the compressed JPEG digest if we computed it.
   3660 
   3661 	if (jpegDigest.IsValid ())
   3662 		{
   3663 
   3664 		SetRawJPEGImageDigest (jpegDigest);
   3665 
   3666 		}
   3667 
   3668 	// We are are reading the main image, we should read the opcode lists
   3669 	// also.
   3670 
   3671 	if (rawIFD.fOpcodeList1Count)
   3672 		{
   3673 
   3674 		#if qDNGValidate
   3675 
   3676 		if (gVerbose)
   3677 			{
   3678 			printf ("\nParsing OpcodeList1: ");
   3679 			}
   3680 
   3681 		#endif
   3682 
   3683 		fOpcodeList1.Parse (host,
   3684 							stream,
   3685 							rawIFD.fOpcodeList1Count,
   3686 							rawIFD.fOpcodeList1Offset);
   3687 
   3688 		}
   3689 
   3690 	if (rawIFD.fOpcodeList2Count)
   3691 		{
   3692 
   3693 		#if qDNGValidate
   3694 
   3695 		if (gVerbose)
   3696 			{
   3697 			printf ("\nParsing OpcodeList2: ");
   3698 			}
   3699 
   3700 		#endif
   3701 
   3702 		fOpcodeList2.Parse (host,
   3703 							stream,
   3704 							rawIFD.fOpcodeList2Count,
   3705 							rawIFD.fOpcodeList2Offset);
   3706 
   3707 		}
   3708 
   3709 	if (rawIFD.fOpcodeList3Count)
   3710 		{
   3711 
   3712 		#if qDNGValidate
   3713 
   3714 		if (gVerbose)
   3715 			{
   3716 			printf ("\nParsing OpcodeList3: ");
   3717 			}
   3718 
   3719 		#endif
   3720 
   3721 		fOpcodeList3.Parse (host,
   3722 							stream,
   3723 							rawIFD.fOpcodeList3Count,
   3724 							rawIFD.fOpcodeList3Offset);
   3725 
   3726 		}
   3727 
   3728 	}
   3729 
   3730 /*****************************************************************************/
   3731 
   3732 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
   3733 	{
   3734 
   3735 	fStage1Image.Reset (image.Release ());
   3736 
   3737 	}
   3738 
   3739 /*****************************************************************************/
   3740 
   3741 void dng_negative::SetStage2Image (AutoPtr<dng_image> &image)
   3742 	{
   3743 
   3744 	fStage2Image.Reset (image.Release ());
   3745 
   3746 	}
   3747 
   3748 /*****************************************************************************/
   3749 
   3750 void dng_negative::SetStage3Image (AutoPtr<dng_image> &image)
   3751 	{
   3752 
   3753 	fStage3Image.Reset (image.Release ());
   3754 
   3755 	}
   3756 
   3757 /*****************************************************************************/
   3758 
   3759 void dng_negative::DoBuildStage2 (dng_host &host)
   3760 	{
   3761 
   3762 	dng_image &stage1 = *fStage1Image.Get ();
   3763 
   3764 	dng_linearization_info &info = *fLinearizationInfo.Get ();
   3765 
   3766 	uint32 pixelType = ttShort;
   3767 
   3768 	if (stage1.PixelType () == ttLong ||
   3769 		stage1.PixelType () == ttFloat)
   3770 		{
   3771 
   3772 		pixelType = ttFloat;
   3773 
   3774 		}
   3775 
   3776 	fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
   3777 											 stage1.Planes (),
   3778 											 pixelType));
   3779 
   3780 	info.Linearize (host,
   3781 					stage1,
   3782 					*fStage2Image.Get ());
   3783 
   3784 	}
   3785 
   3786 /*****************************************************************************/
   3787 
   3788 void dng_negative::DoPostOpcodeList2 (dng_host & /* host */)
   3789 	{
   3790 
   3791 	// Nothing by default.
   3792 
   3793 	}
   3794 
   3795 /*****************************************************************************/
   3796 
   3797 bool dng_negative::NeedDefloatStage2 (dng_host &host)
   3798 	{
   3799 
   3800 	if (fStage2Image->PixelType () == ttFloat)
   3801 		{
   3802 
   3803 		if (fRawImageStage >= rawImageStagePostOpcode2 &&
   3804 			host.SaveDNGVersion () != dngVersion_None  &&
   3805 			host.SaveDNGVersion () <  dngVersion_1_4_0_0)
   3806 			{
   3807 
   3808 			return true;
   3809 
   3810 			}
   3811 
   3812 		}
   3813 
   3814 	return false;
   3815 
   3816 	}
   3817 
   3818 /*****************************************************************************/
   3819 
   3820 void dng_negative::DefloatStage2 (dng_host & /* host */)
   3821 	{
   3822 
   3823 	ThrowNotYetImplemented ("dng_negative::DefloatStage2");
   3824 
   3825 	}
   3826 
   3827 /*****************************************************************************/
   3828 
   3829 void dng_negative::BuildStage2Image (dng_host &host)
   3830 	{
   3831 
   3832 	// If reading the negative to save in DNG format, figure out
   3833 	// when to grab a copy of the raw data.
   3834 
   3835 	if (host.SaveDNGVersion () != dngVersion_None)
   3836 		{
   3837 
   3838 		// Transparency masks are only supported in DNG version 1.4 and
   3839 		// later.  In this case, the flattening of the transparency mask happens
   3840 		// on the the stage3 image.
   3841 
   3842 		if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0)
   3843 			{
   3844 			fRawImageStage = rawImageStagePostOpcode3;
   3845 			}
   3846 
   3847 		else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () ||
   3848 			     fOpcodeList3.AlwaysApply ())
   3849 			{
   3850 			fRawImageStage = rawImageStagePostOpcode3;
   3851 			}
   3852 
   3853 		else if (host.SaveLinearDNG (*this))
   3854 			{
   3855 
   3856 			// If the opcode list 3 has optional tags that are beyond the
   3857 			// the minimum version, and we are saving a linear DNG anyway,
   3858 			// then go ahead and apply them.
   3859 
   3860 			if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ())
   3861 				{
   3862 				fRawImageStage = rawImageStagePostOpcode3;
   3863 				}
   3864 
   3865 			else
   3866 				{
   3867 				fRawImageStage = rawImageStagePreOpcode3;
   3868 				}
   3869 
   3870 			}
   3871 
   3872 		else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () ||
   3873 				 fOpcodeList2.AlwaysApply ())
   3874 			{
   3875 			fRawImageStage = rawImageStagePostOpcode2;
   3876 			}
   3877 
   3878 		else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () ||
   3879 				 fOpcodeList1.AlwaysApply ())
   3880 			{
   3881 			fRawImageStage = rawImageStagePostOpcode1;
   3882 			}
   3883 
   3884 		else
   3885 			{
   3886 			fRawImageStage = rawImageStagePreOpcode1;
   3887 			}
   3888 
   3889 		// We should not save floating point stage1 images unless the target
   3890 		// DNG version is high enough to understand floating point images.
   3891 		// We handle this by converting from floating point to integer if
   3892 		// required after building stage2 image.
   3893 
   3894 		if (fStage1Image->PixelType () == ttFloat)
   3895 			{
   3896 
   3897 			if (fRawImageStage < rawImageStagePostOpcode2)
   3898 				{
   3899 
   3900 				if (host.SaveDNGVersion () < dngVersion_1_4_0_0)
   3901 					{
   3902 
   3903 					fRawImageStage = rawImageStagePostOpcode2;
   3904 
   3905 					}
   3906 
   3907 				}
   3908 
   3909 			}
   3910 
   3911 		}
   3912 
   3913 	// Grab clone of raw image if required.
   3914 
   3915 	if (fRawImageStage == rawImageStagePreOpcode1)
   3916 		{
   3917 
   3918 		fRawImage.Reset (fStage1Image->Clone ());
   3919 
   3920 		if (fTransparencyMask.Get ())
   3921 			{
   3922 			fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
   3923 			}
   3924 
   3925 		}
   3926 
   3927 	else
   3928 		{
   3929 
   3930 		// If we are not keeping the most raw image, we need
   3931 		// to recompute the raw image digest.
   3932 
   3933 		ClearRawImageDigest ();
   3934 
   3935 		// If we don't grab the unprocessed stage 1 image, then
   3936 		// the raw JPEG image is no longer valid.
   3937 
   3938 		ClearRawJPEGImage ();
   3939 
   3940 		// Nor is the digest of the raw JPEG data.
   3941 
   3942 		ClearRawJPEGImageDigest ();
   3943 
   3944 		// We also don't know the raw floating point bit depth.
   3945 
   3946 		SetRawFloatBitDepth (0);
   3947 
   3948 		}
   3949 
   3950 	// Process opcode list 1.
   3951 
   3952 	host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image);
   3953 
   3954 	// See if we are done with the opcode list 1.
   3955 
   3956 	if (fRawImageStage > rawImageStagePreOpcode1)
   3957 		{
   3958 
   3959 		fOpcodeList1.Clear ();
   3960 
   3961 		}
   3962 
   3963 	// Grab clone of raw image if required.
   3964 
   3965 	if (fRawImageStage == rawImageStagePostOpcode1)
   3966 		{
   3967 
   3968 		fRawImage.Reset (fStage1Image->Clone ());
   3969 
   3970 		if (fTransparencyMask.Get ())
   3971 			{
   3972 			fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
   3973 			}
   3974 
   3975 		}
   3976 
   3977 	// Finalize linearization info.
   3978 
   3979 		{
   3980 
   3981 		NeedLinearizationInfo ();
   3982 
   3983 		dng_linearization_info &info = *fLinearizationInfo.Get ();
   3984 
   3985 		info.PostParse (host, *this);
   3986 
   3987 		}
   3988 
   3989 	// Perform the linearization.
   3990 
   3991 	DoBuildStage2 (host);
   3992 
   3993 	// Delete the stage1 image now that we have computed the stage 2 image.
   3994 
   3995 	fStage1Image.Reset ();
   3996 
   3997 	// Are we done with the linearization info.
   3998 
   3999 	if (fRawImageStage > rawImageStagePostOpcode1)
   4000 		{
   4001 
   4002 		ClearLinearizationInfo ();
   4003 
   4004 		}
   4005 
   4006 	// Process opcode list 2.
   4007 
   4008 	host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image);
   4009 
   4010 	// See if we are done with the opcode list 2.
   4011 
   4012 	if (fRawImageStage > rawImageStagePostOpcode1)
   4013 		{
   4014 
   4015 		fOpcodeList2.Clear ();
   4016 
   4017 		}
   4018 
   4019 	// Hook for any required processing just after opcode list 2.
   4020 
   4021 	DoPostOpcodeList2 (host);
   4022 
   4023 	// Convert from floating point to integer if required.
   4024 
   4025 	if (NeedDefloatStage2 (host))
   4026 		{
   4027 
   4028 		DefloatStage2 (host);
   4029 
   4030 		}
   4031 
   4032 	// Grab clone of raw image if required.
   4033 
   4034 	if (fRawImageStage == rawImageStagePostOpcode2)
   4035 		{
   4036 
   4037 		fRawImage.Reset (fStage2Image->Clone ());
   4038 
   4039 		if (fTransparencyMask.Get ())
   4040 			{
   4041 			fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
   4042 			}
   4043 
   4044 		}
   4045 
   4046 	}
   4047 
   4048 /*****************************************************************************/
   4049 
   4050 void dng_negative::DoInterpolateStage3 (dng_host &host,
   4051 								        int32 srcPlane)
   4052 	{
   4053 
   4054 	dng_image &stage2 = *fStage2Image.Get ();
   4055 
   4056 	dng_mosaic_info &info = *fMosaicInfo.Get ();
   4057 
   4058 	dng_point downScale = info.DownScale (host.MinimumSize   (),
   4059 										  host.PreferredSize (),
   4060 										  host.CropFactor    ());
   4061 
   4062 	if (downScale != dng_point (1, 1))
   4063 		{
   4064 		SetIsPreview (true);
   4065 		}
   4066 
   4067 	dng_point dstSize = info.DstSize (downScale);
   4068 
   4069 	fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
   4070 											 info.fColorPlanes,
   4071 											 stage2.PixelType ()));
   4072 
   4073 	if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
   4074 		{
   4075 		srcPlane = 0;
   4076 		}
   4077 
   4078 	info.Interpolate (host,
   4079 					  *this,
   4080 					  stage2,
   4081 					  *fStage3Image.Get (),
   4082 					  downScale,
   4083 					  srcPlane);
   4084 
   4085 	}
   4086 
   4087 /*****************************************************************************/
   4088 
   4089 // Interpolate and merge a multi-channel CFA image.
   4090 
   4091 void dng_negative::DoMergeStage3 (dng_host &host)
   4092 	{
   4093 
   4094 	// The DNG SDK does not provide multi-channel CFA image merging code.
   4095 	// It just grabs the first channel and uses that.
   4096 
   4097 	DoInterpolateStage3 (host, 0);
   4098 
   4099 	// Just grabbing the first channel would often result in the very
   4100 	// bright image using the baseline exposure value.
   4101 
   4102 	fStage3Gain = pow (2.0, BaselineExposure ());
   4103 
   4104 	}
   4105 
   4106 /*****************************************************************************/
   4107 
   4108 void dng_negative::DoBuildStage3 (dng_host &host,
   4109 								  int32 srcPlane)
   4110 	{
   4111 
   4112 	// If we don't have a mosaic pattern, then just move the stage 2
   4113 	// image on to stage 3.
   4114 
   4115 	dng_mosaic_info *info = fMosaicInfo.Get ();
   4116 
   4117 	if (!info || !info->IsColorFilterArray ())
   4118 		{
   4119 
   4120 		fStage3Image.Reset (fStage2Image.Release ());
   4121 
   4122 		}
   4123 
   4124 	else
   4125 		{
   4126 
   4127 		// Remember the size of the stage 2 image.
   4128 
   4129 		dng_point stage2_size = fStage2Image->Size ();
   4130 
   4131 		// Special case multi-channel CFA interpolation.
   4132 
   4133 		if ((fStage2Image->Planes () > 1) && (srcPlane < 0))
   4134 			{
   4135 
   4136 			DoMergeStage3 (host);
   4137 
   4138 			}
   4139 
   4140 		// Else do a single channel interpolation.
   4141 
   4142 		else
   4143 			{
   4144 
   4145 			DoInterpolateStage3 (host, srcPlane);
   4146 
   4147 			}
   4148 
   4149 		// Calculate the ratio of the stage 3 image size to stage 2 image size.
   4150 
   4151 		dng_point stage3_size = fStage3Image->Size ();
   4152 
   4153 		fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
   4154 		fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
   4155 
   4156 		}
   4157 
   4158 	}
   4159 
   4160 /*****************************************************************************/
   4161 
   4162 void dng_negative::BuildStage3Image (dng_host &host,
   4163 									 int32 srcPlane)
   4164 	{
   4165 
   4166 	// Finalize the mosaic information.
   4167 
   4168 	dng_mosaic_info *info = fMosaicInfo.Get ();
   4169 
   4170 	if (info)
   4171 		{
   4172 
   4173 		info->PostParse (host, *this);
   4174 
   4175 		}
   4176 
   4177 	// Do the interpolation as required.
   4178 
   4179 	DoBuildStage3 (host, srcPlane);
   4180 
   4181 	// Delete the stage2 image now that we have computed the stage 3 image.
   4182 
   4183 	fStage2Image.Reset ();
   4184 
   4185 	// Are we done with the mosaic info?
   4186 
   4187 	if (fRawImageStage >= rawImageStagePreOpcode3)
   4188 		{
   4189 
   4190 		ClearMosaicInfo ();
   4191 
   4192 		// To support saving linear DNG files, to need to account for
   4193 		// and upscaling during interpolation.
   4194 
   4195 		if (fRawToFullScaleH > 1.0)
   4196 			{
   4197 
   4198 			uint32 adjust = Round_uint32 (fRawToFullScaleH);
   4199 
   4200 			fDefaultCropSizeH  .n =
   4201 				SafeUint32Mult (fDefaultCropSizeH.n, adjust);
   4202 			fDefaultCropOriginH.n =
   4203 				SafeUint32Mult (fDefaultCropOriginH.n, adjust);
   4204 			fDefaultScaleH     .d = SafeUint32Mult (fDefaultScaleH.d, adjust);
   4205 
   4206 			fRawToFullScaleH /= (real64) adjust;
   4207 
   4208 			}
   4209 
   4210 		if (fRawToFullScaleV > 1.0)
   4211 			{
   4212 
   4213 			uint32 adjust = Round_uint32 (fRawToFullScaleV);
   4214 
   4215 			fDefaultCropSizeV  .n =
   4216 				SafeUint32Mult (fDefaultCropSizeV.n, adjust);
   4217 			fDefaultCropOriginV.n =
   4218 				SafeUint32Mult (fDefaultCropOriginV.n, adjust);
   4219 			fDefaultScaleV     .d =
   4220 				SafeUint32Mult (fDefaultScaleV.d, adjust);
   4221 
   4222 			fRawToFullScaleV /= (real64) adjust;
   4223 
   4224 			}
   4225 
   4226 		}
   4227 
   4228 	// Resample the transparency mask if required.
   4229 
   4230 	ResizeTransparencyToMatchStage3 (host);
   4231 
   4232 	// Grab clone of raw image if required.
   4233 
   4234 	if (fRawImageStage == rawImageStagePreOpcode3)
   4235 		{
   4236 
   4237 		fRawImage.Reset (fStage3Image->Clone ());
   4238 
   4239 		if (fTransparencyMask.Get ())
   4240 			{
   4241 			fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
   4242 			}
   4243 
   4244 		}
   4245 
   4246 	// Process opcode list 3.
   4247 
   4248 	host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image);
   4249 
   4250 	// See if we are done with the opcode list 3.
   4251 
   4252 	if (fRawImageStage > rawImageStagePreOpcode3)
   4253 		{
   4254 
   4255 		fOpcodeList3.Clear ();
   4256 
   4257 		}
   4258 
   4259 	// Just in case the opcode list 3 changed the image size, resample the
   4260 	// transparency mask again if required.  This is nearly always going
   4261 	// to be a fast NOP operation.
   4262 
   4263 	ResizeTransparencyToMatchStage3 (host);
   4264 
   4265 	// Don't need to grab a copy of raw data at this stage since
   4266 	// it is kept around as the stage 3 image.
   4267 
   4268 	}
   4269 
   4270 /******************************************************************************/
   4271 
   4272 class dng_gamma_encode_proxy : public dng_1d_function
   4273 	{
   4274 
   4275 	private:
   4276 
   4277 		real64 fBlack;
   4278 		real64 fWhite;
   4279 
   4280 		bool fIsSceneReferred;
   4281 
   4282 		real64 scale;
   4283 		real64 t1;
   4284 
   4285 	public:
   4286 
   4287 		dng_gamma_encode_proxy (real64 black,
   4288 							    real64 white,
   4289 							    bool isSceneReferred)
   4290 
   4291 			:	fBlack (black)
   4292 			,	fWhite (white)
   4293 			,	fIsSceneReferred (isSceneReferred)
   4294 
   4295 			,	scale (1.0 / (fWhite - fBlack))
   4296 			,	t1 (1.0 / (27.0 * pow (5.0, 3.0 / 2.0)))
   4297 
   4298 			{
   4299 			}
   4300 
   4301 		virtual real64 Evaluate (real64 x) const
   4302 			{
   4303 
   4304 			x = Pin_real64 (0.0, (x - fBlack) * scale, 1.0);
   4305 
   4306 			real64 y;
   4307 
   4308 			if (fIsSceneReferred)
   4309 				{
   4310 
   4311 				real64 t = pow (sqrt (25920.0 * x * x + 1.0) * t1 + x * (8.0 / 15.0), 1.0 / 3.0);
   4312 
   4313 				y = t - 1.0 / (45.0 * t);
   4314 
   4315 				DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * y * 15.0 / 16.0)) < 0.0000001,
   4316 							"Round trip error");
   4317 
   4318 				}
   4319 
   4320 			else
   4321 				{
   4322 
   4323 				y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0;
   4324 
   4325 				DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * (15.0 / 16.0))) < 0.0000001,
   4326 							"Round trip error");
   4327 
   4328 				}
   4329 
   4330 			return y;
   4331 
   4332 			}
   4333 
   4334 	};
   4335 
   4336 /*****************************************************************************/
   4337 
   4338 class dng_encode_proxy_task: public dng_area_task
   4339 	{
   4340 
   4341 	private:
   4342 
   4343 		const dng_image &fSrcImage;
   4344 
   4345 		dng_image &fDstImage;
   4346 
   4347 		AutoPtr<dng_memory_block> fTable16 [kMaxColorPlanes];
   4348 
   4349 	public:
   4350 
   4351 		dng_encode_proxy_task (dng_host &host,
   4352 							   const dng_image &srcImage,
   4353 							   dng_image &dstImage,
   4354 							   const real64 *black,
   4355 							   const real64 *white,
   4356 							   bool isSceneReferred);
   4357 
   4358 		virtual dng_rect RepeatingTile1 () const
   4359 			{
   4360 			return fSrcImage.RepeatingTile ();
   4361 			}
   4362 
   4363 		virtual dng_rect RepeatingTile2 () const
   4364 			{
   4365 			return fDstImage.RepeatingTile ();
   4366 			}
   4367 
   4368 		virtual void Process (uint32 threadIndex,
   4369 							  const dng_rect &tile,
   4370 							  dng_abort_sniffer *sniffer);
   4371 
   4372 	private:
   4373 
   4374 		// Hidden copy constructor and assignment operator.
   4375 
   4376 		dng_encode_proxy_task (const dng_encode_proxy_task &task);
   4377 
   4378 		dng_encode_proxy_task & operator= (const dng_encode_proxy_task &task);
   4379 
   4380 	};
   4381 
   4382 /*****************************************************************************/
   4383 
   4384 dng_encode_proxy_task::dng_encode_proxy_task (dng_host &host,
   4385 											  const dng_image &srcImage,
   4386 										      dng_image &dstImage,
   4387 										      const real64 *black,
   4388 										      const real64 *white,
   4389 										      bool isSceneReferred)
   4390 
   4391 	:	fSrcImage (srcImage)
   4392 	,	fDstImage (dstImage)
   4393 
   4394 	{
   4395 
   4396 	for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
   4397 		{
   4398 
   4399 		dng_gamma_encode_proxy gamma (black [plane],
   4400 									  white [plane],
   4401 									  isSceneReferred);
   4402 
   4403 		dng_1d_table table32;
   4404 
   4405 		table32.Initialize (host.Allocator (), gamma);
   4406 
   4407 		fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16)));
   4408 
   4409 		table32.Expand16 (fTable16 [plane]->Buffer_uint16 ());
   4410 
   4411 		}
   4412 
   4413 	}
   4414 
   4415 /*****************************************************************************/
   4416 
   4417 void dng_encode_proxy_task::Process (uint32 /* threadIndex */,
   4418 								     const dng_rect &tile,
   4419 							  	     dng_abort_sniffer * /* sniffer */)
   4420 	{
   4421 
   4422 	dng_const_tile_buffer srcBuffer (fSrcImage, tile);
   4423 	dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
   4424 
   4425 	int32 sColStep = srcBuffer.fColStep;
   4426 	int32 dColStep = dstBuffer.fColStep;
   4427 
   4428 	const uint16 *noise = dng_dither::Get ().NoiseBuffer16 ();
   4429 
   4430 	for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
   4431 		{
   4432 
   4433 		const uint16 *map = fTable16 [plane]->Buffer_uint16 ();
   4434 
   4435 		for (int32 row = tile.t; row < tile.b; row++)
   4436 			{
   4437 
   4438 			const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane);
   4439 
   4440 			uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane);
   4441 
   4442 			const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize];
   4443 
   4444 			for (int32 col = tile.l; col < tile.r; col++)
   4445 				{
   4446 
   4447 				uint32 x = *sPtr;
   4448 
   4449 				uint32 r = rPtr [col & dng_dither::kRNGMask];
   4450 
   4451 				x = map [x];
   4452 
   4453 				x = (((x << 8) - x) + r) >> 16;
   4454 
   4455 				*dPtr = (uint8) x;
   4456 
   4457 				sPtr += sColStep;
   4458 				dPtr += dColStep;
   4459 
   4460 				}
   4461 
   4462 			}
   4463 
   4464 		}
   4465 
   4466 	}
   4467 
   4468 /******************************************************************************/
   4469 
   4470 dng_image * dng_negative::EncodeRawProxy (dng_host &host,
   4471 										  const dng_image &srcImage,
   4472 										  dng_opcode_list &opcodeList) const
   4473 	{
   4474 
   4475 	if (srcImage.PixelType () != ttShort)
   4476 		{
   4477 		return NULL;
   4478 		}
   4479 
   4480 	real64 black [kMaxColorPlanes];
   4481 	real64 white [kMaxColorPlanes];
   4482 
   4483 	bool isSceneReferred = (ColorimetricReference () == crSceneReferred);
   4484 
   4485 		{
   4486 
   4487 		const real64 kClipFraction = 0.00001;
   4488 
   4489 		uint64 pixels = (uint64) srcImage.Bounds ().H () *
   4490 						(uint64) srcImage.Bounds ().W ();
   4491 
   4492 		uint32 limit = Round_int32 ((real64) pixels * kClipFraction);
   4493 
   4494 		AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32)));
   4495 
   4496 		uint32 *hist = histData->Buffer_uint32 ();
   4497 
   4498 		for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
   4499 			{
   4500 
   4501 			HistogramArea (host,
   4502 						   srcImage,
   4503 						   srcImage.Bounds (),
   4504 						   hist,
   4505 						   65535,
   4506 						   plane);
   4507 
   4508 			uint32 total = 0;
   4509 
   4510 			uint32 upper = 65535;
   4511 
   4512 			while (total + hist [upper] <= limit && upper > 255)
   4513 				{
   4514 
   4515 				total += hist [upper];
   4516 
   4517 				upper--;
   4518 
   4519 				}
   4520 
   4521 			total = 0;
   4522 
   4523 			uint32 lower = 0;
   4524 
   4525 			while (total + hist [lower] <= limit && lower < upper - 255)
   4526 				{
   4527 
   4528 				total += hist [lower];
   4529 
   4530 				lower++;
   4531 
   4532 				}
   4533 
   4534 			black [plane] = lower / 65535.0;
   4535 			white [plane] = upper / 65535.0;
   4536 
   4537 			}
   4538 
   4539 		}
   4540 
   4541 	// Apply the gamma encoding, using dither when downsampling to 8-bit.
   4542 
   4543 	AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (),
   4544 													  srcImage.Planes (),
   4545 													  ttByte));
   4546 
   4547 		{
   4548 
   4549 		dng_encode_proxy_task task (host,
   4550 							        srcImage,
   4551 									*dstImage,
   4552 									black,
   4553 									white,
   4554 									isSceneReferred);
   4555 
   4556 		host.PerformAreaTask (task,
   4557 							  srcImage.Bounds ());
   4558 
   4559 		}
   4560 
   4561 	// Add opcodes to undo the gamma encoding.
   4562 
   4563 		{
   4564 
   4565 		for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
   4566 			{
   4567 
   4568 			dng_area_spec areaSpec (srcImage.Bounds (),
   4569 									plane);
   4570 
   4571 			real64 coefficient [4];
   4572 
   4573 			coefficient [0] = 0.0;
   4574 			coefficient [1] = 1.0 / 16.0;
   4575 
   4576 			if (isSceneReferred)
   4577 				{
   4578 				coefficient [2] = 0.0;
   4579 				coefficient [3] = 15.0 / 16.0;
   4580 				}
   4581 			else
   4582 				{
   4583 				coefficient [2] = 15.0 / 16.0;
   4584 				coefficient [3] = 0.0;
   4585 				}
   4586 
   4587 			coefficient [0] *= white [plane] - black [plane];
   4588 			coefficient [1] *= white [plane] - black [plane];
   4589 			coefficient [2] *= white [plane] - black [plane];
   4590 			coefficient [3] *= white [plane] - black [plane];
   4591 
   4592 			coefficient [0] += black [plane];
   4593 
   4594 			AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec,
   4595 																	  isSceneReferred ? 3 : 2,
   4596 																	  coefficient));
   4597 
   4598 			opcodeList.Append (opcode);
   4599 
   4600 			}
   4601 
   4602 		}
   4603 
   4604 	return dstImage.Release ();
   4605 
   4606 	}
   4607 
   4608 /******************************************************************************/
   4609 
   4610 void dng_negative::AdjustProfileForStage3 ()
   4611 	{
   4612 
   4613 	// For dng_sdk, the stage3 image's color space is always the same as the
   4614 	// raw image's color space.
   4615 
   4616 	}
   4617 
   4618 /******************************************************************************/
   4619 
   4620 void dng_negative::ConvertToProxy (dng_host &host,
   4621 								   dng_image_writer &writer,
   4622 								   uint32 proxySize,
   4623 								   uint64 proxyCount)
   4624 	{
   4625 
   4626 	if (!proxySize)
   4627 		{
   4628 		proxySize = kMaxImageSide;
   4629 		}
   4630 
   4631 	if (!proxyCount)
   4632 		{
   4633 		proxyCount = (uint64) proxySize * proxySize;
   4634 		}
   4635 
   4636 	// Don't need to private data around in non-full size proxies.
   4637 
   4638 	if (proxySize  < kMaxImageSide ||
   4639 		proxyCount < kMaxImageSide * kMaxImageSide)
   4640 		{
   4641 
   4642 		ClearMakerNote ();
   4643 
   4644 		ClearPrivateData ();
   4645 
   4646 		}
   4647 
   4648 	// See if we already have an acceptable proxy image.
   4649 
   4650 	if (fRawImage.Get () &&
   4651 		fRawImage->PixelType () == ttByte &&
   4652 		fRawImage->Bounds () == DefaultCropArea () &&
   4653 		fRawImage->Bounds ().H () <= proxySize &&
   4654 		fRawImage->Bounds ().W () <= proxySize &&
   4655 		(uint64) fRawImage->Bounds ().H () *
   4656 		(uint64) fRawImage->Bounds ().W () <= proxyCount &&
   4657 		(!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) &&
   4658 		fRawJPEGImage.Get () &&
   4659 		(!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
   4660 		{
   4661 
   4662 		return;
   4663 
   4664 		}
   4665 
   4666 	if (fRawImage.Get () &&
   4667 		fRawImage->PixelType () == ttFloat &&
   4668 		fRawImage->Bounds ().H () <= proxySize &&
   4669 		fRawImage->Bounds ().W () <= proxySize &&
   4670 		(uint64) fRawImage->Bounds ().H () *
   4671 		(uint64) fRawImage->Bounds ().W () <= proxyCount &&
   4672 		RawFloatBitDepth () == 16 &&
   4673 		(!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
   4674 		{
   4675 
   4676 		return;
   4677 
   4678 		}
   4679 
   4680 	// Clear any grabbed raw image, since we are going to start
   4681 	// building the proxy with the stage3 image.
   4682 
   4683 	fRawImage.Reset ();
   4684 
   4685 	ClearRawJPEGImage ();
   4686 
   4687 	SetRawFloatBitDepth (0);
   4688 
   4689 	ClearLinearizationInfo ();
   4690 
   4691 	ClearMosaicInfo ();
   4692 
   4693 	fOpcodeList1.Clear ();
   4694 	fOpcodeList2.Clear ();
   4695 	fOpcodeList3.Clear ();
   4696 
   4697 	// Adjust the profile to match the stage 3 image, if required.
   4698 
   4699 	AdjustProfileForStage3 ();
   4700 
   4701 	// Not saving the raw-most image, do the old raw digest is no
   4702 	// longer valid.
   4703 
   4704 	ClearRawImageDigest ();
   4705 
   4706 	ClearRawJPEGImageDigest ();
   4707 
   4708 	// Trim off extra pixels outside the default crop area.
   4709 
   4710 	dng_rect defaultCropArea = DefaultCropArea ();
   4711 
   4712 	if (Stage3Image ()->Bounds () != defaultCropArea)
   4713 		{
   4714 
   4715 		fStage3Image->Trim (defaultCropArea);
   4716 
   4717 		if (fTransparencyMask.Get ())
   4718 			{
   4719 			fTransparencyMask->Trim (defaultCropArea);
   4720 			}
   4721 
   4722 		fDefaultCropOriginH = dng_urational (0, 1);
   4723 		fDefaultCropOriginV = dng_urational (0, 1);
   4724 
   4725 		}
   4726 
   4727 	// Figure out the requested proxy pixel size.
   4728 
   4729 	real64 aspectRatio = AspectRatio ();
   4730 
   4731 	dng_point newSize (proxySize, proxySize);
   4732 
   4733 	if (aspectRatio >= 1.0)
   4734 		{
   4735 		newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio));
   4736 		}
   4737 	else
   4738 		{
   4739 		newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio));
   4740 		}
   4741 
   4742 	newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ());
   4743 	newSize.h = Min_int32 (newSize.h, DefaultFinalWidth  ());
   4744 
   4745 	if ((uint64) newSize.v *
   4746 	    (uint64) newSize.h > proxyCount)
   4747 		{
   4748 
   4749 		if (aspectRatio >= 1.0)
   4750 			{
   4751 
   4752 			newSize.h = (uint32) sqrt (proxyCount * aspectRatio);
   4753 
   4754 			newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio));
   4755 
   4756 			}
   4757 
   4758 		else
   4759 			{
   4760 
   4761 			newSize.v = (uint32) sqrt (proxyCount / aspectRatio);
   4762 
   4763 			newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio));
   4764 
   4765 			}
   4766 
   4767 		}
   4768 
   4769 	// If this is fewer pixels, downsample the stage 3 image to that size.
   4770 
   4771 	dng_point oldSize = defaultCropArea.Size ();
   4772 
   4773 	if ((uint64) newSize.v * (uint64) newSize.h <
   4774 		(uint64) oldSize.v * (uint64) oldSize.h)
   4775 		{
   4776 
   4777 		const dng_image &srcImage (*Stage3Image ());
   4778 
   4779 		AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize,
   4780 														  srcImage.Planes (),
   4781 														  srcImage.PixelType ()));
   4782 
   4783 		host.ResampleImage (srcImage,
   4784 							*dstImage);
   4785 
   4786 		fStage3Image.Reset (dstImage.Release ());
   4787 
   4788 		fDefaultCropSizeH = dng_urational (newSize.h, 1);
   4789 		fDefaultCropSizeV = dng_urational (newSize.v, 1);
   4790 
   4791 		fDefaultScaleH = dng_urational (1, 1);
   4792 		fDefaultScaleV = dng_urational (1, 1);
   4793 
   4794 		fBestQualityScale = dng_urational (1, 1);
   4795 
   4796 		fRawToFullScaleH = 1.0;
   4797 		fRawToFullScaleV = 1.0;
   4798 
   4799 		}
   4800 
   4801 	// Convert 32-bit floating point images to 16-bit floating point to
   4802 	// save space.
   4803 
   4804 	if (Stage3Image ()->PixelType () == ttFloat)
   4805 		{
   4806 
   4807 		fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (),
   4808 											  Stage3Image ()->Planes (),
   4809 											  ttFloat));
   4810 
   4811 		LimitFloatBitDepth (host,
   4812 							*Stage3Image (),
   4813 							*fRawImage,
   4814 							16,
   4815 							32768.0f);
   4816 
   4817 		SetRawFloatBitDepth (16);
   4818 
   4819 		SetWhiteLevel (32768);
   4820 
   4821 		}
   4822 
   4823 	else
   4824 		{
   4825 
   4826 		// Convert 16-bit deep images to 8-bit deep image for saving.
   4827 
   4828 		fRawImage.Reset (EncodeRawProxy (host,
   4829 										 *Stage3Image (),
   4830 										 fOpcodeList2));
   4831 
   4832 		if (fRawImage.Get ())
   4833 			{
   4834 
   4835 			SetWhiteLevel (255);
   4836 
   4837 			// Compute JPEG compressed version.
   4838 
   4839 			if (fRawImage->PixelType () == ttByte &&
   4840 				host.SaveDNGVersion () >= dngVersion_1_4_0_0)
   4841 				{
   4842 
   4843 				AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image);
   4844 
   4845 				jpegImage->Encode (host,
   4846 								   *this,
   4847 								   writer,
   4848 								   *fRawImage);
   4849 
   4850 				SetRawJPEGImage (jpegImage);
   4851 
   4852 				}
   4853 
   4854 			}
   4855 
   4856 		}
   4857 
   4858 	// Deal with transparency mask.
   4859 
   4860 	if (TransparencyMask ())
   4861 		{
   4862 
   4863 		const bool convertTo8Bit = true;
   4864 
   4865 		ResizeTransparencyToMatchStage3 (host, convertTo8Bit);
   4866 
   4867 		fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
   4868 
   4869 		}
   4870 
   4871 	// Recompute the raw data unique ID, since we changed the image data.
   4872 
   4873 	RecomputeRawDataUniqueID (host);
   4874 
   4875 	}
   4876 
   4877 /*****************************************************************************/
   4878 
   4879 dng_linearization_info * dng_negative::MakeLinearizationInfo ()
   4880 	{
   4881 
   4882 	dng_linearization_info *info = new dng_linearization_info ();
   4883 
   4884 	if (!info)
   4885 		{
   4886 		ThrowMemoryFull ();
   4887 		}
   4888 
   4889 	return info;
   4890 
   4891 	}
   4892 
   4893 /*****************************************************************************/
   4894 
   4895 void dng_negative::NeedLinearizationInfo ()
   4896 	{
   4897 
   4898 	if (!fLinearizationInfo.Get ())
   4899 		{
   4900 
   4901 		fLinearizationInfo.Reset (MakeLinearizationInfo ());
   4902 
   4903 		}
   4904 
   4905 	}
   4906 
   4907 /*****************************************************************************/
   4908 
   4909 dng_mosaic_info * dng_negative::MakeMosaicInfo ()
   4910 	{
   4911 
   4912 	dng_mosaic_info *info = new dng_mosaic_info ();
   4913 
   4914 	if (!info)
   4915 		{
   4916 		ThrowMemoryFull ();
   4917 		}
   4918 
   4919 	return info;
   4920 
   4921 	}
   4922 
   4923 /*****************************************************************************/
   4924 
   4925 void dng_negative::NeedMosaicInfo ()
   4926 	{
   4927 
   4928 	if (!fMosaicInfo.Get ())
   4929 		{
   4930 
   4931 		fMosaicInfo.Reset (MakeMosaicInfo ());
   4932 
   4933 		}
   4934 
   4935 	}
   4936 
   4937 /*****************************************************************************/
   4938 
   4939 void dng_negative::SetTransparencyMask (AutoPtr<dng_image> &image,
   4940 										uint32 bitDepth)
   4941 	{
   4942 
   4943 	fTransparencyMask.Reset (image.Release ());
   4944 
   4945 	fRawTransparencyMaskBitDepth = bitDepth;
   4946 
   4947 	}
   4948 
   4949 /*****************************************************************************/
   4950 
   4951 const dng_image * dng_negative::TransparencyMask () const
   4952 	{
   4953 
   4954 	return fTransparencyMask.Get ();
   4955 
   4956 	}
   4957 
   4958 /*****************************************************************************/
   4959 
   4960 const dng_image * dng_negative::RawTransparencyMask () const
   4961 	{
   4962 
   4963 	if (fRawTransparencyMask.Get ())
   4964 		{
   4965 
   4966 		return fRawTransparencyMask.Get ();
   4967 
   4968 		}
   4969 
   4970 	return TransparencyMask ();
   4971 
   4972 	}
   4973 
   4974 /*****************************************************************************/
   4975 
   4976 uint32 dng_negative::RawTransparencyMaskBitDepth () const
   4977 	{
   4978 
   4979 	if (fRawTransparencyMaskBitDepth)
   4980 		{
   4981 
   4982 		return fRawTransparencyMaskBitDepth;
   4983 
   4984 		}
   4985 
   4986 	const dng_image *mask = RawTransparencyMask ();
   4987 
   4988 	if (mask)
   4989 		{
   4990 
   4991 		switch (mask->PixelType ())
   4992 			{
   4993 
   4994 			case ttByte:
   4995 				return 8;
   4996 
   4997 			case ttShort:
   4998 				return 16;
   4999 
   5000 			case ttFloat:
   5001 				return 32;
   5002 
   5003 			default:
   5004 				ThrowProgramError ();
   5005 
   5006 			}
   5007 
   5008 		}
   5009 
   5010 	return 0;
   5011 
   5012 	}
   5013 
   5014 /*****************************************************************************/
   5015 
   5016 void dng_negative::ReadTransparencyMask (dng_host &host,
   5017 									     dng_stream &stream,
   5018 									     dng_info &info)
   5019 	{
   5020 
   5021 	if (info.fMaskIndex != -1)
   5022 		{
   5023 
   5024 		// Allocate image we are reading.
   5025 
   5026 		dng_ifd &maskIFD = *info.fIFD [info.fMaskIndex].Get ();
   5027 
   5028 		fTransparencyMask.Reset (host.Make_dng_image (maskIFD.Bounds (),
   5029 													  1,
   5030 													  maskIFD.PixelType ()));
   5031 
   5032 		// Read the image.
   5033 
   5034 		maskIFD.ReadImage (host,
   5035 						   stream,
   5036 						   *fTransparencyMask.Get ());
   5037 
   5038 		// Remember the pixel depth.
   5039 
   5040 		fRawTransparencyMaskBitDepth = maskIFD.fBitsPerSample [0];
   5041 
   5042 		}
   5043 
   5044 	}
   5045 
   5046 /*****************************************************************************/
   5047 
   5048 void dng_negative::ResizeTransparencyToMatchStage3 (dng_host &host,
   5049 													bool convertTo8Bit)
   5050 	{
   5051 
   5052 	if (TransparencyMask ())
   5053 		{
   5054 
   5055 		if ((TransparencyMask ()->Bounds () != fStage3Image->Bounds ()) ||
   5056 			(TransparencyMask ()->PixelType () != ttByte && convertTo8Bit))
   5057 			{
   5058 
   5059 			AutoPtr<dng_image> newMask (host.Make_dng_image (fStage3Image->Bounds (),
   5060 															 1,
   5061 															 convertTo8Bit ?
   5062 															 ttByte :
   5063 															 TransparencyMask ()->PixelType ()));
   5064 
   5065 			host.ResampleImage (*TransparencyMask (),
   5066 								*newMask);
   5067 
   5068 			fTransparencyMask.Reset (newMask.Release ());
   5069 
   5070 			if (!fRawTransparencyMask.Get ())
   5071 				{
   5072 				fRawTransparencyMaskBitDepth = 0;
   5073 				}
   5074 
   5075 			}
   5076 
   5077 		}
   5078 
   5079 	}
   5080 
   5081 /*****************************************************************************/
   5082 
   5083 bool dng_negative::NeedFlattenTransparency (dng_host & /* host */)
   5084 	{
   5085 
   5086 	if (TransparencyMask ())
   5087 		{
   5088 
   5089 		return true;
   5090 
   5091 		}
   5092 
   5093 	return false;
   5094 
   5095 	}
   5096 
   5097 /*****************************************************************************/
   5098 
   5099 void dng_negative::FlattenTransparency (dng_host & /* host */)
   5100 	{
   5101 
   5102 	ThrowNotYetImplemented ();
   5103 
   5104 	}
   5105 
   5106 /*****************************************************************************/
   5107 
   5108 const dng_image * dng_negative::UnflattenedStage3Image () const
   5109 	{
   5110 
   5111 	if (fUnflattenedStage3Image.Get ())
   5112 		{
   5113 
   5114 		return fUnflattenedStage3Image.Get ();
   5115 
   5116 		}
   5117 
   5118 	return fStage3Image.Get ();
   5119 
   5120 	}
   5121 
   5122 /*****************************************************************************/
   5123