summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/Metadata
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2014-12-13 20:28:24 +0000
committerKirill Volinsky <mataes2007@gmail.com>2014-12-13 20:28:24 +0000
commitd2d798d0f11abcbf141db69869e76e8d123ec1eb (patch)
treecee8645964030b4b80231952885911f724850d12 /plugins/AdvaImg/src/Metadata
parenta400ebf572dcad9b43d1b641b1742814f8b5e8a5 (diff)
FreeImage updated to 3.16
git-svn-id: http://svn.miranda-ng.org/main/trunk@11379 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AdvaImg/src/Metadata')
-rw-r--r--plugins/AdvaImg/src/Metadata/Exif.cpp158
-rw-r--r--plugins/AdvaImg/src/Metadata/FreeImageTag.cpp26
-rw-r--r--plugins/AdvaImg/src/Metadata/FreeImageTag.h23
-rw-r--r--plugins/AdvaImg/src/Metadata/IPTC.cpp2
-rw-r--r--plugins/AdvaImg/src/Metadata/TagConversion.cpp2188
-rw-r--r--plugins/AdvaImg/src/Metadata/XTIFF.cpp1340
6 files changed, 1947 insertions, 1790 deletions
diff --git a/plugins/AdvaImg/src/Metadata/Exif.cpp b/plugins/AdvaImg/src/Metadata/Exif.cpp
index ed667b0974..abc840607b 100644
--- a/plugins/AdvaImg/src/Metadata/Exif.cpp
+++ b/plugins/AdvaImg/src/Metadata/Exif.cpp
@@ -515,17 +515,18 @@ processExifTag(FIBITMAP *dib, FITAG *tag, char *pval, BOOL msb_order, TagLib::MD
}
/**
- 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
+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
+@param starting_md_model Metadata model of the IFD (should be TagLib::EXIF_MAIN for a jpeg)
+@return Returns TRUE if sucessful, returns FALSE otherwise
*/
static BOOL
-jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) {
+jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order, TagLib::MDMODEL starting_md_model) {
WORD de, nde;
std::stack<WORD> destack; // directory entries stack
@@ -548,7 +549,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// set the metadata model to Exif
- TagLib::MDMODEL md_model = TagLib::EXIF_MAIN;
+ TagLib::MDMODEL md_model = starting_md_model;
// set the pointer to the first IFD (0th IFD) and follow it were it leads.
@@ -787,6 +788,8 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
return TRUE;
}
+// --------------------------------------------------------------------------
+
/**
Read and decode JPEG_APP1 marker (Exif profile)
@param dib Input FIBITMAP
@@ -795,7 +798,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
-jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
+jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned 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
@@ -849,11 +852,140 @@ jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen)
}
*/
- // process Exif directories
- return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder);
+ // process Exif directories, starting with Exif-TIFF IFD
+ return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder, TagLib::EXIF_MAIN);
}
return FALSE;
}
+/**
+ Read 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_raw(FIBITMAP *dib, const BYTE *profile, unsigned length) {
+ // marker identifying string for Exif = "Exif\0\0"
+ BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
+
+ // verify the identifying string
+ if(memcmp(exif_signature, profile, sizeof(exif_signature)) != 0) {
+ // not an Exif profile
+ return FALSE;
+ }
+
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if(tag) {
+ FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
+ FreeImage_SetTagLength(tag, (DWORD)length);
+ FreeImage_SetTagCount(tag, (DWORD)length);
+ FreeImage_SetTagType(tag, FIDT_BYTE);
+ FreeImage_SetTagValue(tag, profile);
+
+ // store the tag
+ FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);
+
+ // destroy the tag
+ FreeImage_DeleteTag(tag);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+Read and decode JPEG-XR Exif IFD
+@param dib Input FIBITMAP
+@param profile Pointer to the Exif marker
+@param length Exif marker length
+@return Returns TRUE if successful, FALSE otherwise
+*/
+BOOL
+jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length) {
+ // assume Little Endian order
+ BOOL bMotorolaOrder = FALSE;
+
+ // process Exif specific IFD
+ return jpeg_read_exif_dir(dib, profile, 0, length, bMotorolaOrder, TagLib::EXIF_EXIF);
+}
+
+/**
+Read and decode JPEG-XR Exif-GPS IFD
+@param dib Input FIBITMAP
+@param profile Pointer to the Exif-GPS marker
+@param length Exif-GPS marker length
+@return Returns TRUE if successful, FALSE otherwise
+*/
+BOOL
+jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length) {
+ // assume Little Endian order
+ BOOL bMotorolaOrder = FALSE;
+
+ // process Exif GPS IFD
+ return jpeg_read_exif_dir(dib, profile, 0, length, bMotorolaOrder, TagLib::EXIF_GPS);
+}
+
+/**
+Rotate a dib according to Exif info
+@param dib Input / Output dib to rotate
+@see PluginJPEG.cpp
+*/
+void
+RotateExif(FIBITMAP **dib) {
+ // check for Exif rotation
+ if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, *dib)) {
+ FIBITMAP *rotated = NULL;
+ // process Exif rotation
+ FITAG *tag = NULL;
+ FreeImage_GetMetadata(FIMD_EXIF_MAIN, *dib, "Orientation", &tag);
+ if(tag != NULL) {
+ if(FreeImage_GetTagID(tag) == TAG_ORIENTATION) {
+ unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
+ switch (orientation) {
+ case 1: // "top, left side" => 0°
+ break;
+ case 2: // "top, right side" => flip left-right
+ FreeImage_FlipHorizontal(*dib);
+ break;
+ case 3: // "bottom, right side"; => -180°
+ rotated = FreeImage_Rotate(*dib, 180);
+ FreeImage_Unload(*dib);
+ *dib = rotated;
+ break;
+ case 4: // "bottom, left side" => flip up-down
+ FreeImage_FlipVertical(*dib);
+ break;
+ case 5: // "left side, top" => +90° + flip up-down
+ rotated = FreeImage_Rotate(*dib, 90);
+ FreeImage_Unload(*dib);
+ *dib = rotated;
+ FreeImage_FlipVertical(*dib);
+ break;
+ case 6: // "right side, top" => -90°
+ rotated = FreeImage_Rotate(*dib, -90);
+ FreeImage_Unload(*dib);
+ *dib = rotated;
+ break;
+ case 7: // "right side, bottom" => -90° + flip up-down
+ rotated = FreeImage_Rotate(*dib, -90);
+ FreeImage_Unload(*dib);
+ *dib = rotated;
+ FreeImage_FlipVertical(*dib);
+ break;
+ case 8: // "left side, bottom" => +90°
+ rotated = FreeImage_Rotate(*dib, 90);
+ FreeImage_Unload(*dib);
+ *dib = rotated;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp b/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
index 5d9f3034ec..f8af31f9eb 100644
--- a/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
+++ b/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
@@ -117,11 +117,23 @@ FreeImage_CloneTag(FITAG *tag) {
// 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;
+ switch(dst_tag->type) {
+ case FIDT_ASCII:
+ dst_tag->value = (BYTE*)malloc((src_tag->length + 1) * sizeof(BYTE));
+ if(!dst_tag->value) {
+ throw FI_MSG_ERROR_MEMORY;
+ }
+ memcpy(dst_tag->value, src_tag->value, src_tag->length);
+ ((BYTE*)dst_tag->value)[src_tag->length] = 0;
+ break;
+ default:
+ 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);
+ break;
}
- memcpy(dst_tag->value, src_tag->value, src_tag->length);
return clone;
@@ -305,9 +317,9 @@ FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) {
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
+ 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)
};
diff --git a/plugins/AdvaImg/src/Metadata/FreeImageTag.h b/plugins/AdvaImg/src/Metadata/FreeImageTag.h
index 4f3bffa1ce..f9021ace27 100644
--- a/plugins/AdvaImg/src/Metadata/FreeImageTag.h
+++ b/plugins/AdvaImg/src/Metadata/FreeImageTag.h
@@ -321,15 +321,15 @@ TagInfo *tag_info = s.getTagInfo(EXIF_MAIN, 0x0100);
</code>
Note on multi-threaded applications :
-
-The singleton pattern must be carefully constructed in multi-threaded applications.
-If two threads are to execute the creation method at the same time when a singleton
-does not yet exist, they both must check for an instance of the singleton and then
-only one should create the new one.
-The classic solution to this problem is to use mutual exclusion on the class that
-indicates that the object is being instantiated.
-The FreeImage solution is to instantiate the singleton before any other thread is launched,
-i.e. inside the FreeImage_Initialise function (see Plugin.cpp).
+
+The singleton pattern must be carefully constructed in multi-threaded applications.
+If two threads are to execute the creation method at the same time when a singleton
+does not yet exist, they both must check for an instance of the singleton and then
+only one should create the new one.
+The classic solution to this problem is to use mutual exclusion on the class that
+indicates that the object is being instantiated.
+The FreeImage solution is to instantiate the singleton before any other thread is launched,
+i.e. inside the FreeImage_Initialise function (see Plugin.cpp).
*/
class TagLib {
@@ -468,7 +468,10 @@ extern "C" {
#endif
// JPEG Exif profile
-BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen);
+BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen);
+BOOL jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length);
+BOOL jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length);
+BOOL jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length);
// JPEG / TIFF IPTC profile
BOOL read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen);
diff --git a/plugins/AdvaImg/src/Metadata/IPTC.cpp b/plugins/AdvaImg/src/Metadata/IPTC.cpp
index 6f28c486b3..bde718c986 100644
--- a/plugins/AdvaImg/src/Metadata/IPTC.cpp
+++ b/plugins/AdvaImg/src/Metadata/IPTC.cpp
@@ -91,7 +91,7 @@ read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
offset++;
int directoryType = profile[offset++];
- int tagType = profile[offset++];
+ int tagType = profile[offset++];;
int tagByteCount = ((profile[offset] & 0xFF) << 8) | (profile[offset + 1] & 0xFF);
offset += 2;
diff --git a/plugins/AdvaImg/src/Metadata/TagConversion.cpp b/plugins/AdvaImg/src/Metadata/TagConversion.cpp
index 06a1970cd8..f05818600c 100644
--- a/plugins/AdvaImg/src/Metadata/TagConversion.cpp
+++ b/plugins/AdvaImg/src/Metadata/TagConversion.cpp
@@ -1,1094 +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
- {
- UINT64 *pvalue = (UINT64 *)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)
- {
- UINT64 *pvalue = (UINT64 *)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
- {
- INT64 *pvalue = (INT64 *)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);
-}
-
+// ==========================================================
+// 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
+ {
+ UINT64 *pvalue = (UINT64 *)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)
+ {
+ UINT64 *pvalue = (UINT64 *)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
+ {
+ INT64 *pvalue = (INT64 *)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/AdvaImg/src/Metadata/XTIFF.cpp b/plugins/AdvaImg/src/Metadata/XTIFF.cpp
index e6f6bdd0d9..681eed12c5 100644
--- a/plugins/AdvaImg/src/Metadata/XTIFF.cpp
+++ b/plugins/AdvaImg/src/Metadata/XTIFF.cpp
@@ -1,665 +1,675 @@
-// ==========================================================
-// 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, &params)) {
- // 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: {
- // remember that raw_data = _TIFFmalloc(value_size * value_count);
- const int value_size = _TIFFDataSize(fip->field_type);
- size_t length = value_size * value_count;
- 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_STRIPBYTECOUNTS:
- case TIFFTAG_STRIPOFFSETS:
- 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;
-}
+// ==========================================================
+// 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, &params)) {
+ // 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;
+
+ case TIFF_ASCII:
+ default: {
+ size_t length = 0;
+ if(!mem_alloc && (fip->field_type == TIFF_ASCII) && (fip->field_readcount == TIFF_VARIABLE)) {
+ // when metadata tag is of type ASCII and it's value is of variable size (TIFF_VARIABLE),
+ // tiff_read_exif_tag function gives length of 1 so all strings are truncated ...
+ // ... try to avoid this by using an explicit calculation for 'length'
+ length = strlen((char*)raw_data) + 1;
+ }
+ else {
+ // remember that raw_data = _TIFFmalloc(value_size * value_count);
+ const int value_size = _TIFFDataSize(fip->field_type);
+ length = value_size * value_count;
+ }
+ 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_STRIPBYTECOUNTS:
+ case TIFFTAG_STRIPOFFSETS:
+ 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;
+}