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 /**
34 Convert a tag to a C string
35 */
36 static const char*
ConvertAnyTag(FITAG * tag)37 ConvertAnyTag(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 			UINT64 *pvalue = (UINT64 *)FreeImage_GetTagValue(tag);
201 
202 			sprintf(format, "%lld", pvalue[0]);
203 			buffer += format;
204 			for(i = 1; i < tag_count; i++) {
205 				sprintf(format, "%lld", pvalue[i]);
206 				buffer += format;
207 			}
208 			break;
209 		}
210 
211 		case FIDT_IFD8:		// N x 64-bit unsigned integer (offset)
212 		{
213 			UINT64 *pvalue = (UINT64 *)FreeImage_GetTagValue(tag);
214 
215 			sprintf(format, "%llX", pvalue[0]);
216 			buffer += format;
217 			for(i = 1; i < tag_count; i++) {
218 				sprintf(format, "%llX", pvalue[i]);
219 				buffer += format;
220 			}
221 			break;
222 		}
223 
224 		case FIDT_SLONG8:	// N x 64-bit signed integer
225 		{
226 			INT64 *pvalue = (INT64 *)FreeImage_GetTagValue(tag);
227 
228 			sprintf(format, "%lld", pvalue[0]);
229 			buffer += format;
230 			for(i = 1; i < tag_count; i++) {
231 				sprintf(format, "%lld", 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 /**
255 Convert a Exif tag to a C string
256 */
257 static const char*
ConvertExifTag(FITAG * tag)258 ConvertExifTag(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 /**
989 Convert a Exif GPS tag to a C string
990 */
991 static const char*
ConvertExifGPSTag(FITAG * tag)992 ConvertExifGPSTag(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 
1072 const char* DLL_CALLCONV
FreeImage_TagToString(FREE_IMAGE_MDMODEL model,FITAG * tag,char * Make)1073 FreeImage_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 
1095