PageRenderTime 100ms CodeModel.GetById 2ms app.highlight 92ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/Metadata/TagConversion.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 1094 lines | 942 code | 99 blank | 53 comment | 75 complexity | ad5c0255e89dfcf60732bf9f6cab64a3 MD5 | raw file
   1// ==========================================================
   2// Tag to string conversion functions
   3//
   4// Design and implementation by
   5// - Hervé Drolon <drolon@infonie.fr>
   6//
   7// This file is part of FreeImage 3
   8//
   9// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  10// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  11// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  12// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  13// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  14// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  15// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  16// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  17// THIS DISCLAIMER.
  18//
  19// Use at your own risk!
  20// ==========================================================
  21
  22#ifdef _MSC_VER 
  23#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
  24#endif
  25
  26#include "FreeImage.h"
  27#include "Utilities.h"
  28#include "FreeImageTag.h"
  29#include "FIRational.h"
  30
  31#define MAX_TEXT_EXTENT	512
  32
  33/**
  34Convert a tag to a C string
  35*/
  36static const char* 
  37ConvertAnyTag(FITAG *tag) {
  38	char format[MAX_TEXT_EXTENT];
  39	static std::string buffer;
  40	DWORD i;
  41
  42	if(!tag)
  43		return NULL;
  44
  45	buffer.erase();
  46	
  47	// convert the tag value to a string buffer
  48
  49	FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
  50	DWORD tag_count = FreeImage_GetTagCount(tag);
  51
  52	switch(tag_type) {
  53		case FIDT_BYTE:		// N x 8-bit unsigned integer 
  54		{
  55			BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);
  56
  57			sprintf(format, "%ld",	(LONG) pvalue[0]);
  58			buffer += format;
  59			for(i = 1; i < tag_count; i++) {
  60				sprintf(format, " %ld",	(LONG) pvalue[i]);
  61				buffer += format;
  62			}
  63			break;
  64		}
  65		case FIDT_SHORT:	// N x 16-bit unsigned integer 
  66		{
  67			unsigned short *pvalue = (unsigned short *)FreeImage_GetTagValue(tag);
  68
  69			sprintf(format, "%hu", pvalue[0]);
  70			buffer += format;
  71			for(i = 1; i < tag_count; i++) {
  72				sprintf(format, " %hu",	pvalue[i]);
  73				buffer += format;
  74			}
  75			break;
  76		}
  77		case FIDT_LONG:		// N x 32-bit unsigned integer 
  78		{
  79			DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);
  80
  81			sprintf(format, "%lu", pvalue[0]);
  82			buffer += format;
  83			for(i = 1; i < tag_count; i++) {
  84				sprintf(format, " %lu",	pvalue[i]);
  85				buffer += format;
  86			}
  87			break;
  88		}
  89		case FIDT_RATIONAL: // N x 64-bit unsigned fraction 
  90		{
  91			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
  92
  93			sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
  94			buffer += format;
  95			for(i = 1; i < tag_count; i++) {
  96				sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
  97				buffer += format;
  98			}
  99			break;
 100		}
 101		case FIDT_SBYTE:	// N x 8-bit signed integer 
 102		{
 103			char *pvalue = (char*)FreeImage_GetTagValue(tag);
 104
 105			sprintf(format, "%ld",	(LONG) pvalue[0]);
 106			buffer += format;
 107			for(i = 1; i < tag_count; i++) {
 108				sprintf(format, " %ld",	(LONG) pvalue[i]);
 109				buffer += format;
 110			}
 111			break;
 112		}
 113		case FIDT_SSHORT:	// N x 16-bit signed integer 
 114		{
 115			short *pvalue = (short *)FreeImage_GetTagValue(tag);
 116
 117			sprintf(format, "%hd", pvalue[0]);
 118			buffer += format;
 119			for(i = 1; i < tag_count; i++) {
 120				sprintf(format, " %hd",	pvalue[i]);
 121				buffer += format;
 122			}
 123			break;
 124		}
 125		case FIDT_SLONG:	// N x 32-bit signed integer 
 126		{
 127			LONG *pvalue = (LONG *)FreeImage_GetTagValue(tag);
 128
 129			sprintf(format, "%ld", pvalue[0]);
 130			buffer += format;
 131			for(i = 1; i < tag_count; i++) {
 132				sprintf(format, " %ld",	pvalue[i]);
 133				buffer += format;
 134			}
 135			break;
 136		}
 137		case FIDT_SRATIONAL:// N x 64-bit signed fraction 
 138		{
 139			LONG *pvalue = (LONG*)FreeImage_GetTagValue(tag);
 140
 141			sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
 142			buffer += format;
 143			for(i = 1; i < tag_count; i++) {
 144				sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
 145				buffer += format;
 146			}
 147			break;
 148		}
 149		case FIDT_FLOAT:	// N x 32-bit IEEE floating point 
 150		{
 151			float *pvalue = (float *)FreeImage_GetTagValue(tag);
 152
 153			sprintf(format, "%f", (double) pvalue[0]);
 154			buffer += format;
 155			for(i = 1; i < tag_count; i++) {
 156				sprintf(format, "%f", (double) pvalue[i]);
 157				buffer += format;
 158			}
 159			break;
 160		}
 161		case FIDT_DOUBLE:	// N x 64-bit IEEE floating point 
 162		{
 163			double *pvalue = (double *)FreeImage_GetTagValue(tag);
 164
 165			sprintf(format, "%f", pvalue[0]);
 166			buffer += format;
 167			for(i = 1; i < tag_count; i++) {
 168				sprintf(format, "%f", pvalue[i]);
 169				buffer += format;
 170			}
 171			break;
 172		}
 173		case FIDT_IFD:		// N x 32-bit unsigned integer (offset) 
 174		{
 175			DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);
 176
 177			sprintf(format, "%X", pvalue[0]);
 178			buffer += format;
 179			for(i = 1; i < tag_count; i++) {
 180				sprintf(format, " %X",	pvalue[i]);
 181				buffer += format;
 182			}
 183			break;
 184		}
 185		case FIDT_PALETTE:	// N x 32-bit RGBQUAD 
 186		{
 187			RGBQUAD *pvalue = (RGBQUAD *)FreeImage_GetTagValue(tag);
 188
 189			sprintf(format, "(%d,%d,%d,%d)", pvalue[0].rgbRed, pvalue[0].rgbGreen, pvalue[0].rgbBlue, pvalue[0].rgbReserved);
 190			buffer += format;
 191			for(i = 1; i < tag_count; i++) {
 192				sprintf(format, " (%d,%d,%d,%d)", pvalue[i].rgbRed, pvalue[i].rgbGreen, pvalue[i].rgbBlue, pvalue[i].rgbReserved);
 193				buffer += format;
 194			}
 195			break;
 196		}
 197		
 198		case FIDT_LONG8:	// N x 64-bit unsigned integer 
 199		{
 200			FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);
 201
 202			sprintf(format, "%ld", pvalue[0]);
 203			buffer += format;
 204			for(i = 1; i < tag_count; i++) {
 205				sprintf(format, "%ld", pvalue[i]);
 206				buffer += format;
 207			}
 208			break;
 209		}
 210
 211		case FIDT_IFD8:		// N x 64-bit unsigned integer (offset)
 212		{
 213			FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);
 214
 215			sprintf(format, "%X", pvalue[0]);
 216			buffer += format;
 217			for(i = 1; i < tag_count; i++) {
 218				sprintf(format, "%X", pvalue[i]);
 219				buffer += format;
 220			}
 221			break;
 222		}
 223
 224		case FIDT_SLONG8:	// N x 64-bit signed integer
 225		{
 226			FIINT64 *pvalue = (FIINT64 *)FreeImage_GetTagValue(tag);
 227
 228			sprintf(format, "%ld", pvalue[0]);
 229			buffer += format;
 230			for(i = 1; i < tag_count; i++) {
 231				sprintf(format, "%ld", pvalue[i]);
 232				buffer += format;
 233			}
 234			break;
 235		}
 236
 237		case FIDT_ASCII:	// 8-bit bytes w/ last byte null 
 238		case FIDT_UNDEFINED:// 8-bit untyped data 
 239		default:
 240		{
 241			int max_size = MIN((int)FreeImage_GetTagLength(tag), (int)MAX_TEXT_EXTENT);
 242			if(max_size == MAX_TEXT_EXTENT)
 243				max_size--;
 244			memcpy(format, (char*)FreeImage_GetTagValue(tag), max_size);
 245			format[max_size] = '\0';
 246			buffer += format;
 247			break;
 248		}
 249	}
 250
 251	return buffer.c_str();
 252}
 253
 254/**
 255Convert a Exif tag to a C string
 256*/
 257static const char* 
 258ConvertExifTag(FITAG *tag) {
 259	char format[MAX_TEXT_EXTENT];
 260	static std::string buffer;
 261
 262	if(!tag)
 263		return NULL;
 264
 265	buffer.erase();
 266
 267	// convert the tag value to a string buffer
 268
 269	switch(FreeImage_GetTagID(tag)) {
 270		case TAG_ORIENTATION:
 271		{
 272			unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
 273			switch (orientation) {
 274				case 1:
 275					return "top, left side";
 276				case 2:
 277					return "top, right side";
 278				case 3:
 279					return "bottom, right side";
 280				case 4:
 281					return "bottom, left side";
 282				case 5:
 283					return "left side, top";
 284				case 6:
 285					return "right side, top";
 286				case 7:
 287					return "right side, bottom";
 288				case 8:
 289					return "left side, bottom";
 290				default:
 291					break;
 292			}
 293		}
 294		break;
 295
 296		case TAG_REFERENCE_BLACK_WHITE:
 297		{
 298			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
 299			if(FreeImage_GetTagLength(tag) == 48) {
 300				// reference black point value and reference white point value (ReferenceBlackWhite)
 301				int blackR = 0, whiteR = 0, blackG = 0, whiteG = 0, blackB = 0, whiteB = 0;
 302				if(pvalue[1])
 303					blackR = (int)(pvalue[0] / pvalue[1]);
 304				if(pvalue[3])
 305					whiteR = (int)(pvalue[2] / pvalue[3]);
 306				if(pvalue[5])
 307					blackG = (int)(pvalue[4] / pvalue[5]);
 308				if(pvalue[7])
 309					whiteG = (int)(pvalue[6] / pvalue[7]);
 310				if(pvalue[9])
 311					blackB = (int)(pvalue[8] / pvalue[9]);
 312				if(pvalue[11])
 313					whiteB = (int)(pvalue[10] / pvalue[11]);
 314
 315				sprintf(format, "[%d,%d,%d] [%d,%d,%d]", blackR, blackG, blackB, whiteR, whiteG, whiteB);
 316				buffer += format;
 317				return buffer.c_str();
 318			}
 319
 320		}
 321		break;
 322
 323		case TAG_COLOR_SPACE:
 324		{
 325			unsigned short colorSpace = *((unsigned short *)FreeImage_GetTagValue(tag));
 326			if (colorSpace == 1) {
 327				return "sRGB";
 328			} else if (colorSpace == 65535) {
 329				return "Undefined";
 330			} else {
 331				return "Unknown";
 332			}
 333		}
 334		break;
 335
 336		case TAG_COMPONENTS_CONFIGURATION:
 337		{
 338			const char *componentStrings[7] = {"", "Y", "Cb", "Cr", "R", "G", "B"};
 339			BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);
 340			for(DWORD i = 0; i < MIN((DWORD)4, FreeImage_GetTagCount(tag)); i++) {
 341				int j = pvalue[i];
 342				if(j > 0 && j < 7)
 343					buffer += componentStrings[j];
 344			}
 345			return buffer.c_str();
 346		}
 347		break;
 348
 349		case TAG_COMPRESSED_BITS_PER_PIXEL:
 350		{
 351			FIRational r(tag);
 352			buffer = r.toString();
 353			if(buffer == "1")
 354				buffer += " bit/pixel";
 355			else 
 356				buffer += " bits/pixel";
 357			return buffer.c_str();
 358		}
 359		break;
 360
 361		case TAG_X_RESOLUTION:
 362		case TAG_Y_RESOLUTION:
 363		case TAG_FOCAL_PLANE_X_RES:
 364		case TAG_FOCAL_PLANE_Y_RES:
 365		case TAG_BRIGHTNESS_VALUE:
 366		case TAG_EXPOSURE_BIAS_VALUE:
 367		{
 368			FIRational r(tag);
 369			buffer = r.toString();
 370			return buffer.c_str();
 371		}
 372		break;
 373
 374		case TAG_RESOLUTION_UNIT:
 375		case TAG_FOCAL_PLANE_UNIT:
 376		{
 377			unsigned short resolutionUnit = *((unsigned short *)FreeImage_GetTagValue(tag));
 378			switch (resolutionUnit) {
 379				case 1:
 380					return "(No unit)";
 381				case 2:
 382					return "inches";
 383				case 3:
 384					return "cm";
 385				default:
 386					break;
 387			}
 388		}
 389		break;
 390
 391		case TAG_YCBCR_POSITIONING:
 392		{
 393			unsigned short yCbCrPosition = *((unsigned short *)FreeImage_GetTagValue(tag));
 394			switch (yCbCrPosition) {
 395				case 1:
 396					return "Center of pixel array";
 397				case 2:
 398					return "Datum point";
 399				default:
 400					break;
 401			}
 402		} 
 403		break;
 404
 405		case TAG_EXPOSURE_TIME:
 406		{
 407			FIRational r(tag);
 408			buffer = r.toString();
 409			buffer += " sec";
 410			return buffer.c_str();
 411		}
 412		break;
 413
 414		case TAG_SHUTTER_SPEED_VALUE:
 415		{
 416			FIRational r(tag);
 417			LONG apexValue = r.longValue();
 418			LONG apexPower = 1 << apexValue;
 419			sprintf(format, "1/%d sec", (int)apexPower);
 420			buffer += format;
 421			return buffer.c_str();
 422		}
 423		break;
 424
 425		case TAG_APERTURE_VALUE:
 426		case TAG_MAX_APERTURE_VALUE:
 427		{
 428			FIRational r(tag);
 429			double apertureApex = r.doubleValue();
 430	        double rootTwo = sqrt((double)2);
 431			double fStop = pow(rootTwo, apertureApex);
 432			sprintf(format, "F%.1f", fStop);
 433			buffer += format;
 434			return buffer.c_str();
 435		}
 436		break;
 437
 438		case TAG_FNUMBER:
 439		{
 440			FIRational r(tag);
 441			double fnumber = r.doubleValue();
 442			sprintf(format, "F%.1f", fnumber);
 443			buffer += format;
 444			return buffer.c_str();
 445		}
 446		break;
 447
 448		case TAG_FOCAL_LENGTH:
 449		{
 450			FIRational r(tag);
 451			double focalLength = r.doubleValue();
 452			sprintf(format, "%.1f mm", focalLength);
 453			buffer += format;
 454			return buffer.c_str();
 455		}
 456		break;
 457
 458		case TAG_FOCAL_LENGTH_IN_35MM_FILM:
 459		{
 460			unsigned short focalLength = *((unsigned short *)FreeImage_GetTagValue(tag));
 461			sprintf(format, "%hu mm", focalLength);
 462			buffer += format;
 463			return buffer.c_str();
 464		}
 465		break;
 466
 467		case TAG_FLASH:
 468		{
 469			unsigned short flash = *((unsigned short *)FreeImage_GetTagValue(tag));
 470			switch(flash) {
 471				case 0x0000:
 472					return "Flash did not fire";
 473				case 0x0001:
 474					return "Flash fired";
 475				case 0x0005:
 476					return "Strobe return light not detected";
 477				case 0x0007:
 478					return "Strobe return light detected";
 479				case 0x0009:
 480					return "Flash fired, compulsory flash mode";
 481				case 0x000D:
 482					return "Flash fired, compulsory flash mode, return light not detected";
 483				case 0x000F:
 484					return "Flash fired, compulsory flash mode, return light detected";
 485				case 0x0010:
 486					return "Flash did not fire, compulsory flash mode";
 487				case 0x0018:
 488					return "Flash did not fire, auto mode";
 489				case 0x0019:
 490					return "Flash fired, auto mode";
 491				case 0x001D:
 492					return "Flash fired, auto mode, return light not detected";
 493				case 0x001F:
 494					return "Flash fired, auto mode, return light detected";
 495				case 0x0020:
 496					return "No flash function";
 497				case 0x0041:
 498					return "Flash fired, red-eye reduction mode";
 499				case 0x0045:
 500					return "Flash fired, red-eye reduction mode, return light not detected";
 501				case 0x0047:
 502					return "Flash fired, red-eye reduction mode, return light detected";
 503				case 0x0049:
 504					return "Flash fired, compulsory flash mode, red-eye reduction mode";
 505				case 0x004D:
 506					return "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected";
 507				case 0x004F:
 508					return "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected";
 509				case 0x0059:
 510					return "Flash fired, auto mode, red-eye reduction mode";
 511				case 0x005D:
 512					return "Flash fired, auto mode, return light not detected, red-eye reduction mode";
 513				case 0x005F:
 514					return "Flash fired, auto mode, return light detected, red-eye reduction mode";
 515				default:
 516					sprintf(format, "Unknown (%d)", flash);
 517					buffer += format;
 518					return buffer.c_str();
 519			}
 520		}
 521		break;
 522
 523		case TAG_SCENE_TYPE:
 524		{
 525			BYTE sceneType = *((BYTE*)FreeImage_GetTagValue(tag));
 526			if (sceneType == 1) {
 527				return "Directly photographed image";
 528			} else {
 529				sprintf(format, "Unknown (%d)", sceneType);
 530				buffer += format;
 531				return buffer.c_str();
 532			}
 533		}
 534		break;
 535
 536		case TAG_SUBJECT_DISTANCE:
 537		{
 538			FIRational r(tag);
 539			if(r.getNumerator() == 0xFFFFFFFF) {
 540				return "Infinity";
 541			} else if(r.getNumerator() == 0) {
 542				return "Distance unknown";
 543			} else {
 544				double distance = r.doubleValue();
 545				sprintf(format, "%.3f meters", distance);
 546				buffer += format;
 547				return buffer.c_str();
 548			}
 549		}
 550		break;
 551			
 552		case TAG_METERING_MODE:
 553		{
 554			unsigned short meteringMode = *((unsigned short *)FreeImage_GetTagValue(tag));
 555			switch (meteringMode) {
 556				case 0:
 557					return "Unknown";
 558				case 1:
 559					return "Average";
 560				case 2:
 561					return "Center weighted average";
 562				case 3:
 563					return "Spot";
 564				case 4:
 565					return "Multi-spot";
 566				case 5:
 567					return "Multi-segment";
 568				case 6:
 569					return "Partial";
 570				case 255:
 571					return "(Other)";
 572				default:
 573					return "";
 574			}
 575		}
 576		break;
 577
 578		case TAG_LIGHT_SOURCE:
 579		{
 580			unsigned short lightSource = *((unsigned short *)FreeImage_GetTagValue(tag));
 581			switch (lightSource) {
 582				case 0:
 583					return "Unknown";
 584				case 1:
 585					return "Daylight";
 586				case 2:
 587					return "Fluorescent";
 588				case 3:
 589					return "Tungsten (incandescent light)";
 590				case 4:
 591					return "Flash";
 592				case 9:
 593					return "Fine weather";
 594				case 10:
 595					return "Cloudy weather";
 596				case 11:
 597					return "Shade";
 598				case 12:
 599					return "Daylight fluorescent (D 5700 - 7100K)";
 600				case 13:
 601					return "Day white fluorescent (N 4600 - 5400K)";
 602				case 14:
 603					return "Cool white fluorescent (W 3900 - 4500K)";
 604				case 15:
 605					return "White fluorescent (WW 3200 - 3700K)";
 606				case 17:
 607					return "Standard light A";
 608				case 18:
 609					return "Standard light B";
 610				case 19:
 611					return "Standard light C";
 612				case 20:
 613					return "D55";
 614				case 21:
 615					return "D65";
 616				case 22:
 617					return "D75";
 618				case 23:
 619					return "D50";
 620				case 24:
 621					return "ISO studio tungsten";
 622				case 255:
 623					return "(Other)";
 624				default:
 625					return "";
 626			}
 627		}
 628		break;
 629
 630		case TAG_SENSING_METHOD:
 631		{
 632			unsigned short sensingMethod = *((unsigned short *)FreeImage_GetTagValue(tag));
 633
 634			switch (sensingMethod) {
 635				case 1:
 636					return "(Not defined)";
 637				case 2:
 638					return "One-chip color area sensor";
 639				case 3:
 640					return "Two-chip color area sensor";
 641				case 4:
 642					return "Three-chip color area sensor";
 643				case 5:
 644					return "Color sequential area sensor";
 645				case 7:
 646					return "Trilinear sensor";
 647				case 8:
 648					return "Color sequential linear sensor";
 649				default:
 650					return "";
 651			}
 652		}
 653		break;
 654
 655		case TAG_FILE_SOURCE:
 656		{
 657			BYTE fileSource = *((BYTE*)FreeImage_GetTagValue(tag));
 658			if (fileSource == 3) {
 659				return "Digital Still Camera (DSC)";
 660			} else {
 661				sprintf(format, "Unknown (%d)", fileSource);
 662				buffer += format;
 663				return buffer.c_str();
 664			}
 665        }
 666		break;
 667
 668		case TAG_EXPOSURE_PROGRAM:
 669		{
 670			unsigned short exposureProgram = *((unsigned short *)FreeImage_GetTagValue(tag));
 671
 672			switch (exposureProgram) {
 673				case 1:
 674					return "Manual control";
 675				case 2:
 676					return "Program normal";
 677				case 3:
 678					return "Aperture priority";
 679				case 4:
 680					return "Shutter priority";
 681				case 5:
 682					return "Program creative (slow program)";
 683				case 6:
 684					return "Program action (high-speed program)";
 685				case 7:
 686					return "Portrait mode";
 687				case 8:
 688					return "Landscape mode";
 689				default:
 690					sprintf(format, "Unknown program (%d)", exposureProgram);
 691					buffer += format;
 692					return buffer.c_str();
 693			}
 694		}
 695		break;
 696
 697		case TAG_CUSTOM_RENDERED:
 698		{
 699			unsigned short customRendered = *((unsigned short *)FreeImage_GetTagValue(tag));
 700
 701			switch (customRendered) {
 702				case 0:
 703					return "Normal process";
 704				case 1:
 705					return "Custom process";
 706				default:
 707					sprintf(format, "Unknown rendering (%d)", customRendered);
 708					buffer += format;
 709					return buffer.c_str();
 710			}
 711		}
 712		break;
 713
 714		case TAG_EXPOSURE_MODE:
 715		{
 716			unsigned short exposureMode = *((unsigned short *)FreeImage_GetTagValue(tag));
 717
 718			switch (exposureMode) {
 719				case 0:
 720					return "Auto exposure";
 721				case 1:
 722					return "Manual exposure";
 723				case 2:
 724					return "Auto bracket";
 725				default:
 726					sprintf(format, "Unknown mode (%d)", exposureMode);
 727					buffer += format;
 728					return buffer.c_str();
 729			}
 730		}
 731		break;
 732
 733		case TAG_WHITE_BALANCE:
 734		{
 735			unsigned short whiteBalance = *((unsigned short *)FreeImage_GetTagValue(tag));
 736
 737			switch (whiteBalance) {
 738				case 0:
 739					return "Auto white balance";
 740				case 1:
 741					return "Manual white balance";
 742				default:
 743					sprintf(format, "Unknown (%d)", whiteBalance);
 744					buffer += format;
 745					return buffer.c_str();
 746			}
 747		}
 748		break;
 749
 750		case TAG_SCENE_CAPTURE_TYPE:
 751		{
 752			unsigned short sceneType = *((unsigned short *)FreeImage_GetTagValue(tag));
 753
 754			switch (sceneType) {
 755				case 0:
 756					return "Standard";
 757				case 1:
 758					return "Landscape";
 759				case 2:
 760					return "Portrait";
 761				case 3:
 762					return "Night scene";
 763				default:
 764					sprintf(format, "Unknown (%d)", sceneType);
 765					buffer += format;
 766					return buffer.c_str();
 767			}
 768		}
 769		break;
 770
 771		case TAG_GAIN_CONTROL:
 772		{
 773			unsigned short gainControl = *((unsigned short *)FreeImage_GetTagValue(tag));
 774
 775			switch (gainControl) {
 776				case 0:
 777					return "None";
 778				case 1:
 779					return "Low gain up";
 780				case 2:
 781					return "High gain up";
 782				case 3:
 783					return "Low gain down";
 784				case 4:
 785					return "High gain down";
 786				default:
 787					sprintf(format, "Unknown (%d)", gainControl);
 788					buffer += format;
 789					return buffer.c_str();
 790			}
 791		}
 792		break;
 793
 794		case TAG_CONTRAST:
 795		{
 796			unsigned short contrast = *((unsigned short *)FreeImage_GetTagValue(tag));
 797
 798			switch (contrast) {
 799				case 0:
 800					return "Normal";
 801				case 1:
 802					return "Soft";
 803				case 2:
 804					return "Hard";
 805				default:
 806					sprintf(format, "Unknown (%d)", contrast);
 807					buffer += format;
 808					return buffer.c_str();
 809			}
 810		}
 811		break;
 812
 813		case TAG_SATURATION:
 814		{
 815			unsigned short saturation = *((unsigned short *)FreeImage_GetTagValue(tag));
 816
 817			switch (saturation) {
 818				case 0:
 819					return "Normal";
 820				case 1:
 821					return "Low saturation";
 822				case 2:
 823					return "High saturation";
 824				default:
 825					sprintf(format, "Unknown (%d)", saturation);
 826					buffer += format;
 827					return buffer.c_str();
 828			}
 829		}
 830		break;
 831
 832		case TAG_SHARPNESS:
 833		{
 834			unsigned short sharpness = *((unsigned short *)FreeImage_GetTagValue(tag));
 835
 836			switch (sharpness) {
 837				case 0:
 838					return "Normal";
 839				case 1:
 840					return "Soft";
 841				case 2:
 842					return "Hard";
 843				default:
 844					sprintf(format, "Unknown (%d)", sharpness);
 845					buffer += format;
 846					return buffer.c_str();
 847			}
 848		}
 849		break;
 850
 851		case TAG_SUBJECT_DISTANCE_RANGE:
 852		{
 853			unsigned short distanceRange = *((unsigned short *)FreeImage_GetTagValue(tag));
 854
 855			switch (distanceRange) {
 856				case 0:
 857					return "unknown";
 858				case 1:
 859					return "Macro";
 860				case 2:
 861					return "Close view";
 862				case 3:
 863					return "Distant view";
 864				default:
 865					sprintf(format, "Unknown (%d)", distanceRange);
 866					buffer += format;
 867					return buffer.c_str();
 868			}
 869		}
 870		break;
 871
 872		case TAG_ISO_SPEED_RATINGS:
 873		{
 874			unsigned short isoEquiv = *((unsigned short *)FreeImage_GetTagValue(tag));
 875			if (isoEquiv < 50) {
 876				isoEquiv *= 200;
 877			}
 878			sprintf(format, "%d", isoEquiv);
 879			buffer += format;
 880			return buffer.c_str();
 881		}
 882		break;
 883
 884		case TAG_USER_COMMENT:
 885		{
 886			// first 8 bytes are used to define an ID code
 887			// we assume this is an ASCII string
 888			const BYTE *userComment = (BYTE*)FreeImage_GetTagValue(tag);
 889			for(DWORD i = 8; i < FreeImage_GetTagLength(tag); i++) {
 890				buffer += userComment[i];
 891			}
 892			buffer += '\0';
 893			return buffer.c_str();
 894		}
 895		break;
 896
 897		case TAG_COMPRESSION:
 898		{
 899			WORD compression = *((WORD*)FreeImage_GetTagValue(tag));
 900			switch(compression) {
 901				case TAG_COMPRESSION_NONE:
 902					sprintf(format, "dump mode (%d)", compression);
 903					break;
 904				case TAG_COMPRESSION_CCITTRLE:
 905					sprintf(format, "CCITT modified Huffman RLE (%d)", compression);
 906					break;
 907				case TAG_COMPRESSION_CCITTFAX3:
 908					sprintf(format, "CCITT Group 3 fax encoding (%d)", compression);
 909					break;
 910				/*
 911				case TAG_COMPRESSION_CCITT_T4:
 912					sprintf(format, "CCITT T.4 (TIFF 6 name) (%d)", compression);
 913					break;
 914				*/
 915				case TAG_COMPRESSION_CCITTFAX4:
 916					sprintf(format, "CCITT Group 4 fax encoding (%d)", compression);
 917					break;
 918				/*
 919				case TAG_COMPRESSION_CCITT_T6:
 920					sprintf(format, "CCITT T.6 (TIFF 6 name) (%d)", compression);
 921					break;
 922				*/
 923				case TAG_COMPRESSION_LZW:
 924					sprintf(format, "LZW (%d)", compression);
 925					break;
 926				case TAG_COMPRESSION_OJPEG:
 927					sprintf(format, "!6.0 JPEG (%d)", compression);
 928					break;
 929				case TAG_COMPRESSION_JPEG:
 930					sprintf(format, "JPEG (%d)", compression);
 931					break;
 932				case TAG_COMPRESSION_NEXT:
 933					sprintf(format, "NeXT 2-bit RLE (%d)", compression);
 934					break;
 935				case TAG_COMPRESSION_CCITTRLEW:
 936					sprintf(format, "CCITTRLEW (%d)", compression);
 937					break;
 938				case TAG_COMPRESSION_PACKBITS:
 939					sprintf(format, "PackBits Macintosh RLE (%d)", compression);
 940					break;
 941				case TAG_COMPRESSION_THUNDERSCAN:
 942					sprintf(format, "ThunderScan RLE (%d)", compression);
 943					break;
 944				case TAG_COMPRESSION_PIXARFILM:
 945					sprintf(format, "Pixar companded 10bit LZW (%d)", compression);
 946					break;
 947				case TAG_COMPRESSION_PIXARLOG:
 948					sprintf(format, "Pixar companded 11bit ZIP (%d)", compression);
 949					break;
 950				case TAG_COMPRESSION_DEFLATE:
 951					sprintf(format, "Deflate compression (%d)", compression);
 952					break;
 953				case TAG_COMPRESSION_ADOBE_DEFLATE:
 954					sprintf(format, "Adobe Deflate compression (%d)", compression);
 955					break;
 956				case TAG_COMPRESSION_DCS:
 957					sprintf(format, "Kodak DCS encoding (%d)", compression);
 958					break;
 959				case TAG_COMPRESSION_JBIG:
 960					sprintf(format, "ISO JBIG (%d)", compression);
 961					break;
 962				case TAG_COMPRESSION_SGILOG:
 963					sprintf(format, "SGI Log Luminance RLE (%d)", compression);
 964					break;
 965				case TAG_COMPRESSION_SGILOG24:
 966					sprintf(format, "SGI Log 24-bit packed (%d)", compression);
 967					break;
 968				case TAG_COMPRESSION_JP2000:
 969					sprintf(format, "Leadtools JPEG2000 (%d)", compression);
 970					break;
 971				case TAG_COMPRESSION_LZMA:
 972					sprintf(format, "LZMA2 (%d)", compression);
 973					break;
 974				default:
 975					sprintf(format, "Unknown type (%d)", compression);
 976					break;
 977			}
 978
 979			buffer += format;
 980			return buffer.c_str();
 981		}
 982		break;
 983	}
 984
 985	return ConvertAnyTag(tag);
 986}
 987
 988/**
 989Convert a Exif GPS tag to a C string
 990*/
 991static const char* 
 992ConvertExifGPSTag(FITAG *tag) {
 993	char format[MAX_TEXT_EXTENT];
 994	static std::string buffer;
 995
 996	if(!tag)
 997		return NULL;
 998
 999	buffer.erase();
1000
1001	// convert the tag value to a string buffer
1002
1003	switch(FreeImage_GetTagID(tag)) {
1004		case TAG_GPS_LATITUDE:
1005		case TAG_GPS_LONGITUDE:
1006		case TAG_GPS_TIME_STAMP:
1007		{
1008			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
1009			if(FreeImage_GetTagLength(tag) == 24) {
1010				// dd:mm:ss or hh:mm:ss
1011				int dd = 0, mm = 0;
1012				double ss = 0;
1013
1014				// convert to seconds
1015				if(pvalue[1])
1016					ss += ((double)pvalue[0] / (double)pvalue[1]) * 3600;
1017				if(pvalue[3])
1018					ss += ((double)pvalue[2] / (double)pvalue[3]) * 60;
1019				if(pvalue[5])
1020					ss += ((double)pvalue[4] / (double)pvalue[5]);
1021				
1022				// convert to dd:mm:ss.ss
1023				dd = (int)(ss / 3600);
1024				mm = (int)(ss / 60) - dd * 60;
1025				ss = ss - dd * 3600 - mm * 60;
1026
1027				sprintf(format, "%d:%d:%.2f", dd, mm, ss);
1028				buffer += format;
1029				return buffer.c_str();
1030			}
1031		}
1032		break;
1033
1034		case TAG_GPS_VERSION_ID:
1035		case TAG_GPS_LATITUDE_REF:
1036		case TAG_GPS_LONGITUDE_REF:
1037		case TAG_GPS_ALTITUDE_REF:
1038		case TAG_GPS_ALTITUDE:
1039		case TAG_GPS_SATELLITES:
1040		case TAG_GPS_STATUS:
1041		case TAG_GPS_MEASURE_MODE:
1042		case TAG_GPS_DOP:
1043		case TAG_GPS_SPEED_REF:
1044		case TAG_GPS_SPEED:
1045		case TAG_GPS_TRACK_REF:
1046		case TAG_GPS_TRACK:
1047		case TAG_GPS_IMG_DIRECTION_REF:
1048		case TAG_GPS_IMG_DIRECTION:
1049		case TAG_GPS_MAP_DATUM:
1050		case TAG_GPS_DEST_LATITUDE_REF:
1051		case TAG_GPS_DEST_LATITUDE:
1052		case TAG_GPS_DEST_LONGITUDE_REF:
1053		case TAG_GPS_DEST_LONGITUDE:
1054		case TAG_GPS_DEST_BEARING_REF:
1055		case TAG_GPS_DEST_BEARING:
1056		case TAG_GPS_DEST_DISTANCE_REF:
1057		case TAG_GPS_DEST_DISTANCE:
1058		case TAG_GPS_PROCESSING_METHOD:
1059		case TAG_GPS_AREA_INFORMATION:
1060		case TAG_GPS_DATE_STAMP:
1061		case TAG_GPS_DIFFERENTIAL:
1062			break;
1063	}
1064
1065	return ConvertAnyTag(tag);
1066}
1067
1068// ==========================================================
1069// Tag to string conversion function
1070//
1071
1072const char* DLL_CALLCONV 
1073FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make) {
1074	switch(model) {
1075		case FIMD_EXIF_MAIN:
1076		case FIMD_EXIF_EXIF:
1077			return ConvertExifTag(tag);
1078
1079		case FIMD_EXIF_GPS:
1080			return ConvertExifGPSTag(tag);
1081
1082		case FIMD_EXIF_MAKERNOTE:
1083			// We should use the Make string to select an appropriate conversion function
1084			// TO DO ...
1085			break;
1086
1087		case FIMD_EXIF_INTEROP:
1088		default:
1089			break;
1090	}
1091
1092	return ConvertAnyTag(tag);
1093}
1094