Ejemplo n.º 1
0
void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const
	{
	
	DNG_ASSERT (fCompressedData.Get (),
				"SpoolAdobeThumbnail: no data");
	
	DNG_ASSERT (fPhotometricInterpretation == piYCbCr,
				"SpoolAdobeThumbnail: Non-YCbCr");
	
	uint32 compressedSize = fCompressedData->LogicalSize ();
	
	stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
	stream.Put_uint16 (1036);
	stream.Put_uint16 (0);
	
	stream.Put_uint32 (compressedSize + 28);
	
	uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4;
	
	stream.Put_uint32 (1);
	stream.Put_uint32 (fPreviewSize.h);
	stream.Put_uint32 (fPreviewSize.v);
	stream.Put_uint32 (widthBytes);
	stream.Put_uint32 (widthBytes * fPreviewSize.v);
	stream.Put_uint32 (compressedSize);
	stream.Put_uint16 (24);
	stream.Put_uint16 (1);
	
	stream.Put (fCompressedData->Buffer (),
			    compressedSize);
			    
	if (compressedSize & 1)
		{
		stream.Put_uint8 (0);
		}
	
	}
Ejemplo n.º 2
0
void dng_info::ParseDNGPrivateData (dng_host &host,
									dng_stream &stream)
	{
	
	if (fShared->fDNGPrivateDataCount < 2)
		{
		return;
		}
	
	// DNG private data should always start with a null-terminated 
	// company name, to define the format of the private data.
			
	dng_string privateName;
			
		{
			
		char buffer [64];
		
		stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
	
		uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
										sizeof (buffer) - 1);
		
		stream.Get (buffer, readLength);
		
		buffer [readLength] = 0;
		
		privateName.Set (buffer);
		
		}
		
	// Pentax is storing their MakerNote in the DNGPrivateData data.
	
	if (privateName.StartsWith ("PENTAX" ) ||
		privateName.StartsWith ("SAMSUNG"))
		{
		
		#if qDNGValidate
		
		if (gVerbose)
			{
			printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
			}
			
		#endif

		stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
		
		bool bigEndian = stream.BigEndian ();
		
		uint16 endianMark = stream.Get_uint16 ();
		
		if (endianMark == byteOrderMM)
			{
			bigEndian = true;
			}
			
		else if (endianMark == byteOrderII)
			{
			bigEndian = false;
			}
			
		TempBigEndian temp_endian (stream, bigEndian);
	
		ParseMakerNoteIFD (host,
						   stream,
						   fShared->fDNGPrivateDataCount - 10,
						   fShared->fDNGPrivateDataOffset + 10,
						   fShared->fDNGPrivateDataOffset,
						   fShared->fDNGPrivateDataOffset,
						   fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
						   tcPentaxMakerNote);
						   
		return;
		
		}
				
	// Stop parsing if this is not an Adobe format block.
	
	if (!privateName.Matches ("Adobe"))
		{
		return;
		}
	
	TempBigEndian temp_order (stream);
	
	uint32 section_offset = 6;
	
	while (section_offset + 8 < fShared->fDNGPrivateDataCount)
		{
		
		stream.SetReadPosition (fShared->fDNGPrivateDataOffset + section_offset);
		
		uint32 section_key   = stream.Get_uint32 ();
		uint32 section_count = stream.Get_uint32 ();
		
		if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
			{
			
			#if qDNGValidate
			
			if (gVerbose)
				{
				printf ("Found MakerNote inside DNGPrivateData\n\n");
				}
				
			#endif
				
			uint16 order_mark = stream.Get_uint16 ();
			uint64 old_offset = stream.Get_uint32 ();

			uint32 tempSize = section_count - 6;
			
			AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
			
			uint64 positionInOriginalFile = stream.PositionInOriginalFile();
			
			stream.Get (tempBlock->Buffer (), tempSize);
			
			dng_stream tempStream (tempBlock->Buffer (),
								   tempSize,
								   positionInOriginalFile);
								   
			tempStream.SetBigEndian (order_mark == byteOrderMM);
			
			ParseMakerNote (host,
							tempStream,
							tempSize,
							0,
							0 - old_offset,
							0,
							tempSize);
	
			}
			
		else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
			{
			
			#if qDNGValidate
			
			if (gVerbose)
				{
				printf ("Found Sony private data inside DNGPrivateData\n\n");
				}
				
			#endif
			
			uint16 order_mark = stream.Get_uint16 ();
			uint64 old_offset = stream.Get_uint32 ();

			uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
			
			TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
			
			ParseSonyPrivateData (host,
							  	  stream,
								  section_count - 6,
								  old_offset,
								  new_offset);
				
			}

		else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
			{
			
			#if qDNGValidate
			
			if (gVerbose)
				{
				printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
				}
				
			#endif
			
			uint16 order_mark = stream.Get_uint16 ();
			
			uint32 tagCount = stream.Get_uint32 ();
			
			uint64 tagOffset = stream.Position ();
				
			if (tagCount)
				{
				
				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
				
				ParseTag (host,
						  stream,
						  fExif.Get (),
						  fShared.Get (),
						  NULL,
						  tcFujiRAF,
						  tcFujiHeader,
						  ttUndefined,
						  tagCount,
						  tagOffset,
						  0);
						  
				stream.SetReadPosition (tagOffset + tagCount);
				
				}
			
			tagCount = stream.Get_uint32 ();
			
			tagOffset = stream.Position ();
				
			if (tagCount)
				{
				
				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
				
				ParseTag (host,
						  stream,
						  fExif.Get (),
						  fShared.Get (),
						  NULL,
						  tcFujiRAF,
						  tcFujiRawInfo1,
						  ttUndefined,
						  tagCount,
						  tagOffset,
						  0);
						  
				stream.SetReadPosition (tagOffset + tagCount);
				
				}
			
			tagCount = stream.Get_uint32 ();
			
			tagOffset = stream.Position ();
				
			if (tagCount)
				{
				
				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
				
				ParseTag (host,
						  stream,
						  fExif.Get (),
						  fShared.Get (),
						  NULL,
						  tcFujiRAF,
						  tcFujiRawInfo2,
						  ttUndefined,
						  tagCount,
						  tagOffset,
						  0);
						  
				stream.SetReadPosition (tagOffset + tagCount);
				
				}
			
			}

		else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
			{
			
			#if qDNGValidate
			
			if (gVerbose)
				{
				printf ("Found Contax Raw header inside DNGPrivateData\n\n");
				}
				
			#endif
			
			uint16 order_mark = stream.Get_uint16 ();
			
			uint32 tagCount  = stream.Get_uint32 ();
			
			uint64 tagOffset = stream.Position ();
				
			if (tagCount)
				{
				
				TempBigEndian contax_order (stream, order_mark == byteOrderMM);
				
				ParseTag (host,
						  stream,
						  fExif.Get (),
						  fShared.Get (),
						  NULL,
						  tcContaxRAW,
						  tcContaxHeader,
						  ttUndefined,
						  tagCount,
						  tagOffset,
						  0);
						  
				}
			
			}
			
		else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
			{
			
			#if qDNGValidate
			
			if (gVerbose)
				{
				printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
				}
				
			#endif
				
			uint16 order_mark = stream.Get_uint16 ();
			uint32 entries    = stream.Get_uint16 ();
			
			uint64 crwTagStart = stream.Position ();
			
			for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
				{
				
				stream.SetReadPosition (crwTagStart);
			
				for (uint32 index = 0; index < entries; index++)
					{
					
					uint32 tagCode = stream.Get_uint16 ();
											 
					uint32 tagCount = stream.Get_uint32 ();
					
					uint64 tagOffset = stream.Position ();
					
					// We need to grab the model id tag first, and then all the
					// other tags.
					
					if ((parsePass == 1) == (tagCode == 0x5834))
						{
				
						TempBigEndian tag_order (stream, order_mark == byteOrderMM);
					
						ParseTag (host,
								  stream,
								  fExif.Get (),
								  fShared.Get (),
								  NULL,
								  tcCanonCRW,
								  tagCode,
								  ttUndefined,
								  tagCount,
								  tagOffset,
								  0);
								  
						}
					
					stream.SetReadPosition (tagOffset + tagCount);
					
					}
					
				}
			
			}

		else if (section_count > 4)
			{
			
			uint32 parentCode = 0;
			
			bool code32  = false;
			bool hasType = true;
			
			switch (section_key)
				{
				
				case DNG_CHAR4 ('M','R','W',' '):
					{
					parentCode = tcMinoltaMRW;
					code32     = true;
					hasType    = false;
					break;
					}
				
				case DNG_CHAR4 ('P','a','n','o'):
					{
					parentCode = tcPanasonicRAW;
					break;
					}
					
				case DNG_CHAR4 ('L','e','a','f'):
					{
					parentCode = tcLeafMOS;
					break;
					}
					
				case DNG_CHAR4 ('K','o','d','a'):
					{
					parentCode = tcKodakDCRPrivateIFD;
					break;
					}
					
				case DNG_CHAR4 ('K','D','C',' '):
					{
					parentCode = tcKodakKDCPrivateIFD;
					break;
					}
					
				default:
					break;
					
				}

			if (parentCode)
				{
			
				#if qDNGValidate
				
				if (gVerbose)
					{
					printf ("Found %s tags inside DNGPrivateData\n\n",
							LookupParentCode (parentCode));
					}
					
				#endif
				
				uint16 order_mark = stream.Get_uint16 ();
				uint32 entries    = stream.Get_uint16 ();
				
				for (uint32 index = 0; index < entries; index++)
					{
					
					uint32 tagCode = code32 ? stream.Get_uint32 ()
											: stream.Get_uint16 ();
											 
					uint32 tagType  = hasType ? stream.Get_uint16 () 
											  : ttUndefined;
					
					uint32 tagCount = stream.Get_uint32 ();
					
					uint32 tagSize = tagCount * TagTypeSize (tagType);
					
					uint64 tagOffset = stream.Position ();
					
					TempBigEndian tag_order (stream, order_mark == byteOrderMM);
				
					ParseTag (host,
							  stream,
							  fExif.Get (),
							  fShared.Get (),
							  NULL,
							  parentCode,
							  tagCode,
							  tagType,
							  tagCount,
							  tagOffset,
							  0);
					
					stream.SetReadPosition (tagOffset + tagSize);
					
					}
					
				}
			
			}
		
		section_offset += 8 + section_count;
		
		if (section_offset & 1)
			{
			section_offset++;
			}
		
		}
		
	}
Ejemplo n.º 3
0
void NegativeProcessor::setExifFromRaw(const dng_date_time_info &dateTimeNow, const dng_string &appNameVersion) {
    dng_exif *negExif = m_negative->GetExif();

    // -----------------------------------------------------------------------------------------
    // TIFF 6.0 "D. Other Tags"
    getRawExifTag("Exif.Image.DateTime", &negExif->fDateTime);
    getRawExifTag("Exif.Image.ImageDescription", &negExif->fImageDescription);
    getRawExifTag("Exif.Image.Make", &negExif->fMake);
    getRawExifTag("Exif.Image.Model", &negExif->fModel);
    getRawExifTag("Exif.Image.Software", &negExif->fSoftware);
    getRawExifTag("Exif.Image.Artist", &negExif->fArtist);
    getRawExifTag("Exif.Image.Copyright", &negExif->fCopyright);

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "A. Tags Relating to Version" (order as in spec)
    getRawExifTag("Exif.Photo.ExifVersion", 0, &negExif->fExifVersion);
    // Exif.Photo.FlashpixVersion - fFlashPixVersion : ignoring this here

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "B. Tags Relating to Image data Characteristics" (order as in spec)
    getRawExifTag("Exif.Photo.ColorSpace", 0, &negExif->fColorSpace);
    // Gamma : Supported by DNG SDK (fGamma) but not Exiv2 (v0.24)

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "C. Tags Relating To Image Configuration" (order as in spec)
    getRawExifTag("Exif.Photo.ComponentsConfiguration", 0, &negExif->fComponentsConfiguration);
    getRawExifTag("Exif.Photo.CompressedBitsPerPixel", 0, &negExif->fCompresssedBitsPerPixel);  // nice typo in DNG SDK...
    getRawExifTag("Exif.Photo.PixelXDimension", 0, &negExif->fPixelXDimension);
    getRawExifTag("Exif.Photo.PixelYDimension", 0, &negExif->fPixelYDimension);

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "D. Tags Relating to User Information" (order as in spec)
    // MakerNote: We'll deal with that below
    getRawExifTag("Exif.Photo.UserComment", &negExif->fUserComment);

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "E. Tags Relating to Related File Information" (order as in spec)
    // RelatedSoundFile : DNG SDK doesn't support this

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "F. Tags Relating to Date and Time" (order as in spec)
    getRawExifTag("Exif.Photo.DateTimeOriginal", &negExif->fDateTimeOriginal);
    getRawExifTag("Exif.Photo.DateTimeDigitized", &negExif->fDateTimeDigitized);
    // SubSecTime          : DNG SDK doesn't support this
    // SubSecTimeOriginal  : DNG SDK doesn't support this
    // SubSecTimeDigitized : DNG SDK doesn't support this

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "G. Tags Relating to Picture-Taking Conditions" (order as in spec)
    getRawExifTag("Exif.Photo.ExposureTime", 0, &negExif->fExposureTime);
    getRawExifTag("Exif.Photo.FNumber", 0, &negExif->fFNumber);
    getRawExifTag("Exif.Photo.ExposureProgram", 0, &negExif->fExposureProgram);
    // SpectralSensitivity : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.ISOSpeedRatings", negExif->fISOSpeedRatings, 3); // PhotographicSensitivity in Exif 2.3
    // OECF : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.SensitivityType", 0, &negExif->fSensitivityType);
    getRawExifTag("Exif.Photo.StandardOutputSensitivity", 0, &negExif->fStandardOutputSensitivity);
    getRawExifTag("Exif.Photo.RecommendedExposureIndex", 0, &negExif->fRecommendedExposureIndex);
    getRawExifTag("Exif.Photo.ISOSpeed", 0, &negExif->fISOSpeed);
    getRawExifTag("Exif.Photo.ISOSpeedLatitudeyyy", 0, &negExif->fISOSpeedLatitudeyyy);
    getRawExifTag("Exif.Photo.ISOSpeedLatitudezzz", 0, &negExif->fISOSpeedLatitudezzz);
    getRawExifTag("Exif.Photo.ShutterSpeedValue", 0, &negExif->fShutterSpeedValue);
    getRawExifTag("Exif.Photo.ApertureValue", 0, &negExif->fApertureValue);
    getRawExifTag("Exif.Photo.BrightnessValue", 0, &negExif->fBrightnessValue);
    getRawExifTag("Exif.Photo.ExposureBiasValue", 0, &negExif->fExposureBiasValue);
    getRawExifTag("Exif.Photo.MaxApertureValue", 0, &negExif->fMaxApertureValue);
    getRawExifTag("Exif.Photo.SubjectDistance", 0, &negExif->fSubjectDistance);
    getRawExifTag("Exif.Photo.MeteringMode", 0, &negExif->fMeteringMode);
    getRawExifTag("Exif.Photo.LightSource", 0, &negExif->fLightSource);
    getRawExifTag("Exif.Photo.Flash", 0, &negExif->fFlash);
    getRawExifTag("Exif.Photo.FocalLength", 0, &negExif->fFocalLength);
    negExif->fSubjectAreaCount = getRawExifTag("Exif.Photo.SubjectArea", negExif->fSubjectArea, 4);
    // FlashEnergy : DNG SDK doesn't support this
    // SpatialFrequencyResponse : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.FocalPlaneXResolution", 0, &negExif->fFocalPlaneXResolution);
    getRawExifTag("Exif.Photo.FocalPlaneYResolution", 0, &negExif->fFocalPlaneYResolution);
    getRawExifTag("Exif.Photo.FocalPlaneResolutionUnit", 0, &negExif->fFocalPlaneResolutionUnit);
    // SubjectLocation : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.ExposureIndex", 0, &negExif->fExposureIndex);
    getRawExifTag("Exif.Photo.SensingMethod", 0, &negExif->fSensingMethod);
    getRawExifTag("Exif.Photo.FileSource", 0, &negExif->fFileSource);
    getRawExifTag("Exif.Photo.SceneType", 0, &negExif->fSceneType);
    // CFAPattern: we write it manually from raw data further below
    getRawExifTag("Exif.Photo.CustomRendered", 0, &negExif->fCustomRendered);
    getRawExifTag("Exif.Photo.ExposureMode", 0, &negExif->fExposureMode);
    getRawExifTag("Exif.Photo.WhiteBalance", 0, &negExif->fWhiteBalance);
    getRawExifTag("Exif.Photo.DigitalZoomRatio", 0, &negExif->fDigitalZoomRatio);
    getRawExifTag("Exif.Photo.FocalLengthIn35mmFilm", 0, &negExif->fFocalLengthIn35mmFilm);
    getRawExifTag("Exif.Photo.SceneCaptureType", 0, &negExif->fSceneCaptureType);
    getRawExifTag("Exif.Photo.GainControl", 0, &negExif->fGainControl);
    getRawExifTag("Exif.Photo.Contrast", 0, &negExif->fContrast);
    getRawExifTag("Exif.Photo.Saturation", 0, &negExif->fSaturation);
    getRawExifTag("Exif.Photo.Sharpness", 0, &negExif->fSharpness);
    // DeviceSettingsDescription : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.SubjectDistanceRange", 0, &negExif->fSubjectDistanceRange);

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 "H. Other Tags" (order as in spec)
    // ImageUniqueID : DNG SDK doesn't support this
    getRawExifTag("Exif.Photo.CameraOwnerName", &negExif->fOwnerName);
    getRawExifTag("Exif.Photo.BodySerialNumber", &negExif->fCameraSerialNumber);
    getRawExifTag("Exif.Photo.LensSpecification", negExif->fLensInfo, 4);
    getRawExifTag("Exif.Photo.LensMake", &negExif->fLensMake);
    getRawExifTag("Exif.Photo.LensModel", &negExif->fLensName);
    getRawExifTag("Exif.Photo.LensSerialNumber", &negExif->fLensSerialNumber);

    // -----------------------------------------------------------------------------------------
    // Exif 2.3 GPS "A. Tags Relating to GPS" (order as in spec)
    uint32 gpsVer[4];  gpsVer[0] = gpsVer[1] = gpsVer[2] = gpsVer[3] = 0;
    getRawExifTag("Exif.GPSInfo.GPSVersionID", gpsVer, 4);
    negExif->fGPSVersionID = (gpsVer[0] << 24) + (gpsVer[1] << 16) + (gpsVer[2] <<  8) + gpsVer[3];
    getRawExifTag("Exif.GPSInfo.GPSLatitudeRef", &negExif->fGPSLatitudeRef);
    getRawExifTag("Exif.GPSInfo.GPSLatitude", negExif->fGPSLatitude, 3);
    getRawExifTag("Exif.GPSInfo.GPSLongitudeRef", &negExif->fGPSLongitudeRef);
    getRawExifTag("Exif.GPSInfo.GPSLongitude", negExif->fGPSLongitude, 3);
    getRawExifTag("Exif.GPSInfo.GPSAltitudeRef", 0, &negExif->fGPSAltitudeRef);
    getRawExifTag("Exif.GPSInfo.GPSAltitude", 0, &negExif->fGPSAltitude);
    getRawExifTag("Exif.GPSInfo.GPSTimeStamp", negExif->fGPSTimeStamp, 3);
    getRawExifTag("Exif.GPSInfo.GPSSatellites", &negExif->fGPSSatellites);
    getRawExifTag("Exif.GPSInfo.GPSStatus", &negExif->fGPSStatus);
    getRawExifTag("Exif.GPSInfo.GPSMeasureMode", &negExif->fGPSMeasureMode);
    getRawExifTag("Exif.GPSInfo.GPSDOP", 0, &negExif->fGPSDOP);
    getRawExifTag("Exif.GPSInfo.GPSSpeedRef", &negExif->fGPSSpeedRef);
    getRawExifTag("Exif.GPSInfo.GPSSpeed", 0, &negExif->fGPSSpeed);
    getRawExifTag("Exif.GPSInfo.GPSTrackRef", &negExif->fGPSTrackRef);
    getRawExifTag("Exif.GPSInfo.GPSTrack", 0, &negExif->fGPSTrack);
    getRawExifTag("Exif.GPSInfo.GPSImgDirectionRef", &negExif->fGPSImgDirectionRef);
    getRawExifTag("Exif.GPSInfo.GPSImgDirection", 0, &negExif->fGPSImgDirection);
    getRawExifTag("Exif.GPSInfo.GPSMapDatum", &negExif->fGPSMapDatum);
    getRawExifTag("Exif.GPSInfo.GPSDestLatitudeRef", &negExif->fGPSDestLatitudeRef);
    getRawExifTag("Exif.GPSInfo.GPSDestLatitude", negExif->fGPSDestLatitude, 3);
    getRawExifTag("Exif.GPSInfo.GPSDestLongitudeRef", &negExif->fGPSDestLongitudeRef);
    getRawExifTag("Exif.GPSInfo.GPSDestLongitude", negExif->fGPSDestLongitude, 3);
    getRawExifTag("Exif.GPSInfo.GPSDestBearingRef", &negExif->fGPSDestBearingRef);
    getRawExifTag("Exif.GPSInfo.GPSDestBearing", 0, &negExif->fGPSDestBearing);
    getRawExifTag("Exif.GPSInfo.GPSDestDistanceRef", &negExif->fGPSDestDistanceRef);
    getRawExifTag("Exif.GPSInfo.GPSDestDistance", 0, &negExif->fGPSDestDistance);
    getRawExifTag("Exif.GPSInfo.GPSProcessingMethod", &negExif->fGPSProcessingMethod);
    getRawExifTag("Exif.GPSInfo.GPSAreaInformation", &negExif->fGPSAreaInformation);
    getRawExifTag("Exif.GPSInfo.GPSDateStamp", &negExif->fGPSDateStamp);
    getRawExifTag("Exif.GPSInfo.GPSDifferential", 0, &negExif->fGPSDifferential);
    // GPSHPositioningError : Supported by DNG SDK (fGPSHPositioningError) but not Exiv2 (v0.24)

    // -----------------------------------------------------------------------------------------
    // Exif 2.3, Interoperability IFD "A. Attached Information Related to Interoperability"
    getRawExifTag("Exif.Iop.InteroperabilityIndex", &negExif->fInteroperabilityIndex);
    getRawExifTag("Exif.Iop.InteroperabilityVersion", 0, &negExif->fInteroperabilityVersion); // this is not in the Exif standard but in DNG SDK and Exiv2

/*  Fields in the DNG SDK Exif structure that we are ignoring here. Some could potentially be 
    read through Exiv2 but are not part of the Exif standard so we leave them out:
     - fBatteryLevelA, fBatteryLevelR
     - fSelfTimerMode
     - fTIFF_EP_StandardID, fImageNumber
     - fApproxFocusDistance
     - fFlashCompensation, fFlashMask
     - fFirmware 
     - fLensID
     - fLensNameWasReadFromExif (--> available but not used by SDK)
     - fRelatedImageFileFormat, fRelatedImageWidth, fRelatedImageLength */

    // -----------------------------------------------------------------------------------------
    // Write CFAPattern (section G) manually from mosaicinfo

    const dng_mosaic_info* mosaicinfo = m_negative->GetMosaicInfo();
    if (mosaicinfo != NULL) {
        negExif->fCFARepeatPatternCols = mosaicinfo->fCFAPatternSize.v;
        negExif->fCFARepeatPatternRows = mosaicinfo->fCFAPatternSize.h;
        for (uint16 c = 0; c < negExif->fCFARepeatPatternCols; c++)
            for (uint16 r = 0; r < negExif->fCFARepeatPatternRows; r++)
                negExif->fCFAPattern[r][c] = mosaicinfo->fCFAPattern[c][r];
    }

    // -----------------------------------------------------------------------------------------
    // Reconstruct LensName from LensInfo if not present

    if (negExif->fLensName.IsEmpty()) {
        dng_urational *li = negExif->fLensInfo;
        std::stringstream lensName; lensName.precision(1); lensName.setf(std::ios::fixed, std::ios::floatfield);

        if (li[0].IsValid())      lensName << li[0].As_real64();
        if (li[1] != li[2])       lensName << "-" << li[1].As_real64();
        if (lensName.tellp() > 0) lensName << " mm";
        if (li[2].IsValid())      lensName << " f/" << li[2].As_real64();
        if (li[3] != li[2])       lensName << "-" << li[3].As_real64();

        negExif->fLensName.Set_ASCII(lensName.str().c_str());
    }

    // -----------------------------------------------------------------------------------------
    // Overwrite date, software, version - these are now referencing the DNG-creation

    negExif->fDateTime = dateTimeNow;
    negExif->fSoftware = appNameVersion;
    negExif->fExifVersion = DNG_CHAR4 ('0','2','3','0'); 
}