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