134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Program to pull the information out of various types of EXIF digital
334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// camera files and show it in a reasonably consistent way
434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// This module parses the very complicated exif structures.
634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Matthias Wandel
834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include "jhead.h"
1034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <math.h>
1234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <ctype.h>
1334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <utils/Log.h>
1434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic unsigned char * DirWithThumbnailPtrs;
1634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic double FocalplaneXRes;
1734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic double FocalplaneUnits;
1834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int ExifImageWidth;
1934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int MotorolaOrder = 0;
2034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
2134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// for fixing the rotation.
2234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void * OrientationPtr[2];
2334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int    OrientationNumFormat[2];
2434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint NumOrientations = 0;
2534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
2634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
2734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Define the line below to turn on poor man's debugging output
2834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#undef SUPERDEBUG
2934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
317a314dab81f01bac02d617ffca9dbf7b6cc00700Steve Block#define printf ALOGE
3234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
3334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
3534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Table of Jpeg encoding process names
3634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic const TagTable_t ProcessTable[] = {
3734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF0,   "Baseline", 0, 0},
3834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF1,   "Extended sequential", 0, 0},
3934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF2,   "Progressive", 0, 0},
4034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF3,   "Lossless", 0, 0},
4134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF5,   "Differential sequential", 0, 0},
4234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF6,   "Differential progressive", 0, 0},
4334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF7,   "Differential lossless", 0, 0},
4434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF9,   "Extended sequential, arithmetic coding", 0, 0},
4534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF10,  "Progressive, arithmetic coding", 0, 0},
4634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF11,  "Lossless, arithmetic coding", 0, 0},
4734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF13,  "Differential sequential, arithmetic coding", 0, 0},
4834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF14,  "Differential progressive, arithmetic coding", 0, 0},
4934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { M_SOF15,  "Differential lossless, arithmetic coding", 0, 0},
5034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project};
5134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define PROCESS_TABLE_SIZE  (sizeof(ProcessTable) / sizeof(TagTable_t))
5334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 1 - "The 0th row is at the visual top of the image,    and the 0th column is the visual left-hand side."
5534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 2 - "The 0th row is at the visual top of the image,    and the 0th column is the visual right-hand side."
5634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
5734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
5834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 5 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual top."
6034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
6134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
6234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// 8 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual bottom."
6334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Note: The descriptions here are the same as the name of the command line
6534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// option to pass to jpegtran to right the image
6634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic const char * OrientTab[9] = {
6834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "Undefined",
6934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "Normal",           // 1
7034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "flip horizontal",  // left right reversed mirror
7134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "rotate 180",       // 3
7234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "flip vertical",    // upside down mirror
7334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "transpose",        // Flipped about top-left <--> bottom-right axis.
7434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "rotate 90",        // rotate 90 cw to right it.
7534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "transverse",       // flipped about top-right <--> bottom-left axis
7634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    "rotate 270",       // rotate 270 to right it.
7734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project};
7834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
7934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectconst int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
8034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
8234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Describes tag values
8334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
84d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_INTEROP_INDEX          0x0001
85d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_INTEROP_VERSION        0x0002
86d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_IMAGE_WIDTH            0x0100
87d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_IMAGE_LENGTH           0x0101
88d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_BITS_PER_SAMPLE        0x0102
89d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_COMPRESSION            0x0103
90d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_PHOTOMETRIC_INTERP     0x0106
91d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FILL_ORDER             0x010A
92d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DOCUMENT_NAME          0x010D
93d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_IMAGE_DESCRIPTION      0x010E
94d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_MAKE                   0x010F
95d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_MODEL                  0x0110
96d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SRIP_OFFSET            0x0111
97d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_ORIENTATION            0x0112
98d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SAMPLES_PER_PIXEL      0x0115
99d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_ROWS_PER_STRIP         0x0116
100d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_STRIP_BYTE_COUNTS      0x0117
101d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_X_RESOLUTION           0x011A
102d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_Y_RESOLUTION           0x011B
103d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_PLANAR_CONFIGURATION   0x011C
104d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_RESOLUTION_UNIT        0x0128
105d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_TRANSFER_FUNCTION      0x012D
106d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SOFTWARE               0x0131
107d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DATETIME               0x0132
108d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_ARTIST                 0x013B
109d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WHITE_POINT            0x013E
110d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_PRIMARY_CHROMATICITIES 0x013F
111d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_TRANSFER_RANGE         0x0156
112d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_JPEG_PROC              0x0200
113d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_THUMBNAIL_OFFSET       0x0201
114d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_THUMBNAIL_LENGTH       0x0202
115d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_Y_CB_CR_COEFFICIENTS   0x0211
116d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_Y_CB_CR_SUB_SAMPLING   0x0212
117d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_Y_CB_CR_POSITIONING    0x0213
118d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_REFERENCE_BLACK_WHITE  0x0214
119d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_RELATED_IMAGE_WIDTH    0x1001
120d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_RELATED_IMAGE_LENGTH   0x1002
121d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CFA_REPEAT_PATTERN_DIM 0x828D
122d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CFA_PATTERN1           0x828E
123d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_BATTERY_LEVEL          0x828F
124d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_COPYRIGHT              0x8298
125d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXPOSURETIME           0x829A
126d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FNUMBER                0x829D
127d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_IPTC_NAA               0x83BB
128d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXIF_OFFSET            0x8769
129d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_INTER_COLOR_PROFILE    0x8773
130d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXPOSURE_PROGRAM       0x8822
131d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SPECTRAL_SENSITIVITY   0x8824
132d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_GPSINFO                0x8825
133d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_ISO_EQUIVALENT         0x8827
134d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_OECF                   0x8828
135d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXIF_VERSION           0x9000
136d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DATETIME_ORIGINAL      0x9003
137d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DATETIME_DIGITIZED     0x9004
138d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_COMPONENTS_CONFIG      0x9101
139d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CPRS_BITS_PER_PIXEL    0x9102
140d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SHUTTERSPEED           0x9201
141d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_APERTURE               0x9202
142d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_BRIGHTNESS_VALUE       0x9203
143d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXPOSURE_BIAS          0x9204
144d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_MAXAPERTURE            0x9205
145d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SUBJECT_DISTANCE       0x9206
146d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_METERING_MODE          0x9207
147d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_LIGHT_SOURCE           0x9208
148d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FLASH                  0x9209
149d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FOCALLENGTH            0x920A
150d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_MAKER_NOTE             0x927C
151d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_USERCOMMENT            0x9286
152d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SUBSEC_TIME            0x9290
153d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SUBSEC_TIME_ORIG       0x9291
154d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SUBSEC_TIME_DIG        0x9292
155d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
156d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WINXP_TITLE            0x9c9b // Windows XP - not part of exif standard.
157d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WINXP_COMMENT          0x9c9c // Windows XP - not part of exif standard.
158d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WINXP_AUTHOR           0x9c9d // Windows XP - not part of exif standard.
159d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WINXP_KEYWORDS         0x9c9e // Windows XP - not part of exif standard.
160d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WINXP_SUBJECT          0x9c9f // Windows XP - not part of exif standard.
161d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
162d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FLASH_PIX_VERSION      0xA000
163d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_COLOR_SPACE            0xA001
164d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXIF_IMAGEWIDTH        0xA002
165d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXIF_IMAGELENGTH       0xA003
166d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_RELATED_AUDIO_FILE     0xA004
167d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_INTEROP_OFFSET         0xA005
168d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FLASH_ENERGY           0xA20B
169d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SPATIAL_FREQ_RESP      0xA20C
170d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FOCAL_PLANE_XRES       0xA20E
171d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FOCAL_PLANE_YRES       0xA20F
172d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FOCAL_PLANE_UNITS      0xA210
173d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SUBJECT_LOCATION       0xA214
174d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXPOSURE_INDEX         0xA215
175d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SENSING_METHOD         0xA217
176d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FILE_SOURCE            0xA300
177d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SCENE_TYPE             0xA301
178d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CFA_PATTERN            0xA302
179d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CUSTOM_RENDERED        0xA401
180d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_EXPOSURE_MODE          0xA402
181d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_WHITEBALANCE           0xA403
182d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DIGITALZOOMRATIO       0xA404
183d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_FOCALLENGTH_35MM       0xA405
184d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SCENE_CAPTURE_TYPE     0xA406
185d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_GAIN_CONTROL           0xA407
186d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_CONTRAST               0xA408
187d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SATURATION             0xA409
188d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_SHARPNESS              0xA40A
189d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define TAG_DISTANCE_RANGE         0xA40C
19034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
19134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// TODO: replace the ", 0" values in this table with the correct format, e.g. ", FMT_USHORT"
19234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic const TagTable_t TagTable[] = {
193d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_INTEROP_INDEX,          "InteropIndex", 0, 0},
194d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_INTEROP_VERSION,        "InteropVersion", 0, 0},
195d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_IMAGE_WIDTH,            "ImageWidth", FMT_USHORT, 1},
196d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_IMAGE_LENGTH,           "ImageLength", FMT_USHORT, 1},
197d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_BITS_PER_SAMPLE,        "BitsPerSample", FMT_USHORT, 3},
198d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_COMPRESSION,            "Compression", FMT_USHORT, 1},
199d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_PHOTOMETRIC_INTERP,     "PhotometricInterpretation", FMT_USHORT, 1},
200d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FILL_ORDER,             "FillOrder", 0, 0},
201d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DOCUMENT_NAME,          "DocumentName", 0, 0},
202d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_IMAGE_DESCRIPTION,      "ImageDescription", 0, 0 },
203d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_MAKE,                   "Make", FMT_STRING, -1},
204d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_MODEL,                  "Model", FMT_STRING, -1},
205d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SRIP_OFFSET,            "StripOffsets", FMT_USHORT, 1},
206d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_ORIENTATION,            "Orientation", FMT_USHORT, 1},
207d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SAMPLES_PER_PIXEL,      "SamplesPerPixel", FMT_USHORT, 3},
208d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_ROWS_PER_STRIP,         "RowsPerStrip", FMT_USHORT, 1},
209d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_STRIP_BYTE_COUNTS,      "StripByteCounts", FMT_USHORT, 1},
210d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_X_RESOLUTION,           "XResolution", FMT_URATIONAL, 1},
211d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_Y_RESOLUTION,           "YResolution", FMT_URATIONAL, 1},
212d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_PLANAR_CONFIGURATION,   "PlanarConfiguration", FMT_USHORT, 1},
213d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_RESOLUTION_UNIT,        "ResolutionUnit", FMT_USHORT, 1},
214d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_TRANSFER_FUNCTION,      "TransferFunction", FMT_USHORT, 768},
215d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SOFTWARE,               "Software", FMT_STRING, -1},
216d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DATETIME,               "DateTime", FMT_STRING, 20},
217d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_ARTIST,                 "Artist", FMT_STRING, -1},
218d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WHITE_POINT,            "WhitePoint", FMT_SRATIONAL, 2},
219d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", FMT_SRATIONAL, 6},
220d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_TRANSFER_RANGE,         "TransferRange", 0, 0},
221d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_JPEG_PROC,              "JPEGProc", 0, 0},
222d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_THUMBNAIL_OFFSET,       "ThumbnailOffset", 0, 0},
223d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_THUMBNAIL_LENGTH,       "ThumbnailLength", 0, 0},
224d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_Y_CB_CR_COEFFICIENTS,   "YCbCrCoefficients", FMT_SRATIONAL, 3},
225d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_Y_CB_CR_SUB_SAMPLING,   "YCbCrSubSampling", FMT_USHORT, 2},
226d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_Y_CB_CR_POSITIONING,    "YCbCrPositioning", FMT_USHORT, 1},
227d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_REFERENCE_BLACK_WHITE,  "ReferenceBlackWhite", FMT_SRATIONAL, 6},
228d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_RELATED_IMAGE_WIDTH,    "RelatedImageWidth", 0, 0},
229d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_RELATED_IMAGE_LENGTH,   "RelatedImageLength", 0, 0},
230d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", 0, 0},
231d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CFA_PATTERN1,           "CFAPattern", 0, 0},
232d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_BATTERY_LEVEL,          "BatteryLevel", 0, 0},
233d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_COPYRIGHT,              "Copyright", FMT_STRING, -1},
234754078052c687f6721536009c816644c73e4f145Tyler Luu  { TAG_EXPOSURETIME,           "ExposureTime", FMT_SRATIONAL, 1},
235d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FNUMBER,                "FNumber", FMT_SRATIONAL, 1},
236d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_IPTC_NAA,               "IPTC/NAA", 0, 0},
237d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXIF_OFFSET,            "ExifOffset", 0, 0},
238d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_INTER_COLOR_PROFILE,    "InterColorProfile", 0, 0},
239d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXPOSURE_PROGRAM,       "ExposureProgram", FMT_SSHORT, 1},
240d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SPECTRAL_SENSITIVITY,   "SpectralSensitivity", FMT_STRING, -1},
241d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_GPSINFO,                "GPS Dir offset", 0, 0},
242d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_ISO_EQUIVALENT,         "ISOSpeedRatings", FMT_SSHORT, -1},
243d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_OECF,                   "OECF", 0, 0},
244d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXIF_VERSION,           "ExifVersion", FMT_BYTE, 4},
245d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DATETIME_ORIGINAL,      "DateTimeOriginal", FMT_STRING, 20},
246d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DATETIME_DIGITIZED,     "DateTimeDigitized", FMT_STRING, 20},
247d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_COMPONENTS_CONFIG,      "ComponentsConfiguration", FMT_BYTE, 4},
248d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CPRS_BITS_PER_PIXEL,    "CompressedBitsPerPixel", FMT_SRATIONAL, 1},
249d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SHUTTERSPEED,           "ShutterSpeedValue", FMT_SRATIONAL, 1},
250d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_APERTURE,               "ApertureValue", FMT_URATIONAL, 1},
251d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_BRIGHTNESS_VALUE,       "BrightnessValue", FMT_SRATIONAL, 1},
252d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXPOSURE_BIAS,          "ExposureBiasValue", FMT_SRATIONAL, 1},
253d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_MAXAPERTURE,            "MaxApertureValue", FMT_URATIONAL, 1},
254d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SUBJECT_DISTANCE,       "SubjectDistance", FMT_URATIONAL, 1},
255d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_METERING_MODE,          "MeteringMode", FMT_USHORT, 1},
256d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_LIGHT_SOURCE,           "LightSource", FMT_USHORT, 1},
257d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FLASH,                  "Flash", FMT_USHORT, 1},
258d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FOCALLENGTH,            "FocalLength", FMT_URATIONAL, 1},
259d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_MAKER_NOTE,             "MakerNote", FMT_STRING, -1},
260d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_USERCOMMENT,            "UserComment", FMT_STRING, -1},
261d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SUBSEC_TIME,            "SubSecTime", FMT_STRING, -1},
262d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SUBSEC_TIME_ORIG,       "SubSecTimeOriginal", FMT_STRING, -1},
263d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SUBSEC_TIME_DIG,        "SubSecTimeDigitized", FMT_STRING, -1},
264d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WINXP_TITLE,            "Windows-XP Title", 0, 0},
265d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WINXP_COMMENT,          "Windows-XP comment", 0, 0},
266d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WINXP_AUTHOR,           "Windows-XP author", 0, 0},
267d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WINXP_KEYWORDS,         "Windows-XP keywords", 0, 0},
268d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WINXP_SUBJECT,          "Windows-XP subject", 0, 0},
269d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FLASH_PIX_VERSION,      "FlashPixVersion", FMT_BYTE, 4},
270d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_COLOR_SPACE,            "ColorSpace", FMT_USHORT, 1},
271d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXIF_IMAGEWIDTH,        "ExifImageWidth", 0, 0},
272d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXIF_IMAGELENGTH,       "ExifImageLength", 0, 0},
273d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_RELATED_AUDIO_FILE,     "RelatedAudioFile", 0, 0},
274d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_INTEROP_OFFSET,         "InteroperabilityOffset", 0, 0},
275d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FLASH_ENERGY,           "FlashEnergy", FMT_URATIONAL, 1},
276d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SPATIAL_FREQ_RESP,      "SpatialFrequencyResponse", FMT_STRING, -1},
277d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FOCAL_PLANE_XRES,       "FocalPlaneXResolution", FMT_URATIONAL, 1},
278d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FOCAL_PLANE_YRES,       "FocalPlaneYResolution", FMT_URATIONAL, 1},
279d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FOCAL_PLANE_UNITS,      "FocalPlaneResolutionUnit", FMT_USHORT, 1},
280d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SUBJECT_LOCATION,       "SubjectLocation", FMT_USHORT, 2},
281d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXPOSURE_INDEX,         "ExposureIndex", FMT_URATIONAL, 1},
282d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SENSING_METHOD,         "SensingMethod", FMT_USHORT, 1},
283d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FILE_SOURCE,            "FileSource", 0, 1},
284d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SCENE_TYPE,             "SceneType", 0, 1},
285d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CFA_PATTERN,            "CFA Pattern", 0, -1},
286d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CUSTOM_RENDERED,        "CustomRendered", FMT_USHORT, 1},
287d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_EXPOSURE_MODE,          "ExposureMode", FMT_USHORT, 1},
288d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_WHITEBALANCE,           "WhiteBalance", FMT_USHORT, 1},
289d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DIGITALZOOMRATIO,       "DigitalZoomRatio", FMT_URATIONAL, 1},
290d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_FOCALLENGTH_35MM,       "FocalLengthIn35mmFilm", FMT_USHORT, 1},
291d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SCENE_CAPTURE_TYPE,     "SceneCaptureType", FMT_USHORT, 1},
292d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_GAIN_CONTROL,           "GainControl", FMT_URATIONAL, 1},
293d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_CONTRAST,               "Contrast", FMT_USHORT, 1},
294d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SATURATION,             "Saturation", FMT_USHORT, 1},
295d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_SHARPNESS,              "Sharpness", FMT_USHORT, 1},
296d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang  { TAG_DISTANCE_RANGE,         "SubjectDistanceRange", FMT_USHORT, 1},
29734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project} ;
29834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
29934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_TABLE_SIZE  (sizeof(TagTable) / sizeof(TagTable_t))
30034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
30134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint TagNameToValue(const char* tagName)
30234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
30334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned int i;
30434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < TAG_TABLE_SIZE; i++) {
30534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (strcmp(TagTable[i].Desc, tagName) == 0) {
30634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("found tag %s val %d", TagTable[i].Desc, TagTable[i].Tag);
30734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return TagTable[i].Tag;
30834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
30934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
31034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("tag %s NOT FOUND", tagName);
31134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return -1;
31234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
31334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
314482486a3d21c4d4c933f3081ff14122292314bc7Angus Kongint IsDateTimeTag(unsigned short tag)
315482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong{
316482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong    return ((tag == TAG_DATETIME)? TRUE: FALSE);
317482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong}
318482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong
31934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
32034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert a 16 bit unsigned value to file's native byte order
32134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
32234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void Put16u(void * Short, unsigned short PutValue)
32334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
32434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (MotorolaOrder){
32534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Short)[0] = (uchar)(PutValue>>8);
32634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Short)[1] = (uchar)PutValue;
32734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }else{
32834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Short)[0] = (uchar)PutValue;
32934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Short)[1] = (uchar)(PutValue>>8);
33034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
33134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
33234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
33334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
33434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert a 16 bit unsigned value from file's native byte order
33534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
33634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint Get16u(void * Short)
33734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
33834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (MotorolaOrder){
33934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
34034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }else{
34134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
34234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
34334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
34434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
34534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
34634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert a 32 bit signed value from file's native byte order
34734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
34834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint Get32s(void * Long)
34934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
35034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (MotorolaOrder){
35134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return  ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
35234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project              | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
35334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }else{
35434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return  ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
35534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project              | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
35634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
35734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
35834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
35934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
36034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert a 32 bit unsigned value to file's native byte order
36134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
36234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid Put32u(void * Value, unsigned PutValue)
36334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
36434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (MotorolaOrder){
36534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[0] = (uchar)(PutValue>>24);
36634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[1] = (uchar)(PutValue>>16);
36734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[2] = (uchar)(PutValue>>8);
36834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[3] = (uchar)PutValue;
36934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }else{
37034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[0] = (uchar)PutValue;
37134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[1] = (uchar)(PutValue>>8);
37234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[2] = (uchar)(PutValue>>16);
37334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ((uchar *)Value)[3] = (uchar)(PutValue>>24);
37434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
37534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
37634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
37734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
37834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert a 32 bit unsigned value from file's native byte order
37934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
38034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectunsigned Get32u(void * Long)
38134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
38234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return (unsigned)Get32s(Long) & 0xffffffff;
38334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
38434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
38534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
38634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Display a number as one of its many formats
38734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
38834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid PrintFormatNumber(void * ValuePtr, int Format, int ByteCount)
38934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
39034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int s,n;
39134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
392d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    for(n=0;n<16;n++){
39334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(Format){
39434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SBYTE:
39534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_BYTE:      printf("%02x",*(uchar *)ValuePtr); s=1;  break;
39634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_USHORT:    printf("%d",Get16u(ValuePtr)); s=2;      break;
39734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_ULONG:
39834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SLONG:     printf("%d",Get32s(ValuePtr)); s=4;      break;
39934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SSHORT:    printf("%hd",(signed short)Get16u(ValuePtr)); s=2; break;
40034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_URATIONAL:
40134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SRATIONAL:
40234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project               printf("%d/%d",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
40334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project               s = 8;
40434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project               break;
40534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
40634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SINGLE:    printf("%f",(double)*(float *)ValuePtr); s=8; break;
40734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_DOUBLE:    printf("%f",*(double *)ValuePtr);        s=8; break;
40834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            default:
40934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("Unknown format %d:", Format);
41034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return;
41134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
41234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ByteCount -= s;
41334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ByteCount <= 0) break;
41434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf(", ");
41534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ValuePtr = (void *)((char *)ValuePtr + s);
41634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
41734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
418d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    if (n >= 16) printf("...");
41934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
42034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
42134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
42234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
42334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Evaluate number, be it int, rational, or float from directory.
42434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
42534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectdouble ConvertAnyFormat(void * ValuePtr, int Format)
42634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
42734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    double Value;
42834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Value = 0;
42934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
43034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    switch(Format){
43134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SBYTE:     Value = *(signed char *)ValuePtr;  break;
43234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_BYTE:      Value = *(uchar *)ValuePtr;        break;
43334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
43434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_USHORT:    Value = Get16u(ValuePtr);          break;
43534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_ULONG:     Value = Get32u(ValuePtr);          break;
43634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
43734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_URATIONAL:
43834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SRATIONAL:
43934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            {
44034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                int Num,Den;
44134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                Num = Get32s(ValuePtr);
44234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                Den = Get32s(4+(char *)ValuePtr);
44334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Den == 0){
44434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Value = 0;
44534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
44634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Value = (double)Num/Den;
44734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
44834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
44934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
45034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
45134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SSHORT:    Value = (signed short)Get16u(ValuePtr);  break;
45234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SLONG:     Value = Get32s(ValuePtr);                break;
45334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
45434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Not sure if this is correct (never seen float used in Exif format)
45534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SINGLE:    Value = (double)*(float *)ValuePtr;      break;
45634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_DOUBLE:    Value = *(double *)ValuePtr;             break;
45734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
45834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        default:
45934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Illegal format code %d",Format,0);
46034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
46134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return Value;
46234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
46334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
46434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
46542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang// Convert a double value into a signed or unsigned rational number.
46642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang//--------------------------------------------------------------------------
46742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Changstatic void float2urat(double value, unsigned int max, unsigned int *numerator,
46842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                       unsigned int *denominator) {
46942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    if (value <= 0) {
47042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        *numerator = 0;
47142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        *denominator = 1;
47242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        return;
47342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
47442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
47542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    if (value > max) {
47642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        *numerator = max;
47742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        *denominator = 1;
47842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        return;
47942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
48042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
48142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    // For values less than 1e-9, scale as much as possible
48242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    if (value < 1e-9) {
48342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        unsigned int n = (unsigned int)(value * max);
48442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        if (n == 0) {
48542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *numerator = 0;
48642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *denominator = 1;
48742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        } else {
48842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *numerator = n;
48942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *denominator = max;
49042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        }
49142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        return;
49242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
49342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
49442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    // Try to use a denominator of 1e9, 1e8, ..., until the numerator fits
49542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    unsigned int d;
49642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    for (d = 1000000000; d >= 1; d /= 10) {
49742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        double s = value * d;
49842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        if (s <= max) {
49942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            // Remove the trailing zeros from both.
50042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            unsigned int n = (unsigned int)s;
50142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            while (n % 10 == 0 && d >= 10) {
50242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                n /= 10;
50342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                d /= 10;
50442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            }
50542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *numerator = n;
50642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            *denominator = d;
50742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            return;
50842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        }
50942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
51042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
51142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    // Shouldn't reach here because the denominator 1 should work
51242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    // above. But just in case.
51342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    *numerator = 0;
51442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    *denominator = 1;
51542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang}
51642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
51742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Changstatic void ConvertDoubleToURational(double value, unsigned int *numerator,
51842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                                     unsigned int *denominator) {
51942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    float2urat(value, 0xFFFFFFFFU, numerator, denominator);
52042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang}
52142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
52242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Changstatic void ConvertDoubleToSRational(double value, int *numerator,
52342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                                     int *denominator) {
52442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    int negative = 0;
52542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
52642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    if (value < 0) {
52742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        value = -value;
52842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        negative = 1;
52942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
53042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
53142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    unsigned int n, d;
53242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    float2urat(value, 0x7FFFFFFFU, &n, &d);
53342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    *numerator = (int)n;
53442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    *denominator = (int)d;
53542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    if (negative) {
53642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        *numerator = -*numerator;
53742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    }
53842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang}
53942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang
54042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang//--------------------------------------------------------------------------
54134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Process one of the nested EXIF directories.
54234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
54334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
54434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned ExifLength, int NestingLevel)
54534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
54634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int de;
54734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int a;
54834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int NumDirEntries;
54934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned ThumbnailOffset = 0;
55034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned ThumbnailSize = 0;
55134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char IndentString[25];
55234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
55334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("ProcessExifDir");
55434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (NestingLevel > 4){
55534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
55634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
55734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
55834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
55934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    memset(IndentString, ' ', 25);
56034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    IndentString[NestingLevel * 4] = '\0';
56134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
56234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
56334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    NumDirEntries = Get16u(DirStart);
56434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
56534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
56634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
56734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * DirEnd;
56834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
56934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (DirEnd+4 > (OffsetBase+ExifLength)){
57034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
57134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Version 1.3 of jhead would truncate a bit too much.
57234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // This also caught later on as well.
57334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }else{
574d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
57534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return;
57634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
57734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
57834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (DumpExifMap){
579d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
58034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
58134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
58234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
58334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
58434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
58534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ShowTags){
58634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("(dir has %d entries)\n",NumDirEntries);
58734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
58834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
58934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (de=0;de<NumDirEntries;de++){
59034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int Tag, Format, Components;
59134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * ValuePtr;
59234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int ByteCount;
59334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * DirEntry;
59434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirEntry = DIR_ENTRY_ADDR(DirStart, de);
59534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
59634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Tag = Get16u(DirEntry);
59734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Format = Get16u(DirEntry+2);
59834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Components = Get32u(DirEntry+4);
59934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
60034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if ((Format-1) >= NUM_FORMATS) {
60134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // (-1) catches illegal zero case as unsigned underflows to positive large.
60234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
60334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            continue;
60434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
60534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
60634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if ((unsigned)Components > 0x10000){
60734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
60834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            continue;
60934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
61034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
61134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ByteCount = Components * BytesPerFormat[Format];
61234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
61334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ByteCount > 4){
61434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            unsigned OffsetVal;
61534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            OffsetVal = Get32u(DirEntry+8);
61634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // If its bigger than 4 bytes, the dir entry contains an offset.
61734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (OffsetVal+ByteCount > ExifLength){
61834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Bogus pointer offset and / or bytecount value
61934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
62034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                continue;
62134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
62234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ValuePtr = OffsetBase+OffsetVal;
62334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
62434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (OffsetVal > ImageInfo.LargestExifOffset){
62534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.LargestExifOffset = OffsetVal;
62634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
62734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
62834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (DumpExifMap){
62934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("Map: %05d-%05d:   Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
63034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
63134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
63234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // 4 bytes or less and value is in the dir entry itself
63334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ValuePtr = DirEntry+8;
63434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
63534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
63634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (Tag == TAG_MAKER_NOTE){
63734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (ShowTags){
63834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("%s    Maker note: ",IndentString);
63934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
64034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
64134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            continue;
64234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
64334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
64434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ShowTags){
64534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Show tag name
64634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            for (a=0;;a++){
64734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (a >= (int)TAG_TABLE_SIZE){
64870059dd640afdce1016a7f86a81f625730eb65e4Nick Kralevich                    printf("%s", IndentString);
64934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    printf("    Unknown Tag %04x Value = ", Tag);
65034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
65134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
65234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (TagTable[a].Tag == Tag){
65370059dd640afdce1016a7f86a81f625730eb65e4Nick Kralevich                    printf("%s", IndentString);
65434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    printf("    %s = ",TagTable[a].Desc);
65534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
65634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
65734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
65834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
65934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Show tag value.
66034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            switch(Format){
66134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                case FMT_BYTE:
66234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if(ByteCount>1){
66334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr);
66434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }else{
66534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        PrintFormatNumber(ValuePtr, Format, ByteCount);
66634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        printf("\n");
66734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
66834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
66934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
67034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                case FMT_UNDEFINED:
67134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Undefined is typically an ascii string.
67234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
67334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                case FMT_STRING:
67434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // String arrays printed without function call (different from int arrays)
67534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    {
67634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                          printf("\"%s\"", ValuePtr);
67734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                        int NoPrint = 0;
67834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                        printf("\"");
67934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                        for (a=0;a<ByteCount;a++){
68034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                            if (ValuePtr[a] >= 32){
68134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                putchar(ValuePtr[a]);
68234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                NoPrint = 0;
68334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                            }else{
68434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                // Avoiding indicating too many unprintable characters of proprietary
68534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                // bits of binary information this program may not know how to parse.
68634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                if (!NoPrint && a != ByteCount-1){
68734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                    putchar('?');
68834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                    NoPrint = 1;
68934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                                }
69034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                            }
69134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                        }
69234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//                        printf("\"\n");
69334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
69434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
69534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
69634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                default:
69734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Handle arrays of numbers later (will there ever be?)
69834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    PrintFormatNumber(ValuePtr, Format, ByteCount);
69934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    printf("\n");
70034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
70134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
70234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
70334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Extract useful components of tag
70434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(Tag){
70534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
70634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_MAKE:
70734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31);
70834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
70934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
71034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_MODEL:
71134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39);
71234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
71334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
71434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_DATETIME_ORIGINAL:
71534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // If we get a DATETIME_ORIGINAL, we use that one.
71634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
71734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Fallthru...
71834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
71934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_DATETIME_DIGITIZED:
72034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_DATETIME:
72134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (!isdigit(ImageInfo.DateTime[0])){
72234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // If we don't already have a DATETIME_ORIGINAL, use whatever
72334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // time fields we may have.
72434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
72534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
72634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
72734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
72834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
72934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
73034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
73134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
73234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    (char *)ValuePtr - (char *)OffsetBase;
73334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
73434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
735d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case TAG_WINXP_COMMENT:
736d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
737d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    // Already have a comment (probably windows comment), skip this one.
738d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    if (ShowTags) printf("Windows XP commend and other comment in header\n");
739d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    break; // Already have a windows comment, skip this one.
740d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                }
741d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
742d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                if (ByteCount > 1){
743d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
744d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
745d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    ImageInfo.CommentWidchars = ByteCount/2;
746d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                }
747d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
74834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
74934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_USERCOMMENT:
750d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
751d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    // Already have a comment (probably windows comment), skip this one.
752d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    if (ShowTags) printf("Multiple comments in exif header\n");
753d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    break; // Already have a windows comment, skip this one.
754d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                }
755d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
756d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                // Comment is often padded with trailing spaces.  Remove these first.
75734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                for (a=ByteCount;;){
75834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    a--;
75934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if ((ValuePtr)[a] == ' '){
76034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        (ValuePtr)[a] = '\0';
76134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }else{
76234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        break;
76334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
76434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if (a == 0) break;
76534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
76634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
76734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Copy the comment
76842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                {
76942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    // We want to set copied comment length (msize) to be the
77042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    // minimum of:
77142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    // (1) The space still available in Exif
77242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    // (2) The given comment length (ByteCount)
77342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    // (3) MAX_COMMENT_SIZE - 1
77442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    int msiz = ExifLength - (ValuePtr-OffsetBase);
77542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    if (msiz > ByteCount) msiz = ByteCount;
77642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
77742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
77842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                        for (a = 5; a < 10 && a < msiz; a++) {
77942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                            int c = (ValuePtr)[a];
78042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                            if (c != '\0' && c != ' ') {
78142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                                strncpy(ImageInfo.Comments,
78242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                                        (char *)ValuePtr + a, msiz - a);
78342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                                break;
78442c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                            }
78534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        }
78642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    } else {
78742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                        strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
78834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
78934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
79034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
79134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
79234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_FNUMBER:
79334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Simplest way of expressing aperture, so I trust it the most.
79434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // (overwrite previously computd value if there is one)
79534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
79634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
79734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
79834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_APERTURE:
79934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_MAXAPERTURE:
80034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // More relevant info always comes earlier, so only use this field if we don't
80134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // have appropriate aperture information yet.
80234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ImageInfo.ApertureFNumber == 0){
80334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.ApertureFNumber
80434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
80534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
80634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
80734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
80834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_FOCALLENGTH:
80934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Nice digital cameras actually save the focal length as a function
81034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // of how farthey are zoomed in.
811574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li                ImageInfo.FocalLength.num = Get32u(ValuePtr);
812574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li                ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr);
81334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
81434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
81534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_SUBJECT_DISTANCE:
81634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Inidcates the distacne the autofocus camera is focused to.
81734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Tends to be less accurate as distance increases.
81834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
81934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
82034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
82134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXPOSURETIME:
82234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Simplest way of expressing exposure time, so I trust it most.
82334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // (overwrite previously computd value if there is one)
82434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
82534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
82634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
82734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_SHUTTERSPEED:
82834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // More complicated way of expressing exposure time, so only use
82934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // this value if we don't already have it from somewhere else.
83034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ImageInfo.ExposureTime == 0){
83134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.ExposureTime
83234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
83334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
83434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
83534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
83634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
83734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_FLASH:
83834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format);
83934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
84034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
84134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_ORIENTATION:
84234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (NumOrientations >= 2){
84334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Can have another orientation tag for the thumbnail, but if there's
84434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // a third one, things are stringae.
84534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ErrNonfatal("More than two orientation tags!",0,0);
84634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
84734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
84834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                OrientationPtr[NumOrientations] = ValuePtr;
84934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                OrientationNumFormat[NumOrientations] = Format;
85034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (NumOrientations == 0){
85134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
85234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
85334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){
85434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
85534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.Orientation = 0;
85634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
85734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                NumOrientations += 1;
85834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
85934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
86034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXIF_IMAGELENGTH:
86134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXIF_IMAGEWIDTH:
86234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Use largest of height and width to deal with images that have been
86334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // rotated to portrait format.
86434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                a = (int)ConvertAnyFormat(ValuePtr, Format);
86534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ExifImageWidth < a) ExifImageWidth = a;
86634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
86734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
868d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case TAG_FOCAL_PLANE_XRES:
86934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
87034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
87134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
872d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case TAG_FOCAL_PLANE_UNITS:
87334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                switch((int)ConvertAnyFormat(ValuePtr, Format)){
87434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    case 1: FocalplaneUnits = 25.4; break; // inch
87534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    case 2:
87634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // According to the information I was using, 2 means meters.
87734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // But looking at the Cannon powershot's files, inches is the only
87834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // sensible value.
87934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        FocalplaneUnits = 25.4;
88034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        break;
88134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
88234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    case 3: FocalplaneUnits = 10;   break;  // centimeter
88334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    case 4: FocalplaneUnits = 1;    break;  // millimeter
88434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    case 5: FocalplaneUnits = .001; break;  // micrometer
88534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
88634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
88734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
88834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXPOSURE_BIAS:
88934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
89034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
89134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
89234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_WHITEBALANCE:
89334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
89434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
89534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
89634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_LIGHT_SOURCE:
89734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
89834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
89934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
90034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_METERING_MODE:
90134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
90234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
90334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
90434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXPOSURE_PROGRAM:
90534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
90634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
90734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
90834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXPOSURE_INDEX:
90934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ImageInfo.ISOequivalent == 0){
91034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Exposure index and ISO equivalent are often used interchangeably,
91134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // so we will do the same in jhead.
91234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // http://photography.about.com/library/glossary/bldef_ei.htm
91334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
91434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
91534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
91634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
91734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXPOSURE_MODE:
91834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
91934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
92034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
92134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_ISO_EQUIVALENT:
92234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
92334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if ( ImageInfo.ISOequivalent < 50 ){
92434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Fixes strange encoding on some older digicams.
92534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.ISOequivalent *= 200;
92634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
92734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
92834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
92934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_DIGITALZOOMRATIO:
93034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
93134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
93234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
93334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_THUMBNAIL_OFFSET:
93434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
93534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                DirWithThumbnailPtrs = DirStart;
93634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
93734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
93834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_THUMBNAIL_LENGTH:
93934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
94034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase;
94134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
94234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
94334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_EXIF_OFFSET:
94434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ShowTags) printf("%s    Exif Dir:",IndentString);
94534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
94634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_INTEROP_OFFSET:
94734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s    Interop Dir:",IndentString);
94834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                {
94934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    unsigned char * SubdirStart;
95034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    SubdirStart = OffsetBase + Get32u(ValuePtr);
95134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
95234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
95334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }else{
95434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
95534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
95634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
95734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
95834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
95934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
96034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPSINFO:
96134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ShowTags) printf("%s    GPS info dir:",IndentString);
96234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                {
96334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    unsigned char * SubdirStart;
96434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    SubdirStart = OffsetBase + Get32u(ValuePtr);
96534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
96634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ErrNonfatal("Illegal GPS directory link",0,0);
96734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }else{
96834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
96934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
97034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
97134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
97234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
97334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
97434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_FOCALLENGTH_35MM:
97534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002)
97634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // if its present, use it to compute equivalent focal length instead of
97734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // computing it from sensor geometry and actual focal length.
97834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
97934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
980d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
981d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case TAG_DISTANCE_RANGE:
982d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                // Three possible standard values:
983d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                //   1 = macro, 2 = close, 3 = distant
984d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
985d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
98634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
98734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
98834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
98934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
99034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
99134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // In addition to linking to subdirectories via exif tags,
99234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // there's also a potential link to another directory at the end of each
99334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // directory.  this has got to be the result of a committee!
99434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * SubdirStart;
99534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned Offset;
99634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
99734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
99834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("DirStart %d offset from dirstart %d", (int)DirStart, 2+12*NumDirEntries);
99934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            Offset = Get32u(DirStart+2+12*NumDirEntries);
100034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (Offset){
100134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                SubdirStart = OffsetBase + Offset;
100234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){
100334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    printf("SubdirStart %d OffsetBase %d ExifLength %d Offset %d",
100434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        (int)SubdirStart, (int)OffsetBase, ExifLength, Offset);
100534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){
100634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // Jhead 1.3 or earlier would crop the whole directory!
100734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // As Jhead produces this form of format incorrectness,
100834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        // I'll just let it pass silently
100934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
101034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }else{
101134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ErrNonfatal("Illegal subdirectory link",0,0);
101234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
101334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
101434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    if (SubdirStart <= OffsetBase+ExifLength){
101534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        if (ShowTags) printf("%s    Continued directory ",IndentString);
101634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
101734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
101834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
101934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Offset > ImageInfo.LargestExifOffset){
102034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ImageInfo.LargestExifOffset = Offset;
102134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
102234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
102334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
102434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // The exif header ends before the last next directory pointer.
102534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
102634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
102734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
102834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ThumbnailOffset){
102934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ImageInfo.ThumbnailAtEnd = FALSE;
103034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
103134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (DumpExifMap){
103234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize);
103334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
103434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
103534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ThumbnailOffset <= ExifLength){
103634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (ThumbnailSize > ExifLength-ThumbnailOffset){
103734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // If thumbnail extends past exif header, only save the part that
103834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // actually exists.  Canon's EOS viewer utility will do this - the
103934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // thumbnail extracts ok with this hack.
104034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ThumbnailSize = ExifLength-ThumbnailOffset;
104134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ShowTags) printf("Thumbnail incorrectly placed in header\n");
104234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
104334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
104434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // The thumbnail pointer appears to be valid.  Store it.
104534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ImageInfo.ThumbnailOffset = ThumbnailOffset;
104634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ImageInfo.ThumbnailSize = ThumbnailSize;
104734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
104834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (ShowTags){
104934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("Thumbnail size: %d bytes\n",ThumbnailSize);
105034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
105134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
105234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
105334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("returning from ProcessExifDir");
105434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
105534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
105634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
105734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
105834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Process a EXIF marker
105934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Describes all the drivel that most digital cameras include...
106034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
106134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid process_EXIF (unsigned char * ExifSection, unsigned int length)
106234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
106334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int FirstOffset;
106434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
106534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    FocalplaneXRes = 0;
106634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    FocalplaneUnits = 0;
106734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifImageWidth = 0;
106834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    NumOrientations = 0;
106934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
107034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ShowTags){
107134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Exif header %d bytes long\n",length);
107234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
107334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
107434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {   // Check the EXIF header component
107534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        static uchar ExifHeader[] = "Exif\0\0";
107634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (memcmp(ExifSection+2, ExifHeader,6)){
107734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Incorrect Exif header",0,0);
107834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return;
107934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
108034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
108134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
108234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (memcmp(ExifSection+8,"II",2) == 0){
108334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ShowTags) printf("Exif section in Intel order\n");
108434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        MotorolaOrder = 0;
108534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }else{
108634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (memcmp(ExifSection+8,"MM",2) == 0){
108734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (ShowTags) printf("Exif section in Motorola order\n");
108834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            MotorolaOrder = 1;
108934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
109034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Invalid Exif alignment marker.",0,0);
109134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return;
109234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
109334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
109434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
109534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Check the next value for correctness.
109634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (Get16u(ExifSection+10) != 0x2a){
109734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ErrNonfatal("Invalid Exif start (1)",0,0);
109834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
109934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
110034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
110134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    FirstOffset = Get32u(ExifSection+12);
110234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (FirstOffset < 8 || FirstOffset > 16){
110334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Usually set to 8, but other values valid too.
110434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ErrNonfatal("Suspicious offset of first IFD value",0,0);
110534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
110634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
110734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
110834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    DirWithThumbnailPtrs = NULL;
110934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
111034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
111134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // First directory starts 16 bytes in.  All offset are relative to 8 bytes in.
111234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0);
111334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
111434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.ThumbnailAtEnd = ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE;
111534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
111634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("Thumbnail %s end", (ImageInfo.ThumbnailAtEnd ? "at" : "NOT at"));
111734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
111834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (DumpExifMap){
111934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned a,b;
112034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Map: %05d- End of exif\n",length-8);
112134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//        for (a=0;a<length-8;a+= 10){
112234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//            printf("Map: %05d ",a);
112334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//            for (b=0;b<10;b++) printf(" %02x",*(ExifSection+8+a+b));
112434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//            printf("\n");
112534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//        }
112634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        for (a = 0; a < length - 8; ++a) {
112734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            unsigned char c = *(ExifSection+8+a);
112834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            unsigned pc = isprint(c) ? c : ' ';
112934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Map: %4d %02x %c", a, c, pc);
113034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
113134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
113234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
113334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
113434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Compute the CCD width, in millimeters.
113534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (FocalplaneXRes != 0){
113634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Note: With some cameras, its not possible to compute this correctly because
113734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // they don't adjust the indicated focal plane resolution units when using less
113834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // than maximum resolution, so the CCDWidth value comes out too small.  Nothing
113934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // that Jhad can do about it - its a camera problem.
114034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
114134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1142574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li        if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0
1143574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li            && ImageInfo.FocalLength35mmEquiv == 0){
114434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Compute 35 mm equivalent focal length based on sensor geometry if we haven't
114534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // already got it explicitly from a tag.
1146574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li            ImageInfo.FocalLength35mmEquiv = (int)(
1147574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li                (double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom
1148574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li                / ImageInfo.CCDWidth * 36 + 0.5);
114934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
115034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
115134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
115234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
115334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic const TagTable_t* TagToTagTableEntry(unsigned short tag)
115434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
115534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned int i;
115634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < TAG_TABLE_SIZE; i++) {
115734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (TagTable[i].Tag == tag) {
115834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("found tag %d", tag);
115934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int format = TagTable[i].Format;
116034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (format == 0) {
116134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("tag %s format not defined ***** YOU MUST ADD THE FORMAT TO THE TagTable in exif.c!!!!", TagTable[i].Desc);
116234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return NULL;
116334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
116434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return &TagTable[i];
116534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
116634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
116734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("tag %d NOT FOUND", tag);
116834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return NULL;
116934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
117034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
117134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void writeExifTagAndData(int tag,
117234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                int format,
117334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                long components,
117434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                long value,
117534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                int valueInString,
117634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                char* Buffer,
117734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                int* DirIndex,
117834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                int* DataWriteIndex) {
1179754078052c687f6721536009c816644c73e4f145Tyler Luu    void* componentsPosition = NULL; // for saving component position
1180754078052c687f6721536009c816644c73e4f145Tyler Luu
118134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put16u(Buffer+ (*DirIndex), tag);                    // Tag
118234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put16u(Buffer+(*DirIndex) + 2, format);              // Format
118334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (format == FMT_STRING && components == -1) {
118434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        components = strlen((char*)value) + 1;                 // account for null terminator
118534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (components & 1) ++components;               // no odd lengths
118642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang    } else if (format == FMT_SSHORT && components == -1) {
118742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        // jhead only supports reading one SSHORT anyway
118842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        components = 1;
118934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
1190bd90094d709a579d8d74c326269e492627be9daaTyler Luu    if (format == FMT_UNDEFINED && components == -1) {
1191bd90094d709a579d8d74c326269e492627be9daaTyler Luu        // check if this UNDEFINED format is actually ASCII (as it usually is)
1192bd90094d709a579d8d74c326269e492627be9daaTyler Luu        // if so, we can calculate the size
1193bd90094d709a579d8d74c326269e492627be9daaTyler Luu        if(memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0) {
1194bd90094d709a579d8d74c326269e492627be9daaTyler Luu            components = sizeof(ExifAsciiPrefix) +
1195bd90094d709a579d8d74c326269e492627be9daaTyler Luu                         strlen((char*)value + sizeof(ExifAsciiPrefix)) + 1;
1196bd90094d709a579d8d74c326269e492627be9daaTyler Luu            if (components & 1) ++components;               // no odd lengths
1197bd90094d709a579d8d74c326269e492627be9daaTyler Luu        }
1198bd90094d709a579d8d74c326269e492627be9daaTyler Luu    }
119934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put32u(Buffer+(*DirIndex) + 4, components);         // Components
1200754078052c687f6721536009c816644c73e4f145Tyler Luu    componentsPosition = Buffer+(*DirIndex) + 4; // components # can change for lists
120134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("# components: %ld", components);
120234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (format == FMT_STRING) {
120334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // short strings can fit right in the long, otherwise have to
120434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // go in the data area
120534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (components <= 4) {
120634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            strcpy(Buffer+(*DirIndex) + 8, (char*)value);
120734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        } else {
120834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
120934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("copying value %s to %d", (char*)value, (*DataWriteIndex));
121034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            strncpy(Buffer+(*DataWriteIndex), (char*)value, components);
121134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            (*DataWriteIndex) += components;
121234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
1213bd90094d709a579d8d74c326269e492627be9daaTyler Luu    } else if ((format == FMT_UNDEFINED) &&
1214bd90094d709a579d8d74c326269e492627be9daaTyler Luu               (memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0)) {
1215bd90094d709a579d8d74c326269e492627be9daaTyler Luu        // short strings can fit right in the long, otherwise have to
1216bd90094d709a579d8d74c326269e492627be9daaTyler Luu        // go in the data area
1217bd90094d709a579d8d74c326269e492627be9daaTyler Luu        if (components <= 4) {
1218bd90094d709a579d8d74c326269e492627be9daaTyler Luu            memcpy(Buffer+(*DirIndex) + 8, (char*)value, components);
1219bd90094d709a579d8d74c326269e492627be9daaTyler Luu        } else {
1220bd90094d709a579d8d74c326269e492627be9daaTyler Luu            Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
1221bd90094d709a579d8d74c326269e492627be9daaTyler Luu            printf("copying %s to %d", (char*)value + sizeof(ExifAsciiPrefix), (*DataWriteIndex));
1222bd90094d709a579d8d74c326269e492627be9daaTyler Luu            memcpy(Buffer+(*DataWriteIndex), (char*)value, components);
1223bd90094d709a579d8d74c326269e492627be9daaTyler Luu            (*DataWriteIndex) += components;
1224bd90094d709a579d8d74c326269e492627be9daaTyler Luu        }
122534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    } else if (!valueInString) {
122634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put32u(Buffer+(*DirIndex) + 8, value);   // Value
122734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    } else {
122834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
122942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        // Usually the separator is ',', but sometimes ':' is used, like
123042c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        // TAG_GPS_TIMESTAMP.
123142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang        char* curElement = strtok((char*)value, ",:");
123234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int i;
1233658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu
1234658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu        // (components == -1) Need to handle lists with unknown length too
1235658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu        for (i = 0; ((i < components) || (components == -1)) && curElement != NULL; i++) {
123634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
123734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("processing component %s format %s", curElement, formatStr(format));
123834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
123934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // elements are separated by commas
124034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (format == FMT_URATIONAL) {
124142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                unsigned int numerator;
124242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                unsigned int denominator;
124334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                char* separator = strchr(curElement, '/');
124434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (separator) {
124542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    numerator = atoi(curElement);
124642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    denominator = atoi(separator + 1);
124742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                } else {
124842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    double value = atof(curElement);
124942c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    ConvertDoubleToURational(value, &numerator, &denominator);
125034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
125142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                Put32u(Buffer+(*DataWriteIndex), numerator);
125242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
125342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                (*DataWriteIndex) += 8;
125434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            } else if (format == FMT_SRATIONAL) {
125542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                int numerator;
125642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                int denominator;
125734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                char* separator = strchr(curElement, '/');
125834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (separator) {
1259dc4fa4c9d4d0246b900c587cbeb6dabbbe813199Chih-Chung Chang                    numerator = atoi(curElement);
1260dc4fa4c9d4d0246b900c587cbeb6dabbbe813199Chih-Chung Chang                    denominator = atoi(separator + 1);
126142c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                } else {
126242c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    double value = atof(curElement);
126342c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                    ConvertDoubleToSRational(value, &numerator, &denominator);
126434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
126542c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                Put32u(Buffer+(*DataWriteIndex), numerator);
126642c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
126742c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang                (*DataWriteIndex) += 8;
1268658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu            } else if ((components == -1) && ((format == FMT_USHORT) || (format == FMT_SSHORT))) {
1269658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu                // variable components need to go into data write area
1270658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu                value = atoi(curElement);
1271658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu                Put16u(Buffer+(*DataWriteIndex), value);
1272658ad712aea2756b797d1042b3b4171fccdc5ecfTyler Luu                (*DataWriteIndex) += 4;
127334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            } else {
127434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // TODO: doesn't handle multiple components yet -- if more than one, have to put in data write area.
127534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                value = atoi(curElement);
127634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                Put32u(Buffer+(*DirIndex) + 8, value);   // Value
127734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
127842c1e4bde9be6b05412e6482cc20c3581b6d3b0bChih-Chung Chang            curElement = strtok(NULL, ",:");
127934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
1280754078052c687f6721536009c816644c73e4f145Tyler Luu        if (components == -1) Put32u(componentsPosition, i); // update component # for unknowns
128134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
128234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*DirIndex) += 12;
128334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
128434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
128534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
128634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectchar* formatStr(int format) {
128734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    switch (format) {
128834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_BYTE: return "FMT_BYTE"; break;
128934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_STRING: return "FMT_STRING"; break;
129034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_USHORT: return "FMT_USHORT"; break;
129134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_ULONG: return "FMT_ULONG"; break;
129234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_URATIONAL: return "FMT_URATIONAL"; break;
129334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SBYTE: return "FMT_SBYTE"; break;
129434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_UNDEFINED: return "FMT_UNDEFINED"; break;
129534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SSHORT: return "FMT_SSHORT"; break;
129634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SLONG: return "FMT_SLONG"; break;
129734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SRATIONAL: return "FMT_SRATIONAL"; break;
129834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_SINGLE: return "FMT_SINGLE"; break;
129934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case FMT_DOUBLE: return "FMT_SINGLE"; break;
130034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        default: return "UNKNOWN";
130134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
130234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
130334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
130434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
130534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
130634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Create minimal exif header - just date and thumbnail pointers,
130734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// so that date and thumbnail may be filled later.
130834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
1309482486a3d21c4d4c933f3081ff14122292314bc7Angus Kongstatic void create_EXIF_internal(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag, char* Buffer)
131034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
131134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned short NumEntries;
131234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int DataWriteIndex;
131334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int DirIndex;
13140aba81d4c228ec0681f030ef77a583a8fd9f555aTyler Luu    int DirExifLink = 0;
131534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
131634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
13177a314dab81f01bac02d617ffca9dbf7b6cc00700Steve Block    ALOGE("create_EXIF %d exif elements, %d gps elements", exifTagCount, gpsTagCount);
131834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
1319d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
132034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    MotorolaOrder = 0;
132134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
132234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    memcpy(Buffer+2, "Exif\0\0II",8);
132334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put16u(Buffer+10, 0x2a);
132434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
132534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    DataWriteIndex = 16;
132634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put32u(Buffer+12, DataWriteIndex-8); // first IFD offset.  Means start 16 bytes in.
132734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
132834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
132934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex = DataWriteIndex;
1330482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong        NumEntries = 1 + exifTagCount;  // the extra is the thumbnail
133134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (gpsTagCount) {
133234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ++NumEntries;       // allow for the GPS info tag
133334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
1334482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong        if (!hasDateTimeTag) {
1335482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong            // We have to write extra date time tag. The entry number should be
1336482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong            // adjusted.
1337482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong            ++NumEntries;
1338482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong        }
133934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DataWriteIndex += 2 + NumEntries*12 + 4;
134034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
134134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
134234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex += 2;
1343d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
1344d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        // Entries go here...
1345482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong        if (!hasDateTimeTag) {
134634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Date/time entry
134734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            char* dateTime = NULL;
134834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            char dateBuf[20];
1349482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong            if (ImageInfo.numDateTimeTags) {
135034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // If we had a pre-existing exif header, use time from that.
135134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                dateTime = ImageInfo.DateTime;
135234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            } else {
135334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Oterwise, use the file's timestamp.
135434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                FileTimeAsString(dateBuf);
135534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                dateTime = dateBuf;
135634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
135734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            writeExifTagAndData(TAG_DATETIME,
135834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FMT_STRING,
135934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                20,
136034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                (long)(char*)dateBuf,
136134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FALSE,
136234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                Buffer,
136334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DirIndex,
136434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DataWriteIndex);
136534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
136634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
136734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (exifTagCount > 0) {
136834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int i;
136934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            for (i = 0; i < exifTagCount + gpsTagCount; i++) {
137034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (elements[i].GpsTag) {
137134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
137234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
137334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                const TagTable_t* entry = TagToTagTableEntry(elements[i].Tag);
137434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (entry == NULL) {
137534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
137634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
137734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
13787a314dab81f01bac02d617ffca9dbf7b6cc00700Steve Block                ALOGE("create_EXIF saving tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
137934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
138034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                writeExifTagAndData(elements[i].Tag,
138134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    entry->Format,
138234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    entry->DataLength,
138334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    (long)elements[i].Value,
138434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    TRUE,
138534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    Buffer,
138634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DirIndex,
138734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DataWriteIndex);
138834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
1389482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong
139034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (gpsTagCount) {
139134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Link to gps dir entry
139234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                writeExifTagAndData(TAG_GPSINFO,
139334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    FMT_ULONG,
139434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    1,
139534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    DataWriteIndex-8,
139634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    FALSE,
139734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    Buffer,
139834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DirIndex,
139934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DataWriteIndex);
140034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
140134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
140234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Link to exif dir entry
140334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int exifDirPtr = DataWriteIndex-8;
140434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (gpsTagCount) {
140534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                exifDirPtr += 2 + gpsTagCount*12 + 4;
140634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
14070aba81d4c228ec0681f030ef77a583a8fd9f555aTyler Luu            DirExifLink = DirIndex;
140834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            writeExifTagAndData(TAG_EXIF_OFFSET,
140934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FMT_ULONG,
141034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                1,
141134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                exifDirPtr,
141234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FALSE,
141334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                Buffer,
141434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DirIndex,
141534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DataWriteIndex);
141634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
141734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
141834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // End of directory - contains optional link to continued directory.
14190aba81d4c228ec0681f030ef77a583a8fd9f555aTyler Luu        Put32u(Buffer+DirIndex, 0);
142034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Ending Exif section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
142134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
142234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1423d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
142434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // GPS Section
142534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (gpsTagCount) {
142634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex = DataWriteIndex;
142734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Starting GPS section DirIndex = %d", DirIndex);
142834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        NumEntries = gpsTagCount;
142934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DataWriteIndex += 2 + NumEntries*12 + 4;
143034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
143134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
143234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex += 2;
143334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        {
143434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int i;
143534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            for (i = 0; i < exifTagCount + gpsTagCount; i++) {
143634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (!elements[i].GpsTag) {
143734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
143834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
143934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                const TagTable_t* entry = GpsTagToTagTableEntry(elements[i].Tag);
144034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (entry == NULL) {
144134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    continue;
144234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
144334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
14447a314dab81f01bac02d617ffca9dbf7b6cc00700Steve Block                ALOGE("create_EXIF saving GPS tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
144534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
144634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                writeExifTagAndData(elements[i].Tag,
144734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    entry->Format,
144834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    entry->DataLength,
144934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    (long)elements[i].Value,
145034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    TRUE,
145134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    Buffer,
145234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DirIndex,
145334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    &DataWriteIndex);
145434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
145534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
145634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
145734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // End of directory - contains optional link to continued directory.
145834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put32u(Buffer+DirIndex, 0);
145934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Ending GPS section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
146034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
146134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
146234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
14630aba81d4c228ec0681f030ef77a583a8fd9f555aTyler Luu        // Overwriting TAG_EXIF_OFFSET which links to this directory
14640aba81d4c228ec0681f030ef77a583a8fd9f555aTyler Luu        Put32u(Buffer+DirExifLink+8, DataWriteIndex-8);
146534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
146634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Starting Thumbnail section DirIndex = %d", DirIndex);
146734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex = DataWriteIndex;
146834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        NumEntries = 2;
146934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DataWriteIndex += 2 + NumEntries*12 + 4;
147034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
147134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
147234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirIndex += 2;
147334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        {
147434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Link to exif dir entry
147534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            writeExifTagAndData(TAG_THUMBNAIL_OFFSET,
147634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FMT_ULONG,
147734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                1,
147834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                DataWriteIndex-8,
147934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FALSE,
148034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                Buffer,
148134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DirIndex,
148234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DataWriteIndex);
148334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
148434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
148534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        {
148634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Link to exif dir entry
148734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            writeExifTagAndData(TAG_THUMBNAIL_LENGTH,
148834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FMT_ULONG,
148934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                1,
149034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                0,
149134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                FALSE,
149234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                Buffer,
149334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DirIndex,
149434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                &DataWriteIndex);
149534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
149634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
149734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // End of directory - contains optional link to continued directory.
149834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Put32u(Buffer+DirIndex, 0);
149934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Ending Thumbnail section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
150034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
150134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1502d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
150334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Buffer[0] = (unsigned char)(DataWriteIndex >> 8);
150434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Buffer[1] = (unsigned char)DataWriteIndex;
150534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
150634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Remove old exif section, if there was one.
150734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    RemoveSectionType(M_EXIF);
150834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
150934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
151034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Sections need malloced buffers, so do that now, especially because
151134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // we now know how big it needs to be allocated.
151234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * NewBuf = malloc(DataWriteIndex);
151334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (NewBuf == NULL){
151434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrFatal("Could not allocate memory");
151534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
151634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        memcpy(NewBuf, Buffer, DataWriteIndex);
151734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
151834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        CreateSection(M_EXIF, NewBuf, DataWriteIndex);
151934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
152034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Re-parse new exif section, now that its in place
152134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // otherwise, we risk touching data that has already been freed.
152234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        process_EXIF(NewBuf, DataWriteIndex);
152334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
152434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
152534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1526482486a3d21c4d4c933f3081ff14122292314bc7Angus Kongvoid create_EXIF(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag)
15272645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada{
15282645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    // It is hard to calculate exact necessary size for editing the exif
15292645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    // header dynamically, so we are using the maximum size of EXIF, 64K
15302645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    const int EXIF_MAX_SIZE = 1024*64;
15312645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    char* Buffer = malloc(EXIF_MAX_SIZE);
15322645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada
15332645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    if (Buffer != NULL) {
1534482486a3d21c4d4c933f3081ff14122292314bc7Angus Kong        create_EXIF_internal(elements, exifTagCount, gpsTagCount, hasDateTimeTag, Buffer);
15352645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada        free(Buffer);
15362645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    } else {
15372645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada        ErrFatal("Could not allocate memory");
15382645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada    }
15392645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada}
15402645b48159b2928fe388c6c84991b956f01e8f4eTakahiro Okada
154134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
154234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Cler the rotation tag in the exif header to 1.
154334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
154434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectconst char * ClearOrientation(void)
154534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
154634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int a;
154734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (NumOrientations == 0) return NULL;
154834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
154934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (a=0;a<NumOrientations;a++){
155034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(OrientationNumFormat[a]){
155134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SBYTE:
155234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_BYTE:
155334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                *(uchar *)(OrientationPtr[a]) = 1;
155434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
155534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
155634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_USHORT:
155734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                Put16u(OrientationPtr[a], 1);
155834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
155934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
156034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_ULONG:
156134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case FMT_SLONG:
156234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                memset(OrientationPtr, 0, 4);
156334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Can't be bothered to write  generic Put32 if I only use it once.
156434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (MotorolaOrder){
156534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ((uchar *)OrientationPtr[a])[3] = 1;
156634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
156734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ((uchar *)OrientationPtr[a])[0] = 1;
156834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
156934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
157034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
157134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            default:
157234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return NULL;
157334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
157434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
157534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
157634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return OrientTab[ImageInfo.Orientation];
157734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
157834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
157934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
158034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
158134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
158234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Remove thumbnail out of the exif image.
158334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
158434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint RemoveThumbnail(unsigned char * ExifSection)
158534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
158634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (!DirWithThumbnailPtrs ||
158734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ImageInfo.ThumbnailOffset == 0 ||
158834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ImageInfo.ThumbnailSize == 0){
158934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // No thumbnail, or already deleted it.
159034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return 0;
159134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
159234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ThumbnailAtEnd == FALSE){
159334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ErrNonfatal("Thumbnail is not at end of header, can't chop it off", 0, 0);
159434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return 0;
159534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
159634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
159734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
159834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int de;
159934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int NumDirEntries;
160034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        NumDirEntries = Get16u(DirWithThumbnailPtrs);
160134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
160234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        for (de=0;de<NumDirEntries;de++){
160334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int Tag;
160434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            unsigned char * DirEntry;
160534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            DirEntry = DIR_ENTRY_ADDR(DirWithThumbnailPtrs, de);
160634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            Tag = Get16u(DirEntry);
160734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (Tag == TAG_THUMBNAIL_LENGTH){
160834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Set length to zero.
160934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Get16u(DirEntry+2) != FMT_ULONG){
161034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // non standard format encoding.  Can't do it.
161134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ErrNonfatal("Can't remove thumbnail", 0, 0);
161234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    return 0;
161334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
161434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                Put32u(DirEntry+8, 0);
161534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
161634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
161734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
161834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
161934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // This is how far the non thumbnail data went.
162034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return ImageInfo.ThumbnailOffset+8;
162134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
162234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
162334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
162434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
162534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
162634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Convert exif time to Unix time structure
162734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
162834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint Exif2tm(struct tm * timeptr, char * ExifTime)
162934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
163034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int a;
163134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
163234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    timeptr->tm_wday = -1;
163334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
163434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Check for format: YYYY:MM:DD HH:MM:SS format.
163534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Date and time normally separated by a space, but also seen a ':' there, so
163634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // skip the middle space with '%*c' so it can be any character.
163734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    a = sscanf(ExifTime, "%d%*c%d%*c%d%*c%d:%d:%d",
163834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
163934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
164034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
164134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
164234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (a == 6){
164334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        timeptr->tm_isdst = -1;
164434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        timeptr->tm_mon -= 1;      // Adjust for unix zero-based months
164534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        timeptr->tm_year -= 1900;  // Adjust for year starting at 1900
164634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return TRUE; // worked.
164734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
164834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
164934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return FALSE; // Wasn't in Exif date format.
165034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
165134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
165234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
165334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
165434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Show the collected image info, displaying camera F-stop and shutter speed
165534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// in a consistent and legible fashion.
165634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
165734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid ShowImageInfo(int ShowFileInfo)
165834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
165934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ShowFileInfo){
166034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("File name    : %s\n",ImageInfo.FileName);
166134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("File size    : %d bytes\n",ImageInfo.FileSize);
166234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
166334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        {
166434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            char Temp[20];
166534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            FileTimeAsString(Temp);
166634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("File date    : %s\n",Temp);
166734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
166834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
166934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
167034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.CameraMake[0]){
167134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Camera make  : %s\n",ImageInfo.CameraMake);
167234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Camera model : %s\n",ImageInfo.CameraModel);
167334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
167434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.DateTime[0]){
167534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Date/Time    : %s\n",ImageInfo.DateTime);
167634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
167734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("Resolution   : %d x %d\n",ImageInfo.Width, ImageInfo.Height);
167834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
167934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Orientation > 1){
168034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Only print orientation if one was supplied, and if its not 1 (normal orientation)
168134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Orientation  : %s\n", OrientTab[ImageInfo.Orientation]);
168234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
168334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
168434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.IsColor == 0){
168534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Color/bw     : Black and white\n");
168634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
168734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
168834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.FlashUsed >= 0){
168934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.FlashUsed & 1){
169034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Flash used   : Yes");
169134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            switch (ImageInfo.FlashUsed){
169234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x5: printf(" (Strobe light not detected)"); break;
169334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x7: printf(" (Strobe light detected) "); break;
169434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x9: printf(" (manual)"); break;
169534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0xd: printf(" (manual, return light not detected)"); break;
169634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0xf: printf(" (manual, return light  detected)"); break;
169734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x19:printf(" (auto)"); break;
169834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x1d:printf(" (auto, return light not detected)"); break;
169934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x1f:printf(" (auto, return light detected)"); break;
170034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x41:printf(" (red eye reduction mode)"); break;
170134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x45:printf(" (red eye reduction mode return light not detected)"); break;
170234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x47:printf(" (red eye reduction mode return light  detected)"); break;
170334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x49:printf(" (manual, red eye reduction mode)"); break;
170434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x4d:printf(" (manual, red eye reduction mode, return light not detected)"); break;
170534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x4f:printf(" (red eye reduction mode, return light detected)"); break;
170634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x59:printf(" (auto, red eye reduction mode)"); break;
170734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x5d:printf(" (auto, red eye reduction mode, return light not detected)"); break;
170834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x5f:printf(" (auto, red eye reduction mode, return light detected)"); break;
170934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
171034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
171134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Flash used   : No");
171234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            switch (ImageInfo.FlashUsed){
171334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project	            case 0x18:printf(" (auto)"); break;
171434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
171534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
171634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("\n");
171734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
171834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
171934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1720574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li    if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0) {
1721574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li        printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom);
172234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.FocalLength35mmEquiv){
172334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("  (35mm equivalent: %dmm)", ImageInfo.FocalLength35mmEquiv);
172434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
172534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("\n");
172634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
172734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
172834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.DigitalZoomRatio > 1){
172934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Digital zoom used.  Shame on you!
173034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Digital Zoom : %1.3fx\n", (double)ImageInfo.DigitalZoomRatio);
173134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
173234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
173334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.CCDWidth){
173434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("CCD width    : %4.2fmm\n",(double)ImageInfo.CCDWidth);
173534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
173634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
173734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureTime){
173834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.ExposureTime < 0.010){
173934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure time: %6.4f s ",(double)ImageInfo.ExposureTime);
174034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
174134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure time: %5.3f s ",(double)ImageInfo.ExposureTime);
174234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
174334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.ExposureTime <= 0.5){
174434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
174534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
174634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("\n");
174734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
174834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ApertureFNumber){
174934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Aperture     : f/%3.1f\n",(double)ImageInfo.ApertureFNumber);
175034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
175134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Distance){
175234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.Distance < 0){
175334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Focus dist.  : Infinite\n");
175434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
175534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Focus dist.  : %4.2fm\n",(double)ImageInfo.Distance);
175634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
175734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
175834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
175934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ISOequivalent){
176034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("ISO equiv.   : %2d\n",(int)ImageInfo.ISOequivalent);
176134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
176234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
176334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureBias){
176434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // If exposure bias was specified, but set to zero, presumably its no bias at all,
176534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // so only show it if its nonzero.
176634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Exposure bias: %4.2f\n",(double)ImageInfo.ExposureBias);
176734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
176834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
176934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    switch(ImageInfo.Whitebalance) {
177034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 1:
177134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Whitebalance : Manual\n");
177234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
177334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 0:
177434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Whitebalance : Auto\n");
177534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
177634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
177734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
177834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both
177934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    switch(ImageInfo.LightSource) {
178034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 1:
178134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Daylight\n");
178234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
178334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 2:
178434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Fluorescent\n");
178534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
178634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 3:
178734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Incandescent\n");
178834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
178934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 4:
179034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Flash\n");
179134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
179234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 9:
179334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Fine weather\n");
179434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
179534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 11:
179634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Light Source : Shade\n");
179734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
179834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        default:; //Quercus: 17-1-2004 There are many more modes for this, check Exif2.2 specs
179934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // If it just says 'unknown' or we don't know it, then
180034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // don't bother showing it - it doesn't add any useful information.
180134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
180234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
180334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs
180434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(ImageInfo.MeteringMode) {
180534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 2:
180634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Metering Mode: center weight\n");
180734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
180834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 3:
180934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Metering Mode: spot\n");
181034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
181134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 5:
181234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Metering Mode: matrix\n");
181334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
181434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
181534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
181634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
181734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs
181834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(ImageInfo.ExposureProgram) {
181934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 1:
182034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : Manual\n");
182134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
182234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 2:
182334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : program (auto)\n");
182434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
182534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 3:
182634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : aperture priority (semi-auto)\n");
182734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
182834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 4:
182934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : shutter priority (semi-auto)\n");
183034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
183134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 5:
183234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : Creative Program (based towards depth of field)\n");
183334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
183434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 6:
183534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : Action program (based towards fast shutter speed)\n");
183634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
183734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 7:
183834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : Portrait Mode\n");
183934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
184034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 8:
184134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("Exposure     : LandscapeMode \n");
184234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
184334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        default:
184434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
184534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
184634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
184734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    switch(ImageInfo.ExposureMode){
184834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 0: // Automatic (not worth cluttering up output for)
184934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
185034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 1: printf("Exposure Mode: Manual\n");
185134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
185234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        case 2: printf("Exposure Mode: Auto bracketing\n");
185334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
185434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
185534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1856d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    if (ImageInfo.DistanceRange) {
1857d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        printf("Focus range  : ");
1858d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        switch(ImageInfo.DistanceRange) {
1859d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case 1:
1860d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                printf("macro");
1861d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
1862d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case 2:
1863d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                printf("close");
1864d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
1865d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case 3:
1866d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                printf("distant");
1867d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
1868d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        }
1869d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        printf("\n");
1870d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    }
1871d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
1872d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
187334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
187434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Process != M_SOF0){
187534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // don't show it if its the plain old boring 'baseline' process, but do
187634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // show it if its something else, like 'progressive' (used on web sometimes)
187734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int a;
187834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        for (a=0;;a++){
187934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (a >= (int)PROCESS_TABLE_SIZE){
188034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // ran off the end of the table.
188134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("Jpeg process : Unknown\n");
188234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
188334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
188434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (ProcessTable[a].Tag == ImageInfo.Process){
188534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("Jpeg process : %s\n",ProcessTable[a].Desc);
188634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
188734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
188834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
188934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
189034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
189134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.GpsInfoPresent){
189234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("GPS Latitude : %s\n",ImageInfo.GpsLat);
189334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("GPS Longitude: %s\n",ImageInfo.GpsLong);
189434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.GpsAlt[0]) printf("GPS Altitude : %s\n",ImageInfo.GpsAlt);
189534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
189634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
189734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Print the comment. Print 'Comment:' for each new line of comment.
189834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Comments[0]){
189934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int a,c;
190034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Comment      : ");
1901d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        if (!ImageInfo.CommentWidchars){
1902d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            for (a=0;a<MAX_COMMENT_SIZE;a++){
1903d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                c = ImageInfo.Comments[a];
1904d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                if (c == '\0') break;
1905d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                if (c == '\n'){
1906d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    // Do not start a new line if the string ends with a carriage return.
1907d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    if (ImageInfo.Comments[a+1] != '\0'){
1908d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                        printf("\nComment      : ");
1909d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    }else{
1910d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                        printf("\n");
1911d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    }
191234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
1913d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    putchar(c);
191434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
191534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
1916d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            printf("\n");
1917d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        }else{
1918d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            printf("%.*ls\n", ImageInfo.CommentWidchars, (wchar_t *)ImageInfo.Comments);
191934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
192034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
192134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ThumbnailOffset){
192234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("Map: %05d-%05d: Thumbnail\n",ImageInfo.ThumbnailOffset, ImageInfo.ThumbnailOffset+ImageInfo.ThumbnailSize);
192334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    } else {
192434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("NO thumbnail");
192534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
192634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
192734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
192834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
192934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
193034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Summarize highlights of image info on one line (suitable for grep-ing)
193134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
193234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid ShowConciseImageInfo(void)
193334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
193434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("\"%s\"",ImageInfo.FileName);
193534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
193634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf(" %dx%d",ImageInfo.Width, ImageInfo.Height);
193734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
193834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureTime){
193934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.ExposureTime <= 0.5){
194034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
194134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
194234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf(" (%1.1f)",ImageInfo.ExposureTime);
194334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
194434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
194534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
194634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ApertureFNumber){
194734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf(" f/%3.1f",(double)ImageInfo.ApertureFNumber);
194834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
194934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
195034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.FocalLength35mmEquiv){
195134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf(" f(35)=%dmm",ImageInfo.FocalLength35mmEquiv);
195234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
195334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
195434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.FlashUsed >= 0 && ImageInfo.FlashUsed & 1){
195534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf(" (flash)");
195634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
195734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
195834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.IsColor == 0){
195934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf(" (bw)");
196034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
196134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
196234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("\n");
196334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
1964