1 //-------------------------------------------------------------------------- 2 // Parsing of GPS info from exif header. 3 // 4 // Matthias Wandel, Dec 1999 - Dec 2002 5 //-------------------------------------------------------------------------- 6 #include "jhead.h" 7 8 #include <string.h> 9 #include <utils/Log.h> 10 11 12 #define TAG_GPS_LAT_REF 1 13 #define TAG_GPS_LAT 2 14 #define TAG_GPS_LONG_REF 3 15 #define TAG_GPS_LONG 4 16 #define TAG_GPS_ALT_REF 5 17 #define TAG_GPS_ALT 6 18 #define TAG_GPS_TIMESTAMP 7 19 #define TAG_GPS_PROCESSING_METHOD 27 20 #define TAG_GPS_DATESTAMP 29 21 22 static TagTable_t GpsTags[]= { 23 { 0x00, "GPSVersionID", FMT_BYTE, 4}, 24 { 0x01, "GPSLatitudeRef", FMT_STRING, 2}, 25 { 0x02, "GPSLatitude", FMT_URATIONAL, 3}, 26 { 0x03, "GPSLongitudeRef", FMT_STRING, 2}, 27 { 0x04, "GPSLongitude", FMT_URATIONAL, 3}, 28 { 0x05, "GPSAltitudeRef", FMT_BYTE, 1}, 29 { 0x06, "GPSAltitude", FMT_URATIONAL, 1}, 30 { 0x07, "GPSTimeStamp", FMT_SRATIONAL, 3}, 31 { 0x08, "GPSSatellites", FMT_STRING, -1}, 32 { 0x09, "GPSStatus", FMT_STRING, 2}, 33 { 0x0A, "GPSMeasureMode", FMT_STRING, 2}, 34 { 0x0B, "GPSDOP", FMT_SRATIONAL, 1}, 35 { 0x0C, "GPSSpeedRef", FMT_STRING, 2}, 36 { 0x0D, "GPSSpeed", FMT_SRATIONAL, 1}, 37 { 0x0E, "GPSTrackRef", FMT_STRING, 2}, 38 { 0x0F, "GPSTrack", FMT_SRATIONAL, 1}, 39 { 0x10, "GPSImgDirectionRef", FMT_STRING, -1}, 40 { 0x11, "GPSImgDirection", FMT_SRATIONAL, 1}, 41 { 0x12, "GPSMapDatum", FMT_STRING, -1}, 42 { 0x13, "GPSDestLatitudeRef", FMT_STRING, 2}, 43 { 0x14, "GPSDestLatitude", FMT_SRATIONAL, 3}, 44 { 0x15, "GPSDestLongitudeRef", FMT_STRING, 2}, 45 { 0x16, "GPSDestLongitude", FMT_SRATIONAL, 3}, 46 { 0x17, "GPSDestBearingRef", FMT_STRING, 1}, 47 { 0x18, "GPSDestBearing", FMT_SRATIONAL, 1}, 48 { 0x19, "GPSDestDistanceRef", FMT_STRING, 2}, 49 { 0x1A, "GPSDestDistance", FMT_SRATIONAL, 1}, 50 { 0x1B, "GPSProcessingMethod", FMT_UNDEFINED, -1}, 51 { 0x1C, "GPSAreaInformation", FMT_STRING, -1}, 52 { 0x1D, "GPSDateStamp", FMT_STRING, 11}, 53 { 0x1E, "GPSDifferential", FMT_SSHORT, 1}, 54 }; 55 56 #define MAX_GPS_TAG (sizeof(GpsTags) / sizeof(TagTable_t)) 57 #define EXIF_ASCII_PREFIX_LEN (sizeof(ExifAsciiPrefix)) 58 59 // Define the line below to turn on poor man's debugging output 60 #undef SUPERDEBUG 61 62 #ifdef SUPERDEBUG 63 #define printf ALOGE 64 #endif 65 66 67 int IsGpsTag(const char* tag) { 68 return strstr(tag, "GPS") == tag; 69 } 70 71 TagTable_t* GpsTagToTagTableEntry(unsigned short tag) 72 { 73 unsigned int i; 74 for (i = 0; i < MAX_GPS_TAG; i++) { 75 if (GpsTags[i].Tag == tag) { 76 printf("found tag %d", tag); 77 int format = GpsTags[i].Format; 78 if (format == 0) { 79 printf("tag %s format not defined", GpsTags[i].Desc); 80 return NULL; 81 } 82 return &GpsTags[i]; 83 } 84 } 85 printf("tag %d NOT FOUND", tag); 86 return NULL; 87 } 88 89 int GpsTagToFormatType(unsigned short tag) 90 { 91 unsigned int i; 92 for (i = 0; i < MAX_GPS_TAG; i++) { 93 if (GpsTags[i].Tag == tag) { 94 printf("found tag %d", tag); 95 int format = GpsTags[i].Format; 96 if (format == 0) { 97 printf("tag %s format not defined", GpsTags[i].Desc); 98 return -1; 99 } 100 return format; 101 } 102 } 103 printf("tag %d NOT FOUND", tag); 104 return -1; 105 } 106 107 int GpsTagNameToValue(const char* tagName) 108 { 109 unsigned int i; 110 for (i = 0; i < MAX_GPS_TAG; i++) { 111 if (strcmp(GpsTags[i].Desc, tagName) == 0) { 112 printf("found GPS tag %s val %d", GpsTags[i].Desc, GpsTags[i].Tag); 113 return GpsTags[i].Tag; 114 } 115 } 116 printf("GPS tag %s NOT FOUND", tagName); 117 return -1; 118 } 119 120 121 //-------------------------------------------------------------------------- 122 // Process GPS info directory 123 //-------------------------------------------------------------------------- 124 void ProcessGpsInfo(unsigned char * DirStart, int ByteCountUnused, unsigned char * OffsetBase, unsigned ExifLength) 125 { 126 int de; 127 unsigned a; 128 int NumDirEntries; 129 130 NumDirEntries = Get16u(DirStart); 131 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) 132 133 if (ShowTags){ 134 printf("(dir has %d entries)\n",NumDirEntries); 135 } 136 137 ImageInfo.GpsInfoPresent = TRUE; 138 strcpy(ImageInfo.GpsLat, "? ?"); 139 strcpy(ImageInfo.GpsLong, "? ?"); 140 ImageInfo.GpsAlt[0] = 0; 141 142 for (de=0;de<NumDirEntries;de++){ 143 unsigned Tag, Format, Components; 144 unsigned char * ValuePtr; 145 int ComponentSize; 146 unsigned ByteCount; 147 unsigned char * DirEntry; 148 DirEntry = DIR_ENTRY_ADDR(DirStart, de); 149 150 if (DirEntry+12 > OffsetBase+ExifLength){ 151 ErrNonfatal("GPS info directory goes past end of exif",0,0); 152 return; 153 } 154 155 Tag = Get16u(DirEntry); 156 Format = Get16u(DirEntry+2); 157 Components = Get32u(DirEntry+4); 158 159 if ((Format-1) >= NUM_FORMATS) { 160 // (-1) catches illegal zero case as unsigned underflows to positive large. 161 ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); 162 continue; 163 } 164 165 ComponentSize = BytesPerFormat[Format]; 166 ByteCount = Components * ComponentSize; 167 168 #ifdef SUPERDEBUG 169 printf("GPS tag %x format %s #components %d componentsize %d bytecount %d", Tag, formatStr(Format), Components, ComponentSize, 170 ByteCount); 171 #endif 172 173 if (ByteCount > 4){ 174 unsigned OffsetVal; 175 OffsetVal = Get32u(DirEntry+8); 176 // If its bigger than 4 bytes, the dir entry contains an offset. 177 if (OffsetVal+ByteCount > ExifLength){ 178 // Bogus pointer offset and / or bytecount value 179 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); 180 continue; 181 } 182 ValuePtr = OffsetBase+OffsetVal; 183 }else{ 184 // 4 bytes or less and value is in the dir entry itself 185 ValuePtr = DirEntry+8; 186 } 187 188 switch(Tag){ 189 char FmtString[21]; 190 char TempString[MAX_BUF_SIZE]; 191 double Values[3]; 192 193 case TAG_GPS_LAT_REF: 194 ImageInfo.GpsLat[0] = ValuePtr[0]; 195 ImageInfo.GpsLatRef[0] = ValuePtr[0]; 196 ImageInfo.GpsLatRef[1] = '\0'; 197 break; 198 199 case TAG_GPS_LONG_REF: 200 ImageInfo.GpsLong[0] = ValuePtr[0]; 201 ImageInfo.GpsLongRef[0] = ValuePtr[0]; 202 ImageInfo.GpsLongRef[1] = '\0'; 203 break; 204 205 case TAG_GPS_LAT: 206 case TAG_GPS_LONG: 207 if (Format != FMT_URATIONAL){ 208 ErrNonfatal("Inappropriate format (%d) for GPS coordinates!", Format, 0); 209 } 210 strcpy(FmtString, "%0.0fd %0.0fm %0.0fs"); 211 for (a=0;a<3;a++){ 212 int den, digits; 213 214 den = Get32s(ValuePtr+4+a*ComponentSize); 215 digits = 0; 216 while (den > 1 && digits <= 6){ 217 den = den / 10; 218 digits += 1; 219 } 220 if (digits > 6) digits = 6; 221 FmtString[1+a*7] = (char)('2'+digits+(digits ? 1 : 0)); 222 FmtString[3+a*7] = (char)('0'+digits); 223 224 Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format); 225 } 226 227 sprintf(TempString, FmtString, Values[0], Values[1], Values[2]); 228 229 if (Tag == TAG_GPS_LAT){ 230 strncpy(ImageInfo.GpsLat+2, TempString, 29); 231 }else{ 232 strncpy(ImageInfo.GpsLong+2, TempString, 29); 233 } 234 235 sprintf(TempString, "%d/%d,%d/%d,%d/%d", 236 Get32s(ValuePtr), Get32s(4+(char*)ValuePtr), 237 Get32s(8+(char*)ValuePtr), Get32s(12+(char*)ValuePtr), 238 Get32s(16+(char*)ValuePtr), Get32s(20+(char*)ValuePtr)); 239 if (Tag == TAG_GPS_LAT){ 240 strncpy(ImageInfo.GpsLatRaw, TempString, MAX_BUF_SIZE); 241 }else{ 242 strncpy(ImageInfo.GpsLongRaw, TempString, MAX_BUF_SIZE); 243 } 244 break; 245 246 case TAG_GPS_ALT_REF: 247 ImageInfo.GpsAlt[0] = (char)(ValuePtr[0] ? '-' : ' '); 248 ImageInfo.GpsAltRef = (char)ValuePtr[0]; 249 break; 250 251 case TAG_GPS_ALT: 252 sprintf(ImageInfo.GpsAlt + 1, "%.2fm", 253 ConvertAnyFormat(ValuePtr, Format)); 254 ImageInfo.GpsAltRaw.num = Get32u(ValuePtr); 255 ImageInfo.GpsAltRaw.denom = Get32u(4+(char *)ValuePtr); 256 break; 257 258 case TAG_GPS_TIMESTAMP: 259 snprintf(ImageInfo.GpsTimeStamp, 260 sizeof(ImageInfo.GpsTimeStamp), "%d:%d:%d", 261 (int) ConvertAnyFormat(ValuePtr, Format), 262 (int) ConvertAnyFormat(ValuePtr + 8, Format), 263 (int) ConvertAnyFormat(ValuePtr + 16, Format) 264 ); 265 break; 266 267 case TAG_GPS_DATESTAMP: 268 strncpy(ImageInfo.GpsDateStamp, (char*)ValuePtr, sizeof(ImageInfo.GpsDateStamp)); 269 break; 270 271 case TAG_GPS_PROCESSING_METHOD: 272 if (ByteCount > EXIF_ASCII_PREFIX_LEN && 273 memcmp(ValuePtr, ExifAsciiPrefix, EXIF_ASCII_PREFIX_LEN) == 0) { 274 int length = 275 ByteCount < GPS_PROCESSING_METHOD_LEN + EXIF_ASCII_PREFIX_LEN ? 276 ByteCount - EXIF_ASCII_PREFIX_LEN : GPS_PROCESSING_METHOD_LEN; 277 memcpy(ImageInfo.GpsProcessingMethod, 278 (char*)(ValuePtr + EXIF_ASCII_PREFIX_LEN), length); 279 ImageInfo.GpsProcessingMethod[length] = 0; 280 } else { 281 ALOGW("Unsupported encoding for GPSProcessingMethod"); 282 } 283 break; 284 } 285 286 if (ShowTags){ 287 // Show tag value. 288 if (Tag < MAX_GPS_TAG){ 289 printf(" %s =", GpsTags[Tag].Desc); 290 }else{ 291 // Show unknown tag 292 printf(" Illegal GPS tag %04x=", Tag); 293 } 294 295 switch(Format){ 296 case FMT_UNDEFINED: 297 // Undefined is typically an ascii string. 298 299 case FMT_STRING: 300 // String arrays printed without function call (different from int arrays) 301 { 302 printf("\""); 303 for (a=0;a<ByteCount;a++){ 304 int ZeroSkipped = 0; 305 if (ValuePtr[a] >= 32){ 306 if (ZeroSkipped){ 307 printf("?"); 308 ZeroSkipped = 0; 309 } 310 putchar(ValuePtr[a]); 311 }else{ 312 if (ValuePtr[a] == 0){ 313 ZeroSkipped = 1; 314 } 315 } 316 } 317 printf("\"\n"); 318 } 319 break; 320 321 default: 322 // Handle arrays of numbers later (will there ever be?) 323 for (a=0;;){ 324 PrintFormatNumber(ValuePtr+a*ComponentSize, Format, ByteCount); 325 if (++a >= Components) break; 326 printf(", "); 327 } 328 printf("\n"); 329 } 330 } 331 } 332 } 333 334 335