1 /*****************************************************************************/
2 // Copyright 2006-2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8 
9 /* $Id: //mondo/dng_sdk_1_2/dng_sdk/source/dng_negative.cpp#2 $ */
10 /* $DateTime: 2008/04/02 14:06:57 $ */
11 /* $Change: 440485 $ */
12 /* $Author: tknoll $ */
13 
14 /*****************************************************************************/
15 
16 #include "dng_negative.h"
17 
18 #include "dng_abort_sniffer.h"
19 #include "dng_bottlenecks.h"
20 #include "dng_camera_profile.h"
21 #include "dng_color_spec.h"
22 #include "dng_exceptions.h"
23 #include "dng_host.h"
24 #include "dng_image.h"
25 #include "dng_image_writer.h"
26 #include "dng_info.h"
27 #include "dng_linearization_info.h"
28 #include "dng_memory_stream.h"
29 #include "dng_mosaic_info.h"
30 #include "dng_simple_image.h"
31 #include "dng_tag_codes.h"
32 #include "dng_tag_values.h"
33 #include "dng_tile_iterator.h"
34 #include "dng_xmp.h"
35 
36 /*****************************************************************************/
37 
dng_negative(dng_memory_allocator & allocator)38 dng_negative::dng_negative (dng_memory_allocator &allocator)
39 
40 	:	fAllocator (allocator)
41 
42 	,	fModelName		    		()
43 	,	fLocalName		    		()
44 	,	fHasBaseOrientation 		(false)
45 	,	fBaseOrientation    		()
46 	,	fDefaultCropSizeH   		()
47 	,	fDefaultCropSizeV			()
48 	,	fDefaultCropOriginH 		(0, 1)
49 	,	fDefaultCropOriginV 		(0, 1)
50 	,	fDefaultScaleH      		(1, 1)
51 	,	fDefaultScaleV				(1, 1)
52 	,	fBestQualityScale			(1, 1)
53 	,	fRawToFullScaleH			(1.0)
54 	,	fRawToFullScaleV			(1.0)
55 	,	fBaselineNoise	    		(100, 100)
56 	,	fNoiseReductionApplied		(0, 0)
57 	,	fBaselineExposure			(  0, 100)
58 	,	fBaselineSharpness			(100, 100)
59 	,	fChromaBlurRadius			()
60 	,	fAntiAliasStrength			(100, 100)
61 	,	fLinearResponseLimit		(100, 100)
62 	,	fShadowScale				(1, 1)
63 	,	fColorimetricReference  	(crSceneReferred)
64 	,	fColorChannels				(0)
65 	,	fAnalogBalance				()
66 	,	fCameraNeutral				()
67 	,	fCameraWhiteXY				()
68 	,	fCameraCalibration1			()
69 	,	fCameraCalibration2			()
70 	,	fCameraCalibrationSignature ()
71 	,	fCameraProfile				()
72 	,	fAsShotProfileName			()
73 	,	fRawImageDigest				()
74 	,	fRawDataUniqueID    		()
75 	,	fOriginalRawFileName		()
76 	,	fHasOriginalRawFileData 	(false)
77 	,	fOriginalRawFileData    	()
78 	,	fOriginalRawFileDigest		()
79 	,	fDNGPrivateData				()
80 	,	fIsMakerNoteSafe			(false)
81 	,	fMakerNote					()
82 	,	fExif			    		()
83 	,	fOriginalExif				()
84 	,	fIPTCBlock          		()
85 	,	fIPTCOffset					(kDNGStreamInvalidOffset)
86 	,	fXMP			    		()
87 	,	fValidEmbeddedXMP       	(false)
88 	,	fXMPinSidecar	    		(false)
89 	,	fXMPisNewer		    		(false)
90 	,	fLinearizationInfo  		()
91 	,	fMosaicInfo         		()
92 	,	fStage1Image        		()
93 	,	fStage2Image        		()
94 	,	fStage3Image        		()
95 	,	fStage3Gain					(1.0)
96 	,	fIsPreview					(false)
97 	,	fIsDamaged					(false)
98 
99 	{
100 
101 	}
102 
103 /*****************************************************************************/
104 
~dng_negative()105 dng_negative::~dng_negative ()
106 	{
107 
108 	// Delete any camera profiles owned by this negative.
109 
110 	ClearProfiles ();
111 
112 	}
113 
114 /******************************************************************************/
115 
Initialize()116 void dng_negative::Initialize ()
117 	{
118 
119 	fExif.Reset (MakeExif ());
120 
121 	fXMP.Reset (MakeXMP ());
122 
123 	}
124 
125 /******************************************************************************/
126 
Make(dng_memory_allocator & allocator)127 dng_negative * dng_negative::Make (dng_memory_allocator &allocator)
128 	{
129 
130 	AutoPtr<dng_negative> result (new dng_negative (allocator));
131 
132 	if (!result.Get ())
133 		{
134 		ThrowMemoryFull ();
135 		}
136 
137 	result->Initialize ();
138 
139 	return result.Release ();
140 
141 	}
142 
143 /******************************************************************************/
144 
SetBaseOrientation(const dng_orientation & orientation)145 void dng_negative::SetBaseOrientation (const dng_orientation &orientation)
146 	{
147 
148 	fHasBaseOrientation = true;
149 
150 	fBaseOrientation = orientation;
151 
152 	}
153 
154 /******************************************************************************/
155 
Orientation() const156 dng_orientation dng_negative::Orientation () const
157 	{
158 
159 	return BaseOrientation ();
160 
161 	}
162 
163 /******************************************************************************/
164 
ApplyOrientation(const dng_orientation & orientation)165 void dng_negative::ApplyOrientation (const dng_orientation &orientation)
166 	{
167 
168 	fBaseOrientation += orientation;
169 
170 	fXMP->SetOrientation (fBaseOrientation);
171 
172 	}
173 
174 /******************************************************************************/
175 
SetAnalogBalance(const dng_vector & b)176 void dng_negative::SetAnalogBalance (const dng_vector &b)
177 	{
178 
179 	real64 minEntry = b.MinEntry ();
180 
181 	if (b.NotEmpty () && minEntry > 0.0)
182 		{
183 
184 		fAnalogBalance = b;
185 
186 		fAnalogBalance.Scale (1.0 / minEntry);
187 
188 		fAnalogBalance.Round (1000000.0);
189 
190 		}
191 
192 	else
193 		{
194 
195 		fAnalogBalance.Clear ();
196 
197 		}
198 
199 	}
200 
201 /*****************************************************************************/
202 
AnalogBalance(uint32 channel) const203 real64 dng_negative::AnalogBalance (uint32 channel) const
204 	{
205 
206 	DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
207 
208 	if (channel < fAnalogBalance.Count ())
209 		{
210 
211 		return fAnalogBalance [channel];
212 
213 		}
214 
215 	return 1.0;
216 
217 	}
218 
219 /*****************************************************************************/
220 
AnalogBalanceR(uint32 channel) const221 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
222 	{
223 
224 	dng_urational result;
225 
226 	result.Set_real64 (AnalogBalance (channel), 1000000);
227 
228 	return result;
229 
230 	}
231 
232 /******************************************************************************/
233 
SetCameraNeutral(const dng_vector & n)234 void dng_negative::SetCameraNeutral (const dng_vector &n)
235 	{
236 
237 	real64 maxEntry = n.MaxEntry ();
238 
239 	if (n.NotEmpty () && maxEntry > 0.0)
240 		{
241 
242 		fCameraNeutral = n;
243 
244 		fCameraNeutral.Scale (1.0 / maxEntry);
245 
246 		fCameraNeutral.Round (1000000.0);
247 
248 		}
249 
250 	else
251 		{
252 
253 		fCameraNeutral.Clear ();
254 
255 		}
256 
257 	}
258 
259 /*****************************************************************************/
260 
CameraNeutralR(uint32 channel) const261 dng_urational dng_negative::CameraNeutralR (uint32 channel) const
262 	{
263 
264 	dng_urational result;
265 
266 	result.Set_real64 (CameraNeutral () [channel], 1000000);
267 
268 	return result;
269 
270 	}
271 
272 /******************************************************************************/
273 
SetCameraWhiteXY(const dng_xy_coord & coord)274 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
275 	{
276 
277 	if (coord.IsValid ())
278 		{
279 
280 		fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
281 		fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
282 
283 		}
284 
285 	else
286 		{
287 
288 		fCameraWhiteXY.Clear ();
289 
290 		}
291 
292 	}
293 
294 /*****************************************************************************/
295 
CameraWhiteXY() const296 const dng_xy_coord & dng_negative::CameraWhiteXY () const
297 	{
298 
299 	DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
300 
301 	return fCameraWhiteXY;
302 
303 	}
304 
305 /*****************************************************************************/
306 
GetCameraWhiteXY(dng_urational & x,dng_urational & y) const307 void dng_negative::GetCameraWhiteXY (dng_urational &x,
308 							   		 dng_urational &y) const
309 	{
310 
311 	dng_xy_coord coord = CameraWhiteXY ();
312 
313 	x.Set_real64 (coord.x, 1000000);
314 	y.Set_real64 (coord.y, 1000000);
315 
316 	}
317 
318 /*****************************************************************************/
319 
SetCameraCalibration1(const dng_matrix & m)320 void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
321 	{
322 
323 	fCameraCalibration1 = m;
324 
325 	fCameraCalibration1.Round (10000);
326 
327 	}
328 
329 /******************************************************************************/
330 
SetCameraCalibration2(const dng_matrix & m)331 void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
332 	{
333 
334 	fCameraCalibration2 = m;
335 
336 	fCameraCalibration2.Round (10000);
337 
338 	}
339 
340 /******************************************************************************/
341 
AddProfile(AutoPtr<dng_camera_profile> & profile)342 void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
343 	{
344 
345 	// Make sure we have a profile to add.
346 
347 	if (!profile.Get ())
348 		{
349 
350 		return;
351 
352 		}
353 
354 	// We must have some profile name.  Use "embedded" if nothing else.
355 
356 	if (profile->Name ().IsEmpty ())
357 		{
358 
359 		profile->SetName (kProfileName_Embedded);
360 
361 		}
362 
363 	// Special case support for reading older DNG files which did not store
364 	// the profile name in the main IFD profile.
365 
366 	if (fCameraProfile.size ())
367 		{
368 
369 		// See the first profile has a default "embedded" name, and has
370 		// the same data as the profile we are adding.
371 
372 		if (fCameraProfile [0]->NameIsEmbedded () &&
373 			fCameraProfile [0]->EqualData (*profile.Get ()))
374 			{
375 
376 			// If the profile we are deleting was read from DNG
377 			// then the new profile should be marked as such also.
378 
379 			if (fCameraProfile [0]->WasReadFromDNG ())
380 				{
381 
382 				profile->SetWasReadFromDNG ();
383 
384 				}
385 
386 			// Delete the profile with default name.
387 
388 			delete fCameraProfile [0];
389 
390 			fCameraProfile [0] = NULL;
391 
392 			fCameraProfile.erase (fCameraProfile.begin ());
393 
394 			}
395 
396 		}
397 
398 	// Duplicate detection logic.  We give a preference to last added profile
399 	// so the profiles end up in a more consistent order no matter what profiles
400 	// happen to be embedded in the DNG.
401 
402 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
403 		{
404 
405 		if (fCameraProfile [index]->Fingerprint () == profile->Fingerprint ())
406 			{
407 
408 			// If the profile we are deleting was read from DNG
409 			// then the new profile should be marked as such also.
410 
411 			if (fCameraProfile [index]->WasReadFromDNG ())
412 				{
413 
414 				profile->SetWasReadFromDNG ();
415 
416 				}
417 
418 			// Delete the profile with default name.
419 
420 			delete fCameraProfile [index];
421 
422 			fCameraProfile [index] = NULL;
423 
424 			fCameraProfile.erase (fCameraProfile.begin () + index);
425 
426 			break;
427 
428 			}
429 
430 		}
431 
432 	// Now add to profile list.
433 
434 	fCameraProfile.push_back (NULL);
435 
436 	fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
437 
438 	}
439 
440 /******************************************************************************/
441 
ClearProfiles()442 void dng_negative::ClearProfiles ()
443 	{
444 
445 	// Delete any camera profiles owned by this negative.
446 
447 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
448 		{
449 
450 		if (fCameraProfile [index])
451 			{
452 
453 			delete fCameraProfile [index];
454 
455 			fCameraProfile [index] = NULL;
456 
457 			}
458 
459 		}
460 
461 	// Now empty list.
462 
463 	fCameraProfile.clear ();
464 
465 	}
466 
467 /******************************************************************************/
468 
ProfileCount() const469 uint32 dng_negative::ProfileCount () const
470 	{
471 
472 	return (uint32) fCameraProfile.size ();
473 
474 	}
475 
476 /******************************************************************************/
477 
ProfileByIndex(uint32 index) const478 const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
479 	{
480 
481 	DNG_ASSERT (index < ProfileCount (),
482 				"Invalid index for ProfileByIndex");
483 
484 	return *fCameraProfile [index];
485 
486 	}
487 
488 /*****************************************************************************/
489 
ProfileByID(const dng_camera_profile_id & id,bool useDefaultIfNoMatch) const490 const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
491 													  bool useDefaultIfNoMatch) const
492 	{
493 
494 	// If this negative does not have any profiles, we are not going to
495 	// find a match.
496 
497 	uint32 profileCount = ProfileCount ();
498 
499 	if (profileCount == 0)
500 		{
501 		return NULL;
502 		}
503 
504 	// If we have both a profile name and fingerprint, try matching both.
505 
506 	if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
507 		{
508 
509 		for (uint32 index = 0; index < profileCount; index++)
510 			{
511 
512 			const dng_camera_profile &profile = ProfileByIndex (index);
513 
514 			if (id.Name        () == profile.Name        () &&
515 				id.Fingerprint () == profile.Fingerprint ())
516 				{
517 
518 				return &profile;
519 
520 				}
521 
522 			}
523 
524 		}
525 
526 	// If we have a name, try matching that.
527 
528 	if (id.Name ().NotEmpty ())
529 		{
530 
531 		for (uint32 index = 0; index < profileCount; index++)
532 			{
533 
534 			const dng_camera_profile &profile = ProfileByIndex (index);
535 
536 			if (id.Name () == profile.Name ())
537 				{
538 
539 				return &profile;
540 
541 				}
542 
543 			}
544 
545 		}
546 
547 	// If we have a valid fingerprint, try matching that.
548 
549 	if (id.Fingerprint ().IsValid ())
550 		{
551 
552 		for (uint32 index = 0; index < profileCount; index++)
553 			{
554 
555 			const dng_camera_profile &profile = ProfileByIndex (index);
556 
557 			if (id.Fingerprint () == profile.Fingerprint ())
558 				{
559 
560 				return &profile;
561 
562 				}
563 
564 			}
565 
566 		}
567 
568 	// Did not find a match either way.  See if we should return a default
569 	// value.
570 
571 	if (useDefaultIfNoMatch)
572 		{
573 
574 		return &ProfileByIndex (0);
575 
576 		}
577 
578 	// Found nothing.
579 
580 	return NULL;
581 
582 	}
583 
584 /*****************************************************************************/
585 
CameraProfileToEmbed() const586 const dng_camera_profile * dng_negative::CameraProfileToEmbed () const
587 	{
588 
589 	uint32 index;
590 
591 	uint32 count = ProfileCount ();
592 
593 	if (count == 0)
594 		{
595 
596 		return NULL;
597 
598 		}
599 
600 	// First try to look for the first profile that was already in the DNG
601 	// when we read it.
602 
603 	for (index = 0; index < count; index++)
604 		{
605 
606 		const dng_camera_profile &profile (ProfileByIndex (index));
607 
608 		if (profile.WasReadFromDNG ())
609 			{
610 
611 			return &profile;
612 
613 			}
614 
615 		}
616 
617 	// Next we look for the first profile that is legal to embed.
618 
619 	for (index = 0; index < count; index++)
620 		{
621 
622 		const dng_camera_profile &profile (ProfileByIndex (index));
623 
624 		if (profile.IsLegalToEmbed ())
625 			{
626 
627 			return &profile;
628 
629 			}
630 
631 		}
632 
633 	// Else just return the first profile.
634 
635 	return fCameraProfile [0];
636 
637 	}
638 
639 /*****************************************************************************/
640 
MakeColorSpec(const dng_camera_profile_id & id) const641 dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
642 	{
643 
644 	dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
645 
646 	if (!spec)
647 		{
648 		ThrowMemoryFull ();
649 		}
650 
651 	return spec;
652 
653 	}
654 
655 /*****************************************************************************/
656 
FindRawImageDigest(dng_host & host) const657 void dng_negative::FindRawImageDigest (dng_host &host) const
658 	{
659 
660 	if (fRawImageDigest.IsNull ())
661 		{
662 
663 		const dng_image &image = RawImage ();
664 
665 		dng_md5_printer printer;
666 
667 		dng_pixel_buffer buffer;
668 
669 		buffer.fPlane  = 0;
670 		buffer.fPlanes = image.Planes ();
671 
672 		buffer.fRowStep   = image.Planes () * image.Width ();
673 		buffer.fColStep   = image.Planes ();
674 		buffer.fPlaneStep = 1;
675 
676 		buffer.fPixelType = image.PixelType ();
677 		buffer.fPixelSize = image.PixelSize ();
678 
679 		// Sometimes we expand 8-bit data to 16-bit data while reading or
680 		// writing, so always compute the digest of 8-bit data as 16-bits.
681 
682 		if (buffer.fPixelType == ttByte)
683 			{
684 			buffer.fPixelType = ttShort;
685 			buffer.fPixelSize = 2;
686 			}
687 
688 		const uint32 kBufferRows = 16;
689 
690 		uint32 bufferBytes = kBufferRows * buffer.fRowStep * buffer.fPixelSize;
691 
692 		AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
693 
694 		buffer.fData = bufferData->Buffer ();
695 
696 		dng_rect area;
697 
698 		dng_tile_iterator iter (dng_point (kBufferRows,
699 										   image.Width ()),
700 								image.Bounds ());
701 
702 		while (iter.GetOneTile (area))
703 			{
704 
705 			host.SniffForAbort ();
706 
707 			buffer.fArea = area;
708 
709 			image.Get (buffer);
710 
711 			uint32 count = buffer.fArea.H () *
712 						   buffer.fRowStep *
713 						   buffer.fPixelSize;
714 
715 			#if qDNGBigEndian
716 
717 			// We need to use the same byte order to compute
718 			// the digest, no matter the native order.  Little-endian
719 			// is more common now, so use that.
720 
721 			switch (buffer.fPixelSize)
722 				{
723 
724 				case 1:
725 					break;
726 
727 				case 2:
728 					{
729 					DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
730 					break;
731 					}
732 
733 				case 4:
734 					{
735 					DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
736 					break;
737 					}
738 
739 				default:
740 					{
741 					DNG_REPORT ("Unexpected pixel size");
742 					break;
743 					}
744 
745 				}
746 
747 			#endif
748 
749 			printer.Process (buffer.fData,
750 							 count);
751 
752 			}
753 
754 		fRawImageDigest = printer.Result ();
755 
756 		}
757 
758 	}
759 
760 /*****************************************************************************/
761 
ValidateRawImageDigest(dng_host & host)762 void dng_negative::ValidateRawImageDigest (dng_host &host)
763 	{
764 
765 	if (Stage1Image () && !IsPreview () && fRawImageDigest.IsValid ())
766 		{
767 
768 		dng_fingerprint oldDigest = fRawImageDigest;
769 
770 		try
771 			{
772 
773 			fRawImageDigest.Clear ();
774 
775 			FindRawImageDigest (host);
776 
777 			}
778 
779 		catch (...)
780 			{
781 
782 			fRawImageDigest = oldDigest;
783 
784 			throw;
785 
786 			}
787 
788 		if (oldDigest != fRawImageDigest)
789 			{
790 
791 			#if qDNGValidate
792 
793 			ReportError ("RawImageDigest does not match raw image");
794 
795 			#else
796 
797 			#if 0		// FIX_ME_TFK: Disable for now so the warning code get more testing.
798 
799 			// Note that Lightroom 1.4 Windows had a bug that corrupts the
800 			// first four bytes of the RawImageDigest tag.  So if the last
801 			// twelve bytes match, this is very likely the result of the
802 			// bug, and not an actual corrupt file.  So don't report this
803 			// to the user--just fix it.
804 
805 				{
806 
807 				bool matchLast12 = true;
808 
809 				for (uint32 j = 4; j < 16; j++)
810 					{
811 					matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
812 					}
813 
814 				if (matchLast12)
815 					{
816 					return;
817 					}
818 
819 				}
820 
821 			#endif
822 
823 			SetIsDamaged (true);
824 
825 			#endif
826 
827 			}
828 
829 		}
830 
831 	}
832 
833 /*****************************************************************************/
834 
835 // If the raw data unique ID is missing, compute one based on a MD5 hash of
836 // the raw image data and the model name.
837 
FindRawDataUniqueID(dng_host & host) const838 void dng_negative::FindRawDataUniqueID (dng_host &host) const
839 	{
840 
841 	if (fRawDataUniqueID.IsNull ())
842 		{
843 
844 		FindRawImageDigest (host);
845 
846 		dng_md5_printer printer;
847 
848 		printer.Process (fRawImageDigest.data, 16);
849 
850 		printer.Process (ModelName ().Get    (),
851 						 ModelName ().Length ());
852 
853 		fRawDataUniqueID = printer.Result ();
854 
855 		}
856 
857 	}
858 
859 /******************************************************************************/
860 
FindOriginalRawFileDigest() const861 void dng_negative::FindOriginalRawFileDigest () const
862 	{
863 
864 	if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
865 		{
866 
867 		dng_md5_printer printer;
868 
869 		printer.Process (fOriginalRawFileData->Buffer      (),
870 						 fOriginalRawFileData->LogicalSize ());
871 
872 		fOriginalRawFileDigest = printer.Result ();
873 
874 		}
875 
876 	}
877 
878 /*****************************************************************************/
879 
ValidateOriginalRawFileDigest()880 void dng_negative::ValidateOriginalRawFileDigest ()
881 	{
882 
883 	if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
884 		{
885 
886 		dng_fingerprint oldDigest = fOriginalRawFileDigest;
887 
888 		try
889 			{
890 
891 			fOriginalRawFileDigest.Clear ();
892 
893 			FindOriginalRawFileDigest ();
894 
895 			}
896 
897 		catch (...)
898 			{
899 
900 			fOriginalRawFileDigest = oldDigest;
901 
902 			throw;
903 
904 			}
905 
906 		if (oldDigest != fOriginalRawFileDigest)
907 			{
908 
909 			#if qDNGValidate
910 
911 			ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
912 
913 			#else
914 
915 			SetIsDamaged (true);
916 
917 			#endif
918 
919 			// Don't "repair" the original image data digest.  Once it is
920 			// bad, it stays bad.  The user cannot tell by looking at the image
921 			// whether the damage is acceptable and can be ignored in the
922 			// future.
923 
924 			fOriginalRawFileDigest = oldDigest;
925 
926 			}
927 
928 		}
929 
930 	}
931 
932 /******************************************************************************/
933 
DefaultCropArea(real64 scaleH,real64 scaleV) const934 dng_rect dng_negative::DefaultCropArea (real64 scaleH,
935 				    	  			    real64 scaleV) const
936 	{
937 
938 	const dng_image *image = Stage3Image ();
939 
940 	DNG_ASSERT (image, "DefaultCropArea on NULL image");
941 
942 	dng_point scaledSize;
943 
944 	scaledSize.h = Round_int32 (image->Width  () * scaleH);
945 	scaledSize.v = Round_int32 (image->Height () * scaleV);
946 
947 	// First compute the area using simple rounding.
948 
949 	dng_rect result;
950 
951 	result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH * scaleH);
952 	result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV * scaleV);
953 
954 	result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH * scaleH);
955 	result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV * scaleV);
956 
957 	// Sometimes the simple rounding causes the resulting default crop
958 	// area to slide off the scaled image area.  So we force this not
959 	// to happen.
960 
961 	if (result.r > scaledSize.h)
962 		{
963 		result.l -= result.r - scaledSize.h;
964 		result.r  = scaledSize.h;
965 		}
966 
967 	if (result.b > scaledSize.v)
968 		{
969 		result.t -= result.b - scaledSize.v;
970 		result.b  = scaledSize.v;
971 		}
972 
973 	return result;
974 
975 	}
976 
977 /******************************************************************************/
978 
SetShadowScale(const dng_urational & scale)979 void dng_negative::SetShadowScale (const dng_urational &scale)
980 	{
981 
982 	if (scale.d > 0)
983 		{
984 
985 		real64 s = scale.As_real64 ();
986 
987 		if (s > 0.0 && s <= 1.0)
988 			{
989 
990 			fShadowScale = scale;
991 
992 			}
993 
994 		}
995 
996 	}
997 
998 /******************************************************************************/
999 
BuildExifBlock(const dng_resolution * resolution,bool includeIPTC) const1000 dng_memory_block * dng_negative::BuildExifBlock (const dng_resolution *resolution,
1001 												 bool includeIPTC) const
1002 	{
1003 
1004 	dng_memory_stream stream (Allocator ());
1005 
1006 		{
1007 
1008 		// Create the main IFD
1009 
1010 		dng_tiff_directory mainIFD;
1011 
1012 		// Optionally include the resolution tags.
1013 
1014 		dng_resolution res;
1015 
1016 		if (resolution)
1017 			{
1018 			res = *resolution;
1019 			}
1020 
1021 		tag_urational tagXResolution (tcXResolution, res.fXResolution);
1022 		tag_urational tagYResolution (tcYResolution, res.fYResolution);
1023 
1024 		tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
1025 
1026 		if (resolution)
1027 			{
1028 			mainIFD.Add (&tagXResolution   );
1029 			mainIFD.Add (&tagYResolution   );
1030 			mainIFD.Add (&tagResolutionUnit);
1031 			}
1032 
1033 		// Optionally include IPTC block.
1034 
1035 		tag_iptc tagIPTC (IPTCData   (),
1036 						  IPTCLength ());
1037 
1038 		if (includeIPTC && tagIPTC.Count ())
1039 			{
1040 
1041 			mainIFD.Add (&tagIPTC);
1042 
1043 			}
1044 
1045 		// Exif tags.
1046 
1047 		exif_tag_set exifSet (mainIFD,
1048 							  *GetExif (),
1049 							  IsMakerNoteSafe (),
1050 							  MakerNoteData   (),
1051 							  MakerNoteLength (),
1052 							  false);
1053 
1054 		// Figure out the Exif IFD offset.
1055 
1056 		exifSet.Locate (8 + mainIFD.Size ());
1057 
1058 		// Write TIFF Header.
1059 
1060 		stream.SetWritePosition (0);
1061 
1062 		stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
1063 
1064 		stream.Put_uint16 (42);
1065 
1066 		stream.Put_uint32 (8);
1067 
1068 		// Write the IFDs.
1069 
1070 		mainIFD.Put (stream);
1071 
1072 		exifSet.Put (stream);
1073 
1074 		// Trim the file to this length.
1075 
1076 		stream.Flush ();
1077 
1078 		stream.SetLength (stream.Position ());
1079 
1080 		}
1081 
1082 	return stream.AsMemoryBlock (Allocator ());
1083 
1084 	}
1085 
1086 /******************************************************************************/
1087 
SetIPTC(AutoPtr<dng_memory_block> & block,uint64 offset)1088 void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
1089 	{
1090 
1091 	fIPTCBlock.Reset (block.Release ());
1092 
1093 	fIPTCOffset = offset;
1094 
1095 	}
1096 
1097 /******************************************************************************/
1098 
SetIPTC(AutoPtr<dng_memory_block> & block)1099 void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block)
1100 	{
1101 
1102 	SetIPTC (block, kDNGStreamInvalidOffset);
1103 
1104 	}
1105 
1106 /******************************************************************************/
1107 
ClearIPTC()1108 void dng_negative::ClearIPTC ()
1109 	{
1110 
1111 	fIPTCBlock.Reset ();
1112 
1113 	fIPTCOffset = kDNGStreamInvalidOffset;
1114 
1115 	}
1116 
1117 /*****************************************************************************/
1118 
IPTCData() const1119 const void * dng_negative::IPTCData () const
1120 	{
1121 
1122 	if (fIPTCBlock.Get ())
1123 		{
1124 
1125 		return fIPTCBlock->Buffer ();
1126 
1127 		}
1128 
1129 	return NULL;
1130 
1131 	}
1132 
1133 /*****************************************************************************/
1134 
IPTCLength() const1135 uint32 dng_negative::IPTCLength () const
1136 	{
1137 
1138 	if (fIPTCBlock.Get ())
1139 		{
1140 
1141 		return fIPTCBlock->LogicalSize ();
1142 
1143 		}
1144 
1145 	return 0;
1146 
1147 	}
1148 
1149 /*****************************************************************************/
1150 
IPTCOffset() const1151 uint64 dng_negative::IPTCOffset () const
1152 	{
1153 
1154 	if (fIPTCBlock.Get ())
1155 		{
1156 
1157 		return fIPTCOffset;
1158 
1159 		}
1160 
1161 	return kDNGStreamInvalidOffset;
1162 
1163 	}
1164 
1165 /*****************************************************************************/
1166 
IPTCDigest() const1167 dng_fingerprint dng_negative::IPTCDigest () const
1168 	{
1169 
1170 	if (IPTCLength ())
1171 		{
1172 
1173 		dng_md5_printer printer;
1174 
1175 		const uint8 *data = (const uint8 *) IPTCData ();
1176 
1177 		uint32 count = IPTCLength ();
1178 
1179 		// Because of some stupid ways of storing the IPTC data, the IPTC
1180 		// data might be padded with up to three zeros.  Don't include
1181 		// these zero pad bytes in the digest.
1182 
1183 		uint32 removed = 0;
1184 
1185 		while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
1186 			{
1187 			removed++;
1188 			count--;
1189 			}
1190 
1191 		printer.Process (data, count);
1192 
1193 		return printer.Result ();
1194 
1195 		}
1196 
1197 	return dng_fingerprint ();
1198 
1199 	}
1200 
1201 /******************************************************************************/
1202 
RebuildIPTC()1203 void dng_negative::RebuildIPTC ()
1204 	{
1205 
1206 	ClearIPTC ();
1207 
1208 	fXMP->RebuildIPTC (*this);
1209 
1210 	dng_fingerprint digest = IPTCDigest ();
1211 
1212 	fXMP->SetIPTCDigest (digest);
1213 
1214 	}
1215 
1216 /*****************************************************************************/
1217 
SetXMP(dng_host & host,const void * buffer,uint32 count,bool xmpInSidecar,bool xmpIsNewer)1218 bool dng_negative::SetXMP (dng_host &host,
1219 						   const void *buffer,
1220 					 	   uint32 count,
1221 					 	   bool xmpInSidecar,
1222 					 	   bool xmpIsNewer)
1223 	{
1224 
1225 	bool result = false;
1226 
1227 	try
1228 		{
1229 
1230 		AutoPtr<dng_xmp> tempXMP (MakeXMP ());
1231 
1232 		tempXMP->Parse (host, buffer, count);
1233 
1234 		fXMP.Reset (tempXMP.Release ());
1235 
1236 		fXMPinSidecar = xmpInSidecar;
1237 
1238 		fXMPisNewer = xmpIsNewer;
1239 
1240 		result = true;
1241 
1242 		}
1243 
1244 	catch (dng_exception &except)
1245 		{
1246 
1247 		// Don't ignore transient errors.
1248 
1249 		if (host.IsTransientError (except.ErrorCode ()))
1250 			{
1251 
1252 			throw;
1253 
1254 			}
1255 
1256 		// Eat other parsing errors.
1257 
1258 		}
1259 
1260 	catch (...)
1261 		{
1262 
1263 		// Eat unknown parsing exceptions.
1264 
1265 		}
1266 
1267 	return result;
1268 
1269 	}
1270 
1271 /******************************************************************************/
1272 
SetActiveArea(const dng_rect & area)1273 void dng_negative::SetActiveArea (const dng_rect &area)
1274 	{
1275 
1276 	NeedLinearizationInfo ();
1277 
1278 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1279 
1280 	info.fActiveArea = area;
1281 
1282 	}
1283 
1284 /******************************************************************************/
1285 
SetMaskedAreas(uint32 count,const dng_rect * area)1286 void dng_negative::SetMaskedAreas (uint32 count,
1287 							 	   const dng_rect *area)
1288 	{
1289 
1290 	DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
1291 
1292 	NeedLinearizationInfo ();
1293 
1294 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1295 
1296 	info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
1297 
1298 	for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
1299 		{
1300 
1301 		info.fMaskedArea [index] = area [index];
1302 
1303 		}
1304 
1305 	}
1306 
1307 /*****************************************************************************/
1308 
SetLinearization(AutoPtr<dng_memory_block> & curve)1309 void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
1310 	{
1311 
1312 	NeedLinearizationInfo ();
1313 
1314 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1315 
1316 	info.fLinearizationTable.Reset (curve.Release ());
1317 
1318 	}
1319 
1320 /*****************************************************************************/
1321 
SetBlackLevel(real64 black,int32 plane)1322 void dng_negative::SetBlackLevel (real64 black,
1323 								  int32 plane)
1324 	{
1325 
1326 	NeedLinearizationInfo ();
1327 
1328 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1329 
1330 	info.fBlackLevelRepeatRows = 1;
1331 	info.fBlackLevelRepeatCols = 1;
1332 
1333 	if (plane < 0)
1334 		{
1335 
1336 		for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1337 			{
1338 
1339 			info.fBlackLevel [0] [0] [j] = black;
1340 
1341 			}
1342 
1343 		}
1344 
1345 	else
1346 		{
1347 
1348 		info.fBlackLevel [0] [0] [plane] = black;
1349 
1350 		}
1351 
1352 	info.RoundBlacks ();
1353 
1354 	}
1355 
1356 /*****************************************************************************/
1357 
SetQuadBlacks(real64 black0,real64 black1,real64 black2,real64 black3)1358 void dng_negative::SetQuadBlacks (real64 black0,
1359 						    	  real64 black1,
1360 						    	  real64 black2,
1361 						    	  real64 black3)
1362 	{
1363 
1364 	NeedLinearizationInfo ();
1365 
1366 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1367 
1368 	info.fBlackLevelRepeatRows = 2;
1369 	info.fBlackLevelRepeatCols = 2;
1370 
1371 	for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1372 		{
1373 
1374 		info.fBlackLevel [0] [0] [j] = black0;
1375 		info.fBlackLevel [0] [1] [j] = black1;
1376 		info.fBlackLevel [1] [0] [j] = black2;
1377 		info.fBlackLevel [1] [1] [j] = black3;
1378 
1379 		}
1380 
1381 	info.RoundBlacks ();
1382 
1383 	}
1384 
1385 /*****************************************************************************/
1386 
SetRowBlacks(const real64 * blacks,uint32 count)1387 void dng_negative::SetRowBlacks (const real64 *blacks,
1388 				   		   		 uint32 count)
1389 	{
1390 
1391 	if (count)
1392 		{
1393 
1394 		NeedLinearizationInfo ();
1395 
1396 		dng_linearization_info &info = *fLinearizationInfo.Get ();
1397 
1398 		uint32 byteCount = count * sizeof (real64);
1399 
1400 		info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount));
1401 
1402 		DoCopyBytes (blacks,
1403 					 info.fBlackDeltaV->Buffer (),
1404 					 byteCount);
1405 
1406 		info.RoundBlacks ();
1407 
1408 		}
1409 
1410 	else if (fLinearizationInfo.Get ())
1411 		{
1412 
1413 		dng_linearization_info &info = *fLinearizationInfo.Get ();
1414 
1415 		info.fBlackDeltaV.Reset ();
1416 
1417 		}
1418 
1419 	}
1420 
1421 /*****************************************************************************/
1422 
SetColumnBlacks(const real64 * blacks,uint32 count)1423 void dng_negative::SetColumnBlacks (const real64 *blacks,
1424 					  		  	    uint32 count)
1425 	{
1426 
1427 	if (count)
1428 		{
1429 
1430 		NeedLinearizationInfo ();
1431 
1432 		dng_linearization_info &info = *fLinearizationInfo.Get ();
1433 
1434 		uint32 byteCount = count * sizeof (real64);
1435 
1436 		info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount));
1437 
1438 		DoCopyBytes (blacks,
1439 					 info.fBlackDeltaH->Buffer (),
1440 					 byteCount);
1441 
1442 		info.RoundBlacks ();
1443 
1444 		}
1445 
1446 	else if (fLinearizationInfo.Get ())
1447 		{
1448 
1449 		dng_linearization_info &info = *fLinearizationInfo.Get ();
1450 
1451 		info.fBlackDeltaH.Reset ();
1452 
1453 		}
1454 
1455 	}
1456 
1457 /*****************************************************************************/
1458 
WhiteLevel(uint32 plane) const1459 uint32 dng_negative::WhiteLevel (uint32 plane) const
1460 	{
1461 
1462 	if (fLinearizationInfo.Get ())
1463 		{
1464 
1465 		const dng_linearization_info &info = *fLinearizationInfo.Get ();
1466 
1467 		return Round_uint32 (info.fWhiteLevel [plane]);
1468 
1469 		}
1470 
1471 	return 0x0FFFF;
1472 
1473 	}
1474 
1475 /*****************************************************************************/
1476 
SetWhiteLevel(uint32 white,int32 plane)1477 void dng_negative::SetWhiteLevel (uint32 white,
1478 							      int32 plane)
1479 	{
1480 
1481 	NeedLinearizationInfo ();
1482 
1483 	dng_linearization_info &info = *fLinearizationInfo.Get ();
1484 
1485 	if (plane < 0)
1486 		{
1487 
1488 		for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1489 			{
1490 
1491 			info.fWhiteLevel [j] = (real64) white;
1492 
1493 			}
1494 
1495 		}
1496 
1497 	else
1498 		{
1499 
1500 		info.fWhiteLevel [plane] = (real64) white;
1501 
1502 		}
1503 
1504 	}
1505 
1506 /******************************************************************************/
1507 
SetColorKeys(ColorKeyCode color0,ColorKeyCode color1,ColorKeyCode color2,ColorKeyCode color3)1508 void dng_negative::SetColorKeys (ColorKeyCode color0,
1509 						   		 ColorKeyCode color1,
1510 						   		 ColorKeyCode color2,
1511 						   		 ColorKeyCode color3)
1512 	{
1513 
1514 	NeedMosaicInfo ();
1515 
1516 	dng_mosaic_info &info = *fMosaicInfo.Get ();
1517 
1518 	info.fCFAPlaneColor [0] = color0;
1519 	info.fCFAPlaneColor [1] = color1;
1520 	info.fCFAPlaneColor [2] = color2;
1521 	info.fCFAPlaneColor [3] = color3;
1522 
1523 	}
1524 
1525 /******************************************************************************/
1526 
SetBayerMosaic(uint32 phase)1527 void dng_negative::SetBayerMosaic (uint32 phase)
1528 	{
1529 
1530 	NeedMosaicInfo ();
1531 
1532 	dng_mosaic_info &info = *fMosaicInfo.Get ();
1533 
1534 	ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
1535 	ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
1536 	ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
1537 
1538 	info.fCFAPatternSize = dng_point (2, 2);
1539 
1540 	switch (phase)
1541 		{
1542 
1543 		case 0:
1544 			{
1545 			info.fCFAPattern [0] [0] = color1;
1546 			info.fCFAPattern [0] [1] = color0;
1547 			info.fCFAPattern [1] [0] = color2;
1548 			info.fCFAPattern [1] [1] = color1;
1549 			break;
1550 			}
1551 
1552 		case 1:
1553 			{
1554 			info.fCFAPattern [0] [0] = color0;
1555 			info.fCFAPattern [0] [1] = color1;
1556 			info.fCFAPattern [1] [0] = color1;
1557 			info.fCFAPattern [1] [1] = color2;
1558 			break;
1559 			}
1560 
1561 		case 2:
1562 			{
1563 			info.fCFAPattern [0] [0] = color2;
1564 			info.fCFAPattern [0] [1] = color1;
1565 			info.fCFAPattern [1] [0] = color1;
1566 			info.fCFAPattern [1] [1] = color0;
1567 			break;
1568 			}
1569 
1570 		case 3:
1571 			{
1572 			info.fCFAPattern [0] [0] = color1;
1573 			info.fCFAPattern [0] [1] = color2;
1574 			info.fCFAPattern [1] [0] = color0;
1575 			info.fCFAPattern [1] [1] = color1;
1576 			break;
1577 			}
1578 
1579 		}
1580 
1581 	info.fColorPlanes = 3;
1582 
1583 	info.fCFALayout = 1;
1584 
1585 	}
1586 
1587 /******************************************************************************/
1588 
SetFujiMosaic(uint32 phase)1589 void dng_negative::SetFujiMosaic (uint32 phase)
1590 	{
1591 
1592 	NeedMosaicInfo ();
1593 
1594 	dng_mosaic_info &info = *fMosaicInfo.Get ();
1595 
1596 	ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
1597 	ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
1598 	ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
1599 
1600 	info.fCFAPatternSize = dng_point (2, 4);
1601 
1602 	switch (phase)
1603 		{
1604 
1605 		case 0:
1606 			{
1607 			info.fCFAPattern [0] [0] = color0;
1608 			info.fCFAPattern [0] [1] = color1;
1609 			info.fCFAPattern [0] [2] = color2;
1610 			info.fCFAPattern [0] [3] = color1;
1611 			info.fCFAPattern [1] [0] = color2;
1612 			info.fCFAPattern [1] [1] = color1;
1613 			info.fCFAPattern [1] [2] = color0;
1614 			info.fCFAPattern [1] [3] = color1;
1615 			break;
1616 			}
1617 
1618 		case 1:
1619 			{
1620 			info.fCFAPattern [0] [0] = color2;
1621 			info.fCFAPattern [0] [1] = color1;
1622 			info.fCFAPattern [0] [2] = color0;
1623 			info.fCFAPattern [0] [3] = color1;
1624 			info.fCFAPattern [1] [0] = color0;
1625 			info.fCFAPattern [1] [1] = color1;
1626 			info.fCFAPattern [1] [2] = color2;
1627 			info.fCFAPattern [1] [3] = color1;
1628 			break;
1629 			}
1630 
1631 		}
1632 
1633 	info.fColorPlanes = 3;
1634 
1635 	info.fCFALayout = 2;
1636 
1637 	}
1638 
1639 /******************************************************************************/
1640 
SetQuadMosaic(uint32 pattern)1641 void dng_negative::SetQuadMosaic (uint32 pattern)
1642 	{
1643 
1644 	// The pattern of the four colors is assumed to be repeat at least every two
1645 	// columns and eight rows.  The pattern is encoded as a 32-bit integer,
1646 	// with every two bits encoding a color, in scan order for two columns and
1647 	// eight rows (lsb is first).  The usual color coding is:
1648 	//
1649 	// 0 = Green
1650 	// 1 = Magenta
1651 	// 2 = Cyan
1652 	// 3 = Yellow
1653 	//
1654 	// Examples:
1655 	//
1656 	//	PowerShot 600 uses 0xe1e4e1e4:
1657 	//
1658 	//	  0 1 2 3 4 5
1659 	//	0 G M G M G M
1660 	//	1 C Y C Y C Y
1661 	//	2 M G M G M G
1662 	//	3 C Y C Y C Y
1663 	//
1664 	//	PowerShot A5 uses 0x1e4e1e4e:
1665 	//
1666 	//	  0 1 2 3 4 5
1667 	//	0 C Y C Y C Y
1668 	//	1 G M G M G M
1669 	//	2 C Y C Y C Y
1670 	//	3 M G M G M G
1671 	//
1672 	//	PowerShot A50 uses 0x1b4e4b1e:
1673 	//
1674 	//	  0 1 2 3 4 5
1675 	//	0 C Y C Y C Y
1676 	//	1 M G M G M G
1677 	//	2 Y C Y C Y C
1678 	//	3 G M G M G M
1679 	//	4 C Y C Y C Y
1680 	//	5 G M G M G M
1681 	//	6 Y C Y C Y C
1682 	//	7 M G M G M G
1683 	//
1684 	//	PowerShot Pro70 uses 0x1e4b4e1b:
1685 	//
1686 	//	  0 1 2 3 4 5
1687 	//	0 Y C Y C Y C
1688 	//	1 M G M G M G
1689 	//	2 C Y C Y C Y
1690 	//	3 G M G M G M
1691 	//	4 Y C Y C Y C
1692 	//	5 G M G M G M
1693 	//	6 C Y C Y C Y
1694 	//	7 M G M G M G
1695 	//
1696 	//	PowerShots Pro90 and G1 use 0xb4b4b4b4:
1697 	//
1698 	//	  0 1 2 3 4 5
1699 	//	0 G M G M G M
1700 	//	1 Y C Y C Y C
1701 
1702 	NeedMosaicInfo ();
1703 
1704 	dng_mosaic_info &info = *fMosaicInfo.Get ();
1705 
1706 	if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF))
1707 		{
1708 		info.fCFAPatternSize = dng_point (8, 2);
1709 		}
1710 
1711 	else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF))
1712 		{
1713 		info.fCFAPatternSize = dng_point (4, 2);
1714 		}
1715 
1716 	else
1717 		{
1718 		info.fCFAPatternSize = dng_point (2, 2);
1719 		}
1720 
1721 	for (int32 row = 0; row < info.fCFAPatternSize.v; row++)
1722 		{
1723 
1724 		for (int32 col = 0; col < info.fCFAPatternSize.h; col++)
1725 			{
1726 
1727 			uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3;
1728 
1729 			info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index];
1730 
1731 			}
1732 
1733 		}
1734 
1735 	info.fColorPlanes = 4;
1736 
1737 	info.fCFALayout = 1;
1738 
1739 	}
1740 
1741 /******************************************************************************/
1742 
SetGreenSplit(uint32 split)1743 void dng_negative::SetGreenSplit (uint32 split)
1744 	{
1745 
1746 	NeedMosaicInfo ();
1747 
1748 	dng_mosaic_info &info = *fMosaicInfo.Get ();
1749 
1750 	info.fBayerGreenSplit = split;
1751 
1752 	}
1753 
1754 /*****************************************************************************/
1755 
Parse(dng_host & host,dng_stream & stream,dng_info & info)1756 void dng_negative::Parse (dng_host &host,
1757 						  dng_stream &stream,
1758 						  dng_info &info)
1759 	{
1760 
1761 	// Shared info.
1762 
1763 	dng_shared &shared = *(info.fShared.Get ());
1764 
1765 	// Find IFD holding the main raw information.
1766 
1767 	dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
1768 
1769 	// Model name.
1770 
1771 	SetModelName (shared.fUniqueCameraModel.Get ());
1772 
1773 	// Localized model name.
1774 
1775 	SetLocalName (shared.fLocalizedCameraModel.Get ());
1776 
1777 	// Base orientation.
1778 
1779 		{
1780 
1781 		uint32 orientation = info.fIFD [0]->fOrientation;
1782 
1783 		if (orientation >= 1 && orientation <= 8)
1784 			{
1785 
1786 			SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
1787 
1788 			}
1789 
1790 		}
1791 
1792 	// Default crop rectangle.
1793 
1794 	SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
1795 					    rawIFD.fDefaultCropSizeV);
1796 
1797 	SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
1798 						  rawIFD.fDefaultCropOriginV);
1799 
1800 	// Default scale.
1801 
1802 	SetDefaultScale (rawIFD.fDefaultScaleH,
1803 					 rawIFD.fDefaultScaleV);
1804 
1805 	// Best quality scale.
1806 
1807 	SetBestQualityScale (rawIFD.fBestQualityScale);
1808 
1809 	// Baseline noise.
1810 
1811 	SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
1812 
1813 	// NoiseReductionApplied.
1814 
1815 	SetNoiseReductionApplied (shared.fNoiseReductionApplied);
1816 
1817 	// Baseline exposure.
1818 
1819 	SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
1820 
1821 	// Baseline sharpness.
1822 
1823 	SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
1824 
1825 	// Chroma blur radius.
1826 
1827 	SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
1828 
1829 	// Anti-alias filter strength.
1830 
1831 	SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
1832 
1833 	// Linear response limit.
1834 
1835 	SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
1836 
1837 	// Shadow scale.
1838 
1839 	SetShadowScale (shared.fShadowScale);
1840 
1841 	// Colorimetric reference.
1842 
1843 	SetColorimetricReference (shared.fColorimetricReference);
1844 
1845 	// Color channels.
1846 
1847 	SetColorChannels (shared.fCameraProfile.fColorPlanes);
1848 
1849 	// Analog balance.
1850 
1851 	if (shared.fAnalogBalance.NotEmpty ())
1852 		{
1853 
1854 		SetAnalogBalance (shared.fAnalogBalance);
1855 
1856 		}
1857 
1858 	// Camera calibration matrices
1859 
1860 	if (shared.fCameraCalibration1.NotEmpty ())
1861 		{
1862 
1863 		SetCameraCalibration1 (shared.fCameraCalibration1);
1864 
1865 		}
1866 
1867 	if (shared.fCameraCalibration2.NotEmpty ())
1868 		{
1869 
1870 		SetCameraCalibration2 (shared.fCameraCalibration2);
1871 
1872 		}
1873 
1874 	if (shared.fCameraCalibration1.NotEmpty () ||
1875 		shared.fCameraCalibration2.NotEmpty ())
1876 		{
1877 
1878 		SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
1879 
1880 		}
1881 
1882 	// Embedded camera profiles.
1883 
1884 	if (shared.fCameraProfile.fColorPlanes > 1)
1885 		{
1886 
1887 		if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
1888 			{
1889 
1890 			// Add profile from main IFD.
1891 
1892 				{
1893 
1894 				AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
1895 
1896 				dng_camera_profile_info &profileInfo = shared.fCameraProfile;
1897 
1898 				profile->Parse (stream, profileInfo);
1899 
1900 				// The main embedded profile must be valid.
1901 
1902 				if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
1903 					{
1904 
1905 					ThrowBadFormat ();
1906 
1907 					}
1908 
1909 				profile->SetWasReadFromDNG ();
1910 
1911 				AddProfile (profile);
1912 
1913 				}
1914 
1915 			// Extra profiles.
1916 
1917 			for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
1918 				{
1919 
1920 				try
1921 					{
1922 
1923 					AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
1924 
1925 					dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
1926 
1927 					profile->Parse (stream, profileInfo);
1928 
1929 					if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
1930 						{
1931 
1932 						ThrowBadFormat ();
1933 
1934 						}
1935 
1936 					profile->SetWasReadFromDNG ();
1937 
1938 					AddProfile (profile);
1939 
1940 					}
1941 
1942 				catch (dng_exception &except)
1943 					{
1944 
1945 					// Don't ignore transient errors.
1946 
1947 					if (host.IsTransientError (except.ErrorCode ()))
1948 						{
1949 
1950 						throw;
1951 
1952 						}
1953 
1954 					// Eat other parsing errors.
1955 
1956 					#if qDNGValidate
1957 
1958 					ReportWarning ("Unable to parse extra profile");
1959 
1960 					#endif
1961 
1962 					}
1963 
1964 				}
1965 
1966 			}
1967 
1968 		// As shot profile name.
1969 
1970 		if (shared.fAsShotProfileName.NotEmpty ())
1971 			{
1972 
1973 			SetAsShotProfileName (shared.fAsShotProfileName.Get ());
1974 
1975 			}
1976 
1977 		}
1978 
1979 	// Raw image data digest.
1980 
1981 	if (shared.fRawImageDigest.IsValid ())
1982 		{
1983 
1984 		SetRawImageDigest (shared.fRawImageDigest);
1985 
1986 		}
1987 
1988 	// Raw data unique ID.
1989 
1990 	if (shared.fRawDataUniqueID.IsValid ())
1991 		{
1992 
1993 		SetRawDataUniqueID (shared.fRawDataUniqueID);
1994 
1995 		}
1996 
1997 	// Original raw file name.
1998 
1999 	if (shared.fOriginalRawFileName.NotEmpty ())
2000 		{
2001 
2002 		SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
2003 
2004 		}
2005 
2006 	// Original raw file data.
2007 
2008 	if (shared.fOriginalRawFileDataCount)
2009 		{
2010 
2011 		SetHasOriginalRawFileData (true);
2012 
2013 		if (host.KeepOriginalFile ())
2014 			{
2015 
2016 			uint32 count = shared.fOriginalRawFileDataCount;
2017 
2018 			AutoPtr<dng_memory_block> block (host.Allocate (count));
2019 
2020 			stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
2021 
2022 			stream.Get (block->Buffer (), count);
2023 
2024 			SetOriginalRawFileData (block);
2025 
2026 			SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
2027 
2028 			ValidateOriginalRawFileDigest ();
2029 
2030 			}
2031 
2032 		}
2033 
2034 	// DNG private data.
2035 
2036 	if (shared.fDNGPrivateDataCount && host.KeepDNGPrivate ())
2037 		{
2038 
2039 		uint32 length = shared.fDNGPrivateDataCount;
2040 
2041 		AutoPtr<dng_memory_block> block (host.Allocate (length));
2042 
2043 		stream.SetReadPosition (shared.fDNGPrivateDataOffset);
2044 
2045 		stream.Get (block->Buffer (), length);
2046 
2047 		SetPrivateData (block);
2048 
2049 		}
2050 
2051 	// Hand off EXIF metadata to negative.
2052 
2053 	fExif.Reset (info.fExif.Release ());
2054 
2055 	// Parse linearization info.
2056 
2057 	NeedLinearizationInfo ();
2058 
2059 	fLinearizationInfo.Get ()->Parse (host,
2060 								      stream,
2061 								      info);
2062 
2063 	// Parse mosaic info.
2064 
2065 	if (rawIFD.fPhotometricInterpretation == piCFA)
2066 		{
2067 
2068 		NeedMosaicInfo ();
2069 
2070 		fMosaicInfo.Get ()->Parse (host,
2071 							       stream,
2072 							       info);
2073 
2074 		}
2075 
2076 	}
2077 
2078 /*****************************************************************************/
2079 
PostParse(dng_host & host,dng_stream & stream,dng_info & info)2080 void dng_negative::PostParse (dng_host &host,
2081 						  	  dng_stream &stream,
2082 						  	  dng_info &info)
2083 	{
2084 
2085 	// Shared info.
2086 
2087 	dng_shared &shared = *(info.fShared.Get ());
2088 
2089 	if (host.NeedsMeta ())
2090 		{
2091 
2092 		// MakerNote.
2093 
2094 		if (shared.fMakerNoteCount)
2095 			{
2096 
2097 			// See if we know if the MakerNote is safe or not.
2098 
2099 			SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
2100 
2101 			// If the MakerNote is safe, preserve it as a MakerNote.
2102 
2103 			if (IsMakerNoteSafe ())
2104 				{
2105 
2106 				AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
2107 
2108 				stream.SetReadPosition (shared.fMakerNoteOffset);
2109 
2110 				stream.Get (block->Buffer (), shared.fMakerNoteCount);
2111 
2112 				SetMakerNote (block);
2113 
2114 				}
2115 
2116 			}
2117 
2118 		// IPTC metadata.
2119 
2120 		if (shared.fIPTC_NAA_Count)
2121 			{
2122 
2123 			AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
2124 
2125 			stream.SetReadPosition (shared.fIPTC_NAA_Offset);
2126 
2127 			uint64 iptcOffset = stream.PositionInOriginalFile();
2128 
2129 			stream.Get (block->Buffer      (),
2130 						block->LogicalSize ());
2131 
2132 			SetIPTC (block, iptcOffset);
2133 
2134 			}
2135 
2136 		// XMP metadata.
2137 
2138 		if (shared.fXMPCount)
2139 			{
2140 
2141 			AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount));
2142 
2143 			stream.SetReadPosition (shared.fXMPOffset);
2144 
2145 			stream.Get (block->Buffer      (),
2146 						block->LogicalSize ());
2147 
2148 			fValidEmbeddedXMP = SetXMP (host,
2149 										block->Buffer      (),
2150 										block->LogicalSize ());
2151 
2152 			#if qDNGValidate
2153 
2154 			if (!fValidEmbeddedXMP)
2155 				{
2156 				ReportError ("The embedded XMP is invalid");
2157 				}
2158 
2159 			#endif
2160 
2161 			}
2162 
2163 		// Color info.
2164 
2165 		if (!IsMonochrome ())
2166 			{
2167 
2168 			// If the ColorimetricReference is the ICC profile PCS,
2169 			// then the data must be already be white balanced to the
2170 			// ICC profile PCS white point.
2171 
2172 			if (ColorimetricReference () == crICCProfilePCS)
2173 				{
2174 
2175 				ClearCameraNeutral ();
2176 
2177 				SetCameraWhiteXY (PCStoXY ());
2178 
2179 				}
2180 
2181 			else
2182 				{
2183 
2184 				// AsShotNeutral.
2185 
2186 				if (shared.fAsShotNeutral.Count () == ColorChannels ())
2187 					{
2188 
2189 					SetCameraNeutral (shared.fAsShotNeutral);
2190 
2191 					}
2192 
2193 				// AsShotWhiteXY.
2194 
2195 				if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
2196 					{
2197 
2198 					SetCameraWhiteXY (shared.fAsShotWhiteXY);
2199 
2200 					}
2201 
2202 				}
2203 
2204 			}
2205 
2206 		}
2207 
2208 	}
2209 
2210 /*****************************************************************************/
2211 
SynchronizeMetadata()2212 void dng_negative::SynchronizeMetadata ()
2213 	{
2214 
2215 	if (!fOriginalExif.Get ())
2216 		{
2217 
2218 		fOriginalExif.Reset (fExif->Clone ());
2219 
2220 		}
2221 
2222 	fXMP->IngestIPTC (*this, fXMPisNewer);
2223 
2224 	fXMP->SyncExif (*fExif.Get ());
2225 
2226 	fXMP->SyncOrientation (*this, fXMPinSidecar);
2227 
2228 	}
2229 
2230 /*****************************************************************************/
2231 
UpdateDateTime(const dng_date_time_info & dt)2232 void dng_negative::UpdateDateTime (const dng_date_time_info &dt)
2233 	{
2234 
2235 	fExif->UpdateDateTime (dt);
2236 
2237 	fXMP->UpdateDateTime (dt);
2238 
2239 	}
2240 
2241 /*****************************************************************************/
2242 
UpdateDateTimeToNow()2243 void dng_negative::UpdateDateTimeToNow ()
2244 	{
2245 
2246 	dng_date_time_info dt;
2247 
2248 	CurrentDateTimeAndZone (dt);
2249 
2250 	UpdateDateTime (dt);
2251 
2252 	}
2253 
2254 /*****************************************************************************/
2255 
SetFourColorBayer()2256 bool dng_negative::SetFourColorBayer ()
2257 	{
2258 
2259 	if (ColorChannels () != 3)
2260 		{
2261 		return false;
2262 		}
2263 
2264 	if (!fMosaicInfo.Get ())
2265 		{
2266 		return false;
2267 		}
2268 
2269 	if (!fMosaicInfo.Get ()->SetFourColorBayer ())
2270 		{
2271 		return false;
2272 		}
2273 
2274 	SetColorChannels (4);
2275 
2276 	if (fCameraNeutral.Count () == 3)
2277 		{
2278 
2279 		dng_vector n (4);
2280 
2281 		n [0] = fCameraNeutral [0];
2282 		n [1] = fCameraNeutral [1];
2283 		n [2] = fCameraNeutral [2];
2284 		n [3] = fCameraNeutral [1];
2285 
2286 		fCameraNeutral = n;
2287 
2288 		}
2289 
2290 	fCameraCalibration1.Clear ();
2291 	fCameraCalibration2.Clear ();
2292 
2293 	fCameraCalibrationSignature.Clear ();
2294 
2295 	for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
2296 		{
2297 
2298 		fCameraProfile [index]->SetFourColorBayer ();
2299 
2300 		}
2301 
2302 	return true;
2303 
2304 	}
2305 
2306 /*****************************************************************************/
2307 
RawImage() const2308 const dng_image & dng_negative::RawImage () const
2309 	{
2310 
2311 	if (fStage1Image.Get ())
2312 		{
2313 		return *fStage1Image.Get ();
2314 		}
2315 
2316 	if (fStage2Image.Get ())
2317 		{
2318 		return *fStage2Image.Get ();
2319 		}
2320 
2321 	DNG_ASSERT (fStage3Image.Get (),
2322 				"dng_negative::RawImage with no raw image");
2323 
2324 	return *fStage3Image.Get ();
2325 
2326 	}
2327 
2328 /*****************************************************************************/
2329 
ReadStage1Image(dng_host & host,dng_stream & stream,dng_info & info)2330 void dng_negative::ReadStage1Image (dng_host &host,
2331 									dng_stream &stream,
2332 									dng_info &info)
2333 	{
2334 
2335 	dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
2336 
2337 	fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
2338 											 rawIFD.fSamplesPerPixel,
2339 											 rawIFD.PixelType ()));
2340 
2341 	rawIFD.ReadImage (host,
2342 					  stream,
2343 					  *fStage1Image.Get ());
2344 
2345 	}
2346 
2347 /*****************************************************************************/
2348 
SetStage1Image(AutoPtr<dng_image> & image)2349 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
2350 	{
2351 
2352 	fStage1Image.Reset (image.Release ());
2353 
2354 	}
2355 
2356 /*****************************************************************************/
2357 
DoBuildStage2(dng_host & host,uint32 pixelType)2358 void dng_negative::DoBuildStage2 (dng_host &host,
2359 								  uint32 pixelType)
2360 	{
2361 
2362 	dng_image &stage1 = *fStage1Image.Get ();
2363 
2364 	dng_linearization_info &info = *fLinearizationInfo.Get ();
2365 
2366 	fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
2367 											 stage1.Planes (),
2368 											 pixelType));
2369 
2370 	info.Linearize (host,
2371 					stage1,
2372 					*fStage2Image.Get ());
2373 
2374 	}
2375 
2376 /*****************************************************************************/
2377 
BuildStage2Image(dng_host & host,uint32 pixelType)2378 void dng_negative::BuildStage2Image (dng_host &host,
2379 									 uint32 pixelType)
2380 	{
2381 
2382 	// Finalize linearization info.
2383 
2384 		{
2385 
2386 		NeedLinearizationInfo ();
2387 
2388 		dng_linearization_info &info = *fLinearizationInfo.Get ();
2389 
2390 		info.PostParse (host, *this);
2391 
2392 		}
2393 
2394 	// Perform the linearization.
2395 
2396 	DoBuildStage2 (host,
2397 			       pixelType);
2398 
2399 	// Delete the stage1 image now if we are not keeping it around.
2400 
2401 	if (!host.KeepStage1 ())
2402 		{
2403 
2404 		ClearStage1 ();
2405 
2406 		}
2407 
2408 	}
2409 
2410 /*****************************************************************************/
2411 
ClearStage1()2412 void dng_negative::ClearStage1 ()
2413 	{
2414 
2415 	if (fStage1Image.Get ())
2416 		{
2417 
2418 		fStage1Image.Reset ();
2419 
2420 		ClearRawImageDigest ();
2421 
2422 		}
2423 
2424 	// If we are not keeping the stage 1 image, then the linearization
2425 	// information is now useless.
2426 
2427 	ClearLinearizationInfo ();
2428 
2429 	}
2430 
2431 /*****************************************************************************/
2432 
DoBuildStage3(dng_host & host,int32 srcPlane)2433 void dng_negative::DoBuildStage3 (dng_host &host,
2434 								  int32 srcPlane)
2435 	{
2436 
2437 	dng_image &stage2 = *fStage2Image.Get ();
2438 
2439 	dng_mosaic_info &info = *fMosaicInfo.Get ();
2440 
2441 	dng_point downScale = info.DownScale (host.MinimumSize   (),
2442 										  host.PreferredSize (),
2443 										  host.CropFactor    ());
2444 
2445 	if (downScale != dng_point (1, 1))
2446 		{
2447 		SetIsPreview (true);
2448 		}
2449 
2450 	dng_point dstSize = info.DstSize (downScale);
2451 
2452 	fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
2453 											 info.fColorPlanes,
2454 											 stage2.PixelType ()));
2455 
2456 	if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
2457 		{
2458 		srcPlane = 0;
2459 		}
2460 
2461 	info.Interpolate (host,
2462 					  *this,
2463 					  stage2,
2464 					  *fStage3Image.Get (),
2465 					  downScale,
2466 					  srcPlane);
2467 
2468 	}
2469 
2470 /*****************************************************************************/
2471 
2472 // Interpolate and merge a multi-channel CFA image.
2473 
DoMergeStage3(dng_host & host)2474 void dng_negative::DoMergeStage3 (dng_host &host)
2475 	{
2476 
2477 	// The DNG SDK does not provide multi-channel CFA image merging code.
2478 	// It just grabs the first channel and uses that.
2479 
2480 	DoBuildStage3 (host, 0);
2481 
2482 	// Just grabbing the first channel would often result in the very
2483 	// bright image using the baseline exposure value.
2484 
2485 	fStage3Gain = pow (2.0, BaselineExposure ());
2486 
2487 	}
2488 
2489 /*****************************************************************************/
2490 
BuildStage3Image(dng_host & host,int32 srcPlane)2491 void dng_negative::BuildStage3Image (dng_host &host,
2492 									 int32 srcPlane)
2493 	{
2494 
2495 	// Finalize the mosaic information.
2496 
2497 	dng_mosaic_info *info = fMosaicInfo.Get ();
2498 
2499 	if (info)
2500 		{
2501 
2502 		info->PostParse (host, *this);
2503 
2504 		}
2505 
2506 	// If we don't have a mosaic pattern, then just move the stage 2
2507 	// image on to stage 3.
2508 
2509 	if (!info || !info->IsColorFilterArray ())
2510 		{
2511 
2512 		fStage3Image.Reset (fStage2Image.Release ());
2513 
2514 		}
2515 
2516 	else
2517 		{
2518 
2519 		// Remember the size of the stage 2 image.
2520 
2521 		dng_point stage2_size = fStage2Image->Size ();
2522 
2523 		// Special case multi-channel CFA interpolation.
2524 
2525 		if ((fStage2Image->Planes () > 1) && (srcPlane < 0))
2526 			{
2527 
2528 			DoMergeStage3 (host);
2529 
2530 			}
2531 
2532 		// Else do a single channel interpolation.
2533 
2534 		else
2535 			{
2536 
2537 			DoBuildStage3 (host, srcPlane);
2538 
2539 			}
2540 
2541 		// Calculate the ratio of the stage 3 image size to stage 2 image size.
2542 
2543 		dng_point stage3_size = fStage3Image->Size ();
2544 
2545 		fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
2546 		fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
2547 
2548 		}
2549 
2550 	// Delete the stage2 image if we are done with it.
2551 
2552 	if (!host.KeepStage2 ())
2553 		{
2554 
2555 		ClearStage2 ();
2556 
2557 		}
2558 
2559 	}
2560 
2561 /*****************************************************************************/
2562 
ClearStage2()2563 void dng_negative::ClearStage2 ()
2564 	{
2565 
2566 	if (fStage2Image.Get ())
2567 		{
2568 
2569 		fStage2Image.Reset ();
2570 
2571 		ClearRawImageDigest ();
2572 
2573 		}
2574 
2575 	// If we did not keep the stage 1 image, and we are not keeping
2576 	// the stage 2 image either, then the mosaic information is now
2577 	// useless.
2578 
2579 	if (!fStage1Image.Get ())
2580 		{
2581 
2582 		ClearMosaicInfo ();
2583 
2584 		// To support saving linear DNG files, to need to account for
2585 		// and upscaling during interpolation.
2586 
2587 		if (fRawToFullScaleH > 1.0)
2588 			{
2589 
2590 			uint32 adjust = Round_uint32 (fRawToFullScaleH);
2591 
2592 			fDefaultCropSizeH  .n *= adjust;
2593 			fDefaultCropOriginH.n *= adjust;
2594 			fDefaultScaleH     .d *= adjust;
2595 
2596 			fRawToFullScaleH /= (real64) adjust;
2597 
2598 			}
2599 
2600 		if (fRawToFullScaleV > 1.0)
2601 			{
2602 
2603 			uint32 adjust = Round_uint32 (fRawToFullScaleV);
2604 
2605 			fDefaultCropSizeV  .n *= adjust;
2606 			fDefaultCropOriginV.n *= adjust;
2607 			fDefaultScaleV     .d *= adjust;
2608 
2609 			fRawToFullScaleV /= (real64) adjust;
2610 
2611 			}
2612 
2613 		}
2614 
2615 	}
2616 
2617 /*****************************************************************************/
2618 
ClearStage3()2619 void dng_negative::ClearStage3 ()
2620 	{
2621 
2622 	fStage3Image.Reset ();
2623 
2624 	}
2625 
2626 /*****************************************************************************/
2627 
MakeExif()2628 dng_exif * dng_negative::MakeExif ()
2629 	{
2630 
2631 	dng_exif *exif = new dng_exif ();
2632 
2633 	if (!exif)
2634 		{
2635 		ThrowMemoryFull ();
2636 		}
2637 
2638 	return exif;
2639 
2640 	}
2641 
2642 /*****************************************************************************/
2643 
MakeXMP()2644 dng_xmp * dng_negative::MakeXMP ()
2645 	{
2646 
2647 	dng_xmp *xmp = new dng_xmp (Allocator ());
2648 
2649 	if (!xmp)
2650 		{
2651 		ThrowMemoryFull ();
2652 		}
2653 
2654 	return xmp;
2655 
2656 	}
2657 
2658 /*****************************************************************************/
2659 
MakeLinearizationInfo()2660 dng_linearization_info * dng_negative::MakeLinearizationInfo ()
2661 	{
2662 
2663 	dng_linearization_info *info = new dng_linearization_info ();
2664 
2665 	if (!info)
2666 		{
2667 		ThrowMemoryFull ();
2668 		}
2669 
2670 	return info;
2671 
2672 	}
2673 
2674 /*****************************************************************************/
2675 
NeedLinearizationInfo()2676 void dng_negative::NeedLinearizationInfo ()
2677 	{
2678 
2679 	if (!fLinearizationInfo.Get ())
2680 		{
2681 
2682 		fLinearizationInfo.Reset (MakeLinearizationInfo ());
2683 
2684 		}
2685 
2686 	}
2687 
2688 /*****************************************************************************/
2689 
MakeMosaicInfo()2690 dng_mosaic_info * dng_negative::MakeMosaicInfo ()
2691 	{
2692 
2693 	dng_mosaic_info *info = new dng_mosaic_info ();
2694 
2695 	if (!info)
2696 		{
2697 		ThrowMemoryFull ();
2698 		}
2699 
2700 	return info;
2701 
2702 	}
2703 
2704 /*****************************************************************************/
2705 
NeedMosaicInfo()2706 void dng_negative::NeedMosaicInfo ()
2707 	{
2708 
2709 	if (!fMosaicInfo.Get ())
2710 		{
2711 
2712 		fMosaicInfo.Reset (MakeMosaicInfo ());
2713 
2714 		}
2715 
2716 	}
2717 
2718 /*****************************************************************************/
2719