// ========================================================== // Tag to string conversion functions // // Design and implementation by // - Hervé Drolon // // 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, "%lld", pvalue[0]); buffer += format; for(i = 1; i < tag_count; i++) { sprintf(format, "%lld", pvalue[i]); buffer += format; } break; } case FIDT_IFD8: // N x 64-bit unsigned integer (offset) { UINT64 *pvalue = (UINT64 *)FreeImage_GetTagValue(tag); sprintf(format, "%llX", pvalue[0]); buffer += format; for(i = 1; i < tag_count; i++) { sprintf(format, "%llX", pvalue[i]); buffer += format; } break; } case FIDT_SLONG8: // N x 64-bit signed integer { INT64 *pvalue = (INT64 *)FreeImage_GetTagValue(tag); sprintf(format, "%lld", pvalue[0]); buffer += format; for(i = 1; i < tag_count; i++) { sprintf(format, "%lld", 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); }