diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-10-12 10:49:29 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-10-12 10:49:29 +0000 |
commit | 557f2816f5cd30705dec989c97a8a67c026d36d1 (patch) | |
tree | 4900789ab5d52219bf065744a61f9ea5863b3428 /plugins/FreeImage/src/Metadata | |
parent | 69fe21d6e2262d6fb2b14278b7a20364468cbdcf (diff) |
FreeImage: folders restructurization
git-svn-id: http://svn.miranda-ng.org/main/trunk@1884 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/FreeImage/src/Metadata')
-rw-r--r-- | plugins/FreeImage/src/Metadata/Exif.cpp | 859 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/FIRational.cpp | 176 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/FIRational.h | 108 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/FreeImageTag.cpp | 318 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/FreeImageTag.h | 474 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/IPTC.cpp | 325 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/TagConversion.cpp | 1094 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/TagLib.cpp | 1617 | ||||
-rw-r--r-- | plugins/FreeImage/src/Metadata/XTIFF.cpp | 661 |
9 files changed, 5632 insertions, 0 deletions
diff --git a/plugins/FreeImage/src/Metadata/Exif.cpp b/plugins/FreeImage/src/Metadata/Exif.cpp new file mode 100644 index 0000000000..7d0955c5db --- /dev/null +++ b/plugins/FreeImage/src/Metadata/Exif.cpp @@ -0,0 +1,859 @@ +// ========================================================== +// Metadata functions implementation +// Exif metadata model +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// - Mihail Naydenov (mnaydenov@users.sourceforge.net) +// +// Based on the following implementations: +// - metadata-extractor : http://www.drewnoakes.com/code/exif/ +// - jhead : http://www.sentex.net/~mwandel/jhead/ +// - ImageMagick : http://www.imagemagick.org/ +// +// 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! +// ========================================================== + +#ifdef _MSC_VER +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters +#endif + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageTag.h" + +// ========================================================== +// Exif JPEG routines +// ========================================================== + +#define EXIF_NUM_FORMATS 12 + +#define TAG_EXIF_OFFSET 0x8769 // Exif IFD Pointer +#define TAG_GPS_OFFSET 0x8825 // GPS Info IFD Pointer +#define TAG_INTEROP_OFFSET 0xA005 // Interoperability IFD Pointer +#define TAG_MAKER_NOTE 0x927C // Maker note + +// CANON cameras have some funny bespoke fields that need further processing... +#define TAG_CANON_CAMERA_STATE_0x01 0x0001 // tags under tag 0x001 (CameraSettings) +#define TAG_CANON_CAMERA_STATE_0x02 0x0002 // tags under tag 0x002 (FocalLength) +#define TAG_CANON_CAMERA_STATE_0x04 0x0004 // tags under tag 0x004 (ShotInfo) +#define TAG_CANON_CAMERA_STATE_0x12 0x0012 // tags under tag 0x012 (AFInfo) +#define TAG_CANON_CAMERA_STATE_0xA0 0x00A0 // tags under tag 0x0A0 (ProcessingInfo) +#define TAG_CANON_CAMERA_STATE_0xE0 0x00E0 // tags under tag 0x0E0 (SensorInfo) + + +// ===================================================================== +// Reimplementation of strnicmp (it is not supported on some systems) +// ===================================================================== + +/** +Compare characters of two strings without regard to case. +@param s1 Null-terminated string to compare. +@param s2 Null-terminated string to compare. +@param len Number of characters to compare +@return Returns 0 if s1 substring identical to s2 substring +*/ +static int +FreeImage_strnicmp(const char *s1, const char *s2, size_t len) { + unsigned char c1, c2; + + if (!s1 || !s2) return -1; + + c1 = 0; c2 = 0; + if(len) { + do { + c1 = *s1; c2 = *s2; + s1++; s2++; + if (!c1) + break; + if (!c2) + break; + if (c1 == c2) + continue; + c1 = (BYTE)tolower(c1); + c2 = (BYTE)tolower(c2); + if (c1 != c2) + break; + } while (--len); + } + return (int)c1 - (int)c2; +} + + +// ---------------------------------------------------------- +// Little Endian / Big Endian io routines +// ---------------------------------------------------------- + +static short +ReadInt16(BOOL msb_order, const void *buffer) { + short value; + + if(msb_order) { + value = (short)((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]); + return value; + } + value = (short)((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]); + return value; +} + +static LONG +ReadInt32(BOOL msb_order, const void *buffer) { + LONG value; + + if(msb_order) { + value = (LONG)((((BYTE*) buffer)[0] << 24) | (((BYTE*) buffer)[1] << 16) | (((BYTE*) buffer)[2] << 8) | (((BYTE*) buffer)[3])); + return value; + } + value = (LONG)((((BYTE*) buffer)[3] << 24) | (((BYTE*) buffer)[2] << 16) | (((BYTE*) buffer)[1] << 8 ) | (((BYTE*) buffer)[0])); + return value; +} + +static unsigned short +ReadUint16(BOOL msb_order, const void *buffer) { + unsigned short value; + + if(msb_order) { + value = (unsigned short) ((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]); + return value; + } + value = (unsigned short) ((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]); + return value; +} + +static DWORD +ReadUint32(BOOL msb_order, const void *buffer) { + return ((DWORD) ReadInt32(msb_order, buffer) & 0xFFFFFFFF); +} + +// ---------------------------------------------------------- +// Exif JPEG markers routines +// ---------------------------------------------------------- + +/** +Process a IFD offset +Returns the offset and the metadata model for this tag +*/ +static void +processIFDOffset(FITAG *tag, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) { + // get the IFD offset + *subdirOffset = (DWORD) ReadUint32(msb_order, pval); + + // select a tag info table + switch(FreeImage_GetTagID(tag)) { + case TAG_EXIF_OFFSET: + *md_model = TagLib::EXIF_EXIF; + break; + case TAG_GPS_OFFSET: + *md_model = TagLib::EXIF_GPS; + break; + case TAG_INTEROP_OFFSET: + *md_model = TagLib::EXIF_INTEROP; + break; + } + +} + +/** +Process a maker note IFD offset +Returns the offset and the metadata model for this tag +*/ +static void +processMakerNote(FIBITMAP *dib, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) { + FITAG *tagMake = NULL; + + *subdirOffset = 0; + *md_model = TagLib::UNKNOWN; + + // Determine the camera model and makernote format + // WARNING: note that Maker may be NULL sometimes so check its value before using it + // (NULL pointer checking is done by FreeImage_strnicmp) + FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Make", &tagMake); + const char *Maker = (char*)FreeImage_GetTagValue(tagMake); + + if ((memcmp("OLYMP\x00\x01", pval, 7) == 0) || (memcmp("OLYMP\x00\x02", pval, 7) == 0) || (memcmp("EPSON", pval, 5) == 0) || (memcmp("AGFA", pval, 4) == 0)) { + // Olympus Type 1 Makernote + // Epson and Agfa use Olympus maker note standard, + // see: http://www.ozhiker.com/electronics/pjmt/jpeg_info/ + *md_model = TagLib::EXIF_MAKERNOTE_OLYMPUSTYPE1; + *subdirOffset = 8; + } + else if(memcmp("OLYMPUS\x00\x49\x49\x03\x00", pval, 12) == 0) { + // Olympus Type 2 Makernote + // !!! NOT YET SUPPORTED !!! + *subdirOffset = 0; + *md_model = TagLib::UNKNOWN; + } + else if(memcmp("Nikon", pval, 5) == 0) { + /* There are two scenarios here: + * Type 1: + * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... + * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ + * Type 3: + * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*... + * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200 + */ + if (pval[6] == 1) { + // Nikon type 1 Makernote + *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE1; + *subdirOffset = 8; + } else if (pval[6] == 2) { + // Nikon type 3 Makernote + *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE3; + *subdirOffset = 18; + } else { + // Unsupported makernote data ignored + *subdirOffset = 0; + *md_model = TagLib::UNKNOWN; + } + } else if(Maker && (FreeImage_strnicmp("NIKON", Maker, 5) == 0)) { + // Nikon type 2 Makernote + *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE2; + *subdirOffset = 0; + } else if(Maker && (FreeImage_strnicmp("Canon", Maker, 5) == 0)) { + // Canon Makernote + *md_model = TagLib::EXIF_MAKERNOTE_CANON; + *subdirOffset = 0; + } else if(Maker && (FreeImage_strnicmp("Casio", Maker, 5) == 0)) { + // Casio Makernote + if(memcmp("QVC\x00\x00\x00", pval, 6) == 0) { + // Casio Type 2 Makernote + *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE2; + *subdirOffset = 6; + } else { + // Casio Type 1 Makernote + *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE1; + *subdirOffset = 0; + } + } else if ((memcmp("FUJIFILM", pval, 8) == 0) || (Maker && (FreeImage_strnicmp("Fujifilm", Maker, 8) == 0))) { + // Fujifile Makernote + // Fujifilm's Makernote always use Intel order altough the Exif section maybe in Intel order or in Motorola order. + // If msb_order == TRUE, the Makernote won't be read: + // the value of ifdStart will be 0x0c000000 instead of 0x0000000c and the MakerNote section will be discarded later + // in jpeg_read_exif_dir because the IFD is too high + *md_model = TagLib::EXIF_MAKERNOTE_FUJIFILM; + DWORD ifdStart = (DWORD) ReadUint32(msb_order, pval + 8); + *subdirOffset = ifdStart; + } + else if(memcmp("KYOCERA\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00", pval, 22) == 0) { + *md_model = TagLib::EXIF_MAKERNOTE_KYOCERA; + *subdirOffset = 22; + } + else if(Maker && (FreeImage_strnicmp("Minolta", Maker, 7) == 0)) { + // Minolta maker note + *md_model = TagLib::EXIF_MAKERNOTE_MINOLTA; + *subdirOffset = 0; + } + else if(memcmp("Panasonic\x00\x00\x00", pval, 12) == 0) { + // Panasonic maker note + *md_model = TagLib::EXIF_MAKERNOTE_PANASONIC; + *subdirOffset = 12; + } + else if(Maker && (FreeImage_strnicmp("LEICA", Maker, 5) == 0)) { + // Leica maker note + if(memcmp("LEICA\x00\x00\x00", pval, 8) == 0) { + // not yet supported makernote data ignored + *subdirOffset = 0; + *md_model = TagLib::UNKNOWN; + } + } + else if(Maker && ((FreeImage_strnicmp("Pentax", Maker, 6) == 0) || (FreeImage_strnicmp("Asahi", Maker, 5) == 0))) { + // Pentax maker note + if(memcmp("AOC\x00", pval, 4) == 0) { + // Type 2 Pentax Makernote + *md_model = TagLib::EXIF_MAKERNOTE_PENTAX; + *subdirOffset = 6; + } else { + // Type 1 Pentax Makernote + *md_model = TagLib::EXIF_MAKERNOTE_ASAHI; + *subdirOffset = 0; + } + } + else if ((memcmp("SONY CAM\x20\x00\x00\x00", pval, 12) == 0) || (memcmp("SONY DSC\x20\x00\x00\x00", pval, 12) == 0)) { + *md_model = TagLib::EXIF_MAKERNOTE_SONY; + *subdirOffset = 12; + } + else if ((memcmp("SIGMA\x00\x00\x00", pval, 8) == 0) || (memcmp("FOVEON\x00\x00", pval, 8) == 0)) { + FITAG *tagModel = NULL; + FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Model", &tagModel); + const char *Model = (char*)FreeImage_GetTagValue(tagModel); + if(Model && (memcmp("SIGMA SD1\x00", Model, 10) == 0)) { + // Sigma SD1 maker note + *subdirOffset = 10; + *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_SD1; + } else { + // Sigma / Foveon makernote + *subdirOffset = 10; + *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_FOVEON; + } + } +} + +/** +Process a Canon maker note tag. +A single Canon tag may contain many other tags within. +*/ +static BOOL +processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) { + char defaultKey[16]; + DWORD startIndex = 0; + TagLib& s = TagLib::instance(); + + WORD tag_id = FreeImage_GetTagID(tag); + + int subTagTypeBase = 0; + + switch(tag_id) { + case TAG_CANON_CAMERA_STATE_0x01: + subTagTypeBase = 0xC100; + startIndex = 1; + break; + case TAG_CANON_CAMERA_STATE_0x02: + subTagTypeBase = 0xC200; + startIndex = 0; + break; + case TAG_CANON_CAMERA_STATE_0x04: + subTagTypeBase = 0xC400; + startIndex = 1; + break; + case TAG_CANON_CAMERA_STATE_0x12: + subTagTypeBase = 0x1200; + startIndex = 0; + break; + case TAG_CANON_CAMERA_STATE_0xA0: + subTagTypeBase = 0xCA00; + startIndex = 1; + break; + case TAG_CANON_CAMERA_STATE_0xE0: + subTagTypeBase = 0xCE00; + startIndex = 1; + break; + + default: + { + // process as a normal tag + + // get the tag key and description + const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey); + FreeImage_SetTagKey(tag, key); + const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id); + FreeImage_SetTagDescription(tag, description); + + // store the tag + if(key) { + FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag); + } + + return TRUE; + } + break; + + } + + WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag); + + // create a tag + FITAG *canonTag = FreeImage_CreateTag(); + if (!canonTag) return FALSE; + + // we intentionally skip the first array member (if needed) + for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) { + + tag_id = (WORD)(subTagTypeBase + i); + + FreeImage_SetTagID(canonTag, tag_id); + FreeImage_SetTagType(canonTag, FIDT_SHORT); + FreeImage_SetTagCount(canonTag, 1); + FreeImage_SetTagLength(canonTag, 2); + FreeImage_SetTagValue(canonTag, &pvalue[i]); + + // get the tag key and description + const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey); + FreeImage_SetTagKey(canonTag, key); + const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id); + FreeImage_SetTagDescription(canonTag, description); + + // store the tag + if(key) { + FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag); + } + } + + // delete the tag + FreeImage_DeleteTag(canonTag); + + return TRUE; +} + +/** +Process a standard Exif tag +*/ +static void +processExifTag(FIBITMAP *dib, FITAG *tag, char *pval, BOOL msb_order, TagLib::MDMODEL md_model) { + char defaultKey[16]; + int n; + DWORD i; + + // allocate a buffer to store the tag value + BYTE *exif_value = (BYTE*)malloc(FreeImage_GetTagLength(tag) * sizeof(BYTE)); + if(NULL == exif_value) { + // out of memory ... + return; + } + memset(exif_value, 0, FreeImage_GetTagLength(tag) * sizeof(BYTE)); + + // get the tag value + switch(FreeImage_GetTagType(tag)) { + + case FIDT_SHORT: + { + WORD *value = (WORD*)&exif_value[0]; + for(i = 0; i < FreeImage_GetTagCount(tag); i++) { + value[i] = ReadUint16(msb_order, pval + i * sizeof(WORD)); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_SSHORT: + { + short *value = (short*)&exif_value[0]; + for(i = 0; i < FreeImage_GetTagCount(tag); i++) { + value[i] = ReadInt16(msb_order, pval + i * sizeof(short)); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_LONG: + { + DWORD *value = (DWORD*)&exif_value[0]; + for(i = 0; i < FreeImage_GetTagCount(tag); i++) { + value[i] = ReadUint32(msb_order, pval + i * sizeof(DWORD)); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_SLONG: + { + LONG *value = (LONG*)&exif_value[0]; + for(i = 0; i < FreeImage_GetTagCount(tag); i++) { + value[i] = ReadInt32(msb_order, pval + i * sizeof(LONG)); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_RATIONAL: + { + n = sizeof(DWORD); + + DWORD *value = (DWORD*)&exif_value[0]; + for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) { + // read a sequence of (numerator, denominator) + value[i] = ReadUint32(msb_order, n*i + (char*)pval); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_SRATIONAL: + { + n = sizeof(LONG); + + LONG *value = (LONG*)&exif_value[0]; + for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) { + // read a sequence of (numerator, denominator) + value[i] = ReadInt32(msb_order, n*i + (char*)pval); + } + FreeImage_SetTagValue(tag, value); + break; + } + case FIDT_BYTE: + case FIDT_ASCII: + case FIDT_SBYTE: + case FIDT_UNDEFINED: + case FIDT_FLOAT: + case FIDT_DOUBLE: + default: + FreeImage_SetTagValue(tag, pval); + break; + } + + if(md_model == TagLib::EXIF_MAKERNOTE_CANON) { + // A single Canon tag can have multiple values within + processCanonMakerNoteTag(dib, tag); + } + else { + TagLib& s = TagLib::instance(); + + WORD tag_id = FreeImage_GetTagID(tag); + + // get the tag key and description + const char *key = s.getTagFieldName(md_model, tag_id, defaultKey); + FreeImage_SetTagKey(tag, key); + const char *description = s.getTagDescription(md_model, tag_id); + FreeImage_SetTagDescription(tag, description); + + // store the tag + if(key) { + FreeImage_SetMetadata(s.getFreeImageModel(md_model), dib, key, tag); + } + } + + + // free the temporary buffer + free(exif_value); + +} + +/** + Process Exif directory + + @param dib Input FIBITMAP + @param tiffp Pointer to the TIFF header + @param offset 0th IFD offset + @param length Length of the datafile + @param msb_order Endianess order of the datafile + @return +*/ +static BOOL +jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) { + WORD de, nde; + + std::stack<WORD> destack; // directory entries stack + std::stack<const BYTE*> ifdstack; // IFD stack + std::stack<TagLib::MDMODEL> modelstack; // metadata model stack + + // Keep a list of already visited IFD to avoid stack overflows + // when recursive/cyclic directory structures exist. + // This kind of recursive Exif file was encountered with Kodak images coming from + // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W + std::map<DWORD, int> visitedIFD; + + /* + "An Image File Directory (IFD) consists of a 2-byte count of the number of directory + entries (i.e. the number of fields), followed by a sequence of 12-byte field + entries, followed by a 4-byte offset of the next IFD (or 0 if none)." + The "next IFD" (1st IFD) is the thumbnail. + */ + #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry)) + + // set the metadata model to Exif + + TagLib::MDMODEL md_model = TagLib::EXIF_MAIN; + + // set the pointer to the first IFD (0th IFD) and follow it were it leads. + + const BYTE *ifd0th = (BYTE*)tiffp + offset; + + const BYTE *ifdp = ifd0th; + + de = 0; + + do { + // if there is anything on the stack then pop it off + if (!destack.empty()) { + ifdp = ifdstack.top(); ifdstack.pop(); + de = destack.top(); destack.pop(); + md_model = modelstack.top(); modelstack.pop(); + } + + // remember that we've visited this directory and entry so that we don't visit it again later + DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de ); + if(visitedIFD.find(visited) != visitedIFD.end()) { + continue; + } else { + visitedIFD[visited] = 1; // processed + } + + // determine how many entries there are in the current IFD + nde = ReadUint16(msb_order, ifdp); + + for (; de < nde; de++) { + char *pde = NULL; // pointer to the directory entry + char *pval = NULL; // pointer to the tag value + + // create a tag + FITAG *tag = FreeImage_CreateTag(); + if (!tag) return FALSE; + + // point to the directory entry + pde = (char*) DIR_ENTRY_ADDR(ifdp, de); + + // get the tag ID + FreeImage_SetTagID(tag, ReadUint16(msb_order, pde)); + // get the tag type + WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2); + if ((tag_type - 1) >= EXIF_NUM_FORMATS) { + // a problem occured : delete the tag (not free'd after) + FreeImage_DeleteTag(tag); + // break out of the for loop + break; + } + FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type); + + // get number of components + FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4)); + // check that tag length (size of the tag value in bytes) will fit in a DWORD + unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag)); + if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) { + FreeImage_DeleteTag(tag); + // jump to next entry + continue; + } + FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * tag_data_width); + + if(FreeImage_GetTagLength(tag) <= 4) { + // 4 bytes or less and value is in the dir entry itself + pval = pde + 8; + } else { + // if its bigger than 4 bytes, the directory entry contains an offset + // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data + DWORD offset_value = ReadUint32(msb_order, pde + 8); + if(offset_value > length) { + // a problem occured : delete the tag (not free'd after) + FreeImage_DeleteTag(tag); + // jump to next entry + continue; + } + // now check that length does not exceed the buffer size + if(FreeImage_GetTagLength(tag) > length - offset_value){ + // a problem occured : delete the tag (not free'd after) + FreeImage_DeleteTag(tag); + // jump to next entry + continue; + } + pval = (char*)(tiffp + offset_value); + } + + // check for a IFD offset + BOOL isIFDOffset = FALSE; + switch(FreeImage_GetTagID(tag)) { + case TAG_EXIF_OFFSET: + case TAG_GPS_OFFSET: + case TAG_INTEROP_OFFSET: + case TAG_MAKER_NOTE: + isIFDOffset = TRUE; + break; + } + if(isIFDOffset) { + DWORD sub_offset = 0; + TagLib::MDMODEL next_mdmodel = md_model; + const BYTE *next_ifd = ifdp; + + // get offset and metadata model + if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) { + processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel); + next_ifd = (BYTE*)pval + sub_offset; + } else { + processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel); + next_ifd = (BYTE*)tiffp + sub_offset; + } + + if ((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) { + // push our current directory state onto the stack + ifdstack.push(ifdp); + // bump to the next entry + de++; + destack.push(de); + + // push our current metadata model + modelstack.push(md_model); + + // push new state onto of stack to cause a jump + ifdstack.push(next_ifd); + destack.push(0); + + // select a new metadata model + modelstack.push(next_mdmodel); + + // delete the tag as it won't be stored nor deleted in the for () loop + FreeImage_DeleteTag(tag); + + break; // break out of the for loop + } + else { + // unsupported camera model, canon maker tag or something unknown + // process as a standard tag + processExifTag(dib, tag, pval, msb_order, md_model); + } + + } else { + // process as a standard tag + processExifTag(dib, tag, pval, msb_order, md_model); + } + + // delete the tag + FreeImage_DeleteTag(tag); + + } // for(nde) + + // additional thumbnail data is skipped + + } while (!destack.empty()); + + // + // --- handle thumbnail data --- + // + + const WORD entriesCount0th = ReadUint16(msb_order, ifd0th); + + DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th)); + if ((next_offset == 0) || (next_offset >= length)) { + return TRUE; //< no thumbnail + } + + const BYTE* const ifd1st = (BYTE*)tiffp + next_offset; + const WORD entriesCount1st = ReadUint16(msb_order, ifd1st); + + unsigned thCompression = 0; + unsigned thOffset = 0; + unsigned thSize = 0; + + for(int e = 0; e < entriesCount1st; e++) { + + // point to the directory entry + const BYTE* base = DIR_ENTRY_ADDR(ifd1st, e); + + // check for buffer overflow + const size_t remaining = (size_t)base + 12 - (size_t)tiffp; + if(remaining >= length) { + // bad IFD1 directory, ignore it + return FALSE; + } + + // get the tag ID + WORD tag = ReadUint16(msb_order, base); + // get the tag type + WORD type = ReadUint16(msb_order, base + sizeof(WORD)); + // get number of components + DWORD count = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD)); + // get the tag value + DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD)); + + switch(tag) { + case TAG_COMPRESSION: + // Tiff Compression Tag (should be COMPRESSION_OJPEG (6), but is not always respected) + thCompression = offset; + break; + case TAG_JPEG_INTERCHANGE_FORMAT: + // Tiff JPEGInterchangeFormat Tag + thOffset = offset; + break; + case TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + // Tiff JPEGInterchangeFormatLength Tag + thSize = offset; + break; + // ### X and Y Resolution ignored, orientation ignored + case TAG_X_RESOLUTION: // XResolution + case TAG_Y_RESOLUTION: // YResolution + case TAG_RESOLUTION_UNIT: // ResolutionUnit + case TAG_ORIENTATION: // Orientation + break; + default: + break; + } + } + + if (/*thCompression != 6 ||*/ thOffset == 0 || thSize == 0) { + return TRUE; + } + + if(thOffset + thSize > length) { + return TRUE; + } + + // load the thumbnail + + const BYTE *thLocation = tiffp + thOffset; + + FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(thLocation), thSize); + FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem); + FreeImage_CloseMemory(hmem); + + // store the thumbnail + FreeImage_SetThumbnail(dib, thumbnail); + // then delete it + FreeImage_Unload(thumbnail); + + return TRUE; +} + +/** + Read and decode JPEG_APP1 marker (Exif profile) + @param dib Input FIBITMAP + @param dataptr Pointer to the APP1 marker + @param datalen APP1 marker length + @return Returns TRUE if successful, FALSE otherwise +*/ +BOOL +jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { + // marker identifying string for Exif = "Exif\0\0" + BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Intel order + BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Motorola order + + unsigned int length = datalen; + BYTE *profile = (BYTE*)dataptr; + + // verify the identifying string + + if(memcmp(exif_signature, profile, sizeof(exif_signature)) == 0) { + // Exif profile - TIFF header with 2 IFDs. 0th - the image attributes, 1st - may be used for thumbnail + + profile += sizeof(exif_signature); + length -= sizeof(exif_signature); + + // read the TIFF header (8 bytes) + + // check the endianess order + + BOOL bMotorolaOrder = TRUE; + + if(memcmp(profile, lsb_first, sizeof(lsb_first)) == 0) { + // Exif section in Intel order + bMotorolaOrder = FALSE; + } else { + if(memcmp(profile, msb_first, sizeof(msb_first)) == 0) { + // Exif section in Motorola order + bMotorolaOrder = TRUE; + } else { + // Invalid Exif alignment marker + return FALSE; + } + } + + // this is the offset to the first IFD (Image File Directory) + unsigned long first_offset = ReadUint32(bMotorolaOrder, profile + 4); + if (first_offset > length) { + // bad Exif data + return FALSE; + } + + /* + Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset + => tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D + if (first_offset < 8 || first_offset > 16) { + // This is usually set to 8 + // but PENTAX Optio 230 has it set differently, and uses it as offset. + FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value"); + return FALSE; + } + */ + + // process Exif directories + return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder); + } + + return FALSE; +} + + diff --git a/plugins/FreeImage/src/Metadata/FIRational.cpp b/plugins/FreeImage/src/Metadata/FIRational.cpp new file mode 100644 index 0000000000..d383c8d38f --- /dev/null +++ b/plugins/FreeImage/src/Metadata/FIRational.cpp @@ -0,0 +1,176 @@ +// ========================================================== +// Helper class for rational numbers +// +// 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! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" +#include "FIRational.h" + +/// Initialize and normalize a rational number +void FIRational::initialize(LONG n, LONG d) { + if(d) { + _numerator = n; + _denominator = d; + // normalize rational + normalize(); + } else { + _numerator = 0; + _denominator = 0; + } +} + +/// Default constructor +FIRational::FIRational() { + _numerator = 0; + _denominator = 0; +} + +/// Constructor with longs +FIRational::FIRational(LONG n, LONG d) { + initialize(n, d); +} + +/// Constructor with FITAG +FIRational::FIRational(const FITAG *tag) { + switch(FreeImage_GetTagType((FITAG*)tag)) { + case FIDT_RATIONAL: // 64-bit unsigned fraction + { + DWORD *pvalue = (DWORD*)FreeImage_GetTagValue((FITAG*)tag); + initialize((LONG)pvalue[0], (LONG)pvalue[1]); + break; + } + + case FIDT_SRATIONAL: // 64-bit signed fraction + { + LONG *pvalue = (LONG*)FreeImage_GetTagValue((FITAG*)tag); + initialize((LONG)pvalue[0], (LONG)pvalue[1]); + break; + } + } +} + +FIRational::FIRational(float value) { + if (value == (float)((LONG)value)) { + _numerator = (LONG)value; + _denominator = 1L; + } else { + int k, count; + LONG n[4]; + + float x = fabs(value); + int sign = (value > 0) ? 1 : -1; + + // make a continued-fraction expansion of x + count = -1; + for(k = 0; k < 4; k++) { + n[k] = (LONG)floor(x); + count++; + x -= (float)n[k]; + if(x == 0) break; + x = 1 / x; + } + // compute the rational + _numerator = 1; + _denominator = n[count]; + + for(int i = count - 1; i >= 0; i--) { + if(n[i] == 0) break; + LONG _num = (n[i] * _numerator + _denominator); + LONG _den = _numerator; + _numerator = _num; + _denominator = _den; + } + _numerator *= sign; + } +} + +/// Copy constructor +FIRational::FIRational (const FIRational& r) { + initialize(r._numerator, r._denominator); +} + +/// Destructor +FIRational::~FIRational() { +} + +/// Assignement operator +FIRational& FIRational::operator=(FIRational& r) { + if(this != &r) { + initialize(r._numerator, r._denominator); + } + return *this; +} + +/// Get the numerator +LONG FIRational::getNumerator() { + return _numerator; +} + +/// Get the denominator +LONG FIRational::getDenominator() { + return _denominator; +} + +/// Calculate GCD +LONG FIRational::gcd(LONG a, LONG b) { + LONG temp; + while (b) { // While non-zero value + temp = b; // Save current value + b = a % b; // Assign remainder of division + a = temp; // Copy old value + } + return a; // Return GCD of numbers +} + +/// Normalize numerator / denominator +void FIRational::normalize() { + if (_numerator != 1 && _denominator != 1) { // Is there something to do? + // Calculate GCD + LONG common = gcd(_numerator, _denominator); + if (common != 1) { // If GCD is not one + _numerator /= common; // Calculate new numerator + _denominator /= common; // Calculate new denominator + } + } + if(_denominator < 0) { // If sign is in denominator + _numerator *= -1; // Multiply num and den by -1 + _denominator *= -1; // To keep sign in numerator + } +} + +/// Checks if this rational number is an Integer, either positive or negative +BOOL FIRational::isInteger() { + if(_denominator == 1 || (_denominator != 0 && (_numerator % _denominator == 0)) || (_denominator == 0 && _numerator == 0)) + return TRUE; + return FALSE; +} + +/// Convert as "numerator/denominator" +std::string FIRational::toString() { + std::ostringstream s; + if(isInteger()) { + s << intValue(); + } else { + s << _numerator << "/" << _denominator; + } + return s.str(); +} + + diff --git a/plugins/FreeImage/src/Metadata/FIRational.h b/plugins/FreeImage/src/Metadata/FIRational.h new file mode 100644 index 0000000000..bd3ee13e07 --- /dev/null +++ b/plugins/FreeImage/src/Metadata/FIRational.h @@ -0,0 +1,108 @@ +// ========================================================== +// Helper class for rational numbers +// +// 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 FIRATIONAL_H +#define FIRATIONAL_H + +/** +Helper class to deal with rational numbers. +NB: LONG data type is assumed to be a signed 32-bit number. +*/ +class FIRational { +private: + /// numerator + LONG _numerator; + /// denominator + LONG _denominator; + +public: + /// Default constructor + FIRational(); + + /// Constructor with longs + FIRational(LONG n, LONG d = 1); + + /// Constructor with FITAG + FIRational(const FITAG *tag); + + /// Constructor with a float + FIRational(float value); + + /// Copy constructor + FIRational (const FIRational& r); + + /// Destructor + ~FIRational(); + + /// Assignement operator + FIRational& operator=(FIRational& r); + + /// Get the numerator + LONG getNumerator(); + + /// Get the denominator + LONG getDenominator(); + + /// Converts rational value by truncating towards zero + LONG truncate() { + // Return truncated rational + return _denominator ? (LONG) (_numerator / _denominator) : 0; + } + + /**@name Implicit conversions */ + //@{ + short shortValue() { + return (short)truncate(); + } + int intValue() { + return (int)truncate(); + } + LONG longValue() { + return (LONG)truncate(); + } + float floatValue() { + return _denominator ? ((float)_numerator)/((float)_denominator) : 0; + } + double doubleValue() { + return _denominator ? ((double)_numerator)/((double)_denominator) : 0; + } + //@} + + /// Checks if this rational number is an integer, either positive or negative + BOOL isInteger(); + + /// Convert as "numerator/denominator" + std::string toString(); + +private: + /// Initialize and normalize a rational number + void initialize(LONG n, LONG d); + + /// Calculate GCD + LONG gcd(LONG a, LONG b); + + /// Normalize numerator / denominator + void normalize(); + +}; + +#endif // FIRATIONAL_H + diff --git a/plugins/FreeImage/src/Metadata/FreeImageTag.cpp b/plugins/FreeImage/src/Metadata/FreeImageTag.cpp new file mode 100644 index 0000000000..84e15d0822 --- /dev/null +++ b/plugins/FreeImage/src/Metadata/FreeImageTag.cpp @@ -0,0 +1,318 @@ +// ========================================================== +// 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! +// ========================================================== + +#ifdef _MSC_VER +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters +#endif + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageTag.h" + +// -------------------------------------------------------------------------- +// FITAG header definition +// -------------------------------------------------------------------------- + +FI_STRUCT (FITAGHEADER) { + char *key; // tag field name + char *description; // tag description + WORD id; // tag ID + WORD type; // tag data type (see FREE_IMAGE_MDTYPE) + DWORD count; // number of components (in 'tag data types' units) + DWORD length; // value length in bytes + void *value; // tag value +}; + +// -------------------------------------------------------------------------- +// FITAG creation / destruction +// -------------------------------------------------------------------------- + +FITAG * DLL_CALLCONV +FreeImage_CreateTag() { + FITAG *tag = (FITAG *)malloc(sizeof(FITAG)); + + if (tag != NULL) { + unsigned tag_size = sizeof(FITAGHEADER); + tag->data = (BYTE *)malloc(tag_size * sizeof(BYTE)); + if (tag->data != NULL) { + memset(tag->data, 0, tag_size); + return tag; + } + free(tag); + } + + return NULL; +} + +void DLL_CALLCONV +FreeImage_DeleteTag(FITAG *tag) { + if (NULL != tag) { + if (NULL != tag->data) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + // delete tag members + free(tag_header->key); + free(tag_header->description); + free(tag_header->value); + // delete the tag + free(tag->data); + } + // and the wrapper + free(tag); + } +} + +FITAG * DLL_CALLCONV +FreeImage_CloneTag(FITAG *tag) { + if (!tag) return NULL; + + // allocate a new tag + FITAG *clone = FreeImage_CreateTag(); + if (!clone) return NULL; + + try { + // copy the tag + FITAGHEADER *src_tag = (FITAGHEADER *)tag->data; + FITAGHEADER *dst_tag = (FITAGHEADER *)clone->data; + + // tag ID + dst_tag->id = src_tag->id; + // tag key + if(src_tag->key) { + dst_tag->key = (char*)malloc((strlen(src_tag->key) + 1) * sizeof(char)); + if (!dst_tag->key) { + throw FI_MSG_ERROR_MEMORY; + } + strcpy(dst_tag->key, src_tag->key); + } + // tag description + if(src_tag->description) { + dst_tag->description = (char*)malloc((strlen(src_tag->description) + 1) * sizeof(char)); + if (!dst_tag->description) { + throw FI_MSG_ERROR_MEMORY; + } + strcpy(dst_tag->description, src_tag->description); + } + // tag data type + dst_tag->type = src_tag->type; + // tag count + dst_tag->count = src_tag->count; + // tag length + dst_tag->length = src_tag->length; + // tag value + dst_tag->value = (BYTE*)malloc(src_tag->length * sizeof(BYTE)); + if (!dst_tag->value) { + throw FI_MSG_ERROR_MEMORY; + } + memcpy(dst_tag->value, src_tag->value, src_tag->length); + + return clone; + + } catch(const char *message) { + FreeImage_DeleteTag(clone); + FreeImage_OutputMessageProc(FIF_UNKNOWN, message); + return NULL; + } +} + +// -------------------------------------------------------------------------- +// FITAG getters / setters +// -------------------------------------------------------------------------- + +const char * DLL_CALLCONV +FreeImage_GetTagKey(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->key : 0; +} + +const char * DLL_CALLCONV +FreeImage_GetTagDescription(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->description : 0; +} + +WORD DLL_CALLCONV +FreeImage_GetTagID(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->id : 0; +} + +FREE_IMAGE_MDTYPE DLL_CALLCONV +FreeImage_GetTagType(FITAG *tag) { + return tag ? (FREE_IMAGE_MDTYPE)(((FITAGHEADER *)tag->data)->type) : FIDT_NOTYPE; +} + +DWORD DLL_CALLCONV +FreeImage_GetTagCount(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->count : 0; +} + +DWORD DLL_CALLCONV +FreeImage_GetTagLength(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->length : 0; +} + +const void *DLL_CALLCONV +FreeImage_GetTagValue(FITAG *tag) { + return tag ? ((FITAGHEADER *)tag->data)->value : 0; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagKey(FITAG *tag, const char *key) { + if(tag && key) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + if(tag_header->key) free(tag_header->key); + tag_header->key = (char*)malloc(strlen(key) + 1); + strcpy(tag_header->key, key); + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagDescription(FITAG *tag, const char *description) { + if(tag && description) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + if(tag_header->description) free(tag_header->description); + tag_header->description = (char*)malloc(strlen(description) + 1); + strcpy(tag_header->description, description); + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagID(FITAG *tag, WORD id) { + if(tag) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + tag_header->id = id; + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type) { + if(tag) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + tag_header->type = (WORD)type; + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagCount(FITAG *tag, DWORD count) { + if(tag) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + tag_header->count = count; + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagLength(FITAG *tag, DWORD length) { + if(tag) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + tag_header->length = length; + return TRUE; + } + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_SetTagValue(FITAG *tag, const void *value) { + if(tag && value) { + FITAGHEADER *tag_header = (FITAGHEADER *)tag->data; + // first, check the tag + if(tag_header->count * FreeImage_TagDataWidth((FREE_IMAGE_MDTYPE)tag_header->type) != tag_header->length) { + // invalid data count ? + return FALSE; + } + + if(tag_header->value) { + free(tag_header->value); + } + + switch(tag_header->type) { + case FIDT_ASCII: + { + tag_header->value = (char*)malloc((tag_header->length + 1) * sizeof(char)); + if (!tag_header->value) { + return FALSE; + } + char *src_data = (char*)value; + char *dst_data = (char*)tag_header->value; + for(DWORD i = 0; i < tag_header->length; i++) { + dst_data[i] = src_data[i]; + } + dst_data[tag_header->length] = '\0'; + } + break; + + default: + tag_header->value = malloc(tag_header->length * sizeof(BYTE)); + if (!tag_header->value) { + return FALSE; + } + memcpy(tag_header->value, value, tag_header->length); + break; + } + return TRUE; + } + return FALSE; +} + + +// -------------------------------------------------------------------------- +// FITAG internal helper functions +// -------------------------------------------------------------------------- + +/** +Given a FREE_IMAGE_MDTYPE, calculate the size of this type in bytes unit +@param type Input data type +@return Returns the size of the data type, in bytes unit +*/ +unsigned +FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) { + static const unsigned format_bytes[] = { + 0, // FIDT_NOTYPE = 0, // placeholder + 1, // FIDT_BYTE = 1, // 8-bit unsigned integer + 1, // FIDT_ASCII = 2, // 8-bit bytes w/ last byte null + 2, // FIDT_SHORT = 3, // 16-bit unsigned integer + 4, // FIDT_LONG = 4, // 32-bit unsigned integer + 8, // FIDT_RATIONAL = 5, // 64-bit unsigned fraction + 1, // FIDT_SBYTE = 6, // 8-bit signed integer + 1, // FIDT_UNDEFINED= 7, // 8-bit untyped data + 2, // FIDT_SSHORT = 8, // 16-bit signed integer + 4, // FIDT_SLONG = 9, // 32-bit signed integer + 8, // FIDT_SRATIONAL= 10, // 64-bit signed fraction + 4, // FIDT_FLOAT = 11, // 32-bit IEEE floating point + 8, // FIDT_DOUBLE = 12, // 64-bit IEEE floating point + 4, // FIDT_IFD = 13, // 32-bit unsigned integer (offset) + 4, // FIDT_PALETTE = 14 // 32-bit RGBQUAD
+ 0, // placeholder (15)
+ 8, // FIDT_LONG8 = 16, // 64-bit unsigned integer
+ 8, // FIDT_SLONG8 = 17, // 64-bit signed integer + 8 // FIDT_IFD8 = 18 // 64-bit unsigned integer (offset) + }; + + return (type < (sizeof(format_bytes)/sizeof(format_bytes[0]))) ? + format_bytes[type] : 0; +} + diff --git a/plugins/FreeImage/src/Metadata/FreeImageTag.h b/plugins/FreeImage/src/Metadata/FreeImageTag.h new file mode 100644 index 0000000000..f412603e8d --- /dev/null +++ b/plugins/FreeImage/src/Metadata/FreeImageTag.h @@ -0,0 +1,474 @@ +// ========================================================== +// 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 + +// LibTIF compression modes + +#define TAG_COMPRESSION_NONE 1 /* dump mode */ +#define TAG_COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define TAG_COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define TAG_COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +#define TAG_COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define TAG_COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +#define TAG_COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define TAG_COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define TAG_COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define TAG_COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define TAG_COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define TAG_COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define TAG_COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */ +#define TAG_COMPRESSION_IT8CTPAD 32895 /* IT8 CT w/padding */ +#define TAG_COMPRESSION_IT8LW 32896 /* IT8 Linework RLE */ +#define TAG_COMPRESSION_IT8MP 32897 /* IT8 Monochrome picture */ +#define TAG_COMPRESSION_IT8BL 32898 /* IT8 Binary line art */ +/* compression codes 32908-32911 are reserved for Pixar */ +#define TAG_COMPRESSION_PIXARFILM 32908 /* Pixar companded 10bit LZW */ +#define TAG_COMPRESSION_PIXARLOG 32909 /* Pixar companded 11bit ZIP */ +#define TAG_COMPRESSION_DEFLATE 32946 /* Deflate compression */ +#define TAG_COMPRESSION_ADOBE_DEFLATE 8 /* Deflate compression, + as recognized by Adobe */ +/* compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> */ +#define TAG_COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define TAG_COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define TAG_COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define TAG_COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define TAG_COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define TAG_COMPRESSION_LZMA 34925 /* LZMA2 */ + +// 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 +*/ +unsigned FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE 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, + EXIF_MAKERNOTE_SIGMA_SD1, + EXIF_MAKERNOTE_SIGMA_FOVEON, + 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 const char *g_TagLib_XMPFieldName = "XMLPacket"; + +/// Name of the Exif raw field +static const char *g_TagLib_ExifRawFieldName = "ExifRaw"; + +// -------------------------------------------------------------------------- +// 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 + + diff --git a/plugins/FreeImage/src/Metadata/IPTC.cpp b/plugins/FreeImage/src/Metadata/IPTC.cpp new file mode 100644 index 0000000000..817beddf98 --- /dev/null +++ b/plugins/FreeImage/src/Metadata/IPTC.cpp @@ -0,0 +1,325 @@ +// ========================================================== +// Metadata functions implementation +// +// 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! +// ========================================================== + +#ifdef _MSC_VER +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters +#endif + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageTag.h" + +// ---------------------------------------------------------- +// IPTC JPEG / TIFF markers routines +// ---------------------------------------------------------- + +static const char* IPTC_DELIMITER = ";"; // keywords/supplemental category delimiter +/** + Read and decode IPTC binary data +*/ +BOOL +read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { + char defaultKey[16]; + size_t length = datalen; + BYTE *profile = (BYTE*)dataptr; + + std::string Keywords; + std::string SupplementalCategory; + + WORD tag_id; + + if (!dataptr || (datalen == 0)) { + return FALSE; + } + + // create a tag + + FITAG *tag = FreeImage_CreateTag(); + + TagLib& tag_lib = TagLib::instance(); + + // find start of the BIM portion of the binary data + size_t offset = 0; + while(offset < length - 1) { + if ((profile[offset] == 0x1C) && (profile[offset+1] == 0x02)) + break; + offset++; + } + + // for each tag + while (offset < length) { + + // identifies start of a tag + if (profile[offset] != 0x1c) { + break; + } + // we need at least five bytes left to read a tag + if ((offset + 5) >= length) { + break; + } + + offset++; + + int directoryType = profile[offset++]; + int tagType = profile[offset++];; + int tagByteCount = ((profile[offset] & 0xFF) << 8) | (profile[offset + 1] & 0xFF); + offset += 2; + + if ((offset + tagByteCount) > length) { + // data for tag extends beyond end of iptc segment + break; + } + + // process the tag + + tag_id = (WORD)(tagType | (directoryType << 8)); + + FreeImage_SetTagID(tag, tag_id); + FreeImage_SetTagLength(tag, tagByteCount); + + // allocate a buffer to store the tag value + BYTE *iptc_value = (BYTE*)malloc((tagByteCount + 1) * sizeof(BYTE)); + memset(iptc_value, 0, (tagByteCount + 1) * sizeof(BYTE)); + + // get the tag value + + switch (tag_id) { + case TAG_RECORD_VERSION: + { + // short + FreeImage_SetTagType(tag, FIDT_SSHORT); + FreeImage_SetTagCount(tag, 1); + short *pvalue = (short*)&iptc_value[0]; + *pvalue = (short)((profile[offset] << 8) | profile[offset + 1]); + FreeImage_SetTagValue(tag, pvalue); + break; + } + + case TAG_RELEASE_DATE: + case TAG_DATE_CREATED: + // Date object + case TAG_RELEASE_TIME: + case TAG_TIME_CREATED: + // time + default: + { + // string + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagCount(tag, tagByteCount); + for(int i = 0; i < tagByteCount; i++) { + iptc_value[i] = profile[offset + i]; + } + iptc_value[tagByteCount] = '\0'; + FreeImage_SetTagValue(tag, (char*)&iptc_value[0]); + break; + } + } + + if(tag_id == TAG_SUPPLEMENTAL_CATEGORIES) { + // concatenate the categories + if(SupplementalCategory.length() == 0) { + SupplementalCategory.append((char*)iptc_value); + } else { + SupplementalCategory.append(IPTC_DELIMITER); + SupplementalCategory.append((char*)iptc_value); + } + } + else if(tag_id == TAG_KEYWORDS) { + // concatenate the keywords + if(Keywords.length() == 0) { + Keywords.append((char*)iptc_value); + } else { + Keywords.append(IPTC_DELIMITER); + Keywords.append((char*)iptc_value); + } + } + else { + // get the tag key and description + const char *key = tag_lib.getTagFieldName(TagLib::IPTC, tag_id, defaultKey); + FreeImage_SetTagKey(tag, key); + const char *description = tag_lib.getTagDescription(TagLib::IPTC, tag_id); + FreeImage_SetTagDescription(tag, description); + + // store the tag + if(key) { + FreeImage_SetMetadata(FIMD_IPTC, dib, key, tag); + } + } + + free(iptc_value); + + // next tag + offset += tagByteCount; + + } + + // store the 'keywords' tag + if(Keywords.length()) { + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagID(tag, TAG_KEYWORDS); + FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_KEYWORDS, defaultKey)); + FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_KEYWORDS)); + FreeImage_SetTagLength(tag, (DWORD)Keywords.length()); + FreeImage_SetTagCount(tag, (DWORD)Keywords.length()); + FreeImage_SetTagValue(tag, (char*)Keywords.c_str()); + FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag); + } + + // store the 'supplemental category' tag + if(SupplementalCategory.length()) { + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagID(tag, TAG_SUPPLEMENTAL_CATEGORIES); + FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES, defaultKey)); + FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES)); + FreeImage_SetTagLength(tag, (DWORD)SupplementalCategory.length()); + FreeImage_SetTagCount(tag, (DWORD)SupplementalCategory.length()); + FreeImage_SetTagValue(tag, (char*)SupplementalCategory.c_str()); + FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag); + } + + // delete the tag + + FreeImage_DeleteTag(tag); + + return TRUE; +} + +// -------------------------------------------------------------------------- + +static BYTE* +append_iptc_tag(BYTE *profile, unsigned *profile_size, WORD id, DWORD length, const void *value) { + BYTE *buffer = NULL; + + // calculate the new buffer size + size_t buffer_size = (5 + *profile_size + length) * sizeof(BYTE); + buffer = (BYTE*)malloc(buffer_size); + if (!buffer) + return NULL; + + // add the header + buffer[0] = 0x1C; + buffer[1] = 0x02; + // add the tag type + buffer[2] = (BYTE)(id & 0x00FF); + // add the tag length + buffer[3] = (BYTE)(length >> 8); + buffer[4] = (BYTE)(length & 0xFF); + // add the tag value + memcpy(buffer + 5, (BYTE*)value, length); + // append the previous profile + if(NULL == profile) { + *profile_size = (5 + length); + } + else { + memcpy(buffer + 5 + length, profile, *profile_size); + *profile_size += (5 + length); + free(profile); + } + + return buffer; +} + +/** +Encode IPTC metadata into a binary buffer. +The buffer is allocated by the function and must be freed by the caller. +*/ +BOOL +write_iptc_profile(FIBITMAP *dib, BYTE **profile, unsigned *profile_size) { + FITAG *tag = NULL; + FIMETADATA *mdhandle = NULL; + + BYTE *buffer = NULL; + unsigned buffer_size = 0; + + // parse all IPTC tags and rebuild a IPTC profile + mdhandle = FreeImage_FindFirstMetadata(FIMD_IPTC, dib, &tag); + + if(mdhandle) { + do { + WORD tag_id = FreeImage_GetTagID(tag); + + // append the tag to the profile + + switch(tag_id) { + case TAG_RECORD_VERSION: + // ignore (already handled) + break; + + case TAG_SUPPLEMENTAL_CATEGORIES: + case TAG_KEYWORDS: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + std::string value = (const char*)FreeImage_GetTagValue(tag); + + // split the tag value + std::vector<std::string> output; + std::string delimiter = IPTC_DELIMITER; + + size_t offset = 0; + size_t delimiterIndex = 0; + + delimiterIndex = value.find(delimiter, offset); + while (delimiterIndex != std::string::npos) { + output.push_back(value.substr(offset, delimiterIndex - offset)); + offset += delimiterIndex - offset + delimiter.length(); + delimiterIndex = value.find(delimiter, offset); + } + output.push_back(value.substr(offset)); + + // add as many tags as there are comma separated strings + for(int i = 0; i < (int)output.size(); i++) { + std::string& tag_value = output[i]; + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, (DWORD)tag_value.length(), tag_value.c_str()); + } + + } + break; + + case TAG_URGENCY: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + DWORD length = 1; // keep the first octet only + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag)); + } + break; + + default: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + DWORD length = FreeImage_GetTagLength(tag); + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag)); + } + break; + } + + } while(FreeImage_FindNextMetadata(mdhandle, &tag)); + + FreeImage_FindCloseMetadata(mdhandle); + + // add the DirectoryVersion tag + const short version = 0x0200; + buffer = append_iptc_tag(buffer, &buffer_size, TAG_RECORD_VERSION, sizeof(version), &version); + + *profile = buffer; + *profile_size = buffer_size; + + return TRUE; + } + + return FALSE; +} diff --git a/plugins/FreeImage/src/Metadata/TagConversion.cpp b/plugins/FreeImage/src/Metadata/TagConversion.cpp new file mode 100644 index 0000000000..7b91598014 --- /dev/null +++ b/plugins/FreeImage/src/Metadata/TagConversion.cpp @@ -0,0 +1,1094 @@ +// ==========================================================
+// Tag to string conversion 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!
+// ==========================================================
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
+#endif
+
+#include "FreeImage.h"
+#include "Utilities.h"
+#include "FreeImageTag.h"
+#include "FIRational.h"
+
+#define MAX_TEXT_EXTENT 512
+
+/**
+Convert a tag to a C string
+*/
+static const char*
+ConvertAnyTag(FITAG *tag) {
+ char format[MAX_TEXT_EXTENT];
+ static std::string buffer;
+ DWORD i;
+
+ if (!tag)
+ return NULL;
+
+ buffer.erase();
+
+ // convert the tag value to a string buffer
+
+ FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
+ DWORD tag_count = FreeImage_GetTagCount(tag);
+
+ switch(tag_type) {
+ case FIDT_BYTE: // N x 8-bit unsigned integer
+ {
+ BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld", (LONG) pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %ld", (LONG) pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_SHORT: // N x 16-bit unsigned integer
+ {
+ unsigned short *pvalue = (unsigned short *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%hu", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %hu", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_LONG: // N x 32-bit unsigned integer
+ {
+ DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%lu", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %lu", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_RATIONAL: // N x 64-bit unsigned fraction
+ {
+ DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_SBYTE: // N x 8-bit signed integer
+ {
+ char *pvalue = (char*)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld", (LONG) pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %ld", (LONG) pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_SSHORT: // N x 16-bit signed integer
+ {
+ short *pvalue = (short *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%hd", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %hd", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_SLONG: // N x 32-bit signed integer
+ {
+ LONG *pvalue = (LONG *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %ld", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_SRATIONAL:// N x 64-bit signed fraction
+ {
+ LONG *pvalue = (LONG*)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_FLOAT: // N x 32-bit IEEE floating point
+ {
+ float *pvalue = (float *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%f", (double) pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, "%f", (double) pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_DOUBLE: // N x 64-bit IEEE floating point
+ {
+ double *pvalue = (double *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%f", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, "%f", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_IFD: // N x 32-bit unsigned integer (offset)
+ {
+ DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%X", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " %X", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+ case FIDT_PALETTE: // N x 32-bit RGBQUAD
+ {
+ RGBQUAD *pvalue = (RGBQUAD *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "(%d,%d,%d,%d)", pvalue[0].rgbRed, pvalue[0].rgbGreen, pvalue[0].rgbBlue, pvalue[0].rgbReserved);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, " (%d,%d,%d,%d)", pvalue[i].rgbRed, pvalue[i].rgbGreen, pvalue[i].rgbBlue, pvalue[i].rgbReserved);
+ buffer += format;
+ }
+ break;
+ }
+
+ case FIDT_LONG8: // N x 64-bit unsigned integer
+ {
+ FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, "%ld", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+
+ case FIDT_IFD8: // N x 64-bit unsigned integer (offset)
+ {
+ FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%X", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, "%X", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+
+ case FIDT_SLONG8: // N x 64-bit signed integer
+ {
+ FIINT64 *pvalue = (FIINT64 *)FreeImage_GetTagValue(tag);
+
+ sprintf(format, "%ld", pvalue[0]);
+ buffer += format;
+ for(i = 1; i < tag_count; i++) {
+ sprintf(format, "%ld", pvalue[i]);
+ buffer += format;
+ }
+ break;
+ }
+
+ case FIDT_ASCII: // 8-bit bytes w/ last byte null
+ case FIDT_UNDEFINED:// 8-bit untyped data
+ default:
+ {
+ int max_size = MIN((int)FreeImage_GetTagLength(tag), (int)MAX_TEXT_EXTENT);
+ if(max_size == MAX_TEXT_EXTENT)
+ max_size--;
+ memcpy(format, (char*)FreeImage_GetTagValue(tag), max_size);
+ format[max_size] = '\0';
+ buffer += format;
+ break;
+ }
+ }
+
+ return buffer.c_str();
+}
+
+/**
+Convert a Exif tag to a C string
+*/
+static const char*
+ConvertExifTag(FITAG *tag) {
+ char format[MAX_TEXT_EXTENT];
+ static std::string buffer;
+
+ if (!tag)
+ return NULL;
+
+ buffer.erase();
+
+ // convert the tag value to a string buffer
+
+ switch(FreeImage_GetTagID(tag)) {
+ case TAG_ORIENTATION:
+ {
+ unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (orientation) {
+ case 1:
+ return "top, left side";
+ case 2:
+ return "top, right side";
+ case 3:
+ return "bottom, right side";
+ case 4:
+ return "bottom, left side";
+ case 5:
+ return "left side, top";
+ case 6:
+ return "right side, top";
+ case 7:
+ return "right side, bottom";
+ case 8:
+ return "left side, bottom";
+ default:
+ break;
+ }
+ }
+ break;
+
+ case TAG_REFERENCE_BLACK_WHITE:
+ {
+ DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
+ if(FreeImage_GetTagLength(tag) == 48) {
+ // reference black point value and reference white point value (ReferenceBlackWhite)
+ int blackR = 0, whiteR = 0, blackG = 0, whiteG = 0, blackB = 0, whiteB = 0;
+ if(pvalue[1])
+ blackR = (int)(pvalue[0] / pvalue[1]);
+ if(pvalue[3])
+ whiteR = (int)(pvalue[2] / pvalue[3]);
+ if(pvalue[5])
+ blackG = (int)(pvalue[4] / pvalue[5]);
+ if(pvalue[7])
+ whiteG = (int)(pvalue[6] / pvalue[7]);
+ if(pvalue[9])
+ blackB = (int)(pvalue[8] / pvalue[9]);
+ if(pvalue[11])
+ whiteB = (int)(pvalue[10] / pvalue[11]);
+
+ sprintf(format, "[%d,%d,%d] [%d,%d,%d]", blackR, blackG, blackB, whiteR, whiteG, whiteB);
+ buffer += format;
+ return buffer.c_str();
+ }
+
+ }
+ break;
+
+ case TAG_COLOR_SPACE:
+ {
+ unsigned short colorSpace = *((unsigned short *)FreeImage_GetTagValue(tag));
+ if (colorSpace == 1) {
+ return "sRGB";
+ } else if (colorSpace == 65535) {
+ return "Undefined";
+ } else {
+ return "Unknown";
+ }
+ }
+ break;
+
+ case TAG_COMPONENTS_CONFIGURATION:
+ {
+ const char *componentStrings[7] = {"", "Y", "Cb", "Cr", "R", "G", "B"};
+ BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);
+ for(DWORD i = 0; i < MIN((DWORD)4, FreeImage_GetTagCount(tag)); i++) {
+ int j = pvalue[i];
+ if(j > 0 && j < 7)
+ buffer += componentStrings[j];
+ }
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_COMPRESSED_BITS_PER_PIXEL:
+ {
+ FIRational r(tag);
+ buffer = r.toString();
+ if(buffer == "1")
+ buffer += " bit/pixel";
+ else
+ buffer += " bits/pixel";
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_X_RESOLUTION:
+ case TAG_Y_RESOLUTION:
+ case TAG_FOCAL_PLANE_X_RES:
+ case TAG_FOCAL_PLANE_Y_RES:
+ case TAG_BRIGHTNESS_VALUE:
+ case TAG_EXPOSURE_BIAS_VALUE:
+ {
+ FIRational r(tag);
+ buffer = r.toString();
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_RESOLUTION_UNIT:
+ case TAG_FOCAL_PLANE_UNIT:
+ {
+ unsigned short resolutionUnit = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (resolutionUnit) {
+ case 1:
+ return "(No unit)";
+ case 2:
+ return "inches";
+ case 3:
+ return "cm";
+ default:
+ break;
+ }
+ }
+ break;
+
+ case TAG_YCBCR_POSITIONING:
+ {
+ unsigned short yCbCrPosition = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (yCbCrPosition) {
+ case 1:
+ return "Center of pixel array";
+ case 2:
+ return "Datum point";
+ default:
+ break;
+ }
+ }
+ break;
+
+ case TAG_EXPOSURE_TIME:
+ {
+ FIRational r(tag);
+ buffer = r.toString();
+ buffer += " sec";
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_SHUTTER_SPEED_VALUE:
+ {
+ FIRational r(tag);
+ LONG apexValue = r.longValue();
+ LONG apexPower = 1 << apexValue;
+ sprintf(format, "1/%d sec", (int)apexPower);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_APERTURE_VALUE:
+ case TAG_MAX_APERTURE_VALUE:
+ {
+ FIRational r(tag);
+ double apertureApex = r.doubleValue();
+ double rootTwo = sqrt((double)2);
+ double fStop = pow(rootTwo, apertureApex);
+ sprintf(format, "F%.1f", fStop);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_FNUMBER:
+ {
+ FIRational r(tag);
+ double fnumber = r.doubleValue();
+ sprintf(format, "F%.1f", fnumber);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_FOCAL_LENGTH:
+ {
+ FIRational r(tag);
+ double focalLength = r.doubleValue();
+ sprintf(format, "%.1f mm", focalLength);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_FOCAL_LENGTH_IN_35MM_FILM:
+ {
+ unsigned short focalLength = *((unsigned short *)FreeImage_GetTagValue(tag));
+ sprintf(format, "%hu mm", focalLength);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_FLASH:
+ {
+ unsigned short flash = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch(flash) {
+ case 0x0000:
+ return "Flash did not fire";
+ case 0x0001:
+ return "Flash fired";
+ case 0x0005:
+ return "Strobe return light not detected";
+ case 0x0007:
+ return "Strobe return light detected";
+ case 0x0009:
+ return "Flash fired, compulsory flash mode";
+ case 0x000D:
+ return "Flash fired, compulsory flash mode, return light not detected";
+ case 0x000F:
+ return "Flash fired, compulsory flash mode, return light detected";
+ case 0x0010:
+ return "Flash did not fire, compulsory flash mode";
+ case 0x0018:
+ return "Flash did not fire, auto mode";
+ case 0x0019:
+ return "Flash fired, auto mode";
+ case 0x001D:
+ return "Flash fired, auto mode, return light not detected";
+ case 0x001F:
+ return "Flash fired, auto mode, return light detected";
+ case 0x0020:
+ return "No flash function";
+ case 0x0041:
+ return "Flash fired, red-eye reduction mode";
+ case 0x0045:
+ return "Flash fired, red-eye reduction mode, return light not detected";
+ case 0x0047:
+ return "Flash fired, red-eye reduction mode, return light detected";
+ case 0x0049:
+ return "Flash fired, compulsory flash mode, red-eye reduction mode";
+ case 0x004D:
+ return "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected";
+ case 0x004F:
+ return "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected";
+ case 0x0059:
+ return "Flash fired, auto mode, red-eye reduction mode";
+ case 0x005D:
+ return "Flash fired, auto mode, return light not detected, red-eye reduction mode";
+ case 0x005F:
+ return "Flash fired, auto mode, return light detected, red-eye reduction mode";
+ default:
+ sprintf(format, "Unknown (%d)", flash);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SCENE_TYPE:
+ {
+ BYTE sceneType = *((BYTE*)FreeImage_GetTagValue(tag));
+ if (sceneType == 1) {
+ return "Directly photographed image";
+ } else {
+ sprintf(format, "Unknown (%d)", sceneType);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SUBJECT_DISTANCE:
+ {
+ FIRational r(tag);
+ if(r.getNumerator() == 0xFFFFFFFF) {
+ return "Infinity";
+ } else if(r.getNumerator() == 0) {
+ return "Distance unknown";
+ } else {
+ double distance = r.doubleValue();
+ sprintf(format, "%.3f meters", distance);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_METERING_MODE:
+ {
+ unsigned short meteringMode = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (meteringMode) {
+ case 0:
+ return "Unknown";
+ case 1:
+ return "Average";
+ case 2:
+ return "Center weighted average";
+ case 3:
+ return "Spot";
+ case 4:
+ return "Multi-spot";
+ case 5:
+ return "Multi-segment";
+ case 6:
+ return "Partial";
+ case 255:
+ return "(Other)";
+ default:
+ return "";
+ }
+ }
+ break;
+
+ case TAG_LIGHT_SOURCE:
+ {
+ unsigned short lightSource = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (lightSource) {
+ case 0:
+ return "Unknown";
+ case 1:
+ return "Daylight";
+ case 2:
+ return "Fluorescent";
+ case 3:
+ return "Tungsten (incandescent light)";
+ case 4:
+ return "Flash";
+ case 9:
+ return "Fine weather";
+ case 10:
+ return "Cloudy weather";
+ case 11:
+ return "Shade";
+ case 12:
+ return "Daylight fluorescent (D 5700 - 7100K)";
+ case 13:
+ return "Day white fluorescent (N 4600 - 5400K)";
+ case 14:
+ return "Cool white fluorescent (W 3900 - 4500K)";
+ case 15:
+ return "White fluorescent (WW 3200 - 3700K)";
+ case 17:
+ return "Standard light A";
+ case 18:
+ return "Standard light B";
+ case 19:
+ return "Standard light C";
+ case 20:
+ return "D55";
+ case 21:
+ return "D65";
+ case 22:
+ return "D75";
+ case 23:
+ return "D50";
+ case 24:
+ return "ISO studio tungsten";
+ case 255:
+ return "(Other)";
+ default:
+ return "";
+ }
+ }
+ break;
+
+ case TAG_SENSING_METHOD:
+ {
+ unsigned short sensingMethod = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (sensingMethod) {
+ case 1:
+ return "(Not defined)";
+ case 2:
+ return "One-chip color area sensor";
+ case 3:
+ return "Two-chip color area sensor";
+ case 4:
+ return "Three-chip color area sensor";
+ case 5:
+ return "Color sequential area sensor";
+ case 7:
+ return "Trilinear sensor";
+ case 8:
+ return "Color sequential linear sensor";
+ default:
+ return "";
+ }
+ }
+ break;
+
+ case TAG_FILE_SOURCE:
+ {
+ BYTE fileSource = *((BYTE*)FreeImage_GetTagValue(tag));
+ if (fileSource == 3) {
+ return "Digital Still Camera (DSC)";
+ } else {
+ sprintf(format, "Unknown (%d)", fileSource);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_EXPOSURE_PROGRAM:
+ {
+ unsigned short exposureProgram = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (exposureProgram) {
+ case 1:
+ return "Manual control";
+ case 2:
+ return "Program normal";
+ case 3:
+ return "Aperture priority";
+ case 4:
+ return "Shutter priority";
+ case 5:
+ return "Program creative (slow program)";
+ case 6:
+ return "Program action (high-speed program)";
+ case 7:
+ return "Portrait mode";
+ case 8:
+ return "Landscape mode";
+ default:
+ sprintf(format, "Unknown program (%d)", exposureProgram);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_CUSTOM_RENDERED:
+ {
+ unsigned short customRendered = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (customRendered) {
+ case 0:
+ return "Normal process";
+ case 1:
+ return "Custom process";
+ default:
+ sprintf(format, "Unknown rendering (%d)", customRendered);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_EXPOSURE_MODE:
+ {
+ unsigned short exposureMode = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (exposureMode) {
+ case 0:
+ return "Auto exposure";
+ case 1:
+ return "Manual exposure";
+ case 2:
+ return "Auto bracket";
+ default:
+ sprintf(format, "Unknown mode (%d)", exposureMode);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_WHITE_BALANCE:
+ {
+ unsigned short whiteBalance = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (whiteBalance) {
+ case 0:
+ return "Auto white balance";
+ case 1:
+ return "Manual white balance";
+ default:
+ sprintf(format, "Unknown (%d)", whiteBalance);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SCENE_CAPTURE_TYPE:
+ {
+ unsigned short sceneType = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (sceneType) {
+ case 0:
+ return "Standard";
+ case 1:
+ return "Landscape";
+ case 2:
+ return "Portrait";
+ case 3:
+ return "Night scene";
+ default:
+ sprintf(format, "Unknown (%d)", sceneType);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_GAIN_CONTROL:
+ {
+ unsigned short gainControl = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (gainControl) {
+ case 0:
+ return "None";
+ case 1:
+ return "Low gain up";
+ case 2:
+ return "High gain up";
+ case 3:
+ return "Low gain down";
+ case 4:
+ return "High gain down";
+ default:
+ sprintf(format, "Unknown (%d)", gainControl);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_CONTRAST:
+ {
+ unsigned short contrast = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (contrast) {
+ case 0:
+ return "Normal";
+ case 1:
+ return "Soft";
+ case 2:
+ return "Hard";
+ default:
+ sprintf(format, "Unknown (%d)", contrast);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SATURATION:
+ {
+ unsigned short saturation = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (saturation) {
+ case 0:
+ return "Normal";
+ case 1:
+ return "Low saturation";
+ case 2:
+ return "High saturation";
+ default:
+ sprintf(format, "Unknown (%d)", saturation);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SHARPNESS:
+ {
+ unsigned short sharpness = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (sharpness) {
+ case 0:
+ return "Normal";
+ case 1:
+ return "Soft";
+ case 2:
+ return "Hard";
+ default:
+ sprintf(format, "Unknown (%d)", sharpness);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_SUBJECT_DISTANCE_RANGE:
+ {
+ unsigned short distanceRange = *((unsigned short *)FreeImage_GetTagValue(tag));
+
+ switch (distanceRange) {
+ case 0:
+ return "unknown";
+ case 1:
+ return "Macro";
+ case 2:
+ return "Close view";
+ case 3:
+ return "Distant view";
+ default:
+ sprintf(format, "Unknown (%d)", distanceRange);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_ISO_SPEED_RATINGS:
+ {
+ unsigned short isoEquiv = *((unsigned short *)FreeImage_GetTagValue(tag));
+ if (isoEquiv < 50) {
+ isoEquiv *= 200;
+ }
+ sprintf(format, "%d", isoEquiv);
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_USER_COMMENT:
+ {
+ // first 8 bytes are used to define an ID code
+ // we assume this is an ASCII string
+ const BYTE *userComment = (BYTE*)FreeImage_GetTagValue(tag);
+ for(DWORD i = 8; i < FreeImage_GetTagLength(tag); i++) {
+ buffer += userComment[i];
+ }
+ buffer += '\0';
+ return buffer.c_str();
+ }
+ break;
+
+ case TAG_COMPRESSION:
+ {
+ WORD compression = *((WORD*)FreeImage_GetTagValue(tag));
+ switch(compression) {
+ case TAG_COMPRESSION_NONE:
+ sprintf(format, "dump mode (%d)", compression);
+ break;
+ case TAG_COMPRESSION_CCITTRLE:
+ sprintf(format, "CCITT modified Huffman RLE (%d)", compression);
+ break;
+ case TAG_COMPRESSION_CCITTFAX3:
+ sprintf(format, "CCITT Group 3 fax encoding (%d)", compression);
+ break;
+ /*
+ case TAG_COMPRESSION_CCITT_T4:
+ sprintf(format, "CCITT T.4 (TIFF 6 name) (%d)", compression);
+ break;
+ */
+ case TAG_COMPRESSION_CCITTFAX4:
+ sprintf(format, "CCITT Group 4 fax encoding (%d)", compression);
+ break;
+ /*
+ case TAG_COMPRESSION_CCITT_T6:
+ sprintf(format, "CCITT T.6 (TIFF 6 name) (%d)", compression);
+ break;
+ */
+ case TAG_COMPRESSION_LZW:
+ sprintf(format, "LZW (%d)", compression);
+ break;
+ case TAG_COMPRESSION_OJPEG:
+ sprintf(format, "!6.0 JPEG (%d)", compression);
+ break;
+ case TAG_COMPRESSION_JPEG:
+ sprintf(format, "JPEG (%d)", compression);
+ break;
+ case TAG_COMPRESSION_NEXT:
+ sprintf(format, "NeXT 2-bit RLE (%d)", compression);
+ break;
+ case TAG_COMPRESSION_CCITTRLEW:
+ sprintf(format, "CCITTRLEW (%d)", compression);
+ break;
+ case TAG_COMPRESSION_PACKBITS:
+ sprintf(format, "PackBits Macintosh RLE (%d)", compression);
+ break;
+ case TAG_COMPRESSION_THUNDERSCAN:
+ sprintf(format, "ThunderScan RLE (%d)", compression);
+ break;
+ case TAG_COMPRESSION_PIXARFILM:
+ sprintf(format, "Pixar companded 10bit LZW (%d)", compression);
+ break;
+ case TAG_COMPRESSION_PIXARLOG:
+ sprintf(format, "Pixar companded 11bit ZIP (%d)", compression);
+ break;
+ case TAG_COMPRESSION_DEFLATE:
+ sprintf(format, "Deflate compression (%d)", compression);
+ break;
+ case TAG_COMPRESSION_ADOBE_DEFLATE:
+ sprintf(format, "Adobe Deflate compression (%d)", compression);
+ break;
+ case TAG_COMPRESSION_DCS:
+ sprintf(format, "Kodak DCS encoding (%d)", compression);
+ break;
+ case TAG_COMPRESSION_JBIG:
+ sprintf(format, "ISO JBIG (%d)", compression);
+ break;
+ case TAG_COMPRESSION_SGILOG:
+ sprintf(format, "SGI Log Luminance RLE (%d)", compression);
+ break;
+ case TAG_COMPRESSION_SGILOG24:
+ sprintf(format, "SGI Log 24-bit packed (%d)", compression);
+ break;
+ case TAG_COMPRESSION_JP2000:
+ sprintf(format, "Leadtools JPEG2000 (%d)", compression);
+ break;
+ case TAG_COMPRESSION_LZMA:
+ sprintf(format, "LZMA2 (%d)", compression);
+ break;
+ default:
+ sprintf(format, "Unknown type (%d)", compression);
+ break;
+ }
+
+ buffer += format;
+ return buffer.c_str();
+ }
+ break;
+ }
+
+ return ConvertAnyTag(tag);
+}
+
+/**
+Convert a Exif GPS tag to a C string
+*/
+static const char*
+ConvertExifGPSTag(FITAG *tag) {
+ char format[MAX_TEXT_EXTENT];
+ static std::string buffer;
+
+ if (!tag)
+ return NULL;
+
+ buffer.erase();
+
+ // convert the tag value to a string buffer
+
+ switch(FreeImage_GetTagID(tag)) {
+ case TAG_GPS_LATITUDE:
+ case TAG_GPS_LONGITUDE:
+ case TAG_GPS_TIME_STAMP:
+ {
+ DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
+ if(FreeImage_GetTagLength(tag) == 24) {
+ // dd:mm:ss or hh:mm:ss
+ int dd = 0, mm = 0;
+ double ss = 0;
+
+ // convert to seconds
+ if(pvalue[1])
+ ss += ((double)pvalue[0] / (double)pvalue[1]) * 3600;
+ if(pvalue[3])
+ ss += ((double)pvalue[2] / (double)pvalue[3]) * 60;
+ if(pvalue[5])
+ ss += ((double)pvalue[4] / (double)pvalue[5]);
+
+ // convert to dd:mm:ss.ss
+ dd = (int)(ss / 3600);
+ mm = (int)(ss / 60) - dd * 60;
+ ss = ss - dd * 3600 - mm * 60;
+
+ sprintf(format, "%d:%d:%.2f", dd, mm, ss);
+ buffer += format;
+ return buffer.c_str();
+ }
+ }
+ break;
+
+ case TAG_GPS_VERSION_ID:
+ case TAG_GPS_LATITUDE_REF:
+ case TAG_GPS_LONGITUDE_REF:
+ case TAG_GPS_ALTITUDE_REF:
+ case TAG_GPS_ALTITUDE:
+ case TAG_GPS_SATELLITES:
+ case TAG_GPS_STATUS:
+ case TAG_GPS_MEASURE_MODE:
+ case TAG_GPS_DOP:
+ case TAG_GPS_SPEED_REF:
+ case TAG_GPS_SPEED:
+ case TAG_GPS_TRACK_REF:
+ case TAG_GPS_TRACK:
+ case TAG_GPS_IMG_DIRECTION_REF:
+ case TAG_GPS_IMG_DIRECTION:
+ case TAG_GPS_MAP_DATUM:
+ case TAG_GPS_DEST_LATITUDE_REF:
+ case TAG_GPS_DEST_LATITUDE:
+ case TAG_GPS_DEST_LONGITUDE_REF:
+ case TAG_GPS_DEST_LONGITUDE:
+ case TAG_GPS_DEST_BEARING_REF:
+ case TAG_GPS_DEST_BEARING:
+ case TAG_GPS_DEST_DISTANCE_REF:
+ case TAG_GPS_DEST_DISTANCE:
+ case TAG_GPS_PROCESSING_METHOD:
+ case TAG_GPS_AREA_INFORMATION:
+ case TAG_GPS_DATE_STAMP:
+ case TAG_GPS_DIFFERENTIAL:
+ break;
+ }
+
+ return ConvertAnyTag(tag);
+}
+
+// ==========================================================
+// Tag to string conversion function
+//
+
+const char* DLL_CALLCONV
+FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make) {
+ switch(model) {
+ case FIMD_EXIF_MAIN:
+ case FIMD_EXIF_EXIF:
+ return ConvertExifTag(tag);
+
+ case FIMD_EXIF_GPS:
+ return ConvertExifGPSTag(tag);
+
+ case FIMD_EXIF_MAKERNOTE:
+ // We should use the Make string to select an appropriate conversion function
+ // TO DO ...
+ break;
+
+ case FIMD_EXIF_INTEROP:
+ default:
+ break;
+ }
+
+ return ConvertAnyTag(tag);
+}
+
diff --git a/plugins/FreeImage/src/Metadata/TagLib.cpp b/plugins/FreeImage/src/Metadata/TagLib.cpp new file mode 100644 index 0000000000..eff291beab --- /dev/null +++ b/plugins/FreeImage/src/Metadata/TagLib.cpp @@ -0,0 +1,1617 @@ +// ========================================================== +// Tag library +// +// 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! +// ========================================================== + +// ========================================================== +// Implementation notes : +// ---------------------- +// The tag info tables declared in this file should probably +// be loaded from an XML file. +// This would allow internationalization features and also +// more extensibility. +// Maybe in a future release ? +// ========================================================== + +#ifdef _MSC_VER +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters +#endif + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageTag.h" + +/** + HOW-TO : add a new TagInfo table + -------------------------------------------------------------------------- + 1) add a table identifier in the TagLib class definition (see enum MDMODEL) + 2) declare the tag table as static and use a 0/NULL value as last entry + 3) initialize the table in TagLib::TagLib + 4) provide a conversion in TagLib::getFreeImageModel +*/ + +// -------------------------------------------------------------------------- +// EXIF standard tags definition +// -------------------------------------------------------------------------- + +static TagInfo + exif_exif_tag_table[] = + { + { 0x0100, (char *) "ImageWidth", (char *) "Image width"}, + { 0x0101, (char *) "ImageLength", (char *) "Image height"}, + { 0x0102, (char *) "BitsPerSample", (char *) "Number of bits per component"}, + { 0x0103, (char *) "Compression", (char *) "Compression scheme"}, + { 0x0106, (char *) "PhotometricInterpretation", (char *) "Pixel composition"}, + { 0x010A, (char *) "FillOrder", (char*) NULL}, + { 0x010D, (char *) "DocumentName", (char *) NULL}, + { 0x010E, (char *) "ImageDescription", (char *) "Image title"}, + { 0x010F, (char *) "Make", (char *) "Image input equipment manufacturer"}, + { 0x0110, (char *) "Model", (char *) "Image input equipment model"}, + { 0x0111, (char *) "StripOffsets", (char *) "Image data location"}, + { 0x0112, (char *) "Orientation", (char *) "Orientation of image"}, + { 0x0115, (char *) "SamplesPerPixel", (char *) "Number of components"}, + { 0x0116, (char *) "RowsPerStrip", (char *) "Number of rows per strip"}, + { 0x0117, (char *) "StripByteCounts", (char *) "Bytes per compressed strip"}, + { 0x011A, (char *) "XResolution", (char *) "Image resolution in width direction"}, + { 0x011B, (char *) "YResolution", (char *) "Image resolution in height direction"}, + { 0x011C, (char *) "PlanarConfiguration", (char *) "Image data arrangement"}, + { 0x011D, (char *) "PageName", (char *) "Name of the page"}, + { 0x011E, (char *) "XPosition", (char *) "X position of the image"}, + { 0x011F, (char *) "YPosition", (char *) "Y position of the image"}, + { 0x0128, (char *) "ResolutionUnit", (char *) "Unit of X and Y resolution"}, + { 0x0129, (char *) "PageNumber", (char *) "Page number"}, + { 0x012D, (char *) "TransferFunction", (char *) "Transfer function"}, + { 0x0131, (char *) "Software", (char *) "Software used"}, + { 0x0132, (char *) "DateTime", (char *) "File change date and time"}, + { 0x013B, (char *) "Artist", (char *) "Person who created the image"}, + { 0x013C, (char *) "HostComputer", (char *) "Host computer used to generate the image"}, + { 0x013E, (char *) "WhitePoint", (char *) "White point chromaticity"}, + { 0x013F, (char *) "PrimaryChromaticities", (char *) "Chromaticities of primaries"}, + { 0x0156, (char *) "TransferRange", (char *) NULL}, + { 0x0200, (char *) "JPEGProc", (char *) NULL}, + { 0x0201, (char *) "JPEGInterchangeFormat", (char *) "Offset to JPEG SOI"}, + { 0x0202, (char *) "JPEGInterchangeFormatLength", (char *) "Bytes of JPEG data"}, + { 0x0211, (char *) "YCbCrCoefficients", (char *) "Color space transformation matrix coefficients"}, + { 0x0212, (char *) "YCbCrSubSampling", (char *) "Subsampling ratio of Y to C"}, + { 0x0213, (char *) "YCbCrPositioning", (char *) "Y and C positioning"}, + { 0x0214, (char *) "ReferenceBlackWhite", (char *) "Pair of black and white reference values"}, + { 0x828D, (char *) "CFARepeatPatternDim", (char *) NULL}, + { 0x828E, (char *) "CFAPattern", (char *) NULL}, + { 0x828F, (char *) "BatteryLevel", (char *) NULL}, + { 0x8298, (char *) "Copyright", (char *) "Copyright holder"}, + { 0x829A, (char *) "ExposureTime", (char *) "Exposure time"}, + { 0x829D, (char *) "FNumber", (char *) "F number"}, + { 0x83BB, (char *) "IPTC/NAA", (char *) NULL}, + { 0x8773, (char *) "InterColorProfile", (char *) NULL}, + { 0x8822, (char *) "ExposureProgram", (char *) "Exposure program"}, + { 0x8824, (char *) "SpectralSensitivity", (char *) "Spectral sensitivity"}, + { 0x8825, (char *) "GPSInfo", (char *) NULL}, + { 0x8827, (char *) "ISOSpeedRatings", (char *) "ISO speed rating"}, + { 0x8828, (char *) "OECF", (char *) "Optoelectric conversion factor"}, + { 0x9000, (char *) "ExifVersion", (char *) "Exif version"}, + { 0x9003, (char *) "DateTimeOriginal", (char *) "Date and time of original data generation"}, + { 0x9004, (char *) "DateTimeDigitized", (char *) "Date and time of digital data generation"}, + { 0x9101, (char *) "ComponentsConfiguration", (char *) "Meaning of each component"}, + { 0x9102, (char *) "CompressedBitsPerPixel", (char *) "Image compression mode"}, + { 0x9201, (char *) "ShutterSpeedValue", (char *) "Shutter speed"}, + { 0x9202, (char *) "ApertureValue", (char *) "Aperture"}, + { 0x9203, (char *) "BrightnessValue", (char *) "Brightness"}, + { 0x9204, (char *) "ExposureBiasValue", (char *) "Exposure bias"}, + { 0x9205, (char *) "MaxApertureValue", (char *) "Maximum lens aperture"}, + { 0x9206, (char *) "SubjectDistance", (char *) "Subject distance"}, + { 0x9207, (char *) "MeteringMode", (char *) "Metering mode"}, + { 0x9208, (char *) "LightSource", (char *) "Light source"}, + { 0x9209, (char *) "Flash", (char *) "Flash"}, + { 0x920A, (char *) "FocalLength", (char *) "Lens focal length"}, + { 0x9214, (char *) "SubjectArea", (char *) "Subject area"}, + { 0x927C, (char *) "MakerNote", (char *) "Manufacturer notes"}, + { 0x9286, (char *) "UserComment", (char *) "User comments"}, + { 0x9290, (char *) "SubSecTime", (char *) "DateTime subseconds"}, + { 0x9291, (char *) "SubSecTimeOriginal", (char *) "DateTimeOriginal subseconds"}, + { 0x9292, (char *) "SubSecTimeDigitized", (char *) "DateTimeDigitized subseconds"}, + { 0xA000, (char *) "FlashPixVersion", (char *) "Supported Flashpix version"}, + { 0xA001, (char *) "ColorSpace", (char *) "Color space information"}, + { 0xA002, (char *) "PixelXDimension", (char *) "Valid image width"}, + { 0xA003, (char *) "PixelYDimension", (char *) "Valid image height"}, + { 0xA004, (char *) "RelatedSoundFile", (char *) "Related audio file"}, + { 0xA005, (char *) "InteroperabilityOffset", (char *) NULL}, + { 0xA20B, (char *) "FlashEnergy", (char *) "Flash energy"}, + { 0xA20C, (char *) "SpatialFrequencyResponse", (char *) "Spatial frequency response"}, + { 0xA20E, (char *) "FocalPlaneXResolution", (char *) "Focal plane X resolution"}, + { 0xA20F, (char *) "FocalPlaneYResolution", (char *) "Focal plane Y resolution"}, + { 0xA210, (char *) "FocalPlaneResolutionUnit", (char *) "Focal plane resolution unit"}, + { 0xA214, (char *) "SubjectLocation", (char *) "Subject location"}, + { 0xA215, (char *) "ExposureIndex", (char *) "Exposure index"}, + { 0xA217, (char *) "SensingMethod", (char *) "Sensing method"}, + { 0xA300, (char *) "FileSrc", (char *) "File source"}, + { 0xA301, (char *) "SceneType", (char *) "Scene type"}, + { 0xA302, (char *) "CFAPattern", (char *) "CFA pattern"}, + { 0xA401, (char *) "CustomRendered", (char *) "Custom image processing"}, + { 0xA402, (char *) "ExposureMode", (char *) "Exposure mode"}, + { 0xA403, (char *) "WhiteBalance", (char *) "White balance"}, + { 0xA404, (char *) "DigitalZoomRatio", (char *) "Digital zoom ratio"}, + { 0xA405, (char *) "FocalLengthIn35mmFilm", (char *) "Focal length in 35 mm film"}, + { 0xA406, (char *) "SceneCaptureType", (char *) "Scene capture type"}, + { 0xA407, (char *) "GainControl", (char *) "Gain control"}, + { 0xA408, (char *) "Contrast", (char *) "Contrast"}, + { 0xA409, (char *) "Saturation", (char *) "Saturation"}, + { 0xA40A, (char *) "Sharpness", (char *) "Sharpness"}, + { 0xA40B, (char *) "DeviceSettingDescription", (char *) "Device settings description"}, + { 0xA40C, (char *) "SubjectDistanceRange", (char *) "Subject distance range"}, + { 0xA420, (char *) "ImageUniqueID", (char *) "Unique image ID"}, + { 0xA430, (char *) "CameraOwnerName", (char *) "Camera owner name"}, + { 0xA431, (char *) "BodySerialNumber", (char *) "Body serial number"}, + { 0xA432, (char *) "LensSpecification", (char *) "Lens specification"}, + { 0xA433, (char *) "LensMake", (char *) "Lens make"}, + { 0xA434, (char *) "LensModel", (char *) "Lens model"}, + { 0xA435, (char *) "LensSerialNumber", (char *) "Lens serial number"}, + + // These tags are not part of the Exiv v2.3 specifications but are often loaded by applications as Exif data + { 0x4746, (char *) "Rating", (char *) "Rating tag used by Windows"}, + { 0x4749, (char *) "RatingPercent", (char *) "Rating tag used by Windows, value in percent"}, + { 0x9C9B, (char *) "XPTitle", (char *) "Title tag used by Windows, encoded in UCS2"}, + { 0x9C9C, (char *) "XPComment", (char *) "Comment tag used by Windows, encoded in UCS2"}, + { 0x9C9D, (char *) "XPAuthor", (char *) "Author tag used by Windows, encoded in UCS2"}, + { 0x9C9E, (char *) "XPKeywords", (char *) "Keywords tag used by Windows, encoded in UCS2"}, + { 0x9C9F, (char *) "XPSubject", (char *) "Subject tag used by Windows, encoded in UCS2"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// EXIF GPS tags definition +// -------------------------------------------------------------------------- + +static TagInfo + exif_gps_tag_table[] = + { + { 0x0000, (char *) "GPSVersionID", (char *) "GPS tag version"}, + { 0x0001, (char *) "GPSLatitudeRef", (char *) "North or South Latitude"}, + { 0x0002, (char *) "GPSLatitude", (char *) "Latitude"}, + { 0x0003, (char *) "GPSLongitudeRef", (char *) "East or West Longitude"}, + { 0x0004, (char *) "GPSLongitude", (char *) "Longitude"}, + { 0x0005, (char *) "GPSAltitudeRef", (char *) "Altitude reference"}, + { 0x0006, (char *) "GPSAltitude", (char *) "Altitude"}, + { 0x0007, (char *) "GPSTimeStamp", (char *) "GPS time (atomic clock)"}, + { 0x0008, (char *) "GPSSatellites", (char *) "GPS satellites used for measurement"}, + { 0x0009, (char *) "GPSStatus", (char *) "GPS receiver status"}, + { 0x000A, (char *) "GPSMeasureMode", (char *) "GPS measurement mode"}, + { 0x000B, (char *) "GPSDOP", (char *) "Measurement precision"}, + { 0x000C, (char *) "GPSSpeedRef", (char *) "Speed unit"}, + { 0x000D, (char *) "GPSSpeed", (char *) "Speed of GPS receiver"}, + { 0x000E, (char *) "GPSTrackRef", (char *) "Reference for direction of movement"}, + { 0x000F, (char *) "GPSTrack", (char *) "Direction of movement"}, + { 0x0010, (char *) "GPSImgDirectionRef", (char *) "Reference for direction of image"}, + { 0x0011, (char *) "GPSImgDirection", (char *) "Direction of image"}, + { 0x0012, (char *) "GPSMapDatum", (char *) "Geodetic survey data used"}, + { 0x0013, (char *) "GPSDestLatitudeRef", (char *) "Reference for latitude of destination"}, + { 0x0014, (char *) "GPSDestLatitude", (char *) "Latitude of destination"}, + { 0x0015, (char *) "GPSDestLongitudeRef", (char *) "Reference for longitude of destination"}, + { 0x0016, (char *) "GPSDestLongitude", (char *) "Longitude of destination"}, + { 0x0017, (char *) "GPSDestBearingRef", (char *) "Reference for bearing of destination"}, + { 0x0018, (char *) "GPSDestBearing", (char *) "Bearing of destination"}, + { 0x0019, (char *) "GPSDestDistanceRef", (char *) "Reference for distance to destination"}, + { 0x001A, (char *) "GPSDestDistance", (char *) "Distance to destination"}, + { 0x001B, (char *) "GPSProcessingMethod", (char *) "Name of GPS processing method"}, + { 0x001C, (char *) "GPSAreaInformation", (char *) "Name of GPS area"}, + { 0x001D, (char *) "GPSDateStamp", (char *) "GPS date"}, + { 0x001E, (char *) "GPSDifferential", (char *) "GPS differential correction"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// EXIF interoperability tags definition +// -------------------------------------------------------------------------- + +static TagInfo + exif_interop_tag_table[] = + { + { 0x0001, (char *) "InteroperabilityIndex", (char *) "Interoperability Identification"}, + { 0x0002, (char *) "InteroperabilityVersion", (char *) "Interoperability version"}, + { 0x1000, (char *) "RelatedImageFileFormat", (char *) "File format of image file"}, + { 0x1001, (char *) "RelatedImageWidth", (char *) "Image width"}, + { 0x1002, (char *) "RelatedImageLength", (char *) "Image height"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// EXIF maker note tags definition +// -------------------------------------------------------------------------- + +/** +Canon maker note +*/ +static TagInfo + exif_canon_tag_table[] = + { + { 0x0001, (char *) "CanonCameraSettings", (char *) "Canon CameraSettings Tags"}, + { 0x0002, (char *) "CanonFocalLength", (char *) "Canon FocalLength Tags"}, + { 0x0003, (char *) "CanonFlashInfo?", (char *) NULL}, + { 0x0004, (char *) "CanonShotInfo", (char *) "Canon ShotInfo Tags"}, + { 0x0005, (char *) "CanonPanorama", (char *) "Canon Panorama Tags"}, + { 0x0006, (char *) "CanonImageType", (char *) NULL}, + { 0x0007, (char *) "CanonFirmwareVersion", (char *) NULL}, + { 0x0008, (char *) "FileNumber", (char *) NULL}, + { 0x0009, (char *) "OwnerName", (char *) NULL}, + { 0x000A, (char *) "UnknownD30", (char *) "Canon UnknownD30 Tags"}, + { 0x000C, (char *) "SerialNumber", (char *) NULL}, + { 0x000D, (char *) "CanonCameraInfo", (char *) "Canon CameraInfo Tags"}, + { 0x000E, (char *) "CanonFileLength", (char *) NULL}, + { 0x000F, (char *) "CanonCustomFunctions", (char *) "Custom Functions"}, + { 0x0010, (char *) "CanonModelID", (char *) NULL}, + { 0x0012, (char *) "CanonAFInfo", (char *) "Canon AFInfo Tags"}, + { 0x0013, (char *) "ThumbnailImageValidArea", (char *) NULL}, + { 0x0015, (char *) "SerialNumberFormat", (char *) NULL}, + { 0x001A, (char *) "SuperMacro", (char *) NULL}, + { 0x001C, (char *) "DateStampMode", (char *) NULL}, + { 0x001D, (char *) "MyColors", (char *) NULL}, + { 0x001E, (char *) "FirmwareRevision", (char *) NULL}, + { 0x0023, (char *) "Categories", (char *) NULL}, + { 0x0024, (char *) "FaceDetect1", (char *) NULL}, + { 0x0025, (char *) "FaceDetect2", (char *) NULL}, + { 0x0026, (char *) "CanonAFInfo2", (char *) "Canon AFInfo2 Tags"}, + { 0x0028, (char *) "ImageUniqueID", (char *) NULL}, + { 0x0081, (char *) "RawDataOffset", (char *) NULL}, + { 0x0083, (char *) "OriginalDecisionDataOffset", (char *) NULL}, + { 0x0090, (char *) "CustomFunctions1D", (char *) "CanonCustom Functions1D Tags"}, + { 0x0091, (char *) "PersonalFunctions", (char *) "CanonCustom PersonalFuncs Tags"}, + { 0x0092, (char *) "PersonalFunctionValues", (char *) "CanonCustom PersonalFuncValues Tags"}, + { 0x0093, (char *) "CanonFileInfo", (char *) "Canon FileInfo Tags"}, + { 0x0094, (char *) "AFPointsInFocus1D", (char *) NULL}, + { 0x0095, (char *) "LensModel", (char *) NULL}, + { 0x0096, (char *) "SerialInfo", (char *) NULL}, + { 0x0097, (char *) "DustRemovalData", (char *) NULL}, + { 0x0098, (char *) "CropInfo", (char *) NULL}, + { 0x0099, (char *) "CustomFunctions2", (char *) NULL}, + { 0x009A, (char *) "AspectInfo", (char *) NULL}, + { 0x00A0, (char *) "ProcessingInfo", (char *) NULL}, + { 0x00A1, (char *) "ToneCurveTable", (char *) NULL}, + { 0x00A2, (char *) "SharpnessTable", (char *) NULL}, + { 0x00A3, (char *) "SharpnessFreqTable", (char *) NULL}, + { 0x00A4, (char *) "WhiteBalanceTable", (char *) NULL}, + { 0x00A9, (char *) "ColorBalance", (char *) NULL}, + { 0x00AA, (char *) "MeasuredColor", (char *) NULL}, + { 0x00AE, (char *) "ColorTemperature", (char *) NULL}, + { 0x00B0, (char *) "CanonFlags", (char *) NULL}, + { 0x00B1, (char *) "ModifiedInfo", (char *) NULL}, + { 0x00B2, (char *) "ToneCurveMatching", (char *) NULL}, + { 0x00B3, (char *) "WhiteBalanceMatching", (char *) NULL}, + { 0x00B4, (char *) "ColorSpace", (char *) NULL}, + { 0x00B6, (char *) "PreviewImageInfo", (char *) NULL}, + { 0x00D0, (char *) "VRDOffset", (char *) "Offset of VRD 'recipe data' if it exists"}, + { 0x00E0, (char *) "SensorInfo", (char *) NULL}, + { 0x4001, (char *) "ColorData", (char *) "Canon ColorData Tags"}, + { 0x4002, (char *) "CRWParam?", (char *) NULL}, + { 0x4003, (char *) "ColorInfo", (char *) NULL}, + { 0x4005, (char *) "Flavor?", (char *) NULL}, + { 0x4008, (char *) "BlackLevel?", (char *) NULL}, + { 0x4010, (char *) "CustomPictureStyleFileName", (char *) NULL}, + { 0x4013, (char *) "AFMicroAdj", (char *) NULL}, + { 0x4015, (char *) "VignettingCorr", (char *) NULL}, + { 0x4016, (char *) "VignettingCorr2", (char *) NULL}, + { 0x4018, (char *) "LightingOpt", (char *) NULL}, + { 0x4019, (char *) "LensInfo", (char *) NULL}, + { 0x4020, (char *) "AmbienceInfo", (char *) NULL}, + { 0x4024, (char *) "FilterInfo", (char *) NULL}, + + // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment + + // Fields under tag 0x0001 (we add 0xC100 to make unique tag id) + { 0xC100 + 1, (char *) "CameraSettings:MacroMode", (char *) NULL}, + { 0xC100 + 2, (char *) "CameraSettings:SelfTimer", (char *) NULL}, + { 0xC100 + 3, (char *) "CameraSettings:Quality", (char *) NULL}, + { 0xC100 + 4, (char *) "CameraSettings:CanonFlashMode", (char *) NULL}, + { 0xC100 + 5, (char *) "CameraSettings:ContinuousDrive", (char *) NULL}, + { 0xC100 + 6, (char *) "CameraSettings:0x0006", (char *) NULL}, + { 0xC100 + 7, (char *) "CameraSettings:FocusMode", (char *) NULL}, + { 0xC100 + 8, (char *) "CameraSettings:0x0008", (char *) NULL}, + { 0xC100 + 9, (char *) "CameraSettings:RecordMode", (char *) NULL}, + { 0xC100 + 10, (char *) "CameraSettings:CanonImageSize", (char *) NULL}, + { 0xC100 + 11, (char *) "CameraSettings:EasyMode", (char *) NULL}, + { 0xC100 + 12, (char *) "CameraSettings:DigitalZoom", (char *) NULL}, + { 0xC100 + 13, (char *) "CameraSettings:Contrast", (char *) NULL}, + { 0xC100 + 14, (char *) "CameraSettings:Saturation", (char *) NULL}, + { 0xC100 + 15, (char *) "CameraSettings:Sharpness", (char *) NULL}, + { 0xC100 + 16, (char *) "CameraSettings:CameraISO", (char *) NULL}, + { 0xC100 + 17, (char *) "CameraSettings:MeteringMode", (char *) NULL}, + { 0xC100 + 18, (char *) "CameraSettings:FocusRange", (char *) NULL}, + { 0xC100 + 19, (char *) "CameraSettings:AFPoint", (char *) NULL}, + { 0xC100 + 20, (char *) "CameraSettings:CanonExposureMode", (char *) NULL}, + { 0xC100 + 21, (char *) "CameraSettings:0x0015", (char *) NULL}, + { 0xC100 + 22, (char *) "CameraSettings:LensType", (char *) NULL}, + { 0xC100 + 23, (char *) "CameraSettings:LongFocal", (char *) NULL}, + { 0xC100 + 24, (char *) "CameraSettings:ShortFocal", (char *) NULL}, + { 0xC100 + 25, (char *) "CameraSettings:FocalUnits", (char *) "Focal Units per mm"}, + { 0xC100 + 26, (char *) "CameraSettings:MaxAperture", (char *) NULL}, + { 0xC100 + 27, (char *) "CameraSettings:MinAperture", (char *) NULL}, + { 0xC100 + 28, (char *) "CameraSettings:FlashActivity", (char *) NULL}, + { 0xC100 + 29, (char *) "CameraSettings:FlashBits", (char *) NULL}, + { 0xC100 + 30, (char *) "CameraSettings:0x001E", (char *) NULL}, + { 0xC100 + 31, (char *) "CameraSettings:0x001F", (char *) NULL}, + { 0xC100 + 32, (char *) "CameraSettings:FocusContinuous", (char *) NULL}, + { 0xC100 + 33, (char *) "CameraSettings:AESetting", (char *) NULL}, + { 0xC100 + 34, (char *) "CameraSettings:ImageStabilization", (char *) NULL}, + { 0xC100 + 35, (char *) "CameraSettings:DisplayAperture", (char *) NULL}, + { 0xC100 + 36, (char *) "CameraSettings:ZoomSourceWidth", (char *) NULL}, + { 0xC100 + 37, (char *) "CameraSettings:ZoomTargetWidth", (char *) NULL}, + { 0xC100 + 38, (char *) "CameraSettings:0x0026", (char *) NULL}, + { 0xC100 + 39, (char *) "CameraSettings:SpotMeteringMode", (char *) NULL}, + { 0xC100 + 40, (char *) "CameraSettings:PhotoEffect", (char *) NULL}, + { 0xC100 + 41, (char *) "CameraSettings:ManualFlashOutput", (char *) NULL}, + { 0xC100 + 42, (char *) "CameraSettings:ColorTone", (char *) NULL}, + { 0xC100 + 43, (char *) "CameraSettings:0x002B", (char *) NULL}, + { 0xC100 + 44, (char *) "CameraSettings:0x002C", (char *) NULL}, + { 0xC100 + 45, (char *) "CameraSettings:0x002D", (char *) NULL}, + { 0xC100 + 46, (char *) "CameraSettings:SRAWQuality", (char *) NULL}, + { 0xC100 + 47, (char *) "CameraSettings:0x002F", (char *) NULL}, + { 0xC100 + 48, (char *) "CameraSettings:0x0030", (char *) NULL}, + + // Fields under tag 0x0002 (we add 0xC200 to make unique tag id) + { 0xC200 + 0, (char *) "FocalLength:FocalType", (char *) NULL}, + { 0xC200 + 1, (char *) "FocalLength:FocalLength", (char *) NULL}, + { 0xC200 + 2, (char *) "FocalLength:FocalPlaneXSize", (char *) NULL}, + { 0xC200 + 3, (char *) "FocalLength:FocalPlaneYSize", (char *) NULL}, + + // Fields under tag 0x0004 (we add 0xC400 to make unique tag id) + { 0xC400 + 1, (char *) "ShotInfo:AutoISO", (char *) NULL}, + { 0xC400 + 2, (char *) "ShotInfo:BaseISO", (char *) NULL}, + { 0xC400 + 3, (char *) "ShotInfo:MeasuredEV", (char *) NULL}, + { 0xC400 + 4, (char *) "ShotInfo:TargetAperture", (char *) NULL}, + { 0xC400 + 5, (char *) "ShotInfo:TargetExposureTime", (char *) NULL}, + { 0xC400 + 6, (char *) "ShotInfo:ExposureCompensation", (char *) NULL}, + { 0xC400 + 7, (char *) "ShotInfo:WhiteBalance", (char *) NULL}, + { 0xC400 + 8, (char *) "ShotInfo:SlowShutter", (char *) NULL}, + { 0xC400 + 9, (char *) "ShotInfo:SequenceNumber", (char *) NULL}, + { 0xC400 + 10, (char *) "ShotInfo:OpticalZoomCode", (char *) NULL}, + { 0xC400 + 11, (char *) "ShotInfo:0x000B", (char *) NULL}, + { 0xC400 + 12, (char *) "ShotInfo:CameraTemperature", (char *) NULL}, + { 0xC400 + 13, (char *) "ShotInfo:FlashGuideNumber", (char *) NULL}, + { 0xC400 + 14, (char *) "ShotInfo:AFPointsInFocus", (char *) NULL}, + { 0xC400 + 15, (char *) "ShotInfo:FlashExposureComp", (char *) NULL}, + { 0xC400 + 16, (char *) "ShotInfo:AutoExposureBracketing", (char *) NULL}, + { 0xC400 + 17, (char *) "ShotInfo:AEBBracketValue", (char *) NULL}, + { 0xC400 + 18, (char *) "ShotInfo:ControlMode", (char *) NULL}, + { 0xC400 + 19, (char *) "ShotInfo:FocusDistanceUpper", (char *) NULL}, + { 0xC400 + 20, (char *) "ShotInfo:FocusDistanceLower", (char *) NULL}, + { 0xC400 + 21, (char *) "ShotInfo:FNumber", (char *) NULL}, + { 0xC400 + 22, (char *) "ShotInfo:ExposureTime", (char *) NULL}, + { 0xC400 + 23, (char *) "ShotInfo:MeasuredEV2", (char *) NULL}, + { 0xC400 + 24, (char *) "ShotInfo:BulbDuration", (char *) NULL}, + { 0xC400 + 25, (char *) "ShotInfo:0x0019", (char *) NULL}, + { 0xC400 + 26, (char *) "ShotInfo:CameraType", (char *) NULL}, + { 0xC400 + 27, (char *) "ShotInfo:AutoRotate", (char *) NULL}, + { 0xC400 + 28, (char *) "ShotInfo:NDFilter", (char *) NULL}, + { 0xC400 + 29, (char *) "ShotInfo:SelfTimer2", (char *) NULL}, + { 0xC400 + 30, (char *) "ShotInfo:0x001E", (char *) NULL}, + { 0xC400 + 31, (char *) "ShotInfo:0x001F", (char *) NULL}, + { 0xC400 + 32, (char *) "ShotInfo:0x0020", (char *) NULL}, + { 0xC400 + 33, (char *) "ShotInfo:FlashOutput", (char *) NULL}, + + // Fields under tag 0x0012 (we add 0x1200 to make unique tag id) + { 0x1200 + 0, (char *) "AFInfo:NumAFPoints", (char *) NULL}, + { 0x1200 + 1, (char *) "AFInfo:ValidAFPoints", (char *) NULL}, + { 0x1200 + 2, (char *) "AFInfo:CanonImageWidth", (char *) NULL}, + { 0x1200 + 3, (char *) "AFInfo:CanonImageHeight", (char *) NULL}, + { 0x1200 + 4, (char *) "AFInfo:AFImageWidth", (char *) NULL}, + { 0x1200 + 5, (char *) "AFInfo:AFImageHeight", (char *) NULL}, + { 0x1200 + 6, (char *) "AFInfo:AFAreaWidth", (char *) NULL}, + { 0x1200 + 7, (char *) "AFInfo:AFAreaHeight", (char *) NULL}, + { 0x1200 + 8, (char *) "AFInfo:AFAreaXPositions", (char *) NULL}, + { 0x1200 + 9, (char *) "AFInfo:AFAreaYPositions", (char *) NULL}, + { 0x1200 + 10, (char *) "AFInfo:AFPointsInFocus", (char *) NULL}, + { 0x1200 + 11, (char *) "AFInfo:PrimaryAFPoint?", (char *) NULL}, + { 0x1200 + 12, (char *) "AFInfo:PrimaryAFPoint", (char *) NULL}, + { 0x1200 + 13, (char *) "AFInfo:0x000D", (char *) NULL}, + { 0x1200 + 14, (char *) "AFInfo:0x000E", (char *) NULL}, + { 0x1200 + 15, (char *) "AFInfo:0x000F", (char *) NULL}, + { 0x1200 + 16, (char *) "AFInfo:0x0010", (char *) NULL}, + { 0x1200 + 17, (char *) "AFInfo:0x0011", (char *) NULL}, + { 0x1200 + 18, (char *) "AFInfo:0x0012", (char *) NULL}, + { 0x1200 + 19, (char *) "AFInfo:0x0013", (char *) NULL}, + { 0x1200 + 20, (char *) "AFInfo:0x0014", (char *) NULL}, + { 0x1200 + 21, (char *) "AFInfo:0x0015", (char *) NULL}, + { 0x1200 + 22, (char *) "AFInfo:0x0016", (char *) NULL}, + { 0x1200 + 23, (char *) "AFInfo:0x0017", (char *) NULL}, + { 0x1200 + 24, (char *) "AFInfo:0x0018", (char *) NULL}, + { 0x1200 + 25, (char *) "AFInfo:0x0019", (char *) NULL}, + { 0x1200 + 26, (char *) "AFInfo:0x001A", (char *) NULL}, + { 0x1200 + 27, (char *) "AFInfo:0x001B", (char *) NULL}, + + // Fields under tag 0x00A0 (we add 0xCA00 to make unique tag id) + { 0xCA00 + 1, (char *) "ProcessingInfo:ToneCurve", (char *) NULL}, + { 0xCA00 + 2, (char *) "ProcessingInfo:Sharpness", (char *) NULL}, + { 0xCA00 + 3, (char *) "ProcessingInfo:SharpnessFrequency", (char *) NULL}, + { 0xCA00 + 4, (char *) "ProcessingInfo:SensorRedLevel", (char *) NULL}, + { 0xCA00 + 5, (char *) "ProcessingInfo:SensorBlueLevel", (char *) NULL}, + { 0xCA00 + 6, (char *) "ProcessingInfo:WhiteBalanceRed", (char *) NULL}, + { 0xCA00 + 7, (char *) "ProcessingInfo:WhiteBalanceBlue", (char *) NULL}, + { 0xCA00 + 8, (char *) "ProcessingInfo:WhiteBalance", (char *) NULL}, + { 0xCA00 + 9, (char *) "ProcessingInfo:ColorTemperature", (char *) NULL}, + { 0xCA00 + 10, (char *) "ProcessingInfo:PictureStyle", (char *) NULL}, + { 0xCA00 + 11, (char *) "ProcessingInfo:DigitalGain", (char *) NULL}, + { 0xCA00 + 12, (char *) "ProcessingInfo:WBShiftAB", (char *) NULL}, + { 0xCA00 + 13, (char *) "ProcessingInfo:WBShiftGM", (char *) NULL}, + + // Fields under tag 0x00E0 (we add 0xCE00 to make unique tag id) + { 0xCE00 + 1, (char *) "SensorInfo:SensorWidth", (char *) NULL}, + { 0xCE00 + 2, (char *) "SensorInfo:SensorHeight", (char *) NULL}, + { 0xCE00 + 3, (char *) "SensorInfo:0x0003", (char *) NULL}, + { 0xCE00 + 4, (char *) "SensorInfo:0x0004", (char *) NULL}, + { 0xCE00 + 5, (char *) "SensorInfo:SensorLeftBorder", (char *) NULL}, + { 0xCE00 + 6, (char *) "SensorInfo:SensorTopBorder", (char *) NULL}, + { 0xCE00 + 7, (char *) "SensorInfo:SensorRightBorder", (char *) NULL}, + { 0xCE00 + 8, (char *) "SensorInfo:SensorBottomBorder", (char *) NULL}, + { 0xCE00 + 9, (char *) "SensorInfo:BlackMaskLeftBorder", (char *) NULL}, + { 0xCE00 + 10, (char *) "SensorInfo:BlackMaskTopBorder", (char *) NULL}, + { 0xCE00 + 11, (char *) "SensorInfo:BlackMaskRightBorder", (char *) NULL}, + { 0xCE00 + 12, (char *) "SensorInfo:BlackMaskBottomBorder", (char *) NULL}, + { 0xCE00 + 13, (char *) "SensorInfo:0x000D", (char *) NULL}, + { 0xCE00 + 14, (char *) "SensorInfo:0x000E", (char *) NULL}, + { 0xCE00 + 15, (char *) "SensorInfo:0x000F", (char *) NULL}, + { 0xCE00 + 16, (char *) "SensorInfo:0x0010", (char *) NULL}, + + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Casio type 1 maker note +*/ +static TagInfo + exif_casio_type1_tag_table[] = + { + { 0x0001, (char *) "RecordingMode", (char *) NULL}, + { 0x0002, (char *) "Quality", (char *) NULL}, + { 0x0003, (char *) "FocusMode", (char *) NULL}, + { 0x0004, (char *) "FlashMode", (char *) NULL}, + { 0x0005, (char *) "FlashIntensity", (char *) NULL}, + { 0x0006, (char *) "ObjectDistance", (char *) NULL}, + { 0x0007, (char *) "WhiteBalance", (char *) NULL}, + { 0x000A, (char *) "DigitalZoom", (char *) NULL}, + { 0x000B, (char *) "Sharpness", (char *) NULL}, + { 0x000C, (char *) "Contrast", (char *) NULL}, + { 0x000D, (char *) "Saturation", (char *) NULL}, + { 0x0014, (char *) "ISO", (char *) NULL}, + { 0x0015, (char *) "FirmwareDate", (char *) NULL}, + { 0x0016, (char *) "Enhancement", (char *) NULL}, + { 0x0017, (char *) "ColorFilter", (char *) NULL}, + { 0x0018, (char *) "AFPoint", (char *) NULL}, + { 0x0019, (char *) "FlashIntensity", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Casio type 2 maker note +*/ +static TagInfo + exif_casio_type2_tag_table[] = + { + { 0x0002, (char *) "PreviewImageSize", (char *) NULL}, + { 0x0003, (char *) "PreviewImageLength", (char *) NULL}, + { 0x0004, (char *) "PreviewImageStart", (char *) NULL}, + { 0x0008, (char *) "QualityMode", (char *) NULL}, + { 0x0009, (char *) "CasioImageSize", (char *) NULL}, + { 0x000D, (char *) "FocusMode", (char *) NULL}, + { 0x0014, (char *) "ISO", (char *) NULL}, + { 0x0019, (char *) "WhiteBalance", (char *) NULL}, + { 0x001D, (char *) "FocalLength", (char *) NULL}, + { 0x001F, (char *) "Saturation", (char *) NULL}, + { 0x0020, (char *) "Contrast", (char *) NULL}, + { 0x0021, (char *) "Sharpness", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x2000, (char *) "PreviewImage", (char *) NULL}, + { 0x2001, (char *) "FirmwareDate", (char *) NULL}, + { 0x2011, (char *) "WhiteBalanceBias", (char *) NULL}, + { 0x2012, (char *) "WhiteBalance", (char *) NULL}, + { 0x2021, (char *) "AFPointPosition", (char *) NULL}, + { 0x2022, (char *) "ObjectDistance", (char *) NULL}, + { 0x2034, (char *) "FlashDistance", (char *) NULL}, + { 0x2076, (char *) "SpecialEffectMode", (char *) NULL}, + { 0x3000, (char *) "RecordMode", (char *) NULL}, + { 0x3001, (char *) "ReleaseMode", (char *) NULL}, + { 0x3002, (char *) "Quality", (char *) NULL}, + { 0x3003, (char *) "FocusMode", (char *) NULL}, + { 0x3006, (char *) "HometownCity", (char *) NULL}, + { 0x3007, (char *) "BestShotMode", (char *) NULL}, + { 0x3008, (char *) "AutoISO", (char *) NULL}, + { 0x3009, (char *) "AFMode", (char *) NULL}, + { 0x3011, (char *) "Sharpness", (char *) NULL}, + { 0x3012, (char *) "Contrast", (char *) NULL}, + { 0x3013, (char *) "Saturation", (char *) NULL}, + { 0x3014, (char *) "ISO", (char *) NULL}, + { 0x3015, (char *) "ColorMode", (char *) NULL}, + { 0x3016, (char *) "Enhancement", (char *) NULL}, + { 0x3017, (char *) "ColorFilter", (char *) NULL}, + { 0x301C, (char *) "SequenceNumber", (char *) NULL}, + { 0x301D, (char *) "BracketSequence", (char *) NULL}, + { 0x3020, (char *) "ImageStabilization", (char *) NULL}, + { 0x302A, (char *) "LightingMode", (char *) NULL}, + { 0x302B, (char *) "PortraitRefiner", (char *) NULL}, + { 0x3030, (char *) "SpecialEffectLevel", (char *) NULL}, + { 0x3031, (char *) "SpecialEffectSetting", (char *) NULL}, + { 0x3103, (char *) "DriveMode", (char *) NULL}, + { 0x4001, (char *) "CaptureFrameRate", (char *) NULL}, + { 0x4003, (char *) "VideoQuality", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +FujiFilm maker note +*/ +static TagInfo + exif_fujifilm_tag_table[] = + { + { 0x0000, (char *) "Version", (char *) NULL}, + { 0x0010, (char *) "InternalSerialNumber", (char *) NULL}, + { 0x1000, (char *) "Quality", (char *) NULL}, + { 0x1001, (char *) "Sharpness", (char *) NULL}, + { 0x1002, (char *) "WhiteBalance", (char *) NULL}, + { 0x1003, (char *) "Saturation", (char *) NULL}, + { 0x1004, (char *) "Contrast", (char *) NULL}, + { 0x1005, (char *) "ColorTemperature", (char *) NULL}, + { 0x100A, (char *) "WhiteBalanceFineTune", (char *) NULL}, + { 0x100B, (char *) "NoiseReduction", (char *) NULL}, + { 0x1010, (char *) "FujiFlashMode", (char *) NULL}, + { 0x1011, (char *) "FlashExposureComp", (char *) NULL}, + { 0x1020, (char *) "Macro", (char *) NULL}, + { 0x1021, (char *) "FocusMode", (char *) NULL}, + { 0x1023, (char *) "FocusPixel", (char *) NULL}, + { 0x1030, (char *) "SlowSync", (char *) NULL}, + { 0x1031, (char *) "PictureMode", (char *) NULL}, + { 0x1033, (char *) "EXRAuto", (char *) NULL}, + { 0x1034, (char *) "EXRMode", (char *) NULL}, + { 0x1100, (char *) "AutoBracketting", (char *) NULL}, + { 0x1101, (char *) "SequenceNumber", (char *) NULL}, + { 0x1210, (char *) "ColorMode", (char *) NULL}, + { 0x1300, (char *) "BlurWarning", (char *) NULL}, + { 0x1301, (char *) "FocusWarning", (char *) NULL}, + { 0x1302, (char *) "ExposureWarning", (char *) NULL}, + { 0x1400, (char *) "DynamicRange", (char *) NULL}, + { 0x1401, (char *) "FilmMode", (char *) NULL}, + { 0x1402, (char *) "DynamicRangeSetting", (char *) NULL}, + { 0x1403, (char *) "DevelopmentDynamicRange", (char *) NULL}, + { 0x1404, (char *) "MinFocalLength", (char *) NULL}, + { 0x1405, (char *) "MaxFocalLength", (char *) NULL}, + { 0x1406, (char *) "MaxApertureAtMinFocal", (char *) NULL}, + { 0x1407, (char *) "MaxApertureAtMaxFocal", (char *) NULL}, + { 0x4100, (char *) "FacesDetected", (char *) NULL}, + { 0x4103, (char *) "FacePositions", (char *) NULL}, + { 0x8000, (char *) "FileSource", (char *) NULL}, + { 0x8002, (char *) "OrderNumber", (char *) NULL}, + { 0x8003, (char *) "FrameNumber", (char *) NULL}, + { 0xB211, (char *) "Parallax", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Kyocera maker note +*/ +static TagInfo + exif_kyocera_tag_table[] = + { + { 0x0001, (char *) "ThumbnailImage", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) "Print Image Matching Info"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Olympus Type 1 / Epson / Agfa maker note +*/ +static TagInfo + exif_olympus_type1_tag_table[] = + { + { 0x0000, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x0001, (char *) "MinoltaCameraSettingsOld", (char *) NULL}, + { 0x0003, (char *) "MinoltaCameraSettings", (char *) NULL}, + { 0x0040, (char *) "CompressedImageSize", (char *) NULL}, + { 0x0081, (char *) "PreviewImageData", (char *) NULL}, + { 0x0088, (char *) "PreviewImageStart", (char *) NULL}, + { 0x0089, (char *) "PreviewImageLength", (char *) NULL}, + { 0x0100, (char *) "ThumbnailImage", (char *) NULL}, + { 0x0104, (char *) "BodyFirmwareVersion", (char *) NULL}, + { 0x0200, (char *) "SpecialMode", (char *) NULL}, + { 0x0201, (char *) "Quality", (char *) NULL}, + { 0x0202, (char *) "Macro", (char *) NULL}, + { 0x0203, (char *) "BWMode", (char *) NULL}, + { 0x0204, (char *) "DigitalZoom", (char *) NULL}, + { 0x0205, (char *) "FocalPlaneDiagonal", (char *) NULL}, + { 0x0206, (char *) "LensDistortionParams", (char *) NULL}, + { 0x0207, (char *) "CameraType", (char *) NULL}, + { 0x0208, (char *) "TextInfo", (char *) "Olympus TextInfo Tags"}, + { 0x0209, (char *) "CameraID", (char *) NULL}, + { 0x020B, (char *) "EpsonImageWidth", (char *) NULL}, + { 0x020C, (char *) "EpsonImageHeight", (char *) NULL}, + { 0x020D, (char *) "EpsonSoftware", (char *) NULL}, + { 0x0280, (char *) "PreviewImage", (char *) NULL}, + { 0x0300, (char *) "PreCaptureFrames", (char *) NULL}, + { 0x0301, (char *) "WhiteBoard", (char *) NULL}, + { 0x0302, (char *) "OneTouchWB", (char *) NULL}, + { 0x0303, (char *) "WhiteBalanceBracket", (char *) NULL}, + { 0x0304, (char *) "WhiteBalanceBias", (char *) NULL}, + { 0x0403, (char *) "SceneMode", (char *) NULL}, + { 0x0404, (char *) "SerialNumber", (char *) NULL}, + { 0x0405, (char *) "Firmware", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) "PrintIM Tags"}, + { 0x0F00, (char *) "DataDump", (char *) NULL}, + { 0x0F01, (char *) "DataDump2", (char *) NULL}, + { 0x1000, (char *) "ShutterSpeedValue", (char *) NULL}, + { 0x1001, (char *) "ISOValue", (char *) NULL}, + { 0x1002, (char *) "ApertureValue", (char *) NULL}, + { 0x1003, (char *) "BrightnessValue", (char *) NULL}, + { 0x1004, (char *) "FlashMode", (char *) NULL}, + { 0x1005, (char *) "FlashDevice", (char *) NULL}, + { 0x1006, (char *) "ExposureCompensation", (char *) NULL}, + { 0x1007, (char *) "SensorTemperature", (char *) NULL}, + { 0x1008, (char *) "LensTemperature", (char *) NULL}, + { 0x1009, (char *) "LightCondition", (char *) NULL}, + { 0x100A, (char *) "FocusRange", (char *) NULL}, + { 0x100B, (char *) "FocusMode", (char *) NULL}, + { 0x100C, (char *) "ManualFocusDistance", (char *) NULL}, + { 0x100D, (char *) "ZoomStepCount", (char *) NULL}, + { 0x100E, (char *) "FocusStepCount", (char *) NULL}, + { 0x100F, (char *) "Sharpness", (char *) NULL}, + { 0x1010, (char *) "FlashChargeLevel", (char *) NULL}, + { 0x1011, (char *) "ColorMatrix", (char *) NULL}, + { 0x1012, (char *) "BlackLevel", (char *) NULL}, + { 0x1015, (char *) "WBMode", (char *) NULL}, + { 0x1017, (char *) "RedBalance", (char *) NULL}, + { 0x1018, (char *) "BlueBalance", (char *) NULL}, + { 0x1019, (char *) "ColorMatrixNumber", (char *) NULL}, + { 0x101A, (char *) "SerialNumber", (char *) NULL}, + { 0x1023, (char *) "FlashExposureComp", (char *) NULL}, + { 0x1024, (char *) "InternalFlashTable", (char *) NULL}, + { 0x1025, (char *) "ExternalFlashGValue", (char *) NULL}, + { 0x1026, (char *) "ExternalFlashBounce", (char *) NULL}, + { 0x1027, (char *) "ExternalFlashZoom", (char *) NULL}, + { 0x1028, (char *) "ExternalFlashMode", (char *) NULL}, + { 0x1029, (char *) "Contrast", (char *) NULL}, + { 0x102A, (char *) "SharpnessFactor", (char *) NULL}, + { 0x102B, (char *) "ColorControl", (char *) NULL}, + { 0x102C, (char *) "ValidBits", (char *) NULL}, + { 0x102D, (char *) "CoringFilter", (char *) NULL}, + { 0x102E, (char *) "OlympusImageWidth", (char *) NULL}, + { 0x102F, (char *) "OlympusImageHeight", (char *) NULL}, + { 0x1030, (char *) "SceneDetect", (char *) NULL}, + { 0x1031, (char *) "SceneArea?", (char *) NULL}, + { 0x1033, (char *) "SceneDetectData?", (char *) NULL}, + { 0x1034, (char *) "CompressionRatio", (char *) NULL}, + { 0x1035, (char *) "PreviewImageValid", (char *) NULL}, + { 0x1036, (char *) "PreviewImageStart", (char *) NULL}, + { 0x1037, (char *) "PreviewImageLength", (char *) NULL}, + { 0x1038, (char *) "AFResult", (char *) NULL}, + { 0x1039, (char *) "CCDScanMode", (char *) NULL}, + { 0x103A, (char *) "NoiseReduction", (char *) NULL}, + { 0x103B, (char *) "InfinityLensStep", (char *) NULL}, + { 0x103C, (char *) "NearLensStep", (char *) NULL}, + { 0x103D, (char *) "LightValueCenter", (char *) NULL}, + { 0x103E, (char *) "LightValuePeriphery", (char *) NULL}, + { 0x2010, (char *) "Equipment", (char *) "Olympus Equipment Tags"}, + { 0x2020, (char *) "CameraSettings", (char *) "Olympus CameraSettings Tags"}, + { 0x2030, (char *) "RawDevelopment", (char *) "Olympus RawDevelopment Tags"}, + { 0x2040, (char *) "ImageProcessing", (char *) "Olympus ImageProcessing Tags"}, + { 0x2050, (char *) "FocusInfo", (char *) "Olympus FocusInfo Tags"}, + { 0x2100, (char *) "Olympus2100", (char *) "Olympus FE Tags"}, + { 0x2200, (char *) "Olympus2200", (char *) "Olympus FE Tags"}, + { 0x2300, (char *) "Olympus2300", (char *) "Olympus FE Tags"}, + { 0x2400, (char *) "Olympus2400", (char *) "Olympus FE Tags"}, + { 0x2500, (char *) "Olympus2500", (char *) "Olympus FE Tags"}, + { 0x2600, (char *) "Olympus2600", (char *) "Olympus FE Tags"}, + { 0x2700, (char *) "Olympus2700", (char *) "Olympus FE Tags"}, + { 0x2800, (char *) "Olympus2800", (char *) "Olympus FE Tags"}, + { 0x2900, (char *) "Olympus2900", (char *) "Olympus FE Tags"}, + { 0x3000, (char *) "RawInfo", (char *) "Olympus RawInfo Tags"}, + { 0x4000, (char *) "MainInfo", (char *) "Olympus MainInfo Tags"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Minolta maker note +*/ +static TagInfo + exif_minolta_tag_table[] = + { + { 0x0000, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x0001, (char *) "MinoltaCameraSettingsOld", (char *) NULL}, + { 0x0003, (char *) "MinoltaCameraSettings", (char *) NULL}, + { 0x0004, (char *) "MinoltaCameraSettings7D", (char *) NULL}, + { 0x0018, (char *) "ImageStabilization", (char *) NULL}, + { 0x0040, (char *) "CompressedImageSize", (char *) NULL}, + { 0x0081, (char *) "PreviewImage", (char *) NULL}, + { 0x0088, (char *) "PreviewImageStart", (char *) NULL}, + { 0x0089, (char *) "PreviewImageLength", (char *) NULL}, + { 0x0100, (char *) "SceneMode", (char *) NULL}, + { 0x0101, (char *) "ColorMode", (char *) NULL}, + { 0x0102, (char *) "MinoltaQuality", (char *) NULL}, + { 0x0103, (char *) "MinoltaImageSize", (char *) NULL}, + { 0x0104, (char *) "FlashExposureComp", (char *) NULL}, + { 0x0105, (char *) "Teleconverter", (char *) NULL}, + { 0x0107, (char *) "ImageStabilization", (char *) NULL}, + { 0x0109, (char *) "RawAndJpgRecording", (char *) NULL}, + { 0x010A, (char *) "ZoneMatching", (char *) NULL}, + { 0x010B, (char *) "ColorTemperature", (char *) NULL}, + { 0x010C, (char *) "LensType", (char *) NULL}, + { 0x0111, (char *) "ColorCompensationFilter", (char *) NULL}, + { 0x0112, (char *) "WhiteBalanceFineTune", (char *) NULL}, + { 0x0113, (char *) "ImageStabilization", (char *) NULL}, + { 0x0114, (char *) "MinoltaCameraSettings5D", (char *) NULL}, + { 0x0115, (char *) "WhiteBalance", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x0F00, (char *) "MinoltaCameraSettings2", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +There are 3 formats of Nikon's MakerNote. MakerNote of E700/E800/E900/E900S/E910/E950 +starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from +offset 0x08. This is the same as Olympus except start string. +*/ + +/** +TYPE 1 is for E-Series cameras prior to (not including) E990 +*/ +static TagInfo + exif_nikon_type1_tag_table[] = + { + { 0x0002, (char *) "FamilyID", (char *) NULL}, + { 0x0003, (char *) "Quality", (char *) NULL}, + { 0x0004, (char *) "ColorMode", (char *) NULL}, + { 0x0005, (char *) "ImageAdjustment", (char *) NULL}, + { 0x0006, (char *) "CCDSensitivity", (char *) NULL}, + { 0x0007, (char *) "WhiteBalance", (char *) NULL}, + { 0x0008, (char *) "Focus", (char *) NULL}, + { 0x000A, (char *) "DigitalZoom", (char *) NULL}, + { 0x000B, (char *) "FisheyeConverter", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Nikon type 2 maker note +*/ +static TagInfo + exif_nikon_type2_tag_table[] = + { + { 0x0001, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x0002, (char *) "ISO", (char *) NULL}, + { 0x0003, (char *) "ColorMode", (char *) NULL}, + { 0x0004, (char *) "Quality", (char *) NULL}, + { 0x0005, (char *) "WhiteBalance", (char *) NULL}, + { 0x0006, (char *) "Sharpness", (char *) NULL}, + { 0x0007, (char *) "FocusMode", (char *) NULL}, + { 0x0008, (char *) "FlashSetting", (char *) NULL}, + { 0x0009, (char *) "FlashType", (char *) NULL}, + { 0x000B, (char *) "WhiteBalanceFineTune", (char *) NULL}, + { 0x000F, (char *) "ISOSelection", (char *) NULL}, + { 0x0010, (char *) "DataDump", (char *) NULL}, + { 0x0080, (char *) "ImageAdjustment", (char *) NULL}, + { 0x0082, (char *) "AuxiliaryLens", (char *) NULL}, + { 0x0085, (char *) "ManualFocusDistance", (char *) NULL}, + { 0x0086, (char *) "DigitalZoom", (char *) NULL}, + { 0x0088, (char *) "AFInfo", (char *) NULL}, + { 0x0089, (char *) "ShootingMode", (char *) NULL}, + { 0x008D, (char *) "ColorMode", (char *) NULL}, + { 0x008F, (char *) "SceneMode", (char *) NULL}, + { 0x0092, (char *) "HueAdjustment", (char *) NULL}, + { 0x0094, (char *) "Saturation", (char *) NULL}, + { 0x0095, (char *) "NoiseReduction", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +The type-3 directory is for D-Series cameras such as the D1 and D100. +see http://www.timelesswanderings.net/equipment/D100/NEF.html +*/ +static TagInfo + exif_nikon_type3_tag_table[] = + { + { 0x0001, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x0002, (char *) "ISO", (char *) NULL}, + { 0x0003, (char *) "ColorMode", (char *) NULL}, + { 0x0004, (char *) "Quality", (char *) NULL}, + { 0x0005, (char *) "WhiteBalance", (char *) NULL}, + { 0x0006, (char *) "Sharpness", (char *) NULL}, + { 0x0007, (char *) "FocusMode", (char *) NULL}, + { 0x0008, (char *) "FlashSetting", (char *) NULL}, + { 0x0009, (char *) "FlashType", (char *) NULL}, + { 0x000B, (char *) "WhiteBalanceFineTune", (char *) NULL}, + { 0x000C, (char *) "WB_RBLevels", (char *) NULL}, + { 0x000D, (char *) "ProgramShift", (char *) NULL}, + { 0x000E, (char *) "ExposureDifference", (char *) NULL}, + { 0x000F, (char *) "ISOSelection", (char *) NULL}, + { 0x0010, (char *) "DataDump", (char *) NULL}, + { 0x0011, (char *) "PreviewIFD", (char *) NULL}, + { 0x0012, (char *) "FlashExposureComp", (char *) NULL}, + { 0x0013, (char *) "ISOSetting", (char *) NULL}, + { 0x0014, (char *) "ColorBalanceA", (char *) NULL}, + { 0x0016, (char *) "ImageBoundary", (char *) NULL}, + { 0x0017, (char *) "FlashExposureComp", (char *) NULL}, + { 0x0018, (char *) "FlashExposureBracketValue", (char *) NULL}, + { 0x0019, (char *) "ExposureBracketValue", (char *) NULL}, + { 0x001A, (char *) "ImageProcessing", (char *) NULL}, + { 0x001B, (char *) "CropHiSpeed", (char *) NULL}, + { 0x001C, (char *) "ExposureTuning", (char *) NULL}, + { 0x001D, (char *) "SerialNumber", (char *) NULL}, + { 0x001E, (char *) "ColorSpace", (char *) NULL}, + { 0x001F, (char *) "VRInfo", (char *) NULL}, + { 0x0020, (char *) "ImageAuthentication", (char *) NULL}, + { 0x0022, (char *) "ActiveD-Lighting", (char *) NULL}, + { 0x0023, (char *) "PictureControl", (char *) NULL}, + { 0x0024, (char *) "WorldTime", (char *) NULL}, + { 0x0025, (char *) "ISOInfo", (char *) NULL}, + { 0x002A, (char *) "VignetteControl", (char *) NULL}, + { 0x002B, (char *) "DistortInfo", (char *) NULL}, + { 0x0080, (char *) "ImageAdjustment", (char *) NULL}, + { 0x0081, (char *) "ToneComp", (char *) NULL}, + { 0x0082, (char *) "AuxiliaryLens", (char *) NULL}, + { 0x0083, (char *) "LensType", (char *) NULL}, + { 0x0084, (char *) "Lens", (char *) NULL}, + { 0x0085, (char *) "ManualFocusDistance", (char *) NULL}, + { 0x0086, (char *) "DigitalZoom", (char *) NULL}, + { 0x0087, (char *) "FlashMode", (char *) NULL}, + { 0x0088, (char *) "AFInfo", (char *) NULL}, + { 0x0089, (char *) "ShootingMode", (char *) NULL}, + { 0x008B, (char *) "LensFStops", (char *) NULL}, + { 0x008C, (char *) "ContrastCurve", (char *) NULL}, + { 0x008D, (char *) "ColorHue", (char *) NULL}, + { 0x008F, (char *) "SceneMode", (char *) NULL}, + { 0x0090, (char *) "LightSource", (char *) NULL}, + { 0x0091, (char *) "ShotInfo", (char *) NULL}, + { 0x0092, (char *) "HueAdjustment", (char *) NULL}, + { 0x0093, (char *) "NEFCompression", (char *) NULL}, + { 0x0094, (char *) "Saturation", (char *) NULL}, + { 0x0095, (char *) "NoiseReduction", (char *) NULL}, + { 0x0096, (char *) "LinearizationTable", (char *) NULL}, + { 0x0097, (char *) "ColorBalance", (char *) NULL}, + { 0x0098, (char *) "LensData", (char *) NULL}, + { 0x0099, (char *) "RawImageCenter", (char *) NULL}, + { 0x009A, (char *) "SensorPixelSize", (char *) NULL}, + { 0x009C, (char *) "SceneAssist", (char *) NULL}, + { 0x009E, (char *) "RetouchHistory", (char *) NULL}, + { 0x00A0, (char *) "SerialNumber", (char *) NULL}, + { 0x00A2, (char *) "ImageDataSize", (char *) NULL}, + { 0x00A5, (char *) "ImageCount", (char *) NULL}, + { 0x00A6, (char *) "DeletedImageCount", (char *) NULL}, + { 0x00A7, (char *) "ShutterCount", (char *) NULL}, + { 0x00A8, (char *) "FlashInfo", (char *) NULL}, + { 0x00A9, (char *) "ImageOptimization", (char *) NULL}, + { 0x00AA, (char *) "Saturation", (char *) NULL}, + { 0x00AB, (char *) "VariProgram", (char *) NULL}, + { 0x00AC, (char *) "ImageStabilization", (char *) NULL}, + { 0x00AD, (char *) "AFResponse", (char *) NULL}, + { 0x00B0, (char *) "MultiExposure", (char *) NULL}, + { 0x00B1, (char *) "HighISONoiseReduction", (char *) NULL}, + { 0x00B3, (char *) "ToningEffect", (char *) NULL}, + { 0x00B6, (char *) "PowerUpTime", (char *) NULL}, + { 0x00B7, (char *) "AFInfo2", (char *) NULL}, + { 0x00B8, (char *) "FileInfo", (char *) NULL}, + { 0x00B9, (char *) "AFTune", (char *) NULL}, + { 0x00BD, (char *) "PictureControl", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x0E01, (char *) "NikonCaptureData", (char *) NULL}, + { 0x0E09, (char *) "NikonCaptureVersion", (char *) NULL}, + { 0x0E0E, (char *) "NikonCaptureOffsets", (char *) NULL}, + { 0x0E10, (char *) "NikonScanIFD", (char *) NULL}, + { 0x0E1D, (char *) "NikonICCProfile", (char *) NULL}, + { 0x0E1E, (char *) "NikonCaptureOutput", (char *) NULL}, + { 0x0E22, (char *) "NEFBitDepth", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Panasonic / Leica maker note +*/ +static TagInfo + exif_panasonic_tag_table[] = + { + { 0x0001, (char *) "ImageQuality", (char *) NULL}, + { 0x0002, (char *) "FirmwareVersion", (char *) NULL}, + { 0x0003, (char *) "WhiteBalance", (char *) NULL}, + { 0x0007, (char *) "FocusMode", (char *) NULL}, + { 0x000F, (char *) "AFAreaMode", (char *) NULL}, + { 0x001A, (char *) "ImageStabilization", (char *) NULL}, + { 0x001C, (char *) "MacroMode", (char *) NULL}, + { 0x001F, (char *) "ShootingMode", (char *) NULL}, + { 0x0020, (char *) "Audio", (char *) NULL}, + { 0x0021, (char *) "DataDump", (char *) NULL}, + { 0x0022, (char *) "EasyMode", (char *) NULL}, + { 0x0023, (char *) "WhiteBalanceBias", (char *) NULL}, + { 0x0024, (char *) "FlashBias", (char *) NULL}, + { 0x0025, (char *) "InternalSerialNumber", (char *) NULL}, + { 0x0026, (char *) "PanasonicExifVersion", (char *) NULL}, + { 0x0028, (char *) "ColorEffect", (char *) NULL}, + { 0x0029, (char *) "TimeSincePowerOn", (char *) NULL}, + { 0x002A, (char *) "BurstMode", (char *) NULL}, + { 0x002B, (char *) "SequenceNumber", (char *) NULL}, + { 0x002C, (char *) "ContrastMode", (char *) NULL}, + { 0x002D, (char *) "NoiseReduction", (char *) NULL}, + { 0x002E, (char *) "SelfTimer", (char *) NULL}, + { 0x0030, (char *) "Rotation", (char *) NULL}, + { 0x0031, (char *) "AFAssistLamp", (char *) NULL}, + { 0x0032, (char *) "ColorMode", (char *) NULL}, + { 0x0033, (char *) "BabyAge_0x0033", (char *) NULL}, + { 0x0034, (char *) "OpticalZoomMode", (char *) NULL}, + { 0x0035, (char *) "ConversionLens", (char *) NULL}, + { 0x0036, (char *) "TravelDay", (char *) NULL}, + { 0x0039, (char *) "Contrast", (char *) NULL}, + { 0x003A, (char *) "WorldTimeLocation", (char *) NULL}, + { 0x003B, (char *) "TextStamp_0x003B", (char *) NULL}, + { 0x003C, (char *) "ProgramISO", (char *) NULL}, + { 0x003D, (char *) "AdvancedSceneMode", (char *) NULL}, + { 0x003E, (char *) "TextStamp_0x003E", (char *) NULL}, + { 0x003F, (char *) "FacesDetected", (char *) NULL}, + { 0x0040, (char *) "Saturation", (char *) NULL}, + { 0x0041, (char *) "Sharpness", (char *) NULL}, + { 0x0042, (char *) "FilmMode", (char *) NULL}, + { 0x0046, (char *) "WBAdjustAB", (char *) NULL}, + { 0x0047, (char *) "WBAdjustGM", (char *) NULL}, + { 0x004B, (char *) "PanasonicImageWidth", (char *) NULL}, + { 0x004C, (char *) "PanasonicImageHeight", (char *) NULL}, + { 0x004D, (char *) "AFPointPosition", (char *) NULL}, + { 0x004E, (char *) "FaceDetInfo", (char *) "Panasonic FaceDetInfo Tags"}, + { 0x0051, (char *) "LensType", (char *) NULL}, + { 0x0052, (char *) "LensSerialNumber", (char *) NULL}, + { 0x0053, (char *) "AccessoryType", (char *) NULL}, + { 0x0059, (char *) "Transform", (char *) NULL}, + { 0x005D, (char *) "IntelligentExposure", (char *) NULL}, + { 0x0061, (char *) "FaceRecInfo", (char *) "Panasonic FaceRecInfo Tags"}, + { 0x0062, (char *) "FlashWarning", (char *) NULL}, + { 0x0063, (char *) "RecognizedFaceFlags?", (char *) NULL}, + { 0x0065, (char *) "Title", (char *) NULL}, + { 0x0066, (char *) "BabyName", (char *) NULL}, + { 0x0067, (char *) "Location", (char *) NULL}, + { 0x0069, (char *) "Country", (char *) NULL}, + { 0x006B, (char *) "State", (char *) NULL}, + { 0x006D, (char *) "City", (char *) NULL}, + { 0x006F, (char *) "Landmark", (char *) NULL}, + { 0x0070, (char *) "IntelligentResolution", (char *) NULL}, + { 0x0079, (char *) "IntelligentD-Range", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x8000, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x8001, (char *) "SceneMode", (char *) NULL}, + { 0x8004, (char *) "WBRedLevel", (char *) NULL}, + { 0x8005, (char *) "WBGreenLevel", (char *) NULL}, + { 0x8006, (char *) "WBBlueLevel", (char *) NULL}, + { 0x8007, (char *) "FlashFired", (char *) NULL}, + { 0x8008, (char *) "TextStamp_0x8008", (char *) NULL}, + { 0x8009, (char *) "TextStamp_0x8009", (char *) NULL}, + { 0x8010, (char *) "BabyAge_0x8010", (char *) NULL}, + { 0x8012, (char *) "Transform", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Pentax (Asahi) maker note type 1 +*/ +static TagInfo + exif_asahi_tag_table[] = + { + { 0x0001, (char *) "Capture Mode", (char *) NULL}, + { 0x0002, (char *) "Quality Level", (char *) NULL}, + { 0x0003, (char *) "Focus Mode", (char *) NULL}, + { 0x0004, (char *) "Flash Mode", (char *) NULL}, + { 0x0007, (char *) "White Balance", (char *) NULL}, + { 0x000A, (char *) "Digital Zoom", (char *) NULL}, + { 0x000B, (char *) "Sharpness", (char *) NULL}, + { 0x000C, (char *) "Contrast", (char *) NULL}, + { 0x000D, (char *) "Saturation", (char *) NULL}, + { 0x0014, (char *) "ISO Speed", (char *) NULL}, + { 0x0017, (char *) "Color", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x1000, (char *) "Time Zone", (char *) NULL}, + { 0x1001, (char *) "Daylight Savings", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Pentax maker note type 2 +*/ +static TagInfo + exif_pentax_tag_table[] = + { + { 0x0000, (char *) "PentaxVersion", (char *) NULL}, + { 0x0001, (char *) "PentaxMode", (char *) NULL}, + { 0x0002, (char *) "PreviewImageSize", (char *) NULL}, + { 0x0003, (char *) "PreviewImageLength", (char *) NULL}, + { 0x0004, (char *) "PreviewImageStart", (char *) NULL}, + { 0x0005, (char *) "PentaxModelID", (char *) "Pentax PentaxModelID Values"}, + { 0x0006, (char *) "Date", (char *) NULL}, + { 0x0007, (char *) "Time", (char *) NULL}, + { 0x0008, (char *) "Quality", (char *) NULL}, + { 0x0009, (char *) "PentaxImageSize", (char *) NULL}, + { 0x000B, (char *) "PictureMode", (char *) NULL}, + { 0x000C, (char *) "FlashMode", (char *) NULL}, + { 0x000D, (char *) "FocusMode", (char *) NULL}, + { 0x000E, (char *) "AFPointSelected", (char *) NULL}, + { 0x000F, (char *) "AFPointsInFocus", (char *) NULL}, + { 0x0010, (char *) "FocusPosition", (char *) NULL}, + { 0x0012, (char *) "ExposureTime", (char *) NULL}, + { 0x0013, (char *) "FNumber", (char *) NULL}, + { 0x0014, (char *) "ISO", (char *) NULL}, + { 0x0015, (char *) "LightReading", (char *) NULL}, + { 0x0016, (char *) "ExposureCompensation", (char *) NULL}, + { 0x0017, (char *) "MeteringMode", (char *) NULL}, + { 0x0018, (char *) "AutoBracketing", (char *) NULL}, + { 0x0019, (char *) "WhiteBalance", (char *) NULL}, + { 0x001A, (char *) "WhiteBalanceMode", (char *) NULL}, + { 0x001B, (char *) "BlueBalance", (char *) NULL}, + { 0x001C, (char *) "RedBalance", (char *) NULL}, + { 0x001D, (char *) "FocalLength", (char *) NULL}, + { 0x001E, (char *) "DigitalZoom", (char *) NULL}, + { 0x001F, (char *) "Saturation", (char *) NULL}, + { 0x0020, (char *) "Contrast", (char *) NULL}, + { 0x0021, (char *) "Sharpness", (char *) NULL}, + { 0x0022, (char *) "WorldTimeLocation", (char *) NULL}, + { 0x0023, (char *) "HometownCity", (char *) "Pentax City Values"}, + { 0x0024, (char *) "DestinationCity", (char *) "Pentax City Values"}, + { 0x0025, (char *) "HometownDST", (char *) NULL}, + { 0x0026, (char *) "DestinationDST", (char *) NULL}, + { 0x0027, (char *) "DSPFirmwareVersion", (char *) NULL}, + { 0x0028, (char *) "CPUFirmwareVersion", (char *) NULL}, + { 0x0029, (char *) "FrameNumber", (char *) NULL}, + { 0x002D, (char *) "EffectiveLV", (char *) NULL}, + { 0x0032, (char *) "ImageProcessing", (char *) NULL}, + { 0x0033, (char *) "PictureMode", (char *) NULL}, + { 0x0034, (char *) "DriveMode", (char *) NULL}, + { 0x0035, (char *) "SensorSize", (char *) NULL}, + { 0x0037, (char *) "ColorSpace", (char *) NULL}, + { 0x0039, (char *) "RawImageSize", (char *) NULL}, + { 0x003C, (char *) "AFPointsInFocus", (char *) NULL}, + { 0x003E, (char *) "PreviewImageBorders", (char *) NULL}, + { 0x003F, (char *) "LensType", (char *) "Pentax LensType Values"}, + { 0x0040, (char *) "SensitivityAdjust", (char *) NULL}, + { 0x0041, (char *) "ImageProcessingCount", (char *) NULL}, + { 0x0047, (char *) "CameraTemperature", (char *) NULL}, + { 0x0048, (char *) "AELock", (char *) NULL}, + { 0x0049, (char *) "NoiseReduction", (char *) NULL}, + { 0x004D, (char *) "FlashExposureComp", (char *) NULL}, + { 0x004F, (char *) "ImageTone", (char *) NULL}, + { 0x0050, (char *) "ColorTemperature", (char *) NULL}, + { 0x005C, (char *) "ShakeReductionInfo", (char *) "Pentax SRInfo Tags"}, + { 0x005D, (char *) "ShutterCount", (char *) NULL}, + { 0x0060, (char *) "FaceInfo", (char *) "Pentax FaceInfo Tags"}, + { 0x0067, (char *) "Hue", (char *) NULL}, + { 0x0068, (char *) "AWBInfo", (char *) "Pentax AWBInfo Tags"}, + { 0x0069, (char *) "DynamicRangeExpansion", (char *) NULL}, + { 0x006B, (char *) "TimeInfo", (char *) "Pentax TimeInfo Tags"}, + { 0x006C, (char *) "HighLowKeyAdj", (char *) NULL}, + { 0x006D, (char *) "ContrastHighlight", (char *) NULL}, + { 0x006E, (char *) "ContrastShadow", (char *) NULL}, + { 0x006F, (char *) "ContrastHighlightShadowAdj", (char *) NULL}, + { 0x0070, (char *) "FineSharpness", (char *) NULL}, + { 0x0071, (char *) "HighISONoiseReduction", (char *) NULL}, + { 0x0072, (char *) "AFAdjustment", (char *) NULL}, + { 0x0073, (char *) "MonochromeFilterEffect", (char *) NULL}, + { 0x0074, (char *) "MonochromeToning", (char *) NULL}, + { 0x0076, (char *) "FaceDetect", (char *) NULL}, + { 0x0077, (char *) "FaceDetectFrameSize", (char *) NULL}, + { 0x0079, (char *) "ShadowCompensation", (char *) NULL}, + { 0x007A, (char *) "ISOAutoParameters", (char *) NULL}, + { 0x007B, (char *) "CrossProcess", (char *) NULL}, + { 0x007D, (char *) "LensCorr", (char *) "Pentax LensCorr Tags"}, + { 0x007F, (char *) "BleachBypassToning", (char *) NULL}, + { 0x0200, (char *) "BlackPoint", (char *) NULL}, + { 0x0201, (char *) "WhitePoint", (char *) NULL}, + { 0x0203, (char *) "ColorMatrixA", (char *) NULL}, + { 0x0204, (char *) "ColorMatrixB", (char *) NULL}, + { 0x0205, (char *) "CameraSettings", (char *) "Pentax CameraSettings Tags"}, + { 0x0206, (char *) "AEInfo", (char *) "Pentax AEInfo Tags"}, + { 0x0207, (char *) "LensInfo", (char *) "Pentax LensInfo Tags"}, + { 0x0208, (char *) "FlashInfo", (char *) "Pentax FlashInfo Tags"}, + { 0x0209, (char *) "AEMeteringSegments", (char *) NULL}, + { 0x020A, (char *) "FlashMeteringSegments", (char *) NULL}, + { 0x020B, (char *) "SlaveFlashMeteringSegments", (char *) NULL}, + { 0x020D, (char *) "WB_RGGBLevelsDaylight", (char *) NULL}, + { 0x020E, (char *) "WB_RGGBLevelsShade", (char *) NULL}, + { 0x020F, (char *) "WB_RGGBLevelsCloudy", (char *) NULL}, + { 0x0210, (char *) "WB_RGGBLevelsTungsten", (char *) NULL}, + { 0x0211, (char *) "WB_RGGBLevelsFluorescentD", (char *) NULL}, + { 0x0212, (char *) "WB_RGGBLevelsFluorescentN", (char *) NULL}, + { 0x0213, (char *) "WB_RGGBLevelsFluorescentW", (char *) NULL}, + { 0x0214, (char *) "WB_RGGBLevelsFlash", (char *) NULL}, + { 0x0215, (char *) "CameraInfo", (char *) "Pentax CameraInfo Tags"}, + { 0x0216, (char *) "BatteryInfo", (char *) "Pentax BatteryInfo Tags"}, + { 0x021B, (char *) "SaturationInfo", (char *) NULL}, + { 0x021F, (char *) "AFInfo", (char *) "Pentax AFInfo Tags"}, + { 0x0222, (char *) "ColorInfo", (char *) "Pentax ColorInfo Tags"}, + { 0x0224, (char *) "EVStepInfo", (char *) "Pentax EVStepInfo Tags"}, + { 0x0226, (char *) "ShotInfo", (char *) "Pentax ShotInfo Tags"}, + { 0x0227, (char *) "FacePos", (char *) "Pentax FacePos Tags"}, + { 0x0228, (char *) "FaceSize", (char *) "Pentax FaceSize Tags"}, + { 0x0229, (char *) "SerialNumber", (char *) NULL}, + { 0x022A, (char *) "FilterInfo", (char *) "Pentax FilterInfo Tags"}, + { 0x022B, (char *) "LevelInfo", (char *) "Pentax LevelInfo Tags"}, + { 0x022E, (char *) "Artist", (char *) NULL}, + { 0x022F, (char *) "Copyright", (char *) NULL}, + { 0x0230, (char *) "FirmwareVersion", (char *) NULL}, + { 0x0231, (char *) "ContrastDetectAFArea", (char *) NULL}, + { 0x0235, (char *) "CrossProcessParams", (char *) NULL}, + { 0x03FE, (char *) "DataDump", (char *) NULL}, + { 0x0402, (char *) "ToneCurve", (char *) NULL}, + { 0x0403, (char *) "ToneCurves", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x1000, (char *) "HometownCityCode", (char *) NULL}, + { 0x1001, (char *) "DestinationCityCode", (char *) NULL}, + { 0x2000, (char *) "PreviewImageData", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Sony maker note +*/ +static TagInfo + exif_sony_tag_table[] = + { + { 0x0102, (char *) "Quality", (char *) NULL}, + { 0x0104, (char *) "FlashExposureComp", (char *) NULL}, + { 0x0105, (char *) "Teleconverter", (char *) NULL}, + { 0x0112, (char *) "WhiteBalanceFineTune", (char *) NULL}, + { 0x0114, (char *) "CameraSettings", (char *) NULL}, + { 0x0115, (char *) "WhiteBalance", (char *) NULL}, + { 0x0E00, (char *) "PrintIM", (char *) NULL}, + { 0x1000, (char *) "MultiBurstMode", (char *) NULL}, + { 0x1001, (char *) "MultiBurstImageWidth", (char *) NULL}, + { 0x1002, (char *) "MultiBurstImageHeight", (char *) NULL}, + { 0x1003, (char *) "Panorama", (char *) NULL}, + { 0x2001, (char *) "PreviewImage", (char *) NULL}, + { 0x2004, (char *) "Contrast", (char *) NULL}, + { 0x2005, (char *) "Saturation", (char *) NULL}, + { 0x2006, (char *) "Sharpness", (char *) NULL}, + { 0x2007, (char *) "Brightness", (char *) NULL}, + { 0x2008, (char *) "LongExposureNoiseReduction", (char *) NULL}, + { 0x2009, (char *) "HighISONoiseReduction", (char *) NULL}, + { 0x200A, (char *) "HDR", (char *) NULL}, + { 0x200B, (char *) "MultiFrameNoiseReduction", (char *) NULL}, + { 0x3000, (char *) "ShotInfo", (char *) NULL}, + { 0xB000, (char *) "FileFormat", (char *) NULL}, + { 0xB001, (char *) "SonyModelID", (char *) NULL}, + { 0xB020, (char *) "ColorReproduction", (char *) NULL}, + { 0xB021, (char *) "ColorTemperature", (char *) NULL}, + { 0xB022, (char *) "ColorCompensationFilter", (char *) NULL}, + { 0xB023, (char *) "SceneMode", (char *) NULL}, + { 0xB024, (char *) "ZoneMatching", (char *) NULL}, + { 0xB025, (char *) "DynamicRangeOptimizer", (char *) NULL}, + { 0xB026, (char *) "ImageStabilization", (char *) NULL}, + { 0xB027, (char *) "LensType", (char *) NULL}, + { 0xB028, (char *) "MinoltaMakerNote", (char *) NULL}, + { 0xB029, (char *) "ColorMode", (char *) NULL}, + { 0xB02B, (char *) "FullImageSize", (char *) NULL}, + { 0xB02C, (char *) "PreviewImageSize", (char *) NULL}, + { 0xB040, (char *) "Macro", (char *) NULL}, + { 0xB041, (char *) "ExposureMode", (char *) NULL}, + { 0xB042, (char *) "FocusMode", (char *) NULL}, + { 0xB043, (char *) "AFMode", (char *) NULL}, + { 0xB044, (char *) "AFIlluminator", (char *) NULL}, + { 0xB047, (char *) "Quality2", (char *) NULL}, + { 0xB048, (char *) "FlashLevel", (char *) NULL}, + { 0xB049, (char *) "ReleaseMode", (char *) NULL}, + { 0xB04A, (char *) "SequenceNumber", (char *) NULL}, + { 0xB04B, (char *) "Anti-Blur", (char *) NULL}, + { 0xB04E, (char *) "LongExposureNoiseReduction", (char *) NULL}, + { 0xB04F, (char *) "DynamicRangeOptimizer", (char *) NULL}, + { 0xB052, (char *) "IntelligentAuto", (char *) NULL}, + { 0xB054, (char *) "WhiteBalance2", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Sigma SD1 maker note +*/ +static TagInfo + exif_sigma_sd1_tag_table[] = + { + { 0x0002, (char *) "SerialNumber", (char *) NULL}, + { 0x0003, (char *) "DriveMode", (char *) NULL}, + { 0x0004, (char *) "ResolutionMode", (char *) NULL}, + { 0x0005, (char *) "AFMode", (char *) NULL}, + { 0x0006, (char *) "FocusSetting", (char *) NULL}, + { 0x0007, (char *) "WhiteBalance", (char *) NULL}, + { 0x0008, (char *) "ExposureMode", (char *) NULL}, + { 0x0009, (char *) "MeteringMode", (char *) NULL}, + { 0x000A, (char *) "LensFocalRange", (char *) NULL}, + { 0x000B, (char *) "ColorSpace", (char *) NULL}, + { 0x000C, (char *) "ExposureCompensation", (char *) NULL}, + { 0x000D, (char *) "Contrast", (char *) NULL}, + { 0x000E, (char *) "Shadow", (char *) NULL}, + { 0x000F, (char *) "Highlight", (char *) NULL}, + { 0x0010, (char *) "Saturation", (char *) NULL}, + { 0x0011, (char *) "Sharpness", (char *) NULL}, + { 0x0012, (char *) "X3FillLight", (char *) NULL}, + { 0x0014, (char *) "ColorAdjustment", (char *) NULL}, + { 0x0015, (char *) "AdjustmentMode", (char *) NULL}, + { 0x0016, (char *) "Quality", (char *) NULL}, + { 0x0017, (char *) "Firmware", (char *) NULL}, + { 0x0018, (char *) "Software", (char *) NULL}, + { 0x0019, (char *) "AutoBracket", (char *) NULL}, + { 0x001A, (char *) "ChrominanceNoiseReduction", (char *) NULL}, + { 0x001B, (char *) "LuminanceNoiseReduction", (char *) NULL}, + { 0x001C, (char *) "PreviewImageStart", (char *) NULL}, + { 0x001D, (char *) "PreviewImageLength", (char *) NULL}, + { 0x001F, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x0026, (char *) "FileFormat", (char *) NULL}, + { 0x002C, (char *) "ColorMode", (char *) NULL}, + { 0x0030, (char *) "Calibration", (char *) NULL}, + { 0x0048, (char *) "LensApertureRange", (char *) NULL}, + { 0x0049, (char *) "FNumber", (char *) NULL}, + { 0x004A, (char *) "ExposureTime", (char *) NULL}, + { 0x004B, (char *) "ExposureTime2", (char *) NULL}, + { 0x004D, (char *) "ExposureCompensation_SD1", (char *) NULL}, + { 0x0055, (char *) "SensorTemperature", (char *) NULL}, + { 0x0056, (char *) "FlashExposureComp", (char *) NULL}, + { 0x0057, (char *) "Firmware_SD1", (char *) NULL}, + { 0x0058, (char *) "WhiteBalance", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +/** +Sigma / Foveon maker note (others than SD1 models) +NB: many tags are not consistent between different models +*/ +static TagInfo + exif_sigma_foveon_tag_table[] = + { + { 0x0002, (char *) "SerialNumber", (char *) NULL}, + { 0x0003, (char *) "DriveMode", (char *) NULL}, + { 0x0004, (char *) "ResolutionMode", (char *) NULL}, + { 0x0005, (char *) "AFMode", (char *) NULL}, + { 0x0006, (char *) "FocusSetting", (char *) NULL}, + { 0x0007, (char *) "WhiteBalance", (char *) NULL}, + { 0x0008, (char *) "ExposureMode", (char *) NULL}, + { 0x0009, (char *) "MeteringMode", (char *) NULL}, + { 0x000A, (char *) "LensFocalRange", (char *) NULL}, + { 0x000B, (char *) "ColorSpace", (char *) NULL}, + { 0x000C, (char *) "ExposureCompensation", (char *) NULL}, + { 0x000D, (char *) "Contrast", (char *) NULL}, + { 0x000E, (char *) "Shadow", (char *) NULL}, + { 0x000F, (char *) "Highlight", (char *) NULL}, + { 0x0010, (char *) "Saturation", (char *) NULL}, + { 0x0011, (char *) "Sharpness", (char *) NULL}, + { 0x0012, (char *) "X3FillLight", (char *) NULL}, + { 0x0014, (char *) "ColorAdjustment", (char *) NULL}, + { 0x0015, (char *) "AdjustmentMode", (char *) NULL}, + { 0x0016, (char *) "Quality", (char *) NULL}, + { 0x0017, (char *) "Firmware", (char *) NULL}, + { 0x0018, (char *) "Software", (char *) NULL}, + { 0x0019, (char *) "AutoBracket", (char *) NULL}, + { 0x001A, (char *) "PreviewImageStart", (char *) NULL}, + { 0x001B, (char *) "PreviewImageLength", (char *) NULL}, + { 0x001C, (char *) "PreviewImageSize", (char *) NULL}, + { 0x001D, (char *) "MakerNoteVersion", (char *) NULL}, + { 0x001F, (char *) "AFPoint", (char *) NULL}, + { 0x0022, (char *) "FileFormat", (char *) NULL}, + { 0x0024, (char *) "Calibration", (char *) NULL}, + { 0x002C, (char *) "ColorMode", (char *) NULL}, + { 0x0030, (char *) "LensApertureRange", (char *) NULL}, + { 0x0031, (char *) "FNumber", (char *) NULL}, + { 0x0032, (char *) "ExposureTime", (char *) NULL}, + { 0x0033, (char *) "ExposureTime2", (char *) NULL}, + { 0x0034, (char *) "BurstShot", (char *) NULL}, + { 0x0035, (char *) "ExposureCompensation", (char *) NULL}, + { 0x0039, (char *) "SensorTemperature", (char *) NULL}, + { 0x003A, (char *) "FlashExposureComp", (char *) NULL}, + { 0x003B, (char *) "Firmware", (char *) NULL}, + { 0x003C, (char *) "WhiteBalance", (char *) NULL}, + { 0x003D, (char *) "PictureMode", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// IPTC tags definition +// -------------------------------------------------------------------------- + +static TagInfo + iptc_tag_table[] = + { + // IPTC-NAA IIM version 4 + { 0x0200 + 0, (char *) "ApplicationRecordVersion", (char *) "Application Record Version"}, + { 0x0200 + 3, (char *) "ObjectTypeReference", (char *) "Object Type Reference"}, + { 0x0200 + 4, (char *) "ObjectAttributeReference", (char *) "Object Attribute Reference"}, + { 0x0200 + 5, (char *) "ObjectName", (char *) "Title"}, + { 0x0200 + 7, (char *) "EditStatus", (char *) "Edit Status"}, + { 0x0200 + 8, (char *) "EditorialUpdate", (char *) "Editorial Update"}, + { 0x0200 + 10, (char *) "Urgency", (char *) "Urgency"}, + { 0x0200 + 12, (char *) "SubjectReference", (char *) "Subject Reference"}, + { 0x0200 + 15, (char *) "Category", (char *) "Category"}, + { 0x0200 + 20, (char *) "SupplementalCategories", (char *) "Supplemental Categories"}, + { 0x0200 + 22, (char *) "FixtureIdentifier", (char *) "Fixture Identifier"}, + { 0x0200 + 25, (char *) "Keywords", (char *) "Keywords"}, + { 0x0200 + 26, (char *) "ContentLocationCode", (char *) "Content Location Code"}, + { 0x0200 + 27, (char *) "ContentLocationName", (char *) "Content Location Name"}, + { 0x0200 + 30, (char *) "ReleaseDate", (char *) "Release Date"}, + { 0x0200 + 35, (char *) "ReleaseTime", (char *) "Release Time"}, + { 0x0200 + 37, (char *) "ExpirationDate", (char *) "Expiration Date"}, + { 0x0200 + 38, (char *) "ExpirationTime", (char *) "Expiration Time"}, + { 0x0200 + 40, (char *) "SpecialInstructions", (char *) "Instructions"}, + { 0x0200 + 42, (char *) "ActionAdvised", (char *) "Action Advised"}, + { 0x0200 + 45, (char *) "ReferenceService", (char *) "Reference Service"}, + { 0x0200 + 47, (char *) "ReferenceDate", (char *) "Reference Date"}, + { 0x0200 + 50, (char *) "ReferenceNumber", (char *) "Reference Number"}, + { 0x0200 + 55, (char *) "DateCreated", (char *) "Date Created"}, + { 0x0200 + 60, (char *) "TimeCreated", (char *) "Time Created"}, + { 0x0200 + 62, (char *) "DigitalCreationDate", (char *) "Digital Creation Date"}, + { 0x0200 + 63, (char *) "DigitalCreationTime", (char *) "Digital Creation Time"}, + { 0x0200 + 65, (char *) "OriginatingProgram", (char *) "Originating Program"}, + { 0x0200 + 70, (char *) "ProgramVersion", (char *) "Program Version"}, + { 0x0200 + 75, (char *) "ObjectCycle", (char *) "Object Cycle"}, + { 0x0200 + 80, (char *) "By-line", (char *) "Author"}, + { 0x0200 + 85, (char *) "By-lineTitle", (char *) "Author's Position"}, + { 0x0200 + 90, (char *) "City", (char *) "City"}, + { 0x0200 + 92, (char *) "SubLocation", (char *) "Sub-Location"}, + { 0x0200 + 95, (char *) "Province-State", (char *) "State/Province"}, + { 0x0200 + 100, (char *) "Country-PrimaryLocationCode", (char *) "Country Code"}, + { 0x0200 + 101, (char *) "Country-PrimaryLocationName", (char *) "Country Name"}, + { 0x0200 + 103, (char *) "OriginalTransmissionReference", (char *) "Transmission Reference"}, + { 0x0200 + 105, (char *) "Headline", (char *) "Headline"}, + { 0x0200 + 110, (char *) "Credit", (char *) "Credit"}, + { 0x0200 + 115, (char *) "Source", (char *) "Source"}, + { 0x0200 + 116, (char *) "CopyrightNotice", (char *) "Copyright Notice"}, + { 0x0200 + 118, (char *) "Contact", (char *) "Contact"}, + { 0x0200 + 120, (char *) "Caption-Abstract", (char *) "Caption"}, + { 0x0200 + 122, (char *) "Writer-Editor", (char *) "Caption Writer"}, + { 0x0200 + 125, (char *) "RasterizedCaption", (char *) "Rasterized Caption"}, + { 0x0200 + 130, (char *) "ImageType", (char *) "Image Type"}, + { 0x0200 + 131, (char *) "ImageOrientation", (char *) "Image Orientation"}, + { 0x0200 + 135, (char *) "LanguageIdentifier", (char *) "Language Identifier"}, + { 0x0200 + 150, (char *) "AudioType", (char *) "Audio Type"}, + { 0x0200 + 151, (char *) "AudioSamplingRate", (char *) "Audio Sampling Rate"}, + { 0x0200 + 152, (char *) "AudioSamplingResolution", (char *) "Audio Sampling Resolution"}, + { 0x0200 + 153, (char *) "AudioDuration", (char *) "Audio Duration"}, + { 0x0200 + 154, (char *) "AudioOutcue", (char *) "Audio Outcue"}, + // Metadata seen in other softwares (see also http://owl.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html#ApplicationRecord) + { 0x0200 + 184, (char *) "JobID", (char *) "Job ID"}, + { 0x0200 + 185, (char *) "MasterDocumentID", (char *) "Master Document ID"}, + { 0x0200 + 186, (char *) "ShortDocumentID", (char *) "Short Document ID"}, + { 0x0200 + 187, (char *) "UniqueDocumentID", (char *) "Unique Document ID"}, + { 0x0200 + 188, (char *) "OwnerID", (char *) "Owner ID"}, + // IPTC-NAA IIM version 4 + { 0x0200 + 200, (char *) "ObjectPreviewFileFormat", (char *) "Object Preview File Format"}, + { 0x0200 + 201, (char *) "ObjectPreviewFileVersion", (char *) "Object Preview File Version"}, + { 0x0200 + 202, (char *) "ObjectPreviewData", (char *) "Audio Outcue"}, + // Metadata seen in other softwares (see also http://owl.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html#ApplicationRecord) + { 0x0200 + 221, (char *) "Prefs", (char *) "PhotoMechanic preferences"}, + { 0x0200 + 225, (char *) "ClassifyState", (char *) "Classify State"}, + { 0x0200 + 228, (char *) "SimilarityIndex", (char *) "Similarity Index"}, + { 0x0200 + 230, (char *) "DocumentNotes", (char *) "Document Notes"}, + { 0x0200 + 231, (char *) "DocumentHistory", (char *) "Document History"}, + { 0x0200 + 232, (char *) "ExifCameraInfo", (char *) "Exif Camera Info"}, + + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// GeoTIFF tags definition +// -------------------------------------------------------------------------- + +static TagInfo + geotiff_tag_table[] = + { + { 0x830E, (char *) "GeoPixelScale", (char *) NULL}, + { 0x8480, (char *) "Intergraph TransformationMatrix", (char *) NULL}, + { 0x8482, (char *) "GeoTiePoints", (char *) NULL}, + { 0x85D7, (char *) "JPL Carto IFD offset", (char *) NULL}, + { 0x85D8, (char *) "GeoTransformationMatrix", (char *) NULL}, + { 0x87AF, (char *) "GeoKeyDirectory", (char *) NULL}, + { 0x87B0, (char *) "GeoDoubleParams", (char *) NULL}, + { 0x87B1, (char *) "GeoASCIIParams", (char *) NULL}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// Animation tags definition +// -------------------------------------------------------------------------- + +static TagInfo + animation_tag_table[] = + { + { 0x0001, (char *) "LogicalWidth", (char *) "Logical width"}, + { 0x0002, (char *) "LogicalHeight", (char *) "Logical height"}, + { 0x0003, (char *) "GlobalPalette", (char *) "Global Palette"}, + { 0x0004, (char *) "Loop", (char *) "loop"}, + { 0x1001, (char *) "FrameLeft", (char *) "Frame left"}, + { 0x1002, (char *) "FrameTop", (char *) "Frame top"}, + { 0x1003, (char *) "NoLocalPalette", (char *) "No Local Palette"}, + { 0x1004, (char *) "Interlaced", (char *) "Interlaced"}, + { 0x1005, (char *) "FrameTime", (char *) "Frame display time"}, + { 0x1006, (char *) "DisposalMethod", (char *) "Frame disposal method"}, + { 0x0000, (char *) NULL, (char *) NULL} + }; + +// -------------------------------------------------------------------------- +// TagLib class definition +// -------------------------------------------------------------------------- + + +/** +This is where the tag info tables are initialized +*/ +TagLib::TagLib() { + // initialize all known metadata models + // ==================================== + + // Exif + addMetadataModel(TagLib::EXIF_MAIN, exif_exif_tag_table); + addMetadataModel(TagLib::EXIF_EXIF, exif_exif_tag_table); + addMetadataModel(TagLib::EXIF_GPS, exif_gps_tag_table); + addMetadataModel(TagLib::EXIF_INTEROP, exif_interop_tag_table); + + // Exif maker note + addMetadataModel(TagLib::EXIF_MAKERNOTE_CANON, exif_canon_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_CASIOTYPE1, exif_casio_type1_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_CASIOTYPE2, exif_casio_type2_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_FUJIFILM, exif_fujifilm_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_KYOCERA, exif_kyocera_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_MINOLTA, exif_minolta_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_NIKONTYPE1, exif_nikon_type1_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_NIKONTYPE2, exif_nikon_type2_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_NIKONTYPE3, exif_nikon_type3_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_OLYMPUSTYPE1, exif_olympus_type1_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_PANASONIC, exif_panasonic_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_ASAHI, exif_asahi_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_PENTAX, exif_pentax_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_SONY, exif_sony_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_SIGMA_SD1, exif_sigma_sd1_tag_table); + addMetadataModel(TagLib::EXIF_MAKERNOTE_SIGMA_FOVEON, exif_sigma_foveon_tag_table); + + // IPTC/NAA + addMetadataModel(TagLib::IPTC, iptc_tag_table); + + // GeoTIFF + addMetadataModel(TagLib::GEOTIFF, geotiff_tag_table); + + // Animation + addMetadataModel(TagLib::ANIMATION, animation_tag_table); +} + +BOOL TagLib::addMetadataModel(MDMODEL md_model, TagInfo *tag_table) { + // check that the model doesn't already exist + if ((_table_map.find(md_model) == _table_map.end()) && (tag_table != NULL)) { + + // add the tag description table + TAGINFO *info_map = new(std::nothrow) TAGINFO(); + if (!info_map) return FALSE; + + for(int i = 0; ; i++) { + if ((tag_table[i].tag == 0) && (tag_table[i].fieldname == NULL)) + break; + (*info_map)[tag_table[i].tag] = &tag_table[i]; + } + + // add the metadata model + _table_map[md_model] = info_map; + + return TRUE; + } + + return FALSE; +} + +TagLib::~TagLib() { + // delete metadata models + for(TABLEMAP::iterator i = _table_map.begin(); i != _table_map.end(); i++) { + TAGINFO *info_map = (*i).second; + delete info_map; + } +} + + +TagLib& +TagLib::instance() { + static TagLib s; + return s; +} + +const TagInfo* +TagLib::getTagInfo(MDMODEL md_model, WORD tagID) { + + if(_table_map.find(md_model) != _table_map.end()) { + + TAGINFO *info_map = (TAGINFO*)_table_map[md_model]; + if(info_map->find(tagID) != info_map->end()) { + return (*info_map)[tagID]; + } + } + return NULL; +} + +const char* +TagLib::getTagFieldName(MDMODEL md_model, WORD tagID, char *defaultKey) { + + const TagInfo *info = getTagInfo(md_model, tagID); + if(NULL == info) { + if(defaultKey != NULL) { + sprintf(defaultKey, "Tag 0x%04X", tagID); + return &defaultKey[0]; + } else { + return NULL; + } + } + + return info->fieldname; +} + +const char* +TagLib::getTagDescription(MDMODEL md_model, WORD tagID) { + + const TagInfo *info = getTagInfo(md_model, tagID); + if(info) { + return info->description; + } + + return NULL; +} + +int TagLib::getTagID(MDMODEL md_model, const char *key) { + + if(_table_map.find(md_model) != _table_map.end()) { + + TAGINFO *info_map = (TAGINFO*)_table_map[md_model]; + for(TAGINFO::iterator i = info_map->begin(); i != info_map->end(); i++) { + const TagInfo *info = (*i).second; + if(info && (strcmp(info->fieldname, key) == 0)) { + return (int)info->tag; + } + } + } + return -1; +} + +FREE_IMAGE_MDMODEL +TagLib::getFreeImageModel(MDMODEL model) { + switch(model) { + case EXIF_MAIN: + return FIMD_EXIF_MAIN; + + case EXIF_EXIF: + return FIMD_EXIF_EXIF; + + case EXIF_GPS: + return FIMD_EXIF_GPS; + + case EXIF_INTEROP: + return FIMD_EXIF_INTEROP; + + case EXIF_MAKERNOTE_CANON: + case EXIF_MAKERNOTE_CASIOTYPE1: + case EXIF_MAKERNOTE_CASIOTYPE2: + case EXIF_MAKERNOTE_FUJIFILM: + case EXIF_MAKERNOTE_KYOCERA: + case EXIF_MAKERNOTE_MINOLTA: + case EXIF_MAKERNOTE_NIKONTYPE1: + case EXIF_MAKERNOTE_NIKONTYPE2: + case EXIF_MAKERNOTE_NIKONTYPE3: + case EXIF_MAKERNOTE_OLYMPUSTYPE1: + case EXIF_MAKERNOTE_PANASONIC: + case EXIF_MAKERNOTE_ASAHI: + case EXIF_MAKERNOTE_PENTAX: + case EXIF_MAKERNOTE_SONY: + case EXIF_MAKERNOTE_SIGMA_SD1: + case EXIF_MAKERNOTE_SIGMA_FOVEON: + return FIMD_EXIF_MAKERNOTE; + + case IPTC: + return FIMD_IPTC; + + case GEOTIFF: + return FIMD_GEOTIFF; + + case ANIMATION: + return FIMD_ANIMATION; + } + + return FIMD_NODATA; +} + diff --git a/plugins/FreeImage/src/Metadata/XTIFF.cpp b/plugins/FreeImage/src/Metadata/XTIFF.cpp new file mode 100644 index 0000000000..bc63cf38b2 --- /dev/null +++ b/plugins/FreeImage/src/Metadata/XTIFF.cpp @@ -0,0 +1,661 @@ +// ==========================================================
+// Metadata functions implementation
+// Extended TIFF Directory GEO Tag Support
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - Thorsten Radde (support@IdealSoftware.com)
+// - Berend Engelbrecht (softwarecave@users.sourceforge.net)
+// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
+//
+// Based on the LibTIFF xtiffio sample and on LibGeoTIFF
+//
+// 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!
+// ==========================================================
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
+#endif
+
+#include "../LibTIFF4/tiffiop.h"
+
+#include "FreeImage.h"
+#include "Utilities.h"
+#include "FreeImageTag.h"
+#include "FIRational.h"
+
+// ----------------------------------------------------------
+// Extended TIFF Directory GEO Tag Support
+// ----------------------------------------------------------
+
+/**
+ Tiff info structure.
+ Entry format:
+ { TAGNUMBER, ReadCount, WriteCount, DataType, FIELDNUM, OkToChange, PassDirCountOnSet, AsciiName }
+
+ For ReadCount, WriteCount, -1 = unknown.
+*/
+static const TIFFFieldInfo xtiffFieldInfo[] = {
+ { TIFFTAG_GEOPIXELSCALE, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoPixelScale" },
+ { TIFFTAG_INTERGRAPH_MATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "Intergraph TransformationMatrix" },
+ { TIFFTAG_GEOTRANSMATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoTransformationMatrix" },
+ { TIFFTAG_GEOTIEPOINTS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoTiePoints" },
+ { TIFFTAG_GEOKEYDIRECTORY,-1,-1, TIFF_SHORT, FIELD_CUSTOM, TRUE, TRUE, "GeoKeyDirectory" },
+ { TIFFTAG_GEODOUBLEPARAMS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoDoubleParams" },
+ { TIFFTAG_GEOASCIIPARAMS, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE, "GeoASCIIParams" },
+ { TIFFTAG_JPL_CARTO_IFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, TRUE, TRUE, "JPL Carto IFD offset" } /** Don't use this! **/
+};
+
+static void
+_XTIFFLocalDefaultDirectory(TIFF *tif) {
+ int tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
+ // Install the extended Tag field info
+ TIFFMergeFieldInfo(tif, xtiffFieldInfo, tag_size);
+}
+
+static TIFFExtendProc _ParentExtender;
+
+/**
+This is the callback procedure, and is
+called by the DefaultDirectory method
+every time a new TIFF directory is opened.
+*/
+static void
+_XTIFFDefaultDirectory(TIFF *tif) {
+ // set up our own defaults
+ _XTIFFLocalDefaultDirectory(tif);
+
+ /*
+ Since an XTIFF client module may have overridden
+ the default directory method, we call it now to
+ allow it to set up the rest of its own methods.
+ */
+ if (_ParentExtender)
+ (*_ParentExtender)(tif);
+}
+
+/**
+XTIFF Initializer -- sets up the callback procedure for the TIFF module
+*/
+void
+XTIFFInitialize(void) {
+ static int first_time = 1;
+
+ if (! first_time)
+ return; /* Been there. Done that. */
+ first_time = 0;
+
+ // Grab the inherited method and install
+ _ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
+}
+
+// ----------------------------------------------------------
+// GeoTIFF tag reading / writing
+// ----------------------------------------------------------
+
+void
+tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
+ char defaultKey[16];
+
+ size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
+
+ TagLib& tag_lib = TagLib::instance();
+
+ for(unsigned i = 0; i < tag_size; i++) {
+
+ const TIFFFieldInfo *fieldInfo = &xtiffFieldInfo[i];
+
+ if(fieldInfo->field_type == TIFF_ASCII) {
+ char *params = NULL;
+
+ if(TIFFGetField(tif, fieldInfo->field_tag, ¶ms)) {
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if (!tag)
+ return;
+
+ WORD tag_id = (WORD)fieldInfo->field_tag;
+
+ FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)fieldInfo->field_type);
+ FreeImage_SetTagID(tag, tag_id);
+ FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::GEOTIFF, tag_id, defaultKey));
+ FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::GEOTIFF, tag_id));
+ FreeImage_SetTagLength(tag, (DWORD)strlen(params) + 1);
+ FreeImage_SetTagCount(tag, FreeImage_GetTagLength(tag));
+ FreeImage_SetTagValue(tag, params);
+ FreeImage_SetMetadata(FIMD_GEOTIFF, dib, FreeImage_GetTagKey(tag), tag);
+
+ // delete the tag
+ FreeImage_DeleteTag(tag);
+ }
+ } else {
+ short tag_count = 0;
+ void* data = NULL;
+
+ if(TIFFGetField(tif, fieldInfo->field_tag, &tag_count, &data)) {
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if (!tag)
+ return;
+
+ WORD tag_id = (WORD)fieldInfo->field_tag;
+ FREE_IMAGE_MDTYPE tag_type = (FREE_IMAGE_MDTYPE)fieldInfo->field_type;
+
+ FreeImage_SetTagType(tag, tag_type);
+ FreeImage_SetTagID(tag, tag_id);
+ FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::GEOTIFF, tag_id, defaultKey));
+ FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::GEOTIFF, tag_id));
+ FreeImage_SetTagLength(tag, FreeImage_TagDataWidth(tag_type) * tag_count);
+ FreeImage_SetTagCount(tag, tag_count);
+ FreeImage_SetTagValue(tag, data);
+ FreeImage_SetMetadata(FIMD_GEOTIFF, dib, FreeImage_GetTagKey(tag), tag);
+
+ // delete the tag
+ FreeImage_DeleteTag(tag);
+ }
+ }
+ } // for(tag_size)
+}
+
+void
+tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
+ char defaultKey[16];
+
+ if(FreeImage_GetMetadataCount(FIMD_GEOTIFF, dib) == 0) {
+ return;
+ }
+
+ size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
+
+ TagLib& tag_lib = TagLib::instance();
+
+ for(unsigned i = 0; i < tag_size; i++) {
+ const TIFFFieldInfo *fieldInfo = &xtiffFieldInfo[i];
+
+ FITAG *tag = NULL;
+ const char *key = tag_lib.getTagFieldName(TagLib::GEOTIFF, (WORD)fieldInfo->field_tag, defaultKey);
+
+ if(FreeImage_GetMetadata(FIMD_GEOTIFF, dib, key, &tag)) {
+ if(FreeImage_GetTagType(tag) == FIDT_ASCII) {
+ TIFFSetField(tif, fieldInfo->field_tag, FreeImage_GetTagValue(tag));
+ } else {
+ TIFFSetField(tif, fieldInfo->field_tag, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------
+// EXIF tag reading & writing
+// ----------------------------------------------------------
+
+/**
+Read a single exif tag
+*/
+static BOOL
+tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& tagLib, TIFFDirectory *td, uint32 tag) {
+ const TIFFField *fip;
+ uint32 value_count;
+ int mem_alloc = 0;
+ void *raw_data = NULL;
+
+ if(tag == TIFFTAG_EXIFIFD) {
+ return TRUE;
+ }
+
+ // get the tag key - use NULL to avoid reading GeoTIFF tags
+ const char *key = tagLib.getTagFieldName(md_model, (WORD)tag, NULL);
+ if(key == NULL) {
+ return TRUE;
+ }
+
+ fip = TIFFFieldWithTag(tif, tag);
+ if(fip == NULL) {
+ return TRUE;
+ }
+
+ if(fip->field_passcount) { //<- "passcount" means "returns count"
+ if (fip->field_readcount != TIFF_VARIABLE2) { //<- TIFF_VARIABLE2 means "uses LONG count"
+
+ // assume TIFF_VARIABLE (uses SHORT count)
+ uint16 value_count16;
+ if(TIFFGetField(tif, tag, &value_count16, &raw_data) != 1) {
+ return TRUE;
+ }
+ value_count = value_count16;
+ } else {
+ if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) {
+ return TRUE;
+ }
+ }
+ } else {
+
+ // determine count
+
+ if (fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2) {
+ value_count = 1;
+ } else if (fip->field_readcount == TIFF_SPP) {
+ value_count = td->td_samplesperpixel;
+ } else {
+ value_count = fip->field_readcount;
+ }
+
+ // access fields as pointers to data
+ // (### determining this is NOT robust... and hardly can be. It is implemented looking the _TIFFVGetField code)
+
+ if(fip->field_tag == TIFFTAG_TRANSFERFUNCTION) {
+ // reading this tag cause a bug probably located somewhere inside libtiff
+ return TRUE;
+ }
+
+ if ((fip->field_type == TIFF_ASCII
+ || fip->field_readcount == TIFF_VARIABLE
+ || fip->field_readcount == TIFF_VARIABLE2
+ || fip->field_readcount == TIFF_SPP
+ || value_count > 1)
+
+ && fip->field_tag != TIFFTAG_PAGENUMBER
+ && fip->field_tag != TIFFTAG_HALFTONEHINTS
+ && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
+ && fip->field_tag != TIFFTAG_DOTRANGE
+
+ && fip->field_tag != TIFFTAG_BITSPERSAMPLE //<- these two are tricky -
+ && fip->field_tag != TIFFTAG_COMPRESSION //<- they are defined as TIFF_VARIABLE but in reality return a single value
+ ) {
+ if(TIFFGetField(tif, tag, &raw_data) != 1) {
+ return TRUE;
+ }
+ } else {
+
+ // access fields as values
+
+ const int value_size = _TIFFDataSize(fip->field_type);
+ raw_data = _TIFFmalloc(value_size * value_count);
+ mem_alloc = 1;
+ int ok = FALSE;
+
+ // ### if value_count > 1, tag is PAGENUMBER or HALFTONEHINTS or YCBCRSUBSAMPLING or DOTRANGE,
+ // all off which are value_count == 2 (see tif_dirinfo.c)
+ switch(value_count)
+ {
+ case 1:
+ ok = TIFFGetField(tif, tag, raw_data);
+ break;
+ case 2:
+ ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1);
+ break;
+/* # we might need more in the future:
+ case 3:
+ ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1, (BYTE*)(raw_data) + value_size*2);
+ break;
+*/
+ default:
+ FreeImage_OutputMessageProc(FIF_TIFF, "Unimplemented variable number of parameters for Tiff Tag %s", fip->field_name);
+ break;
+ }
+ if(ok != 1) {
+ _TIFFfree(raw_data);
+ return TRUE;
+ }
+ }
+ }
+
+ // build FreeImage tag from Tiff Tag data we collected
+
+ FITAG *fitag = FreeImage_CreateTag();
+ if (!fitag) {
+ if(mem_alloc) {
+ _TIFFfree(raw_data);
+ }
+ return FALSE;
+ }
+
+ FreeImage_SetTagID(fitag, (WORD)tag);
+ FreeImage_SetTagKey(fitag, key);
+
+ switch(fip->field_type) {
+ case TIFF_BYTE:
+ FreeImage_SetTagType(fitag, FIDT_BYTE);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_UNDEFINED:
+ FreeImage_SetTagType(fitag, FIDT_UNDEFINED);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_SBYTE:
+ FreeImage_SetTagType(fitag, FIDT_SBYTE);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_SHORT:
+ FreeImage_SetTagType(fitag, FIDT_SHORT);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_SSHORT:
+ FreeImage_SetTagType(fitag, FIDT_SSHORT);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_LONG:
+ FreeImage_SetTagType(fitag, FIDT_LONG);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_IFD:
+ FreeImage_SetTagType(fitag, FIDT_IFD);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_SLONG:
+ FreeImage_SetTagType(fitag, FIDT_SLONG);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_RATIONAL: {
+ // LibTIFF converts rational to floats : reconvert floats to rationals
+ DWORD *rvalue = (DWORD*)malloc(2 * value_count * sizeof(DWORD));
+ for(uint32 i = 0; i < value_count; i++) {
+ float *fv = (float*)raw_data;
+ FIRational rational(fv[i]);
+ rvalue[2*i] = rational.getNumerator();
+ rvalue[2*i+1] = rational.getDenominator();
+ }
+ FreeImage_SetTagType(fitag, FIDT_RATIONAL);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, rvalue);
+ free(rvalue);
+ }
+ break;
+
+ case TIFF_SRATIONAL: {
+ // LibTIFF converts rational to floats : reconvert floats to rationals
+ LONG *rvalue = (LONG*)malloc(2 * value_count * sizeof(LONG));
+ for(uint32 i = 0; i < value_count; i++) {
+ float *fv = (float*)raw_data;
+ FIRational rational(fv[i]);
+ rvalue[2*i] = rational.getNumerator();
+ rvalue[2*i+1] = rational.getDenominator();
+ }
+ FreeImage_SetTagType(fitag, FIDT_RATIONAL);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, rvalue);
+ free(rvalue);
+ }
+ break;
+
+ case TIFF_FLOAT:
+ FreeImage_SetTagType(fitag, FIDT_FLOAT);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_DOUBLE:
+ FreeImage_SetTagType(fitag, FIDT_DOUBLE);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_LONG8: // BigTIFF 64-bit unsigned integer
+ FreeImage_SetTagType(fitag, FIDT_LONG8);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_IFD8: // BigTIFF 64-bit unsigned integer (offset)
+ FreeImage_SetTagType(fitag, FIDT_IFD8);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ case TIFF_SLONG8: // BigTIFF 64-bit signed integer
+ FreeImage_SetTagType(fitag, FIDT_SLONG8);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagCount(fitag, value_count);
+ FreeImage_SetTagValue(fitag, raw_data);
+ break;
+
+ default: {
+ size_t length = strlen((char*)raw_data) + 1;
+ FreeImage_SetTagType(fitag, FIDT_ASCII);
+ FreeImage_SetTagLength(fitag, (DWORD)length);
+ FreeImage_SetTagCount(fitag, (DWORD)length);
+ FreeImage_SetTagValue(fitag, raw_data);
+ }
+ break;
+ }
+
+ const char *description = tagLib.getTagDescription(md_model, (WORD)tag);
+ if(description) {
+ FreeImage_SetTagDescription(fitag, description);
+ }
+ // store the tag
+ FreeImage_SetMetadata(tagLib.getFreeImageModel(md_model), dib, FreeImage_GetTagKey(fitag), fitag);
+
+ // destroy the tag
+ FreeImage_DeleteTag(fitag);
+
+ if(mem_alloc) {
+ _TIFFfree(raw_data);
+ }
+ return TRUE;
+}
+
+/**
+Read all known exif tags
+*/
+BOOL
+tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
+ int i;
+ short count;
+
+ TagLib& tagLib = TagLib::instance();
+
+ TIFFDirectory *td = &tif->tif_dir;
+
+ count = (short) TIFFGetTagListCount(tif);
+ for(i = 0; i < count; i++) {
+ uint32 tag = TIFFGetTagListEntry(tif, i);
+ // read the tag
+ if (!tiff_read_exif_tag(tif, md_model, dib, tagLib, td, tag))
+ return FALSE;
+ }
+
+ // we want to know values of standard tags too!!
+
+ // loop over all Core Directory Tags
+ // ### uses private data, but there is no other way
+ if(md_model == TagLib::EXIF_MAIN) {
+
+ uint32 lastTag = 0; //<- used to prevent reading some tags twice (as stored in tif_fieldinfo)
+
+ for (int fi = 0, nfi = (int)tif->tif_nfields; nfi > 0; nfi--, fi++) {
+ const TIFFField *fld = tif->tif_fields[fi];
+
+ if(fld->field_tag == lastTag)
+ continue;
+
+ // test if tag value is set
+ // (lifted directly form LibTiff _TIFFWriteDirectory)
+
+ if ( fld->field_bit == FIELD_CUSTOM ) {
+ int ci, is_set = FALSE;
+
+ for ( ci = 0; ci < td->td_customValueCount; ci++ ) {
+ is_set |= (td->td_customValues[ci].info == fld);
+ }
+
+ if ( !is_set ) {
+ continue;
+ }
+
+ } else if (!TIFFFieldSet(tif, fld->field_bit)) {
+ continue;
+ }
+
+ // process *all* other tags (some will be ignored)
+
+ tiff_read_exif_tag(tif, md_model, dib, tagLib, td, fld->field_tag);
+
+
+ lastTag = fld->field_tag;
+ }
+
+ }
+
+ return TRUE;
+
+}
+
+
+/**
+Skip tags that are already handled by the LibTIFF writing process
+*/
+static BOOL
+skip_write_field(TIFF* tif, uint32 tag) {
+ switch (tag) {
+ case TIFFTAG_SAMPLEFORMAT:
+ case TIFFTAG_IMAGEWIDTH:
+ case TIFFTAG_IMAGELENGTH:
+ case TIFFTAG_SAMPLESPERPIXEL:
+ case TIFFTAG_BITSPERSAMPLE:
+ case TIFFTAG_PHOTOMETRIC:
+ case TIFFTAG_PLANARCONFIG:
+ case TIFFTAG_ROWSPERSTRIP:
+ case TIFFTAG_RESOLUTIONUNIT:
+ case TIFFTAG_XRESOLUTION:
+ case TIFFTAG_YRESOLUTION:
+ case TIFFTAG_SUBFILETYPE:
+ case TIFFTAG_PAGENUMBER:
+ case TIFFTAG_COLORMAP:
+ case TIFFTAG_ORIENTATION:
+ case TIFFTAG_COMPRESSION:
+ case TIFFTAG_PREDICTOR:
+ case TIFFTAG_GROUP3OPTIONS:
+ case TIFFTAG_FILLORDER:
+ // skip always, values have been set in SaveOneTIFF()
+ return TRUE;
+ break;
+
+ case TIFFTAG_RICHTIFFIPTC:
+ // skip always, IPTC metadata model is set in tiff_write_iptc_profile()
+ return TRUE;
+ break;
+
+ case TIFFTAG_YCBCRCOEFFICIENTS:
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ // skip as they cannot be filled yet
+ return TRUE;
+ break;
+
+ case TIFFTAG_PAGENAME:
+ {
+ char *value = NULL;
+ TIFFGetField(tif, TIFFTAG_PAGENAME, &value);
+ // only skip if no value has been set
+ if(value == NULL) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ }
+ default:
+ return FALSE;
+ break;
+ }
+}
+
+/**
+Write all known exif tags
+*/
+BOOL
+tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
+ char defaultKey[16];
+
+ // only EXIF_MAIN so far
+ if(md_model != TagLib::EXIF_MAIN) {
+ return FALSE;
+ }
+
+ if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib) == 0) {
+ return FALSE;
+ }
+
+ TagLib& tag_lib = TagLib::instance();
+
+ for (int fi = 0, nfi = (int)tif->tif_nfields; nfi > 0; nfi--, fi++) {
+ const TIFFField *fld = tif->tif_fields[fi];
+
+ if(skip_write_field(tif, fld->field_tag)) {
+ // skip tags that are already handled by the LibTIFF writing process
+ continue;
+ }
+
+ FITAG *tag = NULL;
+ // get the tag key
+ const char *key = tag_lib.getTagFieldName(TagLib::EXIF_MAIN, (WORD)fld->field_tag, defaultKey);
+
+ if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) {
+ FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
+ TIFFDataType tif_tag_type = fld->field_type;
+
+ // check for identical formats
+
+ // (enum value are the sames between FREE_IMAGE_MDTYPE and TIFFDataType types)
+ if ((int)tif_tag_type != (int)tag_type) {
+ // skip tag or _TIFFmemcpy will fail
+ continue;
+ }
+ // type of storage may differ (e.g. rationnal array vs float array type)
+ if(_TIFFDataSize(tif_tag_type) != FreeImage_TagDataWidth(tag_type)) {
+ // skip tag or _TIFFmemcpy will fail
+ continue;
+ }
+
+ if(tag_type == FIDT_ASCII) {
+ TIFFSetField(tif, fld->field_tag, FreeImage_GetTagValue(tag));
+ } else {
+ TIFFSetField(tif, fld->field_tag, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
+ }
+ }
+ }
+
+ return TRUE;
+}
|