/*****************************************************************************/
// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/** \file
 * EXIF read access support. See the \ref spec_exif "EXIF specification" for full
 * description of tags.
 */

/*****************************************************************************/

#ifndef __dng_exif__
#define __dng_exif__

/*****************************************************************************/

#include "dng_classes.h"
#include "dng_date_time.h"
#include "dng_fingerprint.h"
#include "dng_types.h"
#include "dng_matrix.h"
#include "dng_rational.h"
#include "dng_string.h"
#include "dng_stream.h"
#include "dng_sdk_limits.h"

/*****************************************************************************/

/// \brief Container class for parsing and holding EXIF tags.
///
/// Public member fields are documented in \ref spec_exif "EXIF specification."

class dng_exif
	{
	
	public:
	
		dng_string fImageDescription;
		dng_string fMake;
		dng_string fModel;
		dng_string fSoftware;
		dng_string fArtist;
		dng_string fCopyright;
		dng_string fCopyright2;
		dng_string fUserComment;
		
		dng_date_time_info         fDateTime;
		dng_date_time_storage_info fDateTimeStorageInfo;
		
		dng_date_time_info		   fDateTimeOriginal;
		dng_date_time_storage_info fDateTimeOriginalStorageInfo;

		dng_date_time_info 		   fDateTimeDigitized;
		dng_date_time_storage_info fDateTimeDigitizedStorageInfo;
		
		uint32 fTIFF_EP_StandardID;
		uint32 fExifVersion;
		uint32 fFlashPixVersion;
		
		dng_urational fExposureTime;
		dng_urational fFNumber;
		dng_srational fShutterSpeedValue;
		dng_urational fApertureValue;
		dng_srational fBrightnessValue;
		dng_srational fExposureBiasValue;
		dng_urational fMaxApertureValue;
		dng_urational fFocalLength;
		dng_urational fDigitalZoomRatio;
		dng_urational fExposureIndex;
		dng_urational fSubjectDistance;
		dng_urational fGamma;
		
		dng_urational fBatteryLevelR;
		dng_string    fBatteryLevelA;
		
		uint32 fExposureProgram;
		uint32 fMeteringMode;
		uint32 fLightSource;
		uint32 fFlash;
		uint32 fFlashMask;
		uint32 fSensingMethod;
		uint32 fColorSpace;
		uint32 fFileSource;
		uint32 fSceneType;
		uint32 fCustomRendered;
		uint32 fExposureMode;
		uint32 fWhiteBalance;
		uint32 fSceneCaptureType;
		uint32 fGainControl;
		uint32 fContrast;
		uint32 fSaturation;
		uint32 fSharpness;
		uint32 fSubjectDistanceRange;
		uint32 fSelfTimerMode;
		uint32 fImageNumber;

		uint32 fFocalLengthIn35mmFilm;
		
		uint32 fISOSpeedRatings [3];		 // EXIF 2.3: PhotographicSensitivity.

		// Sensitivity tags added in EXIF 2.3.

		uint32 fSensitivityType;
		uint32 fStandardOutputSensitivity;
		uint32 fRecommendedExposureIndex;
		uint32 fISOSpeed;
		uint32 fISOSpeedLatitudeyyy;
		uint32 fISOSpeedLatitudezzz;
		
		uint32 fSubjectAreaCount;
		uint32 fSubjectArea [4];
		
		uint32 fComponentsConfiguration;
		
		dng_urational fCompresssedBitsPerPixel;
		
		uint32 fPixelXDimension;
		uint32 fPixelYDimension;
		
		dng_urational fFocalPlaneXResolution;
		dng_urational fFocalPlaneYResolution;
		
		uint32 fFocalPlaneResolutionUnit;
		
		uint32 fCFARepeatPatternRows;
		uint32 fCFARepeatPatternCols;
		
		uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
		
		dng_fingerprint fImageUniqueID;
		
		uint32 	      fGPSVersionID;
		dng_string    fGPSLatitudeRef;
		dng_urational fGPSLatitude [3];
		dng_string    fGPSLongitudeRef;
		dng_urational fGPSLongitude [3];
		uint32	      fGPSAltitudeRef;
		dng_urational fGPSAltitude;
		dng_urational fGPSTimeStamp [3];
		dng_string    fGPSSatellites;
		dng_string    fGPSStatus;
		dng_string    fGPSMeasureMode;
		dng_urational fGPSDOP;
		dng_string    fGPSSpeedRef;
		dng_urational fGPSSpeed;
		dng_string    fGPSTrackRef;
		dng_urational fGPSTrack;
		dng_string    fGPSImgDirectionRef;
		dng_urational fGPSImgDirection;
		dng_string    fGPSMapDatum;
		dng_string    fGPSDestLatitudeRef;
		dng_urational fGPSDestLatitude [3];
		dng_string    fGPSDestLongitudeRef;
		dng_urational fGPSDestLongitude [3];
		dng_string    fGPSDestBearingRef;
		dng_urational fGPSDestBearing;
		dng_string    fGPSDestDistanceRef;
		dng_urational fGPSDestDistance;
		dng_string    fGPSProcessingMethod;
		dng_string    fGPSAreaInformation;
		dng_string    fGPSDateStamp;
		uint32 	      fGPSDifferential;
		dng_urational fGPSHPositioningError;
		
		dng_string fInteroperabilityIndex;
		
		uint32 fInteroperabilityVersion;
		
		dng_string fRelatedImageFileFormat;
		
		uint32 fRelatedImageWidth;	
		uint32 fRelatedImageLength;

		dng_string fCameraSerialNumber;		 // EXIF 2.3: BodySerialNumber.
		
		dng_urational fLensInfo [4];		 // EXIF 2.3: LensSpecification.
		
		dng_string fLensID;
		dng_string fLensMake;
		dng_string fLensName;				 // EXIF 2.3: LensModel.
		dng_string fLensSerialNumber;
		
		// Was the lens name field read from a LensModel tag?
		
		bool fLensNameWasReadFromExif;

		// Private field to hold the approximate focus distance of the lens, in
		// meters. This value is often coarsely measured/reported and hence should be
		// interpreted only as a rough estimate of the true distance from the plane
		// of focus (in object space) to the focal plane. It is still useful for the
		// purposes of applying lens corrections.

		dng_urational fApproxFocusDistance;
	
		dng_srational fFlashCompensation;
		
		dng_string fOwnerName;				 // EXIF 2.3: CameraOwnerName.
		dng_string fFirmware;
  
        // EXIF 2.3.1:
        
        dng_srational fTemperature;
        dng_urational fHumidity;
        dng_urational fPressure;
        dng_srational fWaterDepth;
        dng_urational fAcceleration;
        dng_srational fCameraElevationAngle;
        
        // Not really part of EXIF, but some formats may use.
        
        dng_string fTitle;

		// Image-specific radial distortion correction metadata that can be
		// used later during (UI-driven) lens profile corrections. Same model
		// as DNG opcode model.

		dng_srational fLensDistortInfo [4];
		
	public:
	
		dng_exif ();
		
		virtual ~dng_exif ();

		/// Make clone.
		
		virtual dng_exif * Clone () const;

		/// Clear all EXIF fields.
		
		void SetEmpty ();

		/// Copy all GPS-related fields.
		/// \param exif Source object from which to copy GPS fields.
		
		void CopyGPSFrom (const dng_exif &exif);

		/// Utility to fix up common errors and rounding issues with EXIF exposure
		/// times.

		static real64 SnapExposureTime (real64 et);

		/// Set exposure time and shutter speed fields. Optionally fix up common
		/// errors and rounding issues with EXIF exposure times.
		/// \param et Exposure time in seconds.
		/// \param snap Set to true to fix up common errors and rounding issues with
		/// EXIF exposure times.
		
		void SetExposureTime (real64 et,
							  bool snap = true);

		/// Set shutter speed value (APEX units) and exposure time.
		/// \param ss Shutter speed in APEX units.
		
		void SetShutterSpeedValue (real64 ss);

		/// Utility to encode f-number as a rational.
		/// \param fs The f-number to encode.
		
		static dng_urational EncodeFNumber (real64 fs);

		/// Set the FNumber and ApertureValue fields.
		/// \param fs The f-number to set.
		
		void SetFNumber (real64 fs);
		
		/// Set the FNumber and ApertureValue fields.
		/// \param av The aperture value (APEX units).
		
		void SetApertureValue (real64 av);

		/// Utility to convert aperture value (APEX units) to f-number.
		/// \param av The aperture value (APEX units) to convert.
		
		static real64 ApertureValueToFNumber (real64 av);

		/// Utility to convert aperture value (APEX units) to f-number.
		/// \param av The aperture value (APEX units) to convert.
		
		static real64 ApertureValueToFNumber (const dng_urational &av);

		/// Utility to convert f-number to aperture value (APEX units).
		/// \param fNumber The f-number to convert.
		
		static real64 FNumberToApertureValue (real64 fNumber);

		/// Utility to convert f-number to aperture value (APEX units).
		/// \param fNumber The f-number to convert.
		
		static real64 FNumberToApertureValue (const dng_urational &fNumber);

		/// Set the DateTime field.
		/// \param dt The DateTime value.
							   
		void UpdateDateTime (const dng_date_time_info &dt);

		/// Returns true iff the EXIF version is at least 2.3.

		bool AtLeastVersion0230 () const;
  
        /// Returns true iff the EXIF version is at least 2.3.1.
        
        bool AtLeastVersion0231 () const;
        
        /// Sets the EXIF version to 2.3.1.
        
        void SetVersion0231 ();

		bool HasLensDistortInfo () const;
		
		void SetLensDistortInfo (const dng_vector &params);
		
		virtual bool ParseTag (dng_stream &stream,
							   dng_shared &shared,
							   uint32 parentCode,
							   bool isMainIFD,
							   uint32 tagCode,
							   uint32 tagType,
							   uint32 tagCount,
							   uint64 tagOffset);
							   
		virtual void PostParse (dng_host &host,
								dng_shared &shared);
								
	protected:
		
		virtual bool Parse_ifd0 (dng_stream &stream,
							     dng_shared &shared,
							 	 uint32 parentCode,
							 	 uint32 tagCode,
							 	 uint32 tagType,
							 	 uint32 tagCount,
							 	 uint64 tagOffset);
							 		 
		virtual bool Parse_ifd0_main (dng_stream &stream,
							          dng_shared &shared,
						 		 	  uint32 parentCode,
						 		 	  uint32 tagCode,
						 		 	  uint32 tagType,
						 		 	  uint32 tagCount,
						 		 	  uint64 tagOffset);

		virtual bool Parse_ifd0_exif (dng_stream &stream,
							          dng_shared &shared,
						 		 	  uint32 parentCode,
						 		 	  uint32 tagCode,
						 		 	  uint32 tagType,
						 		 	  uint32 tagCount,
						 		 	  uint64 tagOffset);
	
		virtual bool Parse_gps (dng_stream &stream,
							    dng_shared &shared,
						 		uint32 parentCode,
						 		uint32 tagCode,
						 		uint32 tagType,
						 		uint32 tagCount,
						 		uint64 tagOffset);
	
		virtual bool Parse_interoperability (dng_stream &stream,
							    			 dng_shared &shared,
						 					 uint32 parentCode,
											 uint32 tagCode,
											 uint32 tagType,
											 uint32 tagCount,
											 uint64 tagOffset);
	
	};
	
/*****************************************************************************/

#endif
	
/*****************************************************************************/
