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