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
8 //--------------------------------------------------------------------------
9 #include "jhead.h"
10
11 #include <math.h>
12 #include <ctype.h>
13 #include <utils/Log.h>
14
15 static unsigned char * DirWithThumbnailPtrs;
16 static double FocalplaneXRes;
17 static double FocalplaneUnits;
18 static int ExifImageWidth;
19 static int MotorolaOrder = 0;
20
21 // for fixing the rotation.
22 static void * OrientationPtr[2];
23 static int OrientationNumFormat[2];
24 int NumOrientations = 0;
25
26
27 // Define the line below to turn on poor man's debugging output
28 #undef SUPERDEBUG
29
30 #ifdef SUPERDEBUG
31 #define printf ALOGE
32 #endif
33
34 //--------------------------------------------------------------------------
35 // Table of Jpeg encoding process names
36 static const TagTable_t ProcessTable[] = {
37 { M_SOF0, "Baseline", 0, 0},
38 { M_SOF1, "Extended sequential", 0, 0},
39 { M_SOF2, "Progressive", 0, 0},
40 { M_SOF3, "Lossless", 0, 0},
41 { M_SOF5, "Differential sequential", 0, 0},
42 { M_SOF6, "Differential progressive", 0, 0},
43 { M_SOF7, "Differential lossless", 0, 0},
44 { M_SOF9, "Extended sequential, arithmetic coding", 0, 0},
45 { M_SOF10, "Progressive, arithmetic coding", 0, 0},
46 { M_SOF11, "Lossless, arithmetic coding", 0, 0},
47 { M_SOF13, "Differential sequential, arithmetic coding", 0, 0},
48 { M_SOF14, "Differential progressive, arithmetic coding", 0, 0},
49 { M_SOF15, "Differential lossless, arithmetic coding", 0, 0},
50 };
51
52 #define PROCESS_TABLE_SIZE (sizeof(ProcessTable) / sizeof(TagTable_t))
53
54 // 1 - "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."
55 // 2 - "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."
56 // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
57 // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
58
59 // 5 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual top."
60 // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
61 // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
62 // 8 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual bottom."
63
64 // Note: The descriptions here are the same as the name of the command line
65 // option to pass to jpegtran to right the image
66
67 static const char * OrientTab[9] = {
68 "Undefined",
69 "Normal", // 1
70 "flip horizontal", // left right reversed mirror
71 "rotate 180", // 3
72 "flip vertical", // upside down mirror
73 "transpose", // Flipped about top-left <--> bottom-right axis.
74 "rotate 90", // rotate 90 cw to right it.
75 "transverse", // flipped about top-right <--> bottom-left axis
76 "rotate 270", // rotate 270 to right it.
77 };
78
79 const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
80
81 //--------------------------------------------------------------------------
82 // Describes tag values
83
84 #define TAG_INTEROP_INDEX 0x0001
85 #define TAG_INTEROP_VERSION 0x0002
86 #define TAG_IMAGE_WIDTH 0x0100
87 #define TAG_IMAGE_LENGTH 0x0101
88 #define TAG_BITS_PER_SAMPLE 0x0102
89 #define TAG_COMPRESSION 0x0103
90 #define TAG_PHOTOMETRIC_INTERP 0x0106
91 #define TAG_FILL_ORDER 0x010A
92 #define TAG_DOCUMENT_NAME 0x010D
93 #define TAG_IMAGE_DESCRIPTION 0x010E
94 #define TAG_MAKE 0x010F
95 #define TAG_MODEL 0x0110
96 #define TAG_SRIP_OFFSET 0x0111
97 #define TAG_ORIENTATION 0x0112
98 #define TAG_SAMPLES_PER_PIXEL 0x0115
99 #define TAG_ROWS_PER_STRIP 0x0116
100 #define TAG_STRIP_BYTE_COUNTS 0x0117
101 #define TAG_X_RESOLUTION 0x011A
102 #define TAG_Y_RESOLUTION 0x011B
103 #define TAG_PLANAR_CONFIGURATION 0x011C
104 #define TAG_RESOLUTION_UNIT 0x0128
105 #define TAG_TRANSFER_FUNCTION 0x012D
106 #define TAG_SOFTWARE 0x0131
107 #define TAG_DATETIME 0x0132
108 #define TAG_ARTIST 0x013B
109 #define TAG_WHITE_POINT 0x013E
110 #define TAG_PRIMARY_CHROMATICITIES 0x013F
111 #define TAG_TRANSFER_RANGE 0x0156
112 #define TAG_JPEG_PROC 0x0200
113 #define TAG_THUMBNAIL_OFFSET 0x0201
114 #define TAG_THUMBNAIL_LENGTH 0x0202
115 #define TAG_Y_CB_CR_COEFFICIENTS 0x0211
116 #define TAG_Y_CB_CR_SUB_SAMPLING 0x0212
117 #define TAG_Y_CB_CR_POSITIONING 0x0213
118 #define TAG_REFERENCE_BLACK_WHITE 0x0214
119 #define TAG_RELATED_IMAGE_WIDTH 0x1001
120 #define TAG_RELATED_IMAGE_LENGTH 0x1002
121 #define TAG_CFA_REPEAT_PATTERN_DIM 0x828D
122 #define TAG_CFA_PATTERN1 0x828E
123 #define TAG_BATTERY_LEVEL 0x828F
124 #define TAG_COPYRIGHT 0x8298
125 #define TAG_EXPOSURETIME 0x829A
126 #define TAG_FNUMBER 0x829D
127 #define TAG_IPTC_NAA 0x83BB
128 #define TAG_EXIF_OFFSET 0x8769
129 #define TAG_INTER_COLOR_PROFILE 0x8773
130 #define TAG_EXPOSURE_PROGRAM 0x8822
131 #define TAG_SPECTRAL_SENSITIVITY 0x8824
132 #define TAG_GPSINFO 0x8825
133 #define TAG_ISO_EQUIVALENT 0x8827
134 #define TAG_OECF 0x8828
135 #define TAG_EXIF_VERSION 0x9000
136 #define TAG_DATETIME_ORIGINAL 0x9003
137 #define TAG_DATETIME_DIGITIZED 0x9004
138 #define TAG_COMPONENTS_CONFIG 0x9101
139 #define TAG_CPRS_BITS_PER_PIXEL 0x9102
140 #define TAG_SHUTTERSPEED 0x9201
141 #define TAG_APERTURE 0x9202
142 #define TAG_BRIGHTNESS_VALUE 0x9203
143 #define TAG_EXPOSURE_BIAS 0x9204
144 #define TAG_MAXAPERTURE 0x9205
145 #define TAG_SUBJECT_DISTANCE 0x9206
146 #define TAG_METERING_MODE 0x9207
147 #define TAG_LIGHT_SOURCE 0x9208
148 #define TAG_FLASH 0x9209
149 #define TAG_FOCALLENGTH 0x920A
150 #define TAG_MAKER_NOTE 0x927C
151 #define TAG_USERCOMMENT 0x9286
152 #define TAG_SUBSEC_TIME 0x9290
153 #define TAG_SUBSEC_TIME_ORIG 0x9291
154 #define TAG_SUBSEC_TIME_DIG 0x9292
155
156 #define TAG_WINXP_TITLE 0x9c9b // Windows XP - not part of exif standard.
157 #define TAG_WINXP_COMMENT 0x9c9c // Windows XP - not part of exif standard.
158 #define TAG_WINXP_AUTHOR 0x9c9d // Windows XP - not part of exif standard.
159 #define TAG_WINXP_KEYWORDS 0x9c9e // Windows XP - not part of exif standard.
160 #define TAG_WINXP_SUBJECT 0x9c9f // Windows XP - not part of exif standard.
161
162 #define TAG_FLASH_PIX_VERSION 0xA000
163 #define TAG_COLOR_SPACE 0xA001
164 #define TAG_EXIF_IMAGEWIDTH 0xA002
165 #define TAG_EXIF_IMAGELENGTH 0xA003
166 #define TAG_RELATED_AUDIO_FILE 0xA004
167 #define TAG_INTEROP_OFFSET 0xA005
168 #define TAG_FLASH_ENERGY 0xA20B
169 #define TAG_SPATIAL_FREQ_RESP 0xA20C
170 #define TAG_FOCAL_PLANE_XRES 0xA20E
171 #define TAG_FOCAL_PLANE_YRES 0xA20F
172 #define TAG_FOCAL_PLANE_UNITS 0xA210
173 #define TAG_SUBJECT_LOCATION 0xA214
174 #define TAG_EXPOSURE_INDEX 0xA215
175 #define TAG_SENSING_METHOD 0xA217
176 #define TAG_FILE_SOURCE 0xA300
177 #define TAG_SCENE_TYPE 0xA301
178 #define TAG_CFA_PATTERN 0xA302
179 #define TAG_CUSTOM_RENDERED 0xA401
180 #define TAG_EXPOSURE_MODE 0xA402
181 #define TAG_WHITEBALANCE 0xA403
182 #define TAG_DIGITALZOOMRATIO 0xA404
183 #define TAG_FOCALLENGTH_35MM 0xA405
184 #define TAG_SCENE_CAPTURE_TYPE 0xA406
185 #define TAG_GAIN_CONTROL 0xA407
186 #define TAG_CONTRAST 0xA408
187 #define TAG_SATURATION 0xA409
188 #define TAG_SHARPNESS 0xA40A
189 #define TAG_DISTANCE_RANGE 0xA40C
190
191 // TODO: replace the ", 0" values in this table with the correct format, e.g. ", FMT_USHORT"
192 static const TagTable_t TagTable[] = {
193 { TAG_INTEROP_INDEX, "InteropIndex", 0, 0},
194 { TAG_INTEROP_VERSION, "InteropVersion", 0, 0},
195 { TAG_IMAGE_WIDTH, "ImageWidth", FMT_USHORT, 1},
196 { TAG_IMAGE_LENGTH, "ImageLength", FMT_USHORT, 1},
197 { TAG_BITS_PER_SAMPLE, "BitsPerSample", FMT_USHORT, 3},
198 { TAG_COMPRESSION, "Compression", FMT_USHORT, 1},
199 { TAG_PHOTOMETRIC_INTERP, "PhotometricInterpretation", FMT_USHORT, 1},
200 { TAG_FILL_ORDER, "FillOrder", 0, 0},
201 { TAG_DOCUMENT_NAME, "DocumentName", 0, 0},
202 { TAG_IMAGE_DESCRIPTION, "ImageDescription", 0, 0 },
203 { TAG_MAKE, "Make", FMT_STRING, -1},
204 { TAG_MODEL, "Model", FMT_STRING, -1},
205 { TAG_SRIP_OFFSET, "StripOffsets", FMT_USHORT, 1},
206 { TAG_ORIENTATION, "Orientation", FMT_USHORT, 1},
207 { TAG_SAMPLES_PER_PIXEL, "SamplesPerPixel", FMT_USHORT, 3},
208 { TAG_ROWS_PER_STRIP, "RowsPerStrip", FMT_USHORT, 1},
209 { TAG_STRIP_BYTE_COUNTS, "StripByteCounts", FMT_USHORT, 1},
210 { TAG_X_RESOLUTION, "XResolution", FMT_URATIONAL, 1},
211 { TAG_Y_RESOLUTION, "YResolution", FMT_URATIONAL, 1},
212 { TAG_PLANAR_CONFIGURATION, "PlanarConfiguration", FMT_USHORT, 1},
213 { TAG_RESOLUTION_UNIT, "ResolutionUnit", FMT_USHORT, 1},
214 { TAG_TRANSFER_FUNCTION, "TransferFunction", FMT_USHORT, 768},
215 { TAG_SOFTWARE, "Software", FMT_STRING, -1},
216 { TAG_DATETIME, "DateTime", FMT_STRING, 20},
217 { TAG_ARTIST, "Artist", FMT_STRING, -1},
218 { TAG_WHITE_POINT, "WhitePoint", FMT_SRATIONAL, 2},
219 { TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", FMT_SRATIONAL, 6},
220 { TAG_TRANSFER_RANGE, "TransferRange", 0, 0},
221 { TAG_JPEG_PROC, "JPEGProc", 0, 0},
222 { TAG_THUMBNAIL_OFFSET, "ThumbnailOffset", 0, 0},
223 { TAG_THUMBNAIL_LENGTH, "ThumbnailLength", 0, 0},
224 { TAG_Y_CB_CR_COEFFICIENTS, "YCbCrCoefficients", FMT_SRATIONAL, 3},
225 { TAG_Y_CB_CR_SUB_SAMPLING, "YCbCrSubSampling", FMT_USHORT, 2},
226 { TAG_Y_CB_CR_POSITIONING, "YCbCrPositioning", FMT_USHORT, 1},
227 { TAG_REFERENCE_BLACK_WHITE, "ReferenceBlackWhite", FMT_SRATIONAL, 6},
228 { TAG_RELATED_IMAGE_WIDTH, "RelatedImageWidth", 0, 0},
229 { TAG_RELATED_IMAGE_LENGTH, "RelatedImageLength", 0, 0},
230 { TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", 0, 0},
231 { TAG_CFA_PATTERN1, "CFAPattern", 0, 0},
232 { TAG_BATTERY_LEVEL, "BatteryLevel", 0, 0},
233 { TAG_COPYRIGHT, "Copyright", FMT_STRING, -1},
234 { TAG_EXPOSURETIME, "ExposureTime", FMT_SRATIONAL, 1},
235 { TAG_FNUMBER, "FNumber", FMT_SRATIONAL, 1},
236 { TAG_IPTC_NAA, "IPTC/NAA", 0, 0},
237 { TAG_EXIF_OFFSET, "ExifOffset", 0, 0},
238 { TAG_INTER_COLOR_PROFILE, "InterColorProfile", 0, 0},
239 { TAG_EXPOSURE_PROGRAM, "ExposureProgram", FMT_SSHORT, 1},
240 { TAG_SPECTRAL_SENSITIVITY, "SpectralSensitivity", FMT_STRING, -1},
241 { TAG_GPSINFO, "GPS Dir offset", 0, 0},
242 { TAG_ISO_EQUIVALENT, "ISOSpeedRatings", FMT_SSHORT, -1},
243 { TAG_OECF, "OECF", 0, 0},
244 { TAG_EXIF_VERSION, "ExifVersion", FMT_BYTE, 4},
245 { TAG_DATETIME_ORIGINAL, "DateTimeOriginal", FMT_STRING, 20},
246 { TAG_DATETIME_DIGITIZED, "DateTimeDigitized", FMT_STRING, 20},
247 { TAG_COMPONENTS_CONFIG, "ComponentsConfiguration", FMT_BYTE, 4},
248 { TAG_CPRS_BITS_PER_PIXEL, "CompressedBitsPerPixel", FMT_SRATIONAL, 1},
249 { TAG_SHUTTERSPEED, "ShutterSpeedValue", FMT_SRATIONAL, 1},
250 { TAG_APERTURE, "ApertureValue", FMT_URATIONAL, 1},
251 { TAG_BRIGHTNESS_VALUE, "BrightnessValue", FMT_SRATIONAL, 1},
252 { TAG_EXPOSURE_BIAS, "ExposureBiasValue", FMT_SRATIONAL, 1},
253 { TAG_MAXAPERTURE, "MaxApertureValue", FMT_URATIONAL, 1},
254 { TAG_SUBJECT_DISTANCE, "SubjectDistance", FMT_URATIONAL, 1},
255 { TAG_METERING_MODE, "MeteringMode", FMT_USHORT, 1},
256 { TAG_LIGHT_SOURCE, "LightSource", FMT_USHORT, 1},
257 { TAG_FLASH, "Flash", FMT_USHORT, 1},
258 { TAG_FOCALLENGTH, "FocalLength", FMT_URATIONAL, 1},
259 { TAG_MAKER_NOTE, "MakerNote", FMT_STRING, -1},
260 { TAG_USERCOMMENT, "UserComment", FMT_STRING, -1},
261 { TAG_SUBSEC_TIME, "SubSecTime", FMT_STRING, -1},
262 { TAG_SUBSEC_TIME_ORIG, "SubSecTimeOriginal", FMT_STRING, -1},
263 { TAG_SUBSEC_TIME_DIG, "SubSecTimeDigitized", FMT_STRING, -1},
264 { TAG_WINXP_TITLE, "Windows-XP Title", 0, 0},
265 { TAG_WINXP_COMMENT, "Windows-XP comment", 0, 0},
266 { TAG_WINXP_AUTHOR, "Windows-XP author", 0, 0},
267 { TAG_WINXP_KEYWORDS, "Windows-XP keywords", 0, 0},
268 { TAG_WINXP_SUBJECT, "Windows-XP subject", 0, 0},
269 { TAG_FLASH_PIX_VERSION, "FlashPixVersion", FMT_BYTE, 4},
270 { TAG_COLOR_SPACE, "ColorSpace", FMT_USHORT, 1},
271 { TAG_EXIF_IMAGEWIDTH, "ExifImageWidth", 0, 0},
272 { TAG_EXIF_IMAGELENGTH, "ExifImageLength", 0, 0},
273 { TAG_RELATED_AUDIO_FILE, "RelatedAudioFile", 0, 0},
274 { TAG_INTEROP_OFFSET, "InteroperabilityOffset", 0, 0},
275 { TAG_FLASH_ENERGY, "FlashEnergy", FMT_URATIONAL, 1},
276 { TAG_SPATIAL_FREQ_RESP, "SpatialFrequencyResponse", FMT_STRING, -1},
277 { TAG_FOCAL_PLANE_XRES, "FocalPlaneXResolution", FMT_URATIONAL, 1},
278 { TAG_FOCAL_PLANE_YRES, "FocalPlaneYResolution", FMT_URATIONAL, 1},
279 { TAG_FOCAL_PLANE_UNITS, "FocalPlaneResolutionUnit", FMT_USHORT, 1},
280 { TAG_SUBJECT_LOCATION, "SubjectLocation", FMT_USHORT, 2},
281 { TAG_EXPOSURE_INDEX, "ExposureIndex", FMT_URATIONAL, 1},
282 { TAG_SENSING_METHOD, "SensingMethod", FMT_USHORT, 1},
283 { TAG_FILE_SOURCE, "FileSource", 0, 1},
284 { TAG_SCENE_TYPE, "SceneType", 0, 1},
285 { TAG_CFA_PATTERN, "CFA Pattern", 0, -1},
286 { TAG_CUSTOM_RENDERED, "CustomRendered", FMT_USHORT, 1},
287 { TAG_EXPOSURE_MODE, "ExposureMode", FMT_USHORT, 1},
288 { TAG_WHITEBALANCE, "WhiteBalance", FMT_USHORT, 1},
289 { TAG_DIGITALZOOMRATIO, "DigitalZoomRatio", FMT_URATIONAL, 1},
290 { TAG_FOCALLENGTH_35MM, "FocalLengthIn35mmFilm", FMT_USHORT, 1},
291 { TAG_SCENE_CAPTURE_TYPE, "SceneCaptureType", FMT_USHORT, 1},
292 { TAG_GAIN_CONTROL, "GainControl", FMT_URATIONAL, 1},
293 { TAG_CONTRAST, "Contrast", FMT_USHORT, 1},
294 { TAG_SATURATION, "Saturation", FMT_USHORT, 1},
295 { TAG_SHARPNESS, "Sharpness", FMT_USHORT, 1},
296 { TAG_DISTANCE_RANGE, "SubjectDistanceRange", FMT_USHORT, 1},
297 } ;
298
299 #define TAG_TABLE_SIZE (sizeof(TagTable) / sizeof(TagTable_t))
300
TagNameToValue(const char * tagName)301 int TagNameToValue(const char* tagName)
302 {
303 unsigned int i;
304 for (i = 0; i < TAG_TABLE_SIZE; i++) {
305 if (strcmp(TagTable[i].Desc, tagName) == 0) {
306 printf("found tag %s val %d", TagTable[i].Desc, TagTable[i].Tag);
307 return TagTable[i].Tag;
308 }
309 }
310 printf("tag %s NOT FOUND", tagName);
311 return -1;
312 }
313
IsDateTimeTag(unsigned short tag)314 int IsDateTimeTag(unsigned short tag)
315 {
316 return ((tag == TAG_DATETIME)? TRUE: FALSE);
317 }
318
319 //--------------------------------------------------------------------------
320 // Convert a 16 bit unsigned value to file's native byte order
321 //--------------------------------------------------------------------------
Put16u(void * Short,unsigned short PutValue)322 static void Put16u(void * Short, unsigned short PutValue)
323 {
324 if (MotorolaOrder){
325 ((uchar *)Short)[0] = (uchar)(PutValue>>8);
326 ((uchar *)Short)[1] = (uchar)PutValue;
327 }else{
328 ((uchar *)Short)[0] = (uchar)PutValue;
329 ((uchar *)Short)[1] = (uchar)(PutValue>>8);
330 }
331 }
332
333 //--------------------------------------------------------------------------
334 // Convert a 16 bit unsigned value from file's native byte order
335 //--------------------------------------------------------------------------
Get16u(void * Short)336 int Get16u(void * Short)
337 {
338 if (MotorolaOrder){
339 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
340 }else{
341 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
342 }
343 }
344
345 //--------------------------------------------------------------------------
346 // Convert a 32 bit signed value from file's native byte order
347 //--------------------------------------------------------------------------
Get32s(void * Long)348 int Get32s(void * Long)
349 {
350 if (MotorolaOrder){
351 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
352 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
353 }else{
354 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
355 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
356 }
357 }
358
359 //--------------------------------------------------------------------------
360 // Convert a 32 bit unsigned value to file's native byte order
361 //--------------------------------------------------------------------------
Put32u(void * Value,unsigned PutValue)362 void Put32u(void * Value, unsigned PutValue)
363 {
364 if (MotorolaOrder){
365 ((uchar *)Value)[0] = (uchar)(PutValue>>24);
366 ((uchar *)Value)[1] = (uchar)(PutValue>>16);
367 ((uchar *)Value)[2] = (uchar)(PutValue>>8);
368 ((uchar *)Value)[3] = (uchar)PutValue;
369 }else{
370 ((uchar *)Value)[0] = (uchar)PutValue;
371 ((uchar *)Value)[1] = (uchar)(PutValue>>8);
372 ((uchar *)Value)[2] = (uchar)(PutValue>>16);
373 ((uchar *)Value)[3] = (uchar)(PutValue>>24);
374 }
375 }
376
377 //--------------------------------------------------------------------------
378 // Convert a 32 bit unsigned value from file's native byte order
379 //--------------------------------------------------------------------------
Get32u(void * Long)380 unsigned Get32u(void * Long)
381 {
382 return (unsigned)Get32s(Long) & 0xffffffff;
383 }
384
385 //--------------------------------------------------------------------------
386 // Display a number as one of its many formats
387 //--------------------------------------------------------------------------
PrintFormatNumber(void * ValuePtr,int Format,int ByteCount)388 void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount)
389 {
390 int s,n;
391
392 for(n=0;n<16;n++){
393 switch(Format){
394 case FMT_SBYTE:
395 case FMT_BYTE: printf("%02x",*(uchar *)ValuePtr); s=1; break;
396 case FMT_USHORT: printf("%d",Get16u(ValuePtr)); s=2; break;
397 case FMT_ULONG:
398 case FMT_SLONG: printf("%d",Get32s(ValuePtr)); s=4; break;
399 case FMT_SSHORT: printf("%hd",(signed short)Get16u(ValuePtr)); s=2; break;
400 case FMT_URATIONAL:
401 case FMT_SRATIONAL:
402 printf("%d/%d",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
403 s = 8;
404 break;
405
406 case FMT_SINGLE: printf("%f",(double)*(float *)ValuePtr); s=8; break;
407 case FMT_DOUBLE: printf("%f",*(double *)ValuePtr); s=8; break;
408 default:
409 printf("Unknown format %d:", Format);
410 return;
411 }
412 ByteCount -= s;
413 if (ByteCount <= 0) break;
414 printf(", ");
415 ValuePtr = (void *)((char *)ValuePtr + s);
416
417 }
418 if (n >= 16) printf("...");
419 }
420
421
422 //--------------------------------------------------------------------------
423 // Evaluate number, be it int, rational, or float from directory.
424 //--------------------------------------------------------------------------
ConvertAnyFormat(void * ValuePtr,int Format)425 double ConvertAnyFormat(void * ValuePtr, int Format)
426 {
427 double Value;
428 Value = 0;
429
430 switch(Format){
431 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
432 case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
433
434 case FMT_USHORT: Value = Get16u(ValuePtr); break;
435 case FMT_ULONG: Value = Get32u(ValuePtr); break;
436
437 case FMT_URATIONAL:
438 case FMT_SRATIONAL:
439 {
440 int Num,Den;
441 Num = Get32s(ValuePtr);
442 Den = Get32s(4+(char *)ValuePtr);
443 if (Den == 0){
444 Value = 0;
445 }else{
446 Value = (double)Num/Den;
447 }
448 break;
449 }
450
451 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
452 case FMT_SLONG: Value = Get32s(ValuePtr); break;
453
454 // Not sure if this is correct (never seen float used in Exif format)
455 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
456 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
457
458 default:
459 ErrNonfatal("Illegal format code %d",Format,0);
460 }
461 return Value;
462 }
463
464 //--------------------------------------------------------------------------
465 // Convert a double value into a signed or unsigned rational number.
466 //--------------------------------------------------------------------------
float2urat(double value,unsigned int max,unsigned int * numerator,unsigned int * denominator)467 static void float2urat(double value, unsigned int max, unsigned int *numerator,
468 unsigned int *denominator) {
469 if (value <= 0) {
470 *numerator = 0;
471 *denominator = 1;
472 return;
473 }
474
475 if (value > max) {
476 *numerator = max;
477 *denominator = 1;
478 return;
479 }
480
481 // For values less than 1e-9, scale as much as possible
482 if (value < 1e-9) {
483 unsigned int n = (unsigned int)(value * max);
484 if (n == 0) {
485 *numerator = 0;
486 *denominator = 1;
487 } else {
488 *numerator = n;
489 *denominator = max;
490 }
491 return;
492 }
493
494 // Try to use a denominator of 1e9, 1e8, ..., until the numerator fits
495 unsigned int d;
496 for (d = 1000000000; d >= 1; d /= 10) {
497 double s = value * d;
498 if (s <= max) {
499 // Remove the trailing zeros from both.
500 unsigned int n = (unsigned int)s;
501 while (n % 10 == 0 && d >= 10) {
502 n /= 10;
503 d /= 10;
504 }
505 *numerator = n;
506 *denominator = d;
507 return;
508 }
509 }
510
511 // Shouldn't reach here because the denominator 1 should work
512 // above. But just in case.
513 *numerator = 0;
514 *denominator = 1;
515 }
516
ConvertDoubleToURational(double value,unsigned int * numerator,unsigned int * denominator)517 static void ConvertDoubleToURational(double value, unsigned int *numerator,
518 unsigned int *denominator) {
519 float2urat(value, 0xFFFFFFFFU, numerator, denominator);
520 }
521
ConvertDoubleToSRational(double value,int * numerator,int * denominator)522 static void ConvertDoubleToSRational(double value, int *numerator,
523 int *denominator) {
524 int negative = 0;
525
526 if (value < 0) {
527 value = -value;
528 negative = 1;
529 }
530
531 unsigned int n, d;
532 float2urat(value, 0x7FFFFFFFU, &n, &d);
533 *numerator = (int)n;
534 *denominator = (int)d;
535 if (negative) {
536 *numerator = -*numerator;
537 }
538 }
539
540 //--------------------------------------------------------------------------
541 // Process one of the nested EXIF directories.
542 //--------------------------------------------------------------------------
ProcessExifDir(unsigned char * DirStart,unsigned char * OffsetBase,unsigned ExifLength,int NestingLevel)543 static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
544 unsigned ExifLength, int NestingLevel)
545 {
546 int de;
547 int a;
548 int NumDirEntries;
549 unsigned ThumbnailOffset = 0;
550 unsigned ThumbnailSize = 0;
551 char IndentString[25];
552
553 printf("ProcessExifDir");
554 if (NestingLevel > 4){
555 ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
556 return;
557 }
558
559 memset(IndentString, ' ', 25);
560 IndentString[NestingLevel * 4] = '\0';
561
562
563 NumDirEntries = Get16u(DirStart);
564 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
565
566 {
567 unsigned char * DirEnd;
568 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
569 if (DirEnd+4 > (OffsetBase+ExifLength)){
570 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
571 // Version 1.3 of jhead would truncate a bit too much.
572 // This also caught later on as well.
573 }else{
574 ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
575 return;
576 }
577 }
578 if (DumpExifMap){
579 printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
580 }
581
582
583 }
584
585 if (ShowTags){
586 printf("(dir has %d entries)\n",NumDirEntries);
587 }
588
589 for (de=0;de<NumDirEntries;de++){
590 int Tag, Format, Components;
591 unsigned char * ValuePtr;
592 int ByteCount;
593 unsigned char * DirEntry;
594 DirEntry = DIR_ENTRY_ADDR(DirStart, de);
595
596 Tag = Get16u(DirEntry);
597 Format = Get16u(DirEntry+2);
598 Components = Get32u(DirEntry+4);
599
600 if ((Format-1) >= NUM_FORMATS) {
601 // (-1) catches illegal zero case as unsigned underflows to positive large.
602 ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
603 continue;
604 }
605
606 if ((unsigned)Components > 0x10000){
607 ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
608 continue;
609 }
610
611 ByteCount = Components * BytesPerFormat[Format];
612
613 if (ByteCount > 4){
614 unsigned OffsetVal;
615 OffsetVal = Get32u(DirEntry+8);
616 // If its bigger than 4 bytes, the dir entry contains an offset.
617 if (OffsetVal > UINT32_MAX - ByteCount || OffsetVal+ByteCount > ExifLength){
618 // Bogus pointer offset and / or bytecount value
619 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
620 continue;
621 }
622 ValuePtr = OffsetBase+OffsetVal;
623
624 if (OffsetVal > ImageInfo.LargestExifOffset){
625 ImageInfo.LargestExifOffset = OffsetVal;
626 }
627
628 if (DumpExifMap){
629 printf("Map: %05d-%05d: Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
630 }
631 }else{
632 // 4 bytes or less and value is in the dir entry itself
633 ValuePtr = DirEntry+8;
634 }
635
636 if (Tag == TAG_MAKER_NOTE){
637 if (ShowTags){
638 printf("%s Maker note: ",IndentString);
639 }
640 ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
641 continue;
642 }
643
644 if (ShowTags){
645 // Show tag name
646 for (a=0;;a++){
647 if (a >= (int)TAG_TABLE_SIZE){
648 printf("%s", IndentString);
649 printf(" Unknown Tag %04x Value = ", Tag);
650 break;
651 }
652 if (TagTable[a].Tag == Tag){
653 printf("%s", IndentString);
654 printf(" %s = ",TagTable[a].Desc);
655 break;
656 }
657 }
658
659 // Show tag value.
660 switch(Format){
661 case FMT_BYTE:
662 if(ByteCount>1){
663 printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr);
664 }else{
665 PrintFormatNumber(ValuePtr, Format, ByteCount);
666 printf("\n");
667 }
668 break;
669
670 case FMT_UNDEFINED:
671 // Undefined is typically an ascii string.
672
673 case FMT_STRING:
674 // String arrays printed without function call (different from int arrays)
675 {
676 printf("\"%s\"", ValuePtr);
677 // int NoPrint = 0;
678 // printf("\"");
679 // for (a=0;a<ByteCount;a++){
680 // if (ValuePtr[a] >= 32){
681 // putchar(ValuePtr[a]);
682 // NoPrint = 0;
683 // }else{
684 // // Avoiding indicating too many unprintable characters of proprietary
685 // // bits of binary information this program may not know how to parse.
686 // if (!NoPrint && a != ByteCount-1){
687 // putchar('?');
688 // NoPrint = 1;
689 // }
690 // }
691 // }
692 // printf("\"\n");
693 }
694 break;
695
696 default:
697 // Handle arrays of numbers later (will there ever be?)
698 PrintFormatNumber(ValuePtr, Format, ByteCount);
699 printf("\n");
700 }
701 }
702
703 // Extract useful components of tag
704 switch(Tag){
705
706 case TAG_MAKE:
707 strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31);
708 break;
709
710 case TAG_MODEL:
711 strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39);
712 break;
713
714 case TAG_SUBSEC_TIME:
715 strlcpy(ImageInfo.SubSecTime, (char *)ValuePtr, sizeof(ImageInfo.SubSecTime));
716 break;
717
718 case TAG_SUBSEC_TIME_ORIG:
719 strlcpy(ImageInfo.SubSecTimeOrig, (char *)ValuePtr,
720 sizeof(ImageInfo.SubSecTimeOrig));
721 break;
722
723 case TAG_SUBSEC_TIME_DIG:
724 strlcpy(ImageInfo.SubSecTimeDig, (char *)ValuePtr,
725 sizeof(ImageInfo.SubSecTimeDig));
726 break;
727
728 case TAG_DATETIME_DIGITIZED:
729 strlcpy(ImageInfo.DigitizedTime, (char *)ValuePtr,
730 sizeof(ImageInfo.DigitizedTime));
731
732 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
733 ErrNonfatal("More than %d date fields! This is nuts", MAX_DATE_COPIES, 0);
734 break;
735 }
736 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
737 (char *)ValuePtr - (char *)OffsetBase;
738 break;
739
740 case TAG_DATETIME_ORIGINAL:
741 // If we get a DATETIME_ORIGINAL, we use that one.
742 strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
743 // Fallthru...
744
745 case TAG_DATETIME:
746 if (!isdigit(ImageInfo.DateTime[0])){
747 // If we don't already have a DATETIME_ORIGINAL, use whatever
748 // time fields we may have.
749 strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
750 }
751
752 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
753 ErrNonfatal("More than %d date fields! This is nuts", MAX_DATE_COPIES, 0);
754 break;
755 }
756 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
757 (char *)ValuePtr - (char *)OffsetBase;
758 break;
759
760 case TAG_WINXP_COMMENT:
761 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
762 // Already have a comment (probably windows comment), skip this one.
763 if (ShowTags) printf("Windows XP commend and other comment in header\n");
764 break; // Already have a windows comment, skip this one.
765 }
766
767 if (ByteCount > 1){
768 if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
769 memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
770 ImageInfo.CommentWidchars = ByteCount/2;
771 }
772 break;
773
774 case TAG_USERCOMMENT:
775 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
776 // Already have a comment (probably windows comment), skip this one.
777 if (ShowTags) printf("Multiple comments in exif header\n");
778 break; // Already have a windows comment, skip this one.
779 }
780
781 // Comment is often padded with trailing spaces. Remove these first.
782 for (a=ByteCount;;){
783 a--;
784 if ((ValuePtr)[a] == ' '){
785 (ValuePtr)[a] = '\0';
786 }else{
787 break;
788 }
789 if (a == 0) break;
790 }
791
792 // Copy the comment
793 {
794 // We want to set copied comment length (msize) to be the
795 // minimum of:
796 // (1) The space still available in Exif
797 // (2) The given comment length (ByteCount)
798 // (3) MAX_COMMENT_SIZE - 1
799 int msiz = ExifLength - (ValuePtr-OffsetBase);
800 if (msiz > ByteCount) msiz = ByteCount;
801 if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
802 if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
803 for (a = 5; a < 10 && a < msiz; a++) {
804 int c = (ValuePtr)[a];
805 if (c != '\0' && c != ' ') {
806 strncpy(ImageInfo.Comments,
807 (char *)ValuePtr + a, msiz - a);
808 break;
809 }
810 }
811 } else {
812 strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
813 }
814 }
815 break;
816
817 case TAG_FNUMBER:
818 // Simplest way of expressing aperture, so I trust it the most.
819 // (overwrite previously computd value if there is one)
820 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
821 break;
822
823 case TAG_APERTURE:
824 case TAG_MAXAPERTURE:
825 // More relevant info always comes earlier, so only use this field if we don't
826 // have appropriate aperture information yet.
827 if (ImageInfo.ApertureFNumber == 0){
828 ImageInfo.ApertureFNumber
829 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
830 }
831 break;
832
833 case TAG_FOCALLENGTH:
834 // Nice digital cameras actually save the focal length as a function
835 // of how farthey are zoomed in.
836 ImageInfo.FocalLength.num = Get32u(ValuePtr);
837 ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr);
838 break;
839
840 case TAG_SUBJECT_DISTANCE:
841 // Inidcates the distacne the autofocus camera is focused to.
842 // Tends to be less accurate as distance increases.
843 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
844 break;
845
846 case TAG_EXPOSURETIME:
847 // Simplest way of expressing exposure time, so I trust it most.
848 // (overwrite previously computd value if there is one)
849 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
850 break;
851
852 case TAG_SHUTTERSPEED:
853 // More complicated way of expressing exposure time, so only use
854 // this value if we don't already have it from somewhere else.
855 if (ImageInfo.ExposureTime == 0){
856 ImageInfo.ExposureTime
857 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
858 }
859 break;
860
861
862 case TAG_FLASH:
863 ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format);
864 break;
865
866 case TAG_ORIENTATION:
867 if (NumOrientations >= 2){
868 // Can have another orientation tag for the thumbnail, but if there's
869 // a third one, things are stringae.
870 ErrNonfatal("More than two orientation tags!",0,0);
871 break;
872 }
873 OrientationPtr[NumOrientations] = ValuePtr;
874 OrientationNumFormat[NumOrientations] = Format;
875 if (NumOrientations == 0){
876 ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
877 }
878 if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){
879 ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
880 ImageInfo.Orientation = 0;
881 }
882 NumOrientations += 1;
883 break;
884
885 case TAG_EXIF_IMAGELENGTH:
886 case TAG_EXIF_IMAGEWIDTH:
887 // Use largest of height and width to deal with images that have been
888 // rotated to portrait format.
889 a = (int)ConvertAnyFormat(ValuePtr, Format);
890 if (ExifImageWidth < a) ExifImageWidth = a;
891 break;
892
893 case TAG_FOCAL_PLANE_XRES:
894 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
895 break;
896
897 case TAG_FOCAL_PLANE_UNITS:
898 switch((int)ConvertAnyFormat(ValuePtr, Format)){
899 case 1: FocalplaneUnits = 25.4; break; // inch
900 case 2:
901 // According to the information I was using, 2 means meters.
902 // But looking at the Cannon powershot's files, inches is the only
903 // sensible value.
904 FocalplaneUnits = 25.4;
905 break;
906
907 case 3: FocalplaneUnits = 10; break; // centimeter
908 case 4: FocalplaneUnits = 1; break; // millimeter
909 case 5: FocalplaneUnits = .001; break; // micrometer
910 }
911 break;
912
913 case TAG_EXPOSURE_BIAS:
914 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
915 break;
916
917 case TAG_WHITEBALANCE:
918 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
919 break;
920
921 case TAG_LIGHT_SOURCE:
922 ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
923 break;
924
925 case TAG_METERING_MODE:
926 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
927 break;
928
929 case TAG_EXPOSURE_PROGRAM:
930 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
931 break;
932
933 case TAG_EXPOSURE_INDEX:
934 if (ImageInfo.ISOequivalent == 0){
935 // Exposure index and ISO equivalent are often used interchangeably,
936 // so we will do the same in jhead.
937 // http://photography.about.com/library/glossary/bldef_ei.htm
938 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
939 }
940 break;
941
942 case TAG_EXPOSURE_MODE:
943 ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
944 break;
945
946 case TAG_ISO_EQUIVALENT:
947 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
948 break;
949
950 case TAG_DIGITALZOOMRATIO:
951 ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
952 break;
953
954 case TAG_THUMBNAIL_OFFSET:
955 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
956 DirWithThumbnailPtrs = DirStart;
957 break;
958
959 case TAG_THUMBNAIL_LENGTH:
960 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
961 ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase;
962 break;
963
964 case TAG_EXIF_OFFSET:
965 if (ShowTags) printf("%s Exif Dir:",IndentString);
966
967 case TAG_INTEROP_OFFSET:
968 if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s Interop Dir:",IndentString);
969 {
970 unsigned char * SubdirStart;
971 SubdirStart = OffsetBase + Get32u(ValuePtr);
972 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
973 ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
974 }else{
975 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
976 }
977 continue;
978 }
979 break;
980
981 case TAG_GPSINFO:
982 if (ShowTags) printf("%s GPS info dir:",IndentString);
983 {
984 unsigned char * SubdirStart;
985 SubdirStart = OffsetBase + Get32u(ValuePtr);
986 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
987 ErrNonfatal("Illegal GPS directory link",0,0);
988 }else{
989 ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
990 }
991 continue;
992 }
993 break;
994
995 case TAG_FOCALLENGTH_35MM:
996 // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002)
997 // if its present, use it to compute equivalent focal length instead of
998 // computing it from sensor geometry and actual focal length.
999 ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
1000 break;
1001
1002 case TAG_DISTANCE_RANGE:
1003 // Three possible standard values:
1004 // 1 = macro, 2 = close, 3 = distant
1005 ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
1006 break;
1007 }
1008 }
1009
1010
1011 {
1012 // In addition to linking to subdirectories via exif tags,
1013 // there's also a potential link to another directory at the end of each
1014 // directory. this has got to be the result of a committee!
1015 unsigned char * SubdirStart;
1016 unsigned Offset;
1017
1018 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
1019 printf("DirStart %p offset from dirstart %d", DirStart, 2+12*NumDirEntries);
1020 Offset = Get32u(DirStart+2+12*NumDirEntries);
1021 if (Offset){
1022 SubdirStart = OffsetBase + Offset;
1023 if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){
1024 printf("SubdirStart %p OffsetBase %p ExifLength %d Offset %d",
1025 SubdirStart, OffsetBase, ExifLength, Offset);
1026 if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){
1027 // Jhead 1.3 or earlier would crop the whole directory!
1028 // As Jhead produces this form of format incorrectness,
1029 // I'll just let it pass silently
1030 if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
1031 }else{
1032 ErrNonfatal("Illegal subdirectory link",0,0);
1033 }
1034 }else{
1035 if (SubdirStart <= OffsetBase+ExifLength){
1036 if (ShowTags) printf("%s Continued directory ",IndentString);
1037 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
1038 }
1039 }
1040 if (Offset > ImageInfo.LargestExifOffset){
1041 ImageInfo.LargestExifOffset = Offset;
1042 }
1043 }
1044 }else{
1045 // The exif header ends before the last next directory pointer.
1046 }
1047 }
1048
1049 if (ThumbnailOffset){
1050 ImageInfo.ThumbnailAtEnd = FALSE;
1051
1052 if (DumpExifMap){
1053 printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize);
1054 }
1055
1056 if (ThumbnailOffset <= ExifLength){
1057 if (ThumbnailSize > ExifLength-ThumbnailOffset){
1058 // If thumbnail extends past exif header, only save the part that
1059 // actually exists. Canon's EOS viewer utility will do this - the
1060 // thumbnail extracts ok with this hack.
1061 ThumbnailSize = ExifLength-ThumbnailOffset;
1062 if (ShowTags) printf("Thumbnail incorrectly placed in header\n");
1063
1064 }
1065 // The thumbnail pointer appears to be valid. Store it.
1066 ImageInfo.ThumbnailOffset = ThumbnailOffset;
1067 ImageInfo.ThumbnailSize = ThumbnailSize;
1068
1069 if (ShowTags){
1070 printf("Thumbnail size: %d bytes\n",ThumbnailSize);
1071 }
1072 }
1073 }
1074 printf("returning from ProcessExifDir");
1075 }
1076
1077
1078 //--------------------------------------------------------------------------
1079 // Process a EXIF marker
1080 // Describes all the drivel that most digital cameras include...
1081 //--------------------------------------------------------------------------
process_EXIF(unsigned char * ExifSection,unsigned int length)1082 void process_EXIF (unsigned char * ExifSection, unsigned int length)
1083 {
1084 unsigned FirstOffset;
1085
1086 FocalplaneXRes = 0;
1087 FocalplaneUnits = 0;
1088 ExifImageWidth = 0;
1089 NumOrientations = 0;
1090
1091 if (ShowTags){
1092 printf("Exif header %d bytes long\n",length);
1093 }
1094
1095 { // Check the EXIF header component
1096 static uchar ExifHeader[] = "Exif\0\0";
1097 if (memcmp(ExifSection+2, ExifHeader,6)){
1098 ErrNonfatal("Incorrect Exif header",0,0);
1099 return;
1100 }
1101 }
1102
1103 if (memcmp(ExifSection+8,"II",2) == 0){
1104 if (ShowTags) printf("Exif section in Intel order\n");
1105 MotorolaOrder = 0;
1106 }else{
1107 if (memcmp(ExifSection+8,"MM",2) == 0){
1108 if (ShowTags) printf("Exif section in Motorola order\n");
1109 MotorolaOrder = 1;
1110 }else{
1111 ErrNonfatal("Invalid Exif alignment marker.",0,0);
1112 return;
1113 }
1114 }
1115
1116 // Check the next value for correctness.
1117 if (Get16u(ExifSection+10) != 0x2a){
1118 ErrNonfatal("Invalid Exif start (1)",0,0);
1119 return;
1120 }
1121
1122 FirstOffset = Get32u(ExifSection+12);
1123 if (FirstOffset < 8 || FirstOffset+8 >= length) {
1124 ErrNonfatal("Invalid offset of first IFD value: %u", FirstOffset, 0);
1125 return;
1126 }
1127
1128 DirWithThumbnailPtrs = NULL;
1129
1130
1131 // First directory starts 16 bytes in. All offset are relative to 8 bytes in.
1132 ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0);
1133
1134 ImageInfo.ThumbnailAtEnd = ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE;
1135 #ifdef SUPERDEBUG
1136 printf("Thumbnail %s end", (ImageInfo.ThumbnailAtEnd ? "at" : "NOT at"));
1137 #endif
1138 if (DumpExifMap){
1139 unsigned a,b;
1140 printf("Map: %05d- End of exif\n",length-8);
1141 // for (a=0;a<length-8;a+= 10){
1142 // printf("Map: %05d ",a);
1143 // for (b=0;b<10;b++) printf(" %02x",*(ExifSection+8+a+b));
1144 // printf("\n");
1145 // }
1146 for (a = 0; a < length - 8; ++a) {
1147 unsigned char c = *(ExifSection+8+a);
1148 unsigned pc = isprint(c) ? c : ' ';
1149 printf("Map: %4d %02x %c", a, c, pc);
1150 }
1151 }
1152
1153
1154 // Compute the CCD width, in millimeters.
1155 if (FocalplaneXRes != 0){
1156 // Note: With some cameras, its not possible to compute this correctly because
1157 // they don't adjust the indicated focal plane resolution units when using less
1158 // than maximum resolution, so the CCDWidth value comes out too small. Nothing
1159 // that Jhad can do about it - its a camera problem.
1160 ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
1161
1162 if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0
1163 && ImageInfo.FocalLength35mmEquiv == 0){
1164 // Compute 35 mm equivalent focal length based on sensor geometry if we haven't
1165 // already got it explicitly from a tag.
1166 ImageInfo.FocalLength35mmEquiv = (int)(
1167 (double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom
1168 / ImageInfo.CCDWidth * 36 + 0.5);
1169 }
1170 }
1171 }
1172
TagToTagTableEntry(unsigned short tag)1173 static const TagTable_t* TagToTagTableEntry(unsigned short tag)
1174 {
1175 unsigned int i;
1176 for (i = 0; i < TAG_TABLE_SIZE; i++) {
1177 if (TagTable[i].Tag == tag) {
1178 printf("found tag %d", tag);
1179 int format = TagTable[i].Format;
1180 if (format == 0) {
1181 printf("tag %s format not defined ***** YOU MUST ADD THE FORMAT TO THE TagTable in exif.c!!!!", TagTable[i].Desc);
1182 return NULL;
1183 }
1184 return &TagTable[i];
1185 }
1186 }
1187 printf("tag %d NOT FOUND", tag);
1188 return NULL;
1189 }
1190
writeExifTagAndData(int tag,int format,long components,long value,int valueInString,char * Buffer,int * DirIndex,int * DataWriteIndex)1191 static void writeExifTagAndData(int tag,
1192 int format,
1193 long components,
1194 long value,
1195 int valueInString,
1196 char* Buffer,
1197 int* DirIndex,
1198 int* DataWriteIndex) {
1199 void* componentsPosition = NULL; // for saving component position
1200
1201 Put16u(Buffer+ (*DirIndex), tag); // Tag
1202 Put16u(Buffer+(*DirIndex) + 2, format); // Format
1203 if (format == FMT_STRING && components == -1) {
1204 components = strlen((char*)value) + 1; // account for null terminator
1205 if (components & 1) ++components; // no odd lengths
1206 } else if (format == FMT_SSHORT && components == -1) {
1207 // jhead only supports reading one SSHORT anyway
1208 components = 1;
1209 }
1210 if (format == FMT_UNDEFINED && components == -1) {
1211 // check if this UNDEFINED format is actually ASCII (as it usually is)
1212 // if so, we can calculate the size
1213 if(memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0) {
1214 components = sizeof(ExifAsciiPrefix) +
1215 strlen((char*)value + sizeof(ExifAsciiPrefix)) + 1;
1216 if (components & 1) ++components; // no odd lengths
1217 }
1218 }
1219 Put32u(Buffer+(*DirIndex) + 4, components); // Components
1220 componentsPosition = Buffer+(*DirIndex) + 4; // components # can change for lists
1221 printf("# components: %ld", components);
1222 if (format == FMT_STRING) {
1223 // short strings can fit right in the long, otherwise have to
1224 // go in the data area
1225 if (components <= 4) {
1226 strcpy(Buffer+(*DirIndex) + 8, (char*)value);
1227 } else {
1228 Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8); // Pointer
1229 printf("copying value %s to %d", (char*)value, (*DataWriteIndex));
1230 strncpy(Buffer+(*DataWriteIndex), (char*)value, components);
1231 (*DataWriteIndex) += components;
1232 }
1233 } else if ((format == FMT_UNDEFINED) &&
1234 (memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0)) {
1235 // short strings can fit right in the long, otherwise have to
1236 // go in the data area
1237 if (components <= 4) {
1238 memcpy(Buffer+(*DirIndex) + 8, (char*)value, components);
1239 } else {
1240 Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8); // Pointer
1241 printf("copying %s to %d", (char*)value + sizeof(ExifAsciiPrefix), (*DataWriteIndex));
1242 memcpy(Buffer+(*DataWriteIndex), (char*)value, components);
1243 (*DataWriteIndex) += components;
1244 }
1245 } else if (!valueInString) {
1246 Put32u(Buffer+(*DirIndex) + 8, value); // Value
1247 } else {
1248 Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8); // Pointer
1249 // Usually the separator is ',', but sometimes ':' is used, like
1250 // TAG_GPS_TIMESTAMP.
1251 char* curElement = strtok((char*)value, ",:");
1252 int i;
1253
1254 // (components == -1) Need to handle lists with unknown length too
1255 for (i = 0; ((i < components) || (components == -1)) && curElement != NULL; i++) {
1256 #ifdef SUPERDEBUG
1257 printf("processing component %s format %s", curElement, formatStr(format));
1258 #endif
1259 // elements are separated by commas
1260 if (format == FMT_URATIONAL) {
1261 unsigned int numerator;
1262 unsigned int denominator;
1263 char* separator = strchr(curElement, '/');
1264 if (separator) {
1265 numerator = atoi(curElement);
1266 denominator = atoi(separator + 1);
1267 } else {
1268 double value = atof(curElement);
1269 ConvertDoubleToURational(value, &numerator, &denominator);
1270 }
1271 Put32u(Buffer+(*DataWriteIndex), numerator);
1272 Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
1273 (*DataWriteIndex) += 8;
1274 } else if (format == FMT_SRATIONAL) {
1275 int numerator;
1276 int denominator;
1277 char* separator = strchr(curElement, '/');
1278 if (separator) {
1279 numerator = atoi(curElement);
1280 denominator = atoi(separator + 1);
1281 } else {
1282 double value = atof(curElement);
1283 ConvertDoubleToSRational(value, &numerator, &denominator);
1284 }
1285 Put32u(Buffer+(*DataWriteIndex), numerator);
1286 Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
1287 (*DataWriteIndex) += 8;
1288 } else if ((components == -1) && ((format == FMT_USHORT) || (format == FMT_SSHORT))) {
1289 // variable components need to go into data write area
1290 value = atoi(curElement);
1291 Put16u(Buffer+(*DataWriteIndex), value);
1292 (*DataWriteIndex) += 4;
1293 } else {
1294 // TODO: doesn't handle multiple components yet -- if more than one, have to put in data write area.
1295 value = atoi(curElement);
1296 Put32u(Buffer+(*DirIndex) + 8, value); // Value
1297 }
1298 curElement = strtok(NULL, ",:");
1299 }
1300 if (components == -1) Put32u(componentsPosition, i); // update component # for unknowns
1301 }
1302 (*DirIndex) += 12;
1303 }
1304
1305 #ifdef SUPERDEBUG
formatStr(int format)1306 char* formatStr(int format) {
1307 switch (format) {
1308 case FMT_BYTE: return "FMT_BYTE"; break;
1309 case FMT_STRING: return "FMT_STRING"; break;
1310 case FMT_USHORT: return "FMT_USHORT"; break;
1311 case FMT_ULONG: return "FMT_ULONG"; break;
1312 case FMT_URATIONAL: return "FMT_URATIONAL"; break;
1313 case FMT_SBYTE: return "FMT_SBYTE"; break;
1314 case FMT_UNDEFINED: return "FMT_UNDEFINED"; break;
1315 case FMT_SSHORT: return "FMT_SSHORT"; break;
1316 case FMT_SLONG: return "FMT_SLONG"; break;
1317 case FMT_SRATIONAL: return "FMT_SRATIONAL"; break;
1318 case FMT_SINGLE: return "FMT_SINGLE"; break;
1319 case FMT_DOUBLE: return "FMT_SINGLE"; break;
1320 default: return "UNKNOWN";
1321 }
1322 }
1323 #endif
1324
1325 //--------------------------------------------------------------------------
1326 // Create minimal exif header - just date and thumbnail pointers,
1327 // so that date and thumbnail may be filled later.
1328 //--------------------------------------------------------------------------
create_EXIF_internal(ExifElement_t * elements,int exifTagCount,int gpsTagCount,int hasDateTimeTag,char * Buffer)1329 static void create_EXIF_internal(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag, char* Buffer)
1330 {
1331 unsigned short NumEntries;
1332 int DataWriteIndex;
1333 int DirIndex;
1334 int DirExifLink = 0;
1335
1336 #ifdef SUPERDEBUG
1337 ALOGE("create_EXIF %d exif elements, %d gps elements", exifTagCount, gpsTagCount);
1338 #endif
1339
1340 MotorolaOrder = 0;
1341
1342 memcpy(Buffer+2, "Exif\0\0II",8);
1343 Put16u(Buffer+10, 0x2a);
1344
1345 DataWriteIndex = 16;
1346 Put32u(Buffer+12, DataWriteIndex-8); // first IFD offset. Means start 16 bytes in.
1347
1348 {
1349 DirIndex = DataWriteIndex;
1350 NumEntries = 1 + exifTagCount; // the extra is the thumbnail
1351 if (gpsTagCount) {
1352 ++NumEntries; // allow for the GPS info tag
1353 }
1354 if (!hasDateTimeTag) {
1355 // We have to write extra date time tag. The entry number should be
1356 // adjusted.
1357 ++NumEntries;
1358 }
1359 DataWriteIndex += 2 + NumEntries*12 + 4;
1360
1361 Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1362 DirIndex += 2;
1363
1364 // Entries go here...
1365 if (!hasDateTimeTag) {
1366 // Date/time entry
1367 char* dateTime = NULL;
1368 char dateBuf[20];
1369 if (ImageInfo.numDateTimeTags) {
1370 // If we had a pre-existing exif header, use time from that.
1371 dateTime = ImageInfo.DateTime;
1372 } else {
1373 // Oterwise, use the file's timestamp.
1374 FileTimeAsString(dateBuf);
1375 dateTime = dateBuf;
1376 }
1377 writeExifTagAndData(TAG_DATETIME,
1378 FMT_STRING,
1379 20,
1380 (long)(char*)dateBuf,
1381 FALSE,
1382 Buffer,
1383 &DirIndex,
1384 &DataWriteIndex);
1385
1386 }
1387 if (exifTagCount > 0) {
1388 int i;
1389 for (i = 0; i < exifTagCount + gpsTagCount; i++) {
1390 if (elements[i].GpsTag) {
1391 continue;
1392 }
1393 const TagTable_t* entry = TagToTagTableEntry(elements[i].Tag);
1394 if (entry == NULL) {
1395 continue;
1396 }
1397 #ifdef SUPERDEBUG
1398 ALOGE("create_EXIF saving tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
1399 #endif
1400 writeExifTagAndData(elements[i].Tag,
1401 entry->Format,
1402 entry->DataLength,
1403 (long)elements[i].Value,
1404 TRUE,
1405 Buffer,
1406 &DirIndex,
1407 &DataWriteIndex);
1408 }
1409
1410 if (gpsTagCount) {
1411 // Link to gps dir entry
1412 writeExifTagAndData(TAG_GPSINFO,
1413 FMT_ULONG,
1414 1,
1415 DataWriteIndex-8,
1416 FALSE,
1417 Buffer,
1418 &DirIndex,
1419 &DataWriteIndex);
1420 }
1421
1422 // Link to exif dir entry
1423 int exifDirPtr = DataWriteIndex-8;
1424 if (gpsTagCount) {
1425 exifDirPtr += 2 + gpsTagCount*12 + 4;
1426 }
1427 DirExifLink = DirIndex;
1428 writeExifTagAndData(TAG_EXIF_OFFSET,
1429 FMT_ULONG,
1430 1,
1431 exifDirPtr,
1432 FALSE,
1433 Buffer,
1434 &DirIndex,
1435 &DataWriteIndex);
1436 }
1437
1438 // End of directory - contains optional link to continued directory.
1439 Put32u(Buffer+DirIndex, 0);
1440 printf("Ending Exif section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1441 }
1442
1443
1444 // GPS Section
1445 if (gpsTagCount) {
1446 DirIndex = DataWriteIndex;
1447 printf("Starting GPS section DirIndex = %d", DirIndex);
1448 NumEntries = gpsTagCount;
1449 DataWriteIndex += 2 + NumEntries*12 + 4;
1450
1451 Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1452 DirIndex += 2;
1453 {
1454 int i;
1455 for (i = 0; i < exifTagCount + gpsTagCount; i++) {
1456 if (!elements[i].GpsTag) {
1457 continue;
1458 }
1459 const TagTable_t* entry = GpsTagToTagTableEntry(elements[i].Tag);
1460 if (entry == NULL) {
1461 continue;
1462 }
1463 #ifdef SUPERDEBUG
1464 ALOGE("create_EXIF saving GPS tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
1465 #endif
1466 writeExifTagAndData(elements[i].Tag,
1467 entry->Format,
1468 entry->DataLength,
1469 (long)elements[i].Value,
1470 TRUE,
1471 Buffer,
1472 &DirIndex,
1473 &DataWriteIndex);
1474 }
1475 }
1476
1477 // End of directory - contains optional link to continued directory.
1478 Put32u(Buffer+DirIndex, 0);
1479 printf("Ending GPS section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1480 }
1481
1482 {
1483 // Overwriting TAG_EXIF_OFFSET which links to this directory
1484 Put32u(Buffer+DirExifLink+8, DataWriteIndex-8);
1485
1486 printf("Starting Thumbnail section DirIndex = %d", DirIndex);
1487 DirIndex = DataWriteIndex;
1488 NumEntries = 2;
1489 DataWriteIndex += 2 + NumEntries*12 + 4;
1490
1491 Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1492 DirIndex += 2;
1493 {
1494 // Link to exif dir entry
1495 writeExifTagAndData(TAG_THUMBNAIL_OFFSET,
1496 FMT_ULONG,
1497 1,
1498 DataWriteIndex-8,
1499 FALSE,
1500 Buffer,
1501 &DirIndex,
1502 &DataWriteIndex);
1503 }
1504
1505 {
1506 // Link to exif dir entry
1507 writeExifTagAndData(TAG_THUMBNAIL_LENGTH,
1508 FMT_ULONG,
1509 1,
1510 0,
1511 FALSE,
1512 Buffer,
1513 &DirIndex,
1514 &DataWriteIndex);
1515 }
1516
1517 // End of directory - contains optional link to continued directory.
1518 Put32u(Buffer+DirIndex, 0);
1519 printf("Ending Thumbnail section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1520 }
1521
1522
1523 Buffer[0] = (unsigned char)(DataWriteIndex >> 8);
1524 Buffer[1] = (unsigned char)DataWriteIndex;
1525
1526 // Remove old exif section, if there was one.
1527 RemoveSectionType(M_EXIF);
1528
1529 {
1530 // Sections need malloced buffers, so do that now, especially because
1531 // we now know how big it needs to be allocated.
1532 unsigned char * NewBuf = malloc(DataWriteIndex);
1533 if (NewBuf == NULL){
1534 ErrFatal("Could not allocate memory");
1535 }
1536 memcpy(NewBuf, Buffer, DataWriteIndex);
1537
1538 CreateSection(M_EXIF, NewBuf, DataWriteIndex);
1539
1540 // Re-parse new exif section, now that its in place
1541 // otherwise, we risk touching data that has already been freed.
1542 process_EXIF(NewBuf, DataWriteIndex);
1543 }
1544 }
1545
create_EXIF(ExifElement_t * elements,int exifTagCount,int gpsTagCount,int hasDateTimeTag)1546 void create_EXIF(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag)
1547 {
1548 // It is hard to calculate exact necessary size for editing the exif
1549 // header dynamically, so we are using the maximum size of EXIF, 64K
1550 const int EXIF_MAX_SIZE = 1024*64;
1551 char* Buffer = malloc(EXIF_MAX_SIZE);
1552
1553 if (Buffer != NULL) {
1554 create_EXIF_internal(elements, exifTagCount, gpsTagCount, hasDateTimeTag, Buffer);
1555 free(Buffer);
1556 } else {
1557 ErrFatal("Could not allocate memory");
1558 }
1559 }
1560
1561 //--------------------------------------------------------------------------
1562 // Cler the rotation tag in the exif header to 1.
1563 //--------------------------------------------------------------------------
ClearOrientation(void)1564 const char * ClearOrientation(void)
1565 {
1566 int a;
1567 if (NumOrientations == 0) return NULL;
1568
1569 for (a=0;a<NumOrientations;a++){
1570 switch(OrientationNumFormat[a]){
1571 case FMT_SBYTE:
1572 case FMT_BYTE:
1573 *(uchar *)(OrientationPtr[a]) = 1;
1574 break;
1575
1576 case FMT_USHORT:
1577 Put16u(OrientationPtr[a], 1);
1578 break;
1579
1580 case FMT_ULONG:
1581 case FMT_SLONG:
1582 memset(OrientationPtr, 0, 4);
1583 // Can't be bothered to write generic Put32 if I only use it once.
1584 if (MotorolaOrder){
1585 ((uchar *)OrientationPtr[a])[3] = 1;
1586 }else{
1587 ((uchar *)OrientationPtr[a])[0] = 1;
1588 }
1589 break;
1590
1591 default:
1592 return NULL;
1593 }
1594 }
1595
1596 return OrientTab[ImageInfo.Orientation];
1597 }
1598
1599
1600
1601 //--------------------------------------------------------------------------
1602 // Remove thumbnail out of the exif image.
1603 //--------------------------------------------------------------------------
RemoveThumbnail(unsigned char * ExifSection)1604 int RemoveThumbnail(unsigned char * ExifSection)
1605 {
1606 if (!DirWithThumbnailPtrs ||
1607 ImageInfo.ThumbnailOffset == 0 ||
1608 ImageInfo.ThumbnailSize == 0){
1609 // No thumbnail, or already deleted it.
1610 return 0;
1611 }
1612 if (ImageInfo.ThumbnailAtEnd == FALSE){
1613 ErrNonfatal("Thumbnail is not at end of header, can't chop it off", 0, 0);
1614 return 0;
1615 }
1616
1617 {
1618 int de;
1619 int NumDirEntries;
1620 NumDirEntries = Get16u(DirWithThumbnailPtrs);
1621
1622 for (de=0;de<NumDirEntries;de++){
1623 int Tag;
1624 unsigned char * DirEntry;
1625 DirEntry = DIR_ENTRY_ADDR(DirWithThumbnailPtrs, de);
1626 Tag = Get16u(DirEntry);
1627 if (Tag == TAG_THUMBNAIL_LENGTH){
1628 // Set length to zero.
1629 if (Get16u(DirEntry+2) != FMT_ULONG){
1630 // non standard format encoding. Can't do it.
1631 ErrNonfatal("Can't remove thumbnail", 0, 0);
1632 return 0;
1633 }
1634 Put32u(DirEntry+8, 0);
1635 }
1636 }
1637 }
1638
1639 // This is how far the non thumbnail data went.
1640 return ImageInfo.ThumbnailOffset+8;
1641
1642 }
1643
1644
1645 //--------------------------------------------------------------------------
1646 // Convert exif time to Unix time structure
1647 //--------------------------------------------------------------------------
Exif2tm(struct tm * timeptr,char * ExifTime)1648 int Exif2tm(struct tm * timeptr, char * ExifTime)
1649 {
1650 int a;
1651
1652 timeptr->tm_wday = -1;
1653
1654 // Check for format: YYYY:MM:DD HH:MM:SS format.
1655 // Date and time normally separated by a space, but also seen a ':' there, so
1656 // skip the middle space with '%*c' so it can be any character.
1657 a = sscanf(ExifTime, "%d%*c%d%*c%d%*c%d:%d:%d",
1658 &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
1659 &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
1660
1661
1662 if (a == 6){
1663 timeptr->tm_isdst = -1;
1664 timeptr->tm_mon -= 1; // Adjust for unix zero-based months
1665 timeptr->tm_year -= 1900; // Adjust for year starting at 1900
1666 return TRUE; // worked.
1667 }
1668
1669 return FALSE; // Wasn't in Exif date format.
1670 }
1671
1672
1673 //--------------------------------------------------------------------------
1674 // Show the collected image info, displaying camera F-stop and shutter speed
1675 // in a consistent and legible fashion.
1676 //--------------------------------------------------------------------------
ShowImageInfo(int ShowFileInfo)1677 void ShowImageInfo(int ShowFileInfo)
1678 {
1679 if (ShowFileInfo){
1680 printf("File name : %s\n",ImageInfo.FileName);
1681 printf("File size : %d bytes\n",ImageInfo.FileSize);
1682
1683 {
1684 char Temp[20];
1685 FileTimeAsString(Temp);
1686 printf("File date : %s\n",Temp);
1687 }
1688 }
1689
1690 if (ImageInfo.CameraMake[0]){
1691 printf("Camera make : %s\n",ImageInfo.CameraMake);
1692 printf("Camera model : %s\n",ImageInfo.CameraModel);
1693 }
1694 if (ImageInfo.DateTime[0]){
1695 printf("Date/Time : %s\n",ImageInfo.DateTime);
1696 }
1697 printf("Resolution : %d x %d\n",ImageInfo.Width, ImageInfo.Height);
1698
1699 if (ImageInfo.Orientation > 1){
1700 // Only print orientation if one was supplied, and if its not 1 (normal orientation)
1701 printf("Orientation : %s\n", OrientTab[ImageInfo.Orientation]);
1702 }
1703
1704 if (ImageInfo.IsColor == 0){
1705 printf("Color/bw : Black and white\n");
1706 }
1707
1708 if (ImageInfo.FlashUsed >= 0){
1709 if (ImageInfo.FlashUsed & 1){
1710 printf("Flash used : Yes");
1711 switch (ImageInfo.FlashUsed){
1712 case 0x5: printf(" (Strobe light not detected)"); break;
1713 case 0x7: printf(" (Strobe light detected) "); break;
1714 case 0x9: printf(" (manual)"); break;
1715 case 0xd: printf(" (manual, return light not detected)"); break;
1716 case 0xf: printf(" (manual, return light detected)"); break;
1717 case 0x19:printf(" (auto)"); break;
1718 case 0x1d:printf(" (auto, return light not detected)"); break;
1719 case 0x1f:printf(" (auto, return light detected)"); break;
1720 case 0x41:printf(" (red eye reduction mode)"); break;
1721 case 0x45:printf(" (red eye reduction mode return light not detected)"); break;
1722 case 0x47:printf(" (red eye reduction mode return light detected)"); break;
1723 case 0x49:printf(" (manual, red eye reduction mode)"); break;
1724 case 0x4d:printf(" (manual, red eye reduction mode, return light not detected)"); break;
1725 case 0x4f:printf(" (red eye reduction mode, return light detected)"); break;
1726 case 0x59:printf(" (auto, red eye reduction mode)"); break;
1727 case 0x5d:printf(" (auto, red eye reduction mode, return light not detected)"); break;
1728 case 0x5f:printf(" (auto, red eye reduction mode, return light detected)"); break;
1729 }
1730 }else{
1731 printf("Flash used : No");
1732 switch (ImageInfo.FlashUsed){
1733 case 0x18:printf(" (auto)"); break;
1734 }
1735 }
1736 printf("\n");
1737 }
1738
1739
1740 if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0) {
1741 printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom);
1742 if (ImageInfo.FocalLength35mmEquiv){
1743 printf(" (35mm equivalent: %dmm)", ImageInfo.FocalLength35mmEquiv);
1744 }
1745 printf("\n");
1746 }
1747
1748 if (ImageInfo.DigitalZoomRatio > 1){
1749 // Digital zoom used. Shame on you!
1750 printf("Digital Zoom : %5.3fx\n", (double)ImageInfo.DigitalZoomRatio);
1751 }
1752
1753 if (ImageInfo.CCDWidth){
1754 printf("CCD width : %4.2fmm\n",(double)ImageInfo.CCDWidth);
1755 }
1756
1757 if (ImageInfo.ExposureTime){
1758 if (ImageInfo.ExposureTime < 0.010){
1759 printf("Exposure time: %6.4f s ",(double)ImageInfo.ExposureTime);
1760 }else{
1761 printf("Exposure time: %5.3f s ",(double)ImageInfo.ExposureTime);
1762 }
1763 if (ImageInfo.ExposureTime <= 0.5){
1764 printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
1765 }
1766 printf("\n");
1767 }
1768 if (ImageInfo.ApertureFNumber){
1769 printf("Aperture : f/%5.3f\n",(double)ImageInfo.ApertureFNumber);
1770 }
1771 if (ImageInfo.Distance){
1772 if (ImageInfo.Distance < 0){
1773 printf("Focus dist. : Infinite\n");
1774 }else{
1775 printf("Focus dist. : %4.2fm\n",(double)ImageInfo.Distance);
1776 }
1777 }
1778
1779 if (ImageInfo.ISOequivalent){
1780 printf("ISO equiv. : %2d\n",(int)ImageInfo.ISOequivalent);
1781 }
1782
1783 if (ImageInfo.ExposureBias){
1784 // If exposure bias was specified, but set to zero, presumably its no bias at all,
1785 // so only show it if its nonzero.
1786 printf("Exposure bias: %4.2f\n",(double)ImageInfo.ExposureBias);
1787 }
1788
1789 switch(ImageInfo.Whitebalance) {
1790 case 1:
1791 printf("Whitebalance : Manual\n");
1792 break;
1793 case 0:
1794 printf("Whitebalance : Auto\n");
1795 break;
1796 }
1797
1798 //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both
1799 switch(ImageInfo.LightSource) {
1800 case 1:
1801 printf("Light Source : Daylight\n");
1802 break;
1803 case 2:
1804 printf("Light Source : Fluorescent\n");
1805 break;
1806 case 3:
1807 printf("Light Source : Incandescent\n");
1808 break;
1809 case 4:
1810 printf("Light Source : Flash\n");
1811 break;
1812 case 9:
1813 printf("Light Source : Fine weather\n");
1814 break;
1815 case 11:
1816 printf("Light Source : Shade\n");
1817 break;
1818 default:; //Quercus: 17-1-2004 There are many more modes for this, check Exif2.2 specs
1819 // If it just says 'unknown' or we don't know it, then
1820 // don't bother showing it - it doesn't add any useful information.
1821 }
1822
1823 if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs
1824 switch(ImageInfo.MeteringMode) {
1825 case 2:
1826 printf("Metering Mode: center weight\n");
1827 break;
1828 case 3:
1829 printf("Metering Mode: spot\n");
1830 break;
1831 case 5:
1832 printf("Metering Mode: matrix\n");
1833 break;
1834 }
1835 }
1836
1837 if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs
1838 switch(ImageInfo.ExposureProgram) {
1839 case 1:
1840 printf("Exposure : Manual\n");
1841 break;
1842 case 2:
1843 printf("Exposure : program (auto)\n");
1844 break;
1845 case 3:
1846 printf("Exposure : aperture priority (semi-auto)\n");
1847 break;
1848 case 4:
1849 printf("Exposure : shutter priority (semi-auto)\n");
1850 break;
1851 case 5:
1852 printf("Exposure : Creative Program (based towards depth of field)\n");
1853 break;
1854 case 6:
1855 printf("Exposure : Action program (based towards fast shutter speed)\n");
1856 break;
1857 case 7:
1858 printf("Exposure : Portrait Mode\n");
1859 break;
1860 case 8:
1861 printf("Exposure : LandscapeMode \n");
1862 break;
1863 default:
1864 break;
1865 }
1866 }
1867 switch(ImageInfo.ExposureMode){
1868 case 0: // Automatic (not worth cluttering up output for)
1869 break;
1870 case 1: printf("Exposure Mode: Manual\n");
1871 break;
1872 case 2: printf("Exposure Mode: Auto bracketing\n");
1873 break;
1874 }
1875
1876 if (ImageInfo.DistanceRange) {
1877 printf("Focus range : ");
1878 switch(ImageInfo.DistanceRange) {
1879 case 1:
1880 printf("macro");
1881 break;
1882 case 2:
1883 printf("close");
1884 break;
1885 case 3:
1886 printf("distant");
1887 break;
1888 }
1889 printf("\n");
1890 }
1891
1892
1893
1894 if (ImageInfo.Process != M_SOF0){
1895 // don't show it if its the plain old boring 'baseline' process, but do
1896 // show it if its something else, like 'progressive' (used on web sometimes)
1897 int a;
1898 for (a=0;;a++){
1899 if (a >= (int)PROCESS_TABLE_SIZE){
1900 // ran off the end of the table.
1901 printf("Jpeg process : Unknown\n");
1902 break;
1903 }
1904 if (ProcessTable[a].Tag == ImageInfo.Process){
1905 printf("Jpeg process : %s\n",ProcessTable[a].Desc);
1906 break;
1907 }
1908 }
1909 }
1910
1911 if (ImageInfo.GpsInfoPresent){
1912 printf("GPS Latitude : %s\n",ImageInfo.GpsLat);
1913 printf("GPS Longitude: %s\n",ImageInfo.GpsLong);
1914 if (ImageInfo.GpsAlt[0]) printf("GPS Altitude : %s\n",ImageInfo.GpsAlt);
1915 }
1916
1917 // Print the comment. Print 'Comment:' for each new line of comment.
1918 if (ImageInfo.Comments[0]){
1919 int a,c;
1920 printf("Comment : ");
1921 if (!ImageInfo.CommentWidchars){
1922 for (a=0;a<MAX_COMMENT_SIZE;a++){
1923 c = ImageInfo.Comments[a];
1924 if (c == '\0') break;
1925 if (c == '\n'){
1926 // Do not start a new line if the string ends with a carriage return.
1927 if (ImageInfo.Comments[a+1] != '\0'){
1928 printf("\nComment : ");
1929 }else{
1930 printf("\n");
1931 }
1932 }else{
1933 putchar(c);
1934 }
1935 }
1936 printf("\n");
1937 }else{
1938 printf("%.*ls\n", ImageInfo.CommentWidchars, (wchar_t *)ImageInfo.Comments);
1939 }
1940 }
1941 if (ImageInfo.ThumbnailOffset){
1942 printf("Map: %05d-%05d: Thumbnail\n",ImageInfo.ThumbnailOffset, ImageInfo.ThumbnailOffset+ImageInfo.ThumbnailSize);
1943 } else {
1944 printf("NO thumbnail");
1945 }
1946 }
1947
1948
1949 //--------------------------------------------------------------------------
1950 // Summarize highlights of image info on one line (suitable for grep-ing)
1951 //--------------------------------------------------------------------------
ShowConciseImageInfo(void)1952 void ShowConciseImageInfo(void)
1953 {
1954 printf("\"%s\"",ImageInfo.FileName);
1955
1956 printf(" %dx%d",ImageInfo.Width, ImageInfo.Height);
1957
1958 if (ImageInfo.ExposureTime){
1959 if (ImageInfo.ExposureTime <= 0.5){
1960 printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
1961 }else{
1962 printf(" (%3.1f)",ImageInfo.ExposureTime);
1963 }
1964 }
1965
1966 if (ImageInfo.ApertureFNumber){
1967 printf(" f/%3.1f",(double)ImageInfo.ApertureFNumber);
1968 }
1969
1970 if (ImageInfo.FocalLength35mmEquiv){
1971 printf(" f(35)=%dmm",ImageInfo.FocalLength35mmEquiv);
1972 }
1973
1974 if (ImageInfo.FlashUsed >= 0 && ImageInfo.FlashUsed & 1){
1975 printf(" (flash)");
1976 }
1977
1978 if (ImageInfo.IsColor == 0){
1979 printf(" (bw)");
1980 }
1981
1982 printf("\n");
1983 }
1984