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