// ==========================================================
// Tag manipulation functions
//
// Design and implementation by
// - Hervé Drolon <drolon@infonie.fr>
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================

#ifndef FREEIMAGETAG_H
#define FREEIMAGETAG_H

// ==========================================================
// Exif JPEG tags
// ==========================================================

// ----------------------------------------------------------
// TIFF Rev. 6.0 Attribute Information Used in Exif
// ----------------------------------------------------------

// Tags relating to image data structure

#define TAG_IMAGE_WIDTH					0x0100
#define TAG_IMAGE_HEIGHT				0x0101
#define TAG_BITS_PER_SAMPLE				0x0102
#define TAG_COMPRESSION					0x0103
#define TAG_PHOTOMETRIC_INTERPRETATION	0x0106
#define TAG_ORIENTATION					0x0112
#define TAG_SAMPLES_PER_PIXEL			0x0115
#define TAG_PLANAR_CONFIGURATION		0x011C
#define TAG_YCBCR_SUBSAMPLING			0x0212
#define TAG_YCBCR_POSITIONING			0x0213
#define TAG_X_RESOLUTION				0x011A
#define TAG_Y_RESOLUTION				0x011B
#define TAG_RESOLUTION_UNIT				0x0128

// Tags relating to recording offset

#define TAG_STRIP_OFFSETS					0x0111
#define TAG_ROWS_PER_STRIP					0x0116
#define TAG_STRIP_BYTE_COUNTS				0x0117
#define TAG_JPEG_INTERCHANGE_FORMAT			0x0201
#define TAG_JPEG_INTERCHANGE_FORMAT_LENGTH	0x0202

// Tags relating to image data characteristics

#define TAG_TRANSFER_FUNCTION		0x012D
#define TAG_WHITE_POINT				0x013E
#define TAG_PRIMARY_CHROMATICITIES	0x013F
#define TAG_YCBCR_COEFFICIENTS		0x0211
#define TAG_REFERENCE_BLACK_WHITE	0x0214

// Other tags

#define TAG_DATETIME 				0x0132
#define TAG_IMAGE_DESCRIPTION 		0x010E
#define TAG_MAKE 					0x010F
#define TAG_MODEL 					0x0110
#define TAG_SOFTWARE 				0x0131
#define TAG_ARTIST 					0x013B
#define TAG_COPYRIGHT 				0x8298

// ----------------------------------------------------------
// Exif IFD Attribute Information
// ----------------------------------------------------------

// Tags relating to version

#define TAG_EXIF_VERSION 			0x9000
#define TAG_FLASHPIX_VERSION 		0xA000

// Tag relating to image data characteristics

#define TAG_COLOR_SPACE 			0xA001

// Tags relating to image configuration

#define TAG_COMPONENTS_CONFIGURATION	0x9101
#define TAG_COMPRESSED_BITS_PER_PIXEL	0x9102
#define TAG_PIXEL_X_DIMENSION			0xA002
#define TAG_PIXEL_Y_DIMENSION			0xA003

// Tags relating to user information

#define TAG_MARKER_NOTE		0x927C
#define TAG_USER_COMMENT	0x9286
    
// Tag relating to related file information

#define TAG_RELATED_SOUND_FILE			0xA004

// Tags relating to date and time

#define TAG_DATETIME_ORIGINAL			0x9003
#define TAG_DATETIME_DIGITIZED			0x9004
#define TAG_SUBSECOND_TIME				0x9290
#define TAG_SUBSECOND_TIME_ORIGINAL		0x9291
#define TAG_SUBSECOND_TIME_DIGITIZED	0x9292

// Tags relating to picture-taking conditions

#define TAG_EXPOSURE_TIME				0x829A
#define TAG_FNUMBER						0x829D
#define TAG_EXPOSURE_PROGRAM			0x8822
#define TAG_SPECTRAL_SENSITIVITY		0x8824
#define TAG_ISO_SPEED_RATINGS 			0x8827
#define TAG_OECF						0x8828
#define TAG_SHUTTER_SPEED_VALUE 		0x9201
#define TAG_APERTURE_VALUE 				0x9202
#define TAG_BRIGHTNESS_VALUE			0x9203
#define TAG_EXPOSURE_BIAS_VALUE 		0x9204
#define TAG_MAX_APERTURE_VALUE 			0x9205
#define TAG_SUBJECT_DISTANCE			0x9206
#define TAG_METERING_MODE				0x9207
#define TAG_LIGHT_SOURCE				0x9208
#define TAG_FLASH						0x9209
#define TAG_FOCAL_LENGTH				0x920A
#define TAG_SUBJECT_AREA				0x9214
#define TAG_FLASH_ENERGY				0xA20B
#define TAG_SPATIAL_FREQ_RESPONSE 		0xA20C
#define TAG_FOCAL_PLANE_X_RES			0xA20E
#define TAG_FOCAL_PLANE_Y_RES			0xA20F
#define TAG_FOCAL_PLANE_UNIT			0xA210
#define TAG_SUBJECT_LOCATION 			0xA214
#define TAG_EXPOSURE_INDEX				0xA215
#define TAG_SENSING_METHOD				0xA217
#define TAG_FILE_SOURCE					0xA300
#define TAG_SCENE_TYPE					0xA301
#define TAG_CFA_PATTERN					0xA302
#define TAG_CUSTOM_RENDERED				0xA401
#define TAG_EXPOSURE_MODE				0xA402
#define TAG_WHITE_BALANCE				0xA403
#define TAG_DIGITAL_ZOOM_RATIO			0xA404
#define TAG_FOCAL_LENGTH_IN_35MM_FILM	0xA405
#define TAG_SCENE_CAPTURE_TYPE			0xA406
#define TAG_GAIN_CONTROL				0xA407
#define TAG_CONTRAST					0xA408
#define TAG_SATURATION					0xA409
#define TAG_SHARPNESS					0xA40A
#define TAG_DEVICE_SETTING_DESCRIPTION	0xA40B
#define TAG_SUBJECT_DISTANCE_RANGE		0xA40C

// Other tags

#define TAG_IMAGE_UNIQUE_ID				0xA420

// ----------------------------------------------------------
// GPS Attribute Information
// ----------------------------------------------------------

#define TAG_GPS_VERSION_ID				0x0000
#define TAG_GPS_LATITUDE_REF			0x0001
#define TAG_GPS_LATITUDE				0x0002
#define TAG_GPS_LONGITUDE_REF			0x0003
#define TAG_GPS_LONGITUDE				0x0004
#define TAG_GPS_ALTITUDE_REF			0x0005
#define TAG_GPS_ALTITUDE				0x0006
#define TAG_GPS_TIME_STAMP				0x0007
#define TAG_GPS_SATELLITES				0x0008
#define TAG_GPS_STATUS					0x0009
#define TAG_GPS_MEASURE_MODE			0x000A
#define TAG_GPS_DOP						0x000B
#define TAG_GPS_SPEED_REF				0x000C
#define TAG_GPS_SPEED					0x000D
#define TAG_GPS_TRACK_REF				0x000E
#define TAG_GPS_TRACK					0x000F
#define TAG_GPS_IMG_DIRECTION_REF		0x0010
#define TAG_GPS_IMG_DIRECTION			0x0011
#define TAG_GPS_MAP_DATUM				0x0012
#define TAG_GPS_DEST_LATITUDE_REF		0x0013
#define TAG_GPS_DEST_LATITUDE			0x0014
#define TAG_GPS_DEST_LONGITUDE_REF		0x0015
#define TAG_GPS_DEST_LONGITUDE			0x0016
#define TAG_GPS_DEST_BEARING_REF		0x0017
#define TAG_GPS_DEST_BEARING			0x0018
#define TAG_GPS_DEST_DISTANCE_REF		0x0019
#define TAG_GPS_DEST_DISTANCE			0x001A
#define TAG_GPS_PROCESSING_METHOD		0x001B
#define TAG_GPS_AREA_INFORMATION		0x001C
#define TAG_GPS_DATE_STAMP				0x001D
#define TAG_GPS_DIFFERENTIAL			0x001E

// ==========================================================
// IPTC/NAA tags
// ==========================================================

#define TAG_RECORD_VERSION					0x0200
#define TAG_CAPTION							0x0278
#define TAG_WRITER							0x027A
#define TAG_HEADLINE						0x0269
#define TAG_SPECIAL_INSTRUCTIONS			0x0228
#define TAG_BY_LINE							0x0250
#define TAG_BY_LINE_TITLE					0x0255
#define TAG_CREDIT							0x026E
#define TAG_SOURCE							0x0273
#define TAG_OBJECT_NAME						0x0205
#define TAG_DATE_CREATED					0x0237
#define TAG_CITY							0x025A
#define TAG_PROVINCE_OR_STATE				0x025F
#define TAG_COUNTRY_OR_PRIMARY_LOCATION		0x0265
#define TAG_ORIGINAL_TRANSMISSION_REFERENCE 0x0267
#define TAG_CATEGORY						0x020F
#define TAG_SUPPLEMENTAL_CATEGORIES			0x0214
#define TAG_URGENCY							0x020A
#define TAG_KEYWORDS						0x0219
#define TAG_COPYRIGHT_NOTICE				0x0274
#define TAG_RELEASE_DATE					0x021E
#define TAG_RELEASE_TIME					0x0223
#define TAG_TIME_CREATED					0x023C
#define TAG_ORIGINATING_PROGRAM				0x0241

// ==========================================================
// GeoTIFF tags
// ==========================================================

// tags 33550 is a private tag registered to SoftDesk, Inc
#define TIFFTAG_GEOPIXELSCALE		33550
// tags 33920-33921 are private tags registered to Intergraph, Inc
#define TIFFTAG_INTERGRAPH_MATRIX	33920
#define TIFFTAG_GEOTIEPOINTS		33922
// tags 34263-34264 are private tags registered to NASA-JPL Carto Group
#define TIFFTAG_JPL_CARTO_IFD		34263
#define TIFFTAG_GEOTRANSMATRIX		34264    /* New Matrix Tag replaces 33920 */
// tags 34735-3438 are private tags registered to SPOT Image, Inc
#define TIFFTAG_GEOKEYDIRECTORY		34735
#define TIFFTAG_GEODOUBLEPARAMS		34736
#define TIFFTAG_GEOASCIIPARAMS		34737

// ==========================================================
// FreeImage Animation tags
// ==========================================================

#define ANIMTAG_LOGICALWIDTH	0x0001
#define ANIMTAG_LOGICALHEIGHT	0x0002
#define ANIMTAG_GLOBALPALETTE	0x0003
#define ANIMTAG_LOOP			0x0004
#define ANIMTAG_FRAMELEFT		0x1001
#define ANIMTAG_FRAMETOP		0x1002
#define ANIMTAG_NOLOCALPALETTE	0x1003
#define ANIMTAG_INTERLACED		0x1004
#define ANIMTAG_FRAMETIME		0x1005
#define ANIMTAG_DISPOSALMETHOD	0x1006

// --------------------------------------------------------------------------
// Helper functions to deal with the FITAG structure
// --------------------------------------------------------------------------

/** 
Describes the tag format descriptor
@param type Tag data type
@return Returns the width of a single element, in bytes
@see FREE_IMAGE_MDTYPE
*/
int FreeImage_TagDataWidth(WORD type);

// --------------------------------------------------------------------------

/**
	Structure to hold a tag information
*/
typedef struct tagTagInfo {
	WORD tag;			// Tag ID (required)
	char *fieldname;	// Field name (required)
	char *description;	// Field description (may be NULL)
} TagInfo;


/**
	Class to hold tag information (based on Meyers’ Singleton).<br>

	Sample usage :<br>
	<code>
	TagLib& s = TagLib::instance();
	TagInfo *tag_info = s.getTagInfo(EXIF_MAIN, 0x0100);
	</code>

*/

class TagLib {
public:

	/**
	internal tag info tables registered in TagLib
	*/
	enum MDMODEL {
		UNKNOWN,
		EXIF_MAIN, 
		EXIF_EXIF, 
		EXIF_GPS, 
		EXIF_INTEROP,
		EXIF_MAKERNOTE_CANON,
		EXIF_MAKERNOTE_CASIOTYPE1,
		EXIF_MAKERNOTE_CASIOTYPE2,
		EXIF_MAKERNOTE_FUJIFILM,
		EXIF_MAKERNOTE_KYOCERA,
		EXIF_MAKERNOTE_MINOLTA,
		EXIF_MAKERNOTE_NIKONTYPE1,
		EXIF_MAKERNOTE_NIKONTYPE2,
		EXIF_MAKERNOTE_NIKONTYPE3,
		EXIF_MAKERNOTE_OLYMPUSTYPE1,
		EXIF_MAKERNOTE_PANASONIC,
		EXIF_MAKERNOTE_ASAHI,
		EXIF_MAKERNOTE_PENTAX,
		EXIF_MAKERNOTE_SONY,
		IPTC,
		GEOTIFF,
		ANIMATION
	};

private:

	typedef std::map<WORD, TagInfo*> TAGINFO;
	typedef std::map<int, TAGINFO*>  TABLEMAP;

	/// store hash tables for all known tag info tables
	TABLEMAP _table_map;

private:
	/**
	Constructor (private)<br>
	This is where the tag info tables are initialized.
	@see addMetadataModel
	*/
	TagLib();

	/// Assignement operator (disabled)
	void operator=(TagLib&);

	/// Copy constructor (disabled)
	TagLib(const TagLib&);
	
	/** 
	Used in the constructor to initialize the tag tables
	@param md_model Internal metadata model
	@param tag_table Tag info table
	@return Returns TRUE if successful, returns FALSE otherwise
	*/
	BOOL addMetadataModel(MDMODEL md_model, TagInfo *tag_table);

public:
	/// Destructor
	~TagLib();

	/**
	@return Returns a reference to the TagLib instance
	*/
	static TagLib& instance();

	/**
	Given a tag ID, returns its TagInfo descriptor
	@param md_model Internal metadata model
	@param tagID tag ID
	@return Returns the TagInfo descriptor if successful, returns NULL otherwise
	*/
	const TagInfo* getTagInfo(MDMODEL md_model, WORD tagID);

	/**
	Given a tag ID, returns its tag field name. 
	When the tag is unknown and defaultKey is not NULL, a string such as "Tag 0x1234" is returned. 
	This string is contained in the provided defaultKey buffer (assumed to be an array of at least 16 chars). 
	@param md_model Internal metadata model
	@param tagID tag ID
	@param defaultKey Assumed to be an array of 16 chars. If not NULL, build a key for unknown tags
	@return Returns the tag field name if successful, returns an 'unknown tag' string contained in defaultKey otherwise
	*/
	const char* getTagFieldName(MDMODEL md_model, WORD tagID, char *defaultKey);

	/**
	Given a tag ID, returns its description. 
	When the tag has no description, a NULL value is returned.
	@param md_model Internal metadata model
	@param tagID tag ID
	@return Returns the tag description if successful, returns NULL otherwise
	*/
	const char* getTagDescription(MDMODEL md_model, WORD tagID);

	/**
	Given a tag field name, returns its tag ID. 
	When the tag doesn't exists, a value '-1' is returned.
	@param md_model Internal metadata model
	@param key tag field name
	@return Returns the tag ID if successful, returns -1 otherwise
	*/
	int getTagID(MDMODEL md_model, const char *key);

	/**
	Perform a conversion between internal metadata models and FreeImage public metadata models
	@param md_model Internal metadata model
	*/
	FREE_IMAGE_MDMODEL getFreeImageModel(MDMODEL model);

};

// --------------------------------------------------------------------------
// Constant strings
// --------------------------------------------------------------------------

/// Name of the XMP field
static char *g_TagLib_XMPFieldName = "XMLPacket";

// --------------------------------------------------------------------------
// Metadata routines
// --------------------------------------------------------------------------

#if defined(__cplusplus)
extern "C" {
#endif

// JPEG Exif profile
BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen);

// JPEG / TIFF IPTC profile
BOOL read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen);
BOOL write_iptc_profile(FIBITMAP *dib, BYTE **profile, unsigned *profile_size);

#if defined(__cplusplus)
}
#endif


#endif // FREEIMAGETAG_H


