1 //--------------------------------------------------------------------------
2 // Program to pull the information out of various types of EXIF digital
3 // camera files and show it in a reasonably consistent way
4 //
5 // This module parses the very complicated exif structures.
6 //
7 // Matthias Wandel, Dec 1999 - May 2002
8 //--------------------------------------------------------------------------
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <ctype.h>
16
17
18 #ifdef _WIN32
19 #include <sys/utime.h>
20 #else
21 #include <utime.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <limits.h>
26 #endif
27
28 #include "jhead.h"
29
30 static unsigned char * LastExifRefd;
31 static unsigned char * DirWithThumbnailPtrs;
32 static double FocalplaneXRes;
33 static double FocalplaneUnits;
34 static int ExifImageWidth;
35 static int MotorolaOrder = 0;
36
37 typedef struct {
38 unsigned short Tag;
39 char * Desc;
40 }TagTable_t;
41
42
43 //--------------------------------------------------------------------------
44 // Describes format descriptor
45 static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
46 #define NUM_FORMATS 12
47
48 #define FMT_BYTE 1
49 #define FMT_STRING 2
50 #define FMT_USHORT 3
51 #define FMT_ULONG 4
52 #define FMT_URATIONAL 5
53 #define FMT_SBYTE 6
54 #define FMT_UNDEFINED 7
55 #define FMT_SSHORT 8
56 #define FMT_SLONG 9
57 #define FMT_SRATIONAL 10
58 #define FMT_SINGLE 11
59 #define FMT_DOUBLE 12
60
61 //--------------------------------------------------------------------------
62 // Describes tag values
63
64 #define TAG_EXIF_OFFSET 0x8769
65 #define TAG_INTEROP_OFFSET 0xa005
66
67 #define TAG_MAKE 0x010F
68 #define TAG_MODEL 0x0110
69
70 #define TAG_ORIENTATION 0x0112
71
72 #define TAG_EXPOSURETIME 0x829A
73 #define TAG_FNUMBER 0x829D
74
75 #define TAG_SHUTTERSPEED 0x9201
76 #define TAG_APERTURE 0x9202
77 #define TAG_MAXAPERTURE 0x9205
78 #define TAG_FOCALLENGTH 0x920A
79
80 #define TAG_DATETIME_ORIGINAL 0x9003
81 #define TAG_USERCOMMENT 0x9286
82
83 #define TAG_SUBJECT_DISTANCE 0x9206
84 #define TAG_FLASH 0x9209
85
86 #define TAG_FOCALPLANEXRES 0xa20E
87 #define TAG_FOCALPLANEUNITS 0xa210
88 #define TAG_EXIF_IMAGEWIDTH 0xA002
89 #define TAG_EXIF_IMAGELENGTH 0xA003
90
91 // the following is added 05-jan-2001 vcs
92 #define TAG_EXPOSURE_BIAS 0x9204
93 #define TAG_WHITEBALANCE 0x9208
94 #define TAG_METERING_MODE 0x9207
95 #define TAG_EXPOSURE_PROGRAM 0x8822
96 #define TAG_ISO_EQUIVALENT 0x8827
97 #define TAG_COMPRESSION_LEVEL 0x9102
98
99 #define TAG_THUMBNAIL_OFFSET 0x0201
100 #define TAG_THUMBNAIL_LENGTH 0x0202
101
102 static TagTable_t TagTable[] = {
103 { 0x100, "ImageWidth"},
104 { 0x101, "ImageLength"},
105 { 0x102, "BitsPerSample"},
106 { 0x103, "Compression"},
107 { 0x106, "PhotometricInterpretation"},
108 { 0x10A, "FillOrder"},
109 { 0x10D, "DocumentName"},
110 { 0x10E, "ImageDescription"},
111 { 0x10F, "Make"},
112 { 0x110, "Model"},
113 { 0x111, "StripOffsets"},
114 { 0x112, "Orientation"},
115 { 0x115, "SamplesPerPixel"},
116 { 0x116, "RowsPerStrip"},
117 { 0x117, "StripByteCounts"},
118 { 0x11A, "XResolution"},
119 { 0x11B, "YResolution"},
120 { 0x11C, "PlanarConfiguration"},
121 { 0x128, "ResolutionUnit"},
122 { 0x12D, "TransferFunction"},
123 { 0x131, "Software"},
124 { 0x132, "DateTime"},
125 { 0x13B, "Artist"},
126 { 0x13E, "WhitePoint"},
127 { 0x13F, "PrimaryChromaticities"},
128 { 0x156, "TransferRange"},
129 { 0x200, "JPEGProc"},
130 { 0x201, "ThumbnailOffset"},
131 { 0x202, "ThumbnailLength"},
132 { 0x211, "YCbCrCoefficients"},
133 { 0x212, "YCbCrSubSampling"},
134 { 0x213, "YCbCrPositioning"},
135 { 0x214, "ReferenceBlackWhite"},
136 { 0x828D, "CFARepeatPatternDim"},
137 { 0x828E, "CFAPattern"},
138 { 0x828F, "BatteryLevel"},
139 { 0x8298, "Copyright"},
140 { 0x829A, "ExposureTime"},
141 { 0x829D, "FNumber"},
142 { 0x83BB, "IPTC/NAA"},
143 { 0x8769, "ExifOffset"},
144 { 0x8773, "InterColorProfile"},
145 { 0x8822, "ExposureProgram"},
146 { 0x8824, "SpectralSensitivity"},
147 { 0x8825, "GPSInfo"},
148 { 0x8827, "ISOSpeedRatings"},
149 { 0x8828, "OECF"},
150 { 0x9000, "ExifVersion"},
151 { 0x9003, "DateTimeOriginal"},
152 { 0x9004, "DateTimeDigitized"},
153 { 0x9101, "ComponentsConfiguration"},
154 { 0x9102, "CompressedBitsPerPixel"},
155 { 0x9201, "ShutterSpeedValue"},
156 { 0x9202, "ApertureValue"},
157 { 0x9203, "BrightnessValue"},
158 { 0x9204, "ExposureBiasValue"},
159 { 0x9205, "MaxApertureValue"},
160 { 0x9206, "SubjectDistance"},
161 { 0x9207, "MeteringMode"},
162 { 0x9208, "LightSource"},
163 { 0x9209, "Flash"},
164 { 0x920A, "FocalLength"},
165 { 0x927C, "MakerNote"},
166 { 0x9286, "UserComment"},
167 { 0x9290, "SubSecTime"},
168 { 0x9291, "SubSecTimeOriginal"},
169 { 0x9292, "SubSecTimeDigitized"},
170 { 0xA000, "FlashPixVersion"},
171 { 0xA001, "ColorSpace"},
172 { 0xA002, "ExifImageWidth"},
173 { 0xA003, "ExifImageLength"},
174 { 0xA005, "InteroperabilityOffset"},
175 { 0xA20B, "FlashEnergy"}, // 0x920B in TIFF/EP
176 { 0xA20C, "SpatialFrequencyResponse"}, // 0x920C - -
177 { 0xA20E, "FocalPlaneXResolution"}, // 0x920E - -
178 { 0xA20F, "FocalPlaneYResolution"}, // 0x920F - -
179 { 0xA210, "FocalPlaneResolutionUnit"}, // 0x9210 - -
180 { 0xA214, "SubjectLocation"}, // 0x9214 - -
181 { 0xA215, "ExposureIndex"}, // 0x9215 - -
182 { 0xA217, "SensingMethod"}, // 0x9217 - -
183 { 0xA300, "FileSource"},
184 { 0xA301, "SceneType"},
185 { 0, NULL}
186 } ;
187
188
189 //--------------------------------------------------------------------------
190 // Convert a 16 bit unsigned value from file's native byte order
191 //--------------------------------------------------------------------------
Put16u(void * Short,unsigned short PutValue)192 static void Put16u(void * Short, unsigned short PutValue)
193 {
194 if (MotorolaOrder){
195 ((uchar *)Short)[0] = (uchar)(PutValue>>8);
196 ((uchar *)Short)[1] = (uchar)PutValue;
197 }else{
198 ((uchar *)Short)[0] = (uchar)PutValue;
199 ((uchar *)Short)[1] = (uchar)(PutValue>>8);
200 }
201 }
202
203
204 //--------------------------------------------------------------------------
205 // Convert a 16 bit unsigned value from file's native byte order
206 //--------------------------------------------------------------------------
Get16u(void * Short)207 static int Get16u(void * Short)
208 {
209 if (MotorolaOrder){
210 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
211 }else{
212 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
213 }
214 }
215
216 //--------------------------------------------------------------------------
217 // Convert a 32 bit signed value from file's native byte order
218 //--------------------------------------------------------------------------
Get32s(void * Long)219 static int Get32s(void * Long)
220 {
221 if (MotorolaOrder){
222 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
223 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
224 }else{
225 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
226 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
227 }
228 }
229
230 //--------------------------------------------------------------------------
231 // Convert a 32 bit unsigned value from file's native byte order
232 //--------------------------------------------------------------------------
Get32u(void * Long)233 static unsigned Get32u(void * Long)
234 {
235 return (unsigned)Get32s(Long) & 0xffffffff;
236 }
237
238 //--------------------------------------------------------------------------
239 // Display a number as one of its many formats
240 //--------------------------------------------------------------------------
PrintFormatNumber(void * ValuePtr,int Format,int ByteCount)241 static void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount)
242 {
243 switch(Format){
244 case FMT_SBYTE:
245 case FMT_BYTE: printf("%02x\n",*(uchar *)ValuePtr); break;
246 case FMT_USHORT: printf("%d\n",Get16u(ValuePtr)); break;
247 case FMT_ULONG:
248 case FMT_SLONG: printf("%d\n",Get32s(ValuePtr)); break;
249 case FMT_SSHORT: printf("%hd\n",(signed short)Get16u(ValuePtr)); break;
250 case FMT_URATIONAL:
251 case FMT_SRATIONAL:
252 printf("%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr)); break;
253
254 case FMT_SINGLE: printf("%f\n",(double)*(float *)ValuePtr); break;
255 case FMT_DOUBLE: printf("%f\n",*(double *)ValuePtr); break;
256 default:
257 printf("Unknown format %d:", Format);
258
259 }
260 }
261
262
263 //--------------------------------------------------------------------------
264 // Evaluate number, be it int, rational, or float from directory.
265 //--------------------------------------------------------------------------
ConvertAnyFormat(void * ValuePtr,int Format)266 static double ConvertAnyFormat(void * ValuePtr, int Format)
267 {
268 double Value;
269 Value = 0;
270
271 switch(Format){
272 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
273 case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
274
275 case FMT_USHORT: Value = Get16u(ValuePtr); break;
276 case FMT_ULONG: Value = Get32u(ValuePtr); break;
277
278 case FMT_URATIONAL:
279 case FMT_SRATIONAL:
280 {
281 int Num,Den;
282 Num = Get32s(ValuePtr);
283 Den = Get32s(4+(char *)ValuePtr);
284 if (Den == 0){
285 Value = 0;
286 }else{
287 Value = (double)Num/Den;
288 }
289 break;
290 }
291
292 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
293 case FMT_SLONG: Value = Get32s(ValuePtr); break;
294
295 // Not sure if this is correct (never seen float used in Exif format)
296 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
297 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
298 }
299 return Value;
300 }
301
302 //--------------------------------------------------------------------------
303 // Process one of the nested EXIF directories.
304 //--------------------------------------------------------------------------
ProcessExifDir(unsigned char * DirStart,unsigned char * OffsetBase,unsigned ExifLength)305 static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
306 {
307 int de;
308 int a;
309 int NumDirEntries;
310 unsigned ThumbnailOffset = 0;
311 unsigned ThumbnailSize = 0;
312
313 NumDirEntries = Get16u(DirStart);
314 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
315
316 {
317 unsigned char * DirEnd;
318 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
319 if (DirEnd+4 > (OffsetBase+ExifLength)){
320 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
321 // Version 1.3 of jhead would truncate a bit too much.
322 // This also caught later on as well.
323 }else{
324 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
325 // might trigger this.
326 ErrNonfatal("Illegally sized directory",0,0);
327 return;
328 }
329 }
330 if (DirEnd > LastExifRefd) LastExifRefd = DirEnd;
331 }
332
333 if (ShowTags){
334 printf("Directory with %d entries\n",NumDirEntries);
335 }
336
337 for (de=0;de<NumDirEntries;de++){
338 int Tag, Format, Components;
339 unsigned char * ValuePtr;
340 int ByteCount;
341 char * DirEntry;
342 DirEntry = DIR_ENTRY_ADDR((char*)DirStart, de);
343
344 Tag = Get16u(DirEntry);
345 Format = Get16u(DirEntry+2);
346 Components = Get32u(DirEntry+4);
347
348 if ((Format-1) >= NUM_FORMATS) {
349 // (-1) catches illegal zero case as unsigned underflows to positive large.
350 ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
351 continue;
352 }
353
354 ByteCount = Components * BytesPerFormat[Format];
355
356 if (ByteCount > 4){
357 unsigned OffsetVal;
358 OffsetVal = Get32u(DirEntry+8);
359 // If its bigger than 4 bytes, the dir entry contains an offset.
360 if (OffsetVal+ByteCount > ExifLength){
361 // Bogus pointer offset and / or bytecount value
362 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
363 continue;
364 }
365 ValuePtr = OffsetBase+OffsetVal;
366 }else{
367 // 4 bytes or less and value is in the dir entry itself
368 ValuePtr = (unsigned char*)DirEntry+8;
369 }
370
371 if (LastExifRefd < ValuePtr+ByteCount){
372 // Keep track of last byte in the exif header that was actually referenced.
373 // That way, we know where the discardable thumbnail data begins.
374 LastExifRefd = ValuePtr+ByteCount;
375
376 }
377
378 if (ShowTags){
379 // Show tag name
380 for (a=0;;a++){
381 if (TagTable[a].Tag == 0){
382 printf(" Unknown Tag %04x Value = ", Tag);
383 break;
384 }
385 if (TagTable[a].Tag == Tag){
386 printf(" %s = ",TagTable[a].Desc);
387 break;
388 }
389 }
390
391 // Show tag value.
392 switch(Format){
393
394 case FMT_UNDEFINED:
395 // Undefined is typically an ascii string.
396
397 case FMT_STRING:
398 // String arrays printed without function call (different from int arrays)
399 {
400 int NoPrint = 0;
401 printf("\"");
402 for (a=0;a<ByteCount;a++){
403 if (isprint((ValuePtr)[a])){
404 putchar((ValuePtr)[a]);
405 NoPrint = 0;
406 }else{
407 // Avoiding indicating too many unprintable characters of proprietary
408 // bits of binary information this program may not know how to parse.
409 if (!NoPrint){
410 putchar('?');
411 NoPrint = 1;
412 }
413 }
414 }
415 printf("\"\n");
416 }
417 break;
418
419 default:
420 // Handle arrays of numbers later (will there ever be?)
421 PrintFormatNumber(ValuePtr, Format, ByteCount);
422 }
423 }
424
425 // Extract useful components of tag
426 switch(Tag){
427
428 case TAG_MAKE:
429 strncpy(ImageInfo.CameraMake, (char*)ValuePtr, 31);
430 break;
431
432 case TAG_MODEL:
433 strncpy(ImageInfo.CameraModel, (char*)ValuePtr, 39);
434 break;
435
436 case TAG_DATETIME_ORIGINAL:
437 strncpy(ImageInfo.DateTime, (char*)ValuePtr, 19);
438 ImageInfo.DatePointer = (char*)ValuePtr;
439 break;
440
441 case TAG_USERCOMMENT:
442 // Olympus has this padded with trailing spaces. Remove these first.
443 for (a=ByteCount;;){
444 a--;
445 if ((ValuePtr)[a] == ' '){
446 (ValuePtr)[a] = '\0';
447 }else{
448 break;
449 }
450 if (a == 0) break;
451 }
452
453 // Copy the comment
454 if (memcmp(ValuePtr, "ASCII",5) == 0){
455 for (a=5;a<10;a++){
456 int c;
457 c = (ValuePtr)[a];
458 if (c != '\0' && c != ' '){
459 strncpy(ImageInfo.Comments, a+(char*)ValuePtr, 199);
460 break;
461 }
462 }
463
464 }else{
465 strncpy(ImageInfo.Comments, (char*)ValuePtr, 199);
466 }
467 break;
468
469 case TAG_FNUMBER:
470 // Simplest way of expressing aperture, so I trust it the most.
471 // (overwrite previously computd value if there is one)
472 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
473 break;
474
475 case TAG_APERTURE:
476 case TAG_MAXAPERTURE:
477 // More relevant info always comes earlier, so only use this field if we don't
478 // have appropriate aperture information yet.
479 if (ImageInfo.ApertureFNumber == 0){
480 ImageInfo.ApertureFNumber
481 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
482 }
483 break;
484
485 case TAG_FOCALLENGTH:
486 // Nice digital cameras actually save the focal length as a function
487 // of how farthey are zoomed in.
488 ImageInfo.FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
489 break;
490
491 case TAG_SUBJECT_DISTANCE:
492 // Inidcates the distacne the autofocus camera is focused to.
493 // Tends to be less accurate as distance increases.
494 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
495 break;
496
497 case TAG_EXPOSURETIME:
498 // Simplest way of expressing exposure time, so I trust it most.
499 // (overwrite previously computd value if there is one)
500 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
501 break;
502
503 case TAG_SHUTTERSPEED:
504 // More complicated way of expressing exposure time, so only use
505 // this value if we don't already have it from somewhere else.
506 if (ImageInfo.ExposureTime == 0){
507 ImageInfo.ExposureTime
508 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
509 }
510 break;
511
512 case TAG_FLASH:
513 if (ConvertAnyFormat(ValuePtr, Format)){
514 ImageInfo.FlashUsed = 1;
515 }
516 break;
517
518 case TAG_ORIENTATION:
519 ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
520 if (ImageInfo.Orientation < 1 || ImageInfo.Orientation > 8){
521 ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
522 ImageInfo.Orientation = 0;
523 }
524 break;
525
526 case TAG_EXIF_IMAGELENGTH:
527 case TAG_EXIF_IMAGEWIDTH:
528 // Use largest of height and width to deal with images that have been
529 // rotated to portrait format.
530 a = (int)ConvertAnyFormat(ValuePtr, Format);
531 if (ExifImageWidth < a) ExifImageWidth = a;
532 break;
533
534 case TAG_FOCALPLANEXRES:
535 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
536 break;
537
538 case TAG_FOCALPLANEUNITS:
539 switch((int)ConvertAnyFormat(ValuePtr, Format)){
540 case 1: FocalplaneUnits = 25.4; break; // inch
541 case 2:
542 // According to the information I was using, 2 means meters.
543 // But looking at the Cannon powershot's files, inches is the only
544 // sensible value.
545 FocalplaneUnits = 25.4;
546 break;
547
548 case 3: FocalplaneUnits = 10; break; // centimeter
549 case 4: FocalplaneUnits = 1; break; // milimeter
550 case 5: FocalplaneUnits = .001; break; // micrometer
551 }
552 break;
553
554 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
555
556 case TAG_EXPOSURE_BIAS:
557 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
558 break;
559
560 case TAG_WHITEBALANCE:
561 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
562 break;
563
564 case TAG_METERING_MODE:
565 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
566 break;
567
568 case TAG_EXPOSURE_PROGRAM:
569 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
570 break;
571
572 case TAG_ISO_EQUIVALENT:
573 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
574 if ( ImageInfo.ISOequivalent < 50 ) ImageInfo.ISOequivalent *= 200;
575 break;
576
577 case TAG_COMPRESSION_LEVEL:
578 ImageInfo.CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
579 break;
580
581 case TAG_THUMBNAIL_OFFSET:
582 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
583 DirWithThumbnailPtrs = DirStart;
584 break;
585
586 case TAG_THUMBNAIL_LENGTH:
587 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
588 break;
589
590 case TAG_EXIF_OFFSET:
591 case TAG_INTEROP_OFFSET:
592 {
593 unsigned char * SubdirStart;
594 SubdirStart = OffsetBase + Get32u(ValuePtr);
595 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
596 ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
597 }else{
598 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
599 }
600 continue;
601 }
602 }
603 }
604
605
606 {
607 // In addition to linking to subdirectories via exif tags,
608 // there's also a potential link to another directory at the end of each
609 // directory. this has got to be the result of a comitee!
610 unsigned char * SubdirStart;
611 unsigned Offset;
612
613 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
614 Offset = Get32u(DirStart+2+12*NumDirEntries);
615 if (Offset){
616 SubdirStart = OffsetBase + Offset;
617 if (SubdirStart > OffsetBase+ExifLength){
618 if (SubdirStart < OffsetBase+ExifLength+20){
619 // Jhead 1.3 or earlier would crop the whole directory!
620 // As Jhead produces this form of format incorrectness,
621 // I'll just let it pass silently
622 if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
623 }else{
624 ErrNonfatal("Illegal subdirectory link",0,0);
625 }
626 }else{
627 if (SubdirStart <= OffsetBase+ExifLength){
628 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
629 }
630 }
631 }
632 }else{
633 // The exif header ends before the last next directory pointer.
634 }
635 }
636
637
638 if (ThumbnailSize && ThumbnailOffset){
639 if (ThumbnailSize + ThumbnailOffset <= ExifLength){
640 // The thumbnail pointer appears to be valid. Store it.
641 ImageInfo.ThumbnailPointer = OffsetBase + ThumbnailOffset;
642 ImageInfo.ThumbnailSize = ThumbnailSize;
643
644 if (ShowTags){
645 printf("Thumbnail size: %d bytes\n",ThumbnailSize);
646 }
647 }
648 }
649 }
650
651 //--------------------------------------------------------------------------
652 // Process a EXIF marker
653 // Describes all the drivel that most digital cameras include...
654 //--------------------------------------------------------------------------
process_EXIF(unsigned char * ExifSection,unsigned int length)655 void process_EXIF (unsigned char * ExifSection, unsigned int length)
656 {
657 ImageInfo.FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.
658
659 FocalplaneXRes = 0;
660 FocalplaneUnits = 0;
661 ExifImageWidth = 0;
662
663 if (ShowTags){
664 printf("Exif header %d bytes long\n",length);
665 }
666
667 { // Check the EXIF header component
668 static uchar ExifHeader[] = "Exif\0\0";
669 if (memcmp(ExifSection+2, ExifHeader,6)){
670 ErrNonfatal("Incorrect Exif header",0,0);
671 return;
672 }
673 }
674
675 if (memcmp(ExifSection+8,"II",2) == 0){
676 if (ShowTags) printf("Exif section in Intel order\n");
677 MotorolaOrder = 0;
678 }else{
679 if (memcmp(ExifSection+8,"MM",2) == 0){
680 if (ShowTags) printf("Exif section in Motorola order\n");
681 MotorolaOrder = 1;
682 }else{
683 ErrNonfatal("Invalid Exif alignment marker.",0,0);
684 return;
685 }
686 }
687
688 // Check the next two values for correctness.
689 if (Get16u(ExifSection+10) != 0x2a
690 || Get32u(ExifSection+12) != 0x08){
691 ErrNonfatal("Invalid Exif start (1)",0,0);
692 return;
693 }
694
695 LastExifRefd = ExifSection;
696 DirWithThumbnailPtrs = NULL;
697
698 // First directory starts 16 bytes in. All offset are relative to 8 bytes in.
699 ProcessExifDir(ExifSection+16, ExifSection+8, length-6);
700
701 // Compute the CCD width, in milimeters.
702 if (FocalplaneXRes != 0){
703 ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
704 }
705
706 if (ShowTags){
707 printf("Non settings part of Exif header: %ld bytes\n",
708 ExifSection+length-LastExifRefd);
709 }
710 }
711
712
713
714 //--------------------------------------------------------------------------
715 // Remove thumbnail out of the exif image.
716 //--------------------------------------------------------------------------
RemoveThumbnail(unsigned char * ExifSection,unsigned int Length)717 int RemoveThumbnail(unsigned char * ExifSection, unsigned int Length)
718 {
719
720 // Ensure pointers are up to date.
721 {
722 int ShowTagsTemp = ShowTags;
723 ShowTags = FALSE;
724 process_EXIF(ExifSection, Length);
725 ShowTags = ShowTagsTemp;
726 }
727
728 if (DirWithThumbnailPtrs){
729 int de;
730 int NumDirEntries;
731 NumDirEntries = Get16u(DirWithThumbnailPtrs);
732
733 for (de=0;de<NumDirEntries;de++){
734 int Tag;
735 char * DirEntry;
736 DirEntry = DIR_ENTRY_ADDR((char*)DirWithThumbnailPtrs, de);
737 Tag = Get16u(DirEntry);
738 if (Tag == TAG_THUMBNAIL_OFFSET || Tag == TAG_THUMBNAIL_LENGTH){
739 // We remove data out of the exif directory by doing a memmove on the rest
740 // of the directory to close the gap.
741 // It would of course be far better to have a general purpose read/write
742 // implementation of the filesystem in the exif header, but that would
743 // be quite complicated and therefore very error prone.
744 memmove(DirEntry,
745 DIR_ENTRY_ADDR(DirWithThumbnailPtrs, de+1),
746 (NumDirEntries-de-1)*12+4);
747 NumDirEntries -= 1;
748 de -= 1;
749 }
750 }
751 Put16u(DirWithThumbnailPtrs, (unsigned short)NumDirEntries);
752 }
753
754 // This is how far the non thumbnail data went.
755 return LastExifRefd - ExifSection;
756 }
757
758
759 //--------------------------------------------------------------------------
760 // Convert exif time to Unix time structure
761 //--------------------------------------------------------------------------
Exif2tm(struct tm * timeptr,char * ExifTime)762 int Exif2tm(struct tm * timeptr, char * ExifTime)
763 {
764 int a;
765
766 timeptr->tm_wday = -1;
767
768 // Check for format: YYYY:MM:DD HH:MM:SS format.
769 a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d",
770 &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
771 &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
772
773
774 if (a == 6){
775 timeptr->tm_isdst = -1;
776 timeptr->tm_mon -= 1; // Adjust for unix zero-based months
777 timeptr->tm_year -= 1900; // Adjust for year starting at 1900
778 return TRUE; // worked.
779 }
780
781 return FALSE; // Wasn't in Exif date format.
782 }
783
784 // 1 - "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."
785 // 2 - "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."
786 // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
787 // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
788
789 // 5 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual top."
790 // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
791 // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
792 // 8 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual bottom."
793
794 // Note: The descriptions here are the same as the name of the command line
795 // ption to pass to jpegtran to right the image
796 char * OrientTab[9] = {
797 "Undefined",
798 "Normal", // 1
799 "flip horizontal", // left right reversed mirror
800 "rotate 180", // 3
801 "flip vertical", // upside down mirror
802 "transpose", // Flipped about top-left <--> bottom-right axis.
803 "rotate 90", // rotate 90 cw to right it.
804 "transverse", // flipped about top-right <--> bottom-left axis
805 "rotate 270", // rotate 270 to right it.
806 };
807 int OrientRot[9] = {
808 0, 0, 0, 180, 180, 180, 90, 180, 270
809 };
810
811 #ifdef VERBOSE
812 //--------------------------------------------------------------------------
813 // Show the collected image info, displaying camera F-stop and shutter speed
814 // in a consistent and legible fashion.
815 //--------------------------------------------------------------------------
ShowImageInfo(void)816 void ShowImageInfo(void)
817 {
818 int a;
819 printf("File name : %s\n",ImageInfo.FileName);
820 printf("File size : %d bytes\n",ImageInfo.FileSize);
821
822 {
823 char Temp[20];
824 struct tm ts;
825 ts = *localtime(&ImageInfo.FileDateTime);
826 strftime(Temp, 20, "%Y:%m:%d %H:%M:%S", &ts);
827 printf("File date : %s\n",Temp);
828 }
829
830 if (ImageInfo.CameraMake[0]){
831 printf("Camera make : %s\n",ImageInfo.CameraMake);
832 printf("Camera model : %s\n",ImageInfo.CameraModel);
833 }
834 if (ImageInfo.DateTime[0]){
835 printf("Date/Time : %s\n",ImageInfo.DateTime);
836 }
837 printf("Resolution : %d x %d\n",ImageInfo.Width, ImageInfo.Height);
838
839 if (ImageInfo.Orientation > 1){
840 // Only print orientation if one was supplied, and if its not 1 (normal orientation)
841
842 printf("Orientation : %s\n", OrientTab[ImageInfo.Orientation]);
843 }
844
845 if (ImageInfo.IsColor == 0){
846 printf("Color/bw : Black and white\n");
847 }
848 if (ImageInfo.FlashUsed >= 0){
849 printf("Flash used : %s\n",ImageInfo.FlashUsed ? "Yes" :"No");
850 }
851 if (ImageInfo.FocalLength){
852 printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength);
853 if (ImageInfo.CCDWidth){
854 printf(" (35mm equivalent: %dmm)",
855 (int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*36 + 0.5));
856 }
857 printf("\n");
858 }
859
860 if (ImageInfo.CCDWidth){
861 printf("CCD width : %4.2fmm\n",(double)ImageInfo.CCDWidth);
862 }
863
864 if (ImageInfo.ExposureTime){
865 printf("Exposure time:%6.3f s ",(double)ImageInfo.ExposureTime);
866 if (ImageInfo.ExposureTime <= 0.5){
867 printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
868 }
869 printf("\n");
870 }
871 if (ImageInfo.ApertureFNumber){
872 printf("Aperture : f/%3.1f\n",(double)ImageInfo.ApertureFNumber);
873 }
874 if (ImageInfo.Distance){
875 if (ImageInfo.Distance < 0){
876 printf("Focus dist. : Infinite\n");
877 }else{
878 printf("Focus dist. : %4.2fm\n",(double)ImageInfo.Distance);
879 }
880 }
881
882
883 if (ImageInfo.ISOequivalent){ // 05-jan-2001 vcs
884 printf("ISO equiv. : %2d\n",(int)ImageInfo.ISOequivalent);
885 }
886 if (ImageInfo.ExposureBias){ // 05-jan-2001 vcs
887 printf("Exposure bias:%4.2f\n",(double)ImageInfo.ExposureBias);
888 }
889
890 if (ImageInfo.Whitebalance){ // 05-jan-2001 vcs
891 switch(ImageInfo.Whitebalance) {
892 case 1:
893 printf("Whitebalance : sunny\n");
894 break;
895 case 2:
896 printf("Whitebalance : fluorescent\n");
897 break;
898 case 3:
899 printf("Whitebalance : incandescent\n");
900 break;
901 default:
902 printf("Whitebalance : cloudy\n");
903 }
904 }
905 if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs
906 switch(ImageInfo.MeteringMode) {
907 case 2:
908 printf("Metering Mode: center weight\n");
909 break;
910 case 3:
911 printf("Metering Mode: spot\n");
912 break;
913 case 5:
914 printf("Metering Mode: matrix\n");
915 break;
916 }
917 }
918 if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs
919 switch(ImageInfo.ExposureProgram) {
920 case 2:
921 printf("Exposure : program (auto)\n");
922 break;
923 case 3:
924 printf("Exposure : aperture priority (semi-auto)\n");
925 break;
926 case 4:
927 printf("Exposure : shutter priority (semi-auto)\n");
928 break;
929 }
930 }
931 if (ImageInfo.CompressionLevel){ // 05-jan-2001 vcs
932 switch(ImageInfo.CompressionLevel) {
933 case 1:
934 printf("Jpeg Quality : basic\n");
935 break;
936 case 2:
937 printf("Jpeg Quality : normal\n");
938 break;
939 case 4:
940 printf("Jpeg Quality : fine\n");
941 break;
942 }
943 }
944
945
946
947 for (a=0;;a++){
948 if (ProcessTable[a].Tag == ImageInfo.Process || ProcessTable[a].Tag == 0){
949 printf("Jpeg process : %s\n",ProcessTable[a].Desc);
950 break;
951 }
952 }
953
954
955
956 // Print the comment. Print 'Comment:' for each new line of comment.
957 if (ImageInfo.Comments[0]){
958 int a,c;
959 printf("Comment : ");
960 for (a=0;a<MAX_COMMENT;a++){
961 c = ImageInfo.Comments[a];
962 if (c == '\0') break;
963 if (c == '\n'){
964 // Do not start a new line if the string ends with a carriage return.
965 if (ImageInfo.Comments[a+1] != '\0'){
966 printf("\nComment : ");
967 }else{
968 printf("\n");
969 }
970 }else{
971 putchar(c);
972 }
973 }
974 }
975
976 printf("\n");
977 }
978
979
980 //--------------------------------------------------------------------------
981 // Summarize highlights of image info on one line (suitable for grep-ing)
982 //--------------------------------------------------------------------------
ShowConciseImageInfo(void)983 void ShowConciseImageInfo(void)
984 {
985 printf("\"%s\"",ImageInfo.FileName);
986
987 printf(" %dx%d",ImageInfo.Width, ImageInfo.Height);
988
989 if (ImageInfo.ExposureTime){
990 printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
991 }
992
993 if (ImageInfo.ApertureFNumber){
994 printf(" f/%3.1f",(double)ImageInfo.ApertureFNumber);
995 }
996
997 if (ImageInfo.FocalLength){
998 if (ImageInfo.CCDWidth){
999 // 35 mm equivalent focal length.
1000 printf(" f(35)=%dmm",(int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35 + 0.5));
1001 }
1002 }
1003
1004 if (ImageInfo.FlashUsed > 0){
1005 printf(" (flash)");
1006 }
1007
1008 if (ImageInfo.IsColor == 0){
1009 printf(" (bw)");
1010 }
1011
1012 printf("\n");
1013 }
1014 #endif /* VERBOSE */
1015