1 /*
2
3 Support for embedded (JPEG) Exif-GPS information.
4
5 Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
20
21 */
22
23 #include <ctype.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "defs.h"
29 #include "garmin_tables.h"
30 #include "jeeps/gpsmath.h"
31 #include "strptime.h"
32
33 #define MYNAME "exif"
34
35 // #define EXIF_DBG
36
37 #define UNKNOWN_TIMESTAMP 999999999
38
39 #define IFD0 0
40 #define IFD1 1
41 #define EXIF_IFD 2 /* dummy index */
42 #define GPS_IFD 3 /* dummy index */
43 #define INTER_IFD 4 /* dummy index */
44
45 #define EXIF_TYPE_BYTE 1
46 #define EXIF_TYPE_ASCII 2
47 #define EXIF_TYPE_SHORT 3
48 #define EXIF_TYPE_LONG 4
49 #define EXIF_TYPE_RAT 5
50 /* TIFF 6.0 */
51 #define EXIF_TYPE_SBYTE 6
52 #define EXIF_TYPE_UNK 7
53 #define EXIF_TYPE_SSHORT 8
54 #define EXIF_TYPE_SLONG 9
55 #define EXIF_TYPE_SRAT 10
56 #define EXIF_TYPE_FLOAT 11
57 #define EXIF_TYPE_DOUBLE 12
58 #define EXIF_TYPE_IFD 13
59 #define EXIF_TYPE_UNICODE 14
60 #define EXIF_TYPE_COMPLEX 15
61 #define EXIF_TYPE_LONG8 16
62 #define EXIF_TYPE_SLONG8 17
63 #define EXIF_TYPE_IFD8 18
64
65 #define BYTE_TYPE(a) ( (a==EXIF_TYPE_BYTE) || (a==EXIF_TYPE_ASCII) || (a==EXIF_TYPE_UNK) )
66 #define WORD_TYPE(a) ( (a==EXIF_TYPE_SHORT) || (a==EXIF_TYPE_SSHORT) )
67 #define LONG_TYPE(a) ( (a==EXIF_TYPE_LONG) || (a==EXIF_TYPE_SLONG) || (a==EXIF_TYPE_IFD) )
68
69 #define IFD0_TAG_EXIF_IFD_OFFS 0x8769
70 #define IFD0_TAG_GPS_IFD_OFFS 0x8825
71
72 #define IFD1_TAG_STRIP_OFFS 0x0111
73 #define IFD1_TAG_JPEG_OFFS 0x0201
74 #define IFD1_TAG_JPEG_SIZE 0x0202
75
76 #define EXIF_IFD_TAG_USER_CMT 0x9286
77 #define EXIF_IFD_TAG_INTER_IFD_OFFS 0xA005
78
79 #define GPS_IFD_TAG_VERSION 0x0000
80 #define GPS_IFD_TAG_LATREF 0x0001
81 #define GPS_IFD_TAG_LAT 0x0002
82 #define GPS_IFD_TAG_LONREF 0x0003
83 #define GPS_IFD_TAG_LON 0x0004
84 #define GPS_IFD_TAG_ALTREF 0x0005
85 #define GPS_IFD_TAG_ALT 0x0006
86 #define GPS_IFD_TAG_TIMESTAMP 0x0007
87 #define GPS_IFD_TAG_SAT 0x0008
88 #define GPS_IFD_TAG_MODE 0x000A
89 #define GPS_IFD_TAG_DOP 0x000B
90 #define GPS_IFD_TAG_SPEEDREF 0x000C
91 #define GPS_IFD_TAG_SPEED 0x000D
92 #define GPS_IFD_TAG_DATUM 0x0012
93 #define GPS_IFD_TAG_DATESTAMP 0x001D
94
95 typedef struct exif_tag_s {
96 queue Q;
97 gbuint16 id;
98 gbuint16 type;
99 gbuint32 count;
100 gbuint32 value;
101 gbuint32 origin;
102 gbuint32 size;
103 #ifdef EXIF_DBG
104 gbuint32 offs;
105 #endif
106 unsigned char data_is_dynamic:1;
107 void* data;
108 } exif_tag_t;
109
110 typedef struct exif_ifd_s {
111 queue Q;
112 gbuint32 next_ifd;
113 gbuint16 nr;
114 gbuint16 count;
115 queue tags;
116 } exif_ifd_t, *exif_ifd_p;
117
118 typedef struct exif_app_s {
119 queue Q;
120 gbuint16 marker;
121 gbsize_t len;
122 gbfile* fcache;
123 gbfile* fexif;
124 queue ifds;
125 } exif_app_t;
126
127 static gbfile* fin, *fout;
128 static queue exif_apps;
129 static exif_app_t* exif_app;
130 const waypoint* exif_wpt_ref;
131 time_t exif_time_ref;
132 static char exif_success;
133 static char* exif_fout_name;
134
135 static char* opt_filename, *opt_overwrite, *opt_frame, *opt_name;
136
137 arglist_t exif_args[] = {
138 { "filename", &opt_filename, "Set waypoint name to source filename", "Y", ARGTYPE_BOOL, ARG_NOMINMAX },
139 { "frame", &opt_frame, "Time-frame (in seconds)", "10", ARGTYPE_INT, "0", NULL },
140 { "name", &opt_name, "Locate waypoint for tagging by this name", NULL, ARGTYPE_STRING, ARG_NOMINMAX },
141 { "overwrite", &opt_overwrite, "!OVERWRITE! the original file. Default=N", "N", ARGTYPE_BOOL, ARG_NOMINMAX },
142 ARG_TERMINATOR
143 };
144
145 #ifdef EXIF_DBG
146 static void
print_buff(const char * buf,int sz,const char * cmt)147 print_buff(const char* buf, int sz, const char* cmt)
148 {
149 int i;
150
151 printf("%s: ", cmt);
152 for (i = 0; i < sz; i++) {
153 printf("%02x ", buf[i] & 0xFF);
154 }
155 for (i = 0; i < sz; i++) {
156 char c = buf[i];
157 if (isspace(c)) {
158 c = ' ';
159 } else if (! isprint(c)) {
160 c = '.';
161 }
162 printf("%c", c);
163 }
164 }
165 #endif
166
167 static gbuint16
exif_type_size(const gbuint16 type)168 exif_type_size(const gbuint16 type)
169 {
170 gbuint16 size;
171
172 switch (type) {
173 case EXIF_TYPE_BYTE:
174 case EXIF_TYPE_ASCII:
175 case EXIF_TYPE_UNK:
176 size = 1;
177 break;
178
179 case EXIF_TYPE_SHORT:
180 case EXIF_TYPE_SSHORT:
181 case EXIF_TYPE_UNICODE:
182 size = 2;
183 break;
184 case EXIF_TYPE_IFD:
185 case EXIF_TYPE_LONG:
186 case EXIF_TYPE_SLONG:
187 case EXIF_TYPE_FLOAT:
188 size = 4;
189 break;
190
191 case EXIF_TYPE_RAT:
192 case EXIF_TYPE_SRAT:
193 case EXIF_TYPE_DOUBLE:
194 case EXIF_TYPE_LONG8:
195 case EXIF_TYPE_SLONG8:
196 case EXIF_TYPE_IFD8:
197 size = 8;
198 break;
199
200 default:
201 fatal(MYNAME ": Unknown data type %d! Please report.\n", type);
202 }
203 return size;
204 }
205
206 static char*
exif_time_str(const time_t time)207 exif_time_str(const time_t time)
208 {
209 struct tm tm;
210 char* res;
211
212 tm = *localtime(&time);
213 tm.tm_year += 1900;
214 tm.tm_mon += 1;
215 xasprintf(&res, "%04d/%02d/%02d, %02d:%02d:%02d",
216 tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
217
218 return res;
219 }
220
221 static char*
exif_read_str(exif_tag_t * tag)222 exif_read_str(exif_tag_t* tag)
223 {
224 // Panasonic DMC-TZ10 stores datum with trailing spaces.
225 char* buf = xstrndup((char*)tag->data, tag->size);
226 rtrim(buf);
227 return buf;
228 }
229
230 static double
exif_read_double(const exif_tag_t * tag,const int index)231 exif_read_double(const exif_tag_t* tag, const int index)
232 {
233 unsigned int num, den;
234 gbint32* data = (gbint32*)tag->data;
235
236 num = data[index * 2];
237 den = data[(index * 2) + 1];
238 if (den == 0) {
239 den = 1;
240 }
241
242 return (double)num / (double)den;
243 }
244
245 static double
exif_read_coord(const exif_tag_t * tag)246 exif_read_coord(const exif_tag_t* tag)
247 {
248 double res, min, sec;
249
250 res = exif_read_double(tag, 0);
251 if (tag->count == 1) {
252 return res;
253 }
254
255 min = exif_read_double(tag, 1);
256 res += (min / 60);
257 if (tag->count == 2) {
258 return res;
259 }
260
261 sec = exif_read_double(tag, 2);
262 res += (sec / 3600);
263
264 return res;
265 }
266
267 static time_t
exif_read_timestamp(const exif_tag_t * tag)268 exif_read_timestamp(const exif_tag_t* tag)
269 {
270 double hour, min, sec;
271
272 hour = exif_read_double(tag, 0);
273 min = exif_read_double(tag, 1);
274 sec = exif_read_double(tag, 2);
275
276 return ((int)hour * SECONDS_PER_HOUR) + ((int)min * 60) + (int)sec;
277 }
278
279 static time_t
exif_read_datestamp(const exif_tag_t * tag)280 exif_read_datestamp(const exif_tag_t* tag)
281 {
282 struct tm tm;
283 char* str;
284
285 memset(&tm, 0, sizeof(tm));
286 str = xstrndup((char*)tag->data, tag->size);
287 sscanf(str, "%d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
288 xfree(str);
289
290 tm.tm_year -= 1900;
291 tm.tm_mon -= 1;
292
293 return mkgmtime(&tm);
294 }
295
296 static void
exif_release_tag(exif_tag_t * tag)297 exif_release_tag(exif_tag_t* tag)
298 {
299 dequeue(&tag->Q);
300 if (tag->data_is_dynamic) {
301 xfree(tag->data);
302 }
303 xfree(tag);
304 }
305
306 static void
exif_release_ifd(exif_ifd_t * ifd)307 exif_release_ifd(exif_ifd_t* ifd)
308 {
309 if (ifd != NULL) {
310 queue* elem, *tmp;
311
312 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
313 exif_release_tag((exif_tag_t*)elem);
314 }
315 xfree(ifd);
316 }
317 }
318
319 static void
exif_release_apps(void)320 exif_release_apps(void)
321 {
322 queue* e0, *t0;
323
324 QUEUE_FOR_EACH(&exif_apps, e0, t0) {
325 queue* e1, *t1;
326 exif_app_t* app = (exif_app_t*)dequeue(e0);
327
328 if (app->fcache) {
329 gbfclose(app->fcache);
330 }
331 if (app->fexif) {
332 gbfclose(app->fexif);
333 }
334 QUEUE_FOR_EACH(&app->ifds, e1, t1) {
335 exif_ifd_t* ifd = (exif_ifd_t*)dequeue(e1);
336 exif_release_ifd(ifd);
337 }
338 xfree(app);
339 }
340 }
341
342 static gbuint32
exif_ifd_size(exif_ifd_t * ifd)343 exif_ifd_size(exif_ifd_t* ifd)
344 {
345 queue* elem, *tmp;
346 gbuint32 res = 6; /* nr of tags + next_ifd */
347
348 res += (ifd->count * 12);
349 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
350 exif_tag_t* tag = (exif_tag_t*)elem;
351 if (tag->size > 4) {
352 gbuint32 size = tag->size;
353 if (size & 1) {
354 size++;
355 }
356 res += size;
357 }
358 }
359
360 return res;
361 }
362
363 static exif_app_t*
exif_load_apps(void)364 exif_load_apps(void)
365 {
366 exif_app_t* exif_app = NULL;
367
368 while (! gbfeof(fin)) {
369 exif_app_t* app = (exif_app_t*) xcalloc(sizeof(*app), 1);
370
371 ENQUEUE_TAIL(&exif_apps, &app->Q);
372 QUEUE_INIT(&app->ifds);
373 app->fcache = gbfopen(NULL, "wb", MYNAME);
374
375 app->marker = gbfgetuint16(fin);
376 app->len = gbfgetuint16(fin);
377 #ifdef EXIF_DBG
378 printf(MYNAME ": api = %02X, len = %d, offs = %04X\n", app->marker & 0xFF, app->len, gbftell(fin));
379 #endif
380 if (exif_app || (app->marker == 0xFFDA)) /* compressed data */ {
381 gbfcopyfrom(app->fcache, fin, 0x7FFFFFFF);
382 #ifdef EXIF_DBG
383 printf(MYNAME ": compressed data size = %d\n", gbftell(app->fcache));
384 #endif
385 } else {
386 gbfcopyfrom(app->fcache, fin, app->len - 2);
387 if (app->marker == 0xFFE1) {
388 exif_app = app;
389 }
390 }
391 }
392
393 return exif_app;
394 }
395
396 static exif_ifd_t*
exif_read_ifd(exif_app_t * app,const gbuint16 ifd_nr,gbsize_t offs,gbuint32 * exif_ifd_ofs,gbuint32 * gps_ifd_ofs,gbuint32 * inter_ifd_ofs)397 exif_read_ifd(exif_app_t* app, const gbuint16 ifd_nr, gbsize_t offs,
398 gbuint32* exif_ifd_ofs, gbuint32* gps_ifd_ofs, gbuint32* inter_ifd_ofs)
399 {
400 queue* elem, *tmp;
401 gbuint16 i;
402 exif_ifd_t* ifd;
403 gbfile* fin = app->fexif;
404
405 ifd = (exif_ifd_t*) xcalloc(sizeof(*ifd), 1);
406 QUEUE_INIT(&ifd->tags);
407 ENQUEUE_TAIL(&app->ifds, &ifd->Q);
408 ifd->nr = ifd_nr;
409
410 gbfseek(fin, offs, SEEK_SET);
411 ifd->count = gbfgetuint16(fin);
412
413 #ifdef EXIF_DBG
414 {
415 char* name;
416 switch (ifd_nr) {
417 case IFD0:
418 name = "IFD0";
419 break;
420 case IFD1:
421 name = "IFD1";
422 break;
423 case GPS_IFD:
424 name = "GPS";
425 break;
426 case EXIF_IFD:
427 name = "EXIF";
428 break;
429 case INTER_IFD:
430 name = "INTER";
431 break;
432 default:
433 name = "private";
434 break;
435 }
436 printf(MYNAME "-offs 0x%04X: Number of items in IFD%d \"%s\" = %d (0x%2x)\n",
437 offs, ifd_nr, name, ifd->count, ifd->count);
438 }
439 #endif
440 if (ifd->count == 0) {
441 return ifd;
442 }
443
444 for (i = 0; i < ifd->count; i++) {
445 exif_tag_t* tag;
446 offs = gbftell(fin);
447
448 tag = (exif_tag_t*) xcalloc(sizeof(*tag), 1);
449
450 ENQUEUE_TAIL(&ifd->tags, &tag->Q);
451
452 tag->id = gbfgetuint16(fin);
453 tag->type = gbfgetuint16(fin);
454 tag->count = gbfgetuint32(fin);
455 tag->size = exif_type_size(tag->type) * tag->count;
456 tag->data = &tag->value;
457 #ifdef EXIF_DBG
458 tag->offs = offs;
459 #endif
460
461 if (BYTE_TYPE(tag->type) && (tag->count <= 4)) {
462 gbfread(tag->data, 4, 1, fin);
463 } else {
464 tag->value = gbfgetuint32(fin);
465 tag->origin = tag->value;
466 }
467
468 if (ifd_nr == IFD0) {
469 if (tag->id == IFD0_TAG_EXIF_IFD_OFFS) {
470 *exif_ifd_ofs = tag->value;
471 } else if (tag->id == IFD0_TAG_GPS_IFD_OFFS) {
472 *gps_ifd_ofs = tag->value;
473 }
474 } else if (ifd_nr == EXIF_IFD) {
475 if (tag->id == EXIF_IFD_TAG_INTER_IFD_OFFS) {
476 *inter_ifd_ofs = tag->value;
477 }
478 }
479 }
480
481 ifd->next_ifd = gbfgetuint16(fin);
482
483 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
484 exif_tag_t* tag = (exif_tag_t*)elem;
485 if ((tag->size > 4) && (tag->value)) {
486 gbuint16 i;
487 char* ptr;
488
489 tag->data = xmalloc(tag->size);
490 tag->data_is_dynamic = 1;
491
492 ptr = (char*) tag->data;
493 gbfseek(fin, tag->value, SEEK_SET);
494
495 if (BYTE_TYPE(tag->type)) {
496 gbfread(ptr, tag->count, 1, fin);
497 } else for (i = 0; i < tag->count; i++) {
498 switch (tag->type) {
499 case EXIF_TYPE_SHORT:
500 case EXIF_TYPE_SSHORT:
501 *(gbint16*)ptr = gbfgetuint16(fin);
502 break;
503 case EXIF_TYPE_IFD:
504 case EXIF_TYPE_LONG:
505 case EXIF_TYPE_SLONG:
506 *(gbint32*)ptr = gbfgetuint32(fin);
507 break;
508 case EXIF_TYPE_RAT:
509 case EXIF_TYPE_SRAT:
510 *(gbint32*)ptr = gbfgetuint32(fin);
511 *(gbint32*)(ptr+4) = gbfgetuint32(fin);
512 break;
513 case EXIF_TYPE_FLOAT:
514 *(float*)ptr = gbfgetflt(fin);
515 break;
516 case EXIF_TYPE_DOUBLE:
517 *(double*)ptr = gbfgetdbl(fin);
518 break;
519 default:
520 gbfread(ptr, 1, 1, fin);
521 break;
522 }
523 ptr += (tag->size / tag->count);
524 }
525 }
526 #ifdef EXIF_DBG
527 printf(MYNAME "-offs 0x%04X: ifd=%d id=0x%04X t=0x%04X c=%4d s=%4d v=0x%08X",
528 tag->offs, ifd->nr, tag->id, tag->type, tag->count, tag->size, tag->value);
529 if (tag->type == EXIF_TYPE_ASCII) {
530 printf(" \"%s\"", exif_read_str(tag));
531 }
532 printf("\n");
533 #endif
534 }
535
536 return ifd;
537 }
538
539 static void
exif_read_app(exif_app_t * app)540 exif_read_app(exif_app_t* app)
541 {
542 gbsize_t offs;
543 gbuint32 exif_ifd_ofs, gps_ifd_ofs, inter_ifd_ofs;
544 exif_ifd_t* ifd;
545 gbfile* fin = app->fexif;
546
547 #ifdef EXIF_DBG
548 printf(MYNAME ": read_app...\n");
549 print_buff((const char*)fin->handle.mem, 16, MYNAME);
550 printf("\n");
551 #endif
552 exif_ifd_ofs = gps_ifd_ofs = inter_ifd_ofs = 0;
553
554 gbfseek(fin, 4, SEEK_SET);
555 offs = gbfgetuint32(fin);
556
557 ifd = exif_read_ifd(app, IFD0, offs, &exif_ifd_ofs, &gps_ifd_ofs, &inter_ifd_ofs);
558 if (ifd == NULL) {
559 return;
560 }
561
562 if (ifd->next_ifd) {
563 ifd = exif_read_ifd(app, IFD1, ifd->next_ifd, &exif_ifd_ofs, &gps_ifd_ofs, &inter_ifd_ofs);
564 }
565 if (exif_ifd_ofs) {
566 ifd = exif_read_ifd(app, EXIF_IFD, exif_ifd_ofs, NULL, NULL, &inter_ifd_ofs);
567 }
568 if (gps_ifd_ofs) {
569 ifd = exif_read_ifd(app, 3, gps_ifd_ofs, NULL, NULL, NULL);
570 }
571 if (inter_ifd_ofs) {
572 ifd = exif_read_ifd(app, 4, inter_ifd_ofs, NULL, NULL, NULL);
573 }
574 }
575
576 static void
exif_examine_app(exif_app_t * app)577 exif_examine_app(exif_app_t* app)
578 {
579 gbuint16 endianess;
580 gbuint32 ident;
581 gbfile* ftmp = exif_app->fcache;
582 int i;
583
584 gbfrewind(ftmp);
585 ident = gbfgetuint32(ftmp);
586 is_fatal(ident != 0x66697845, MYNAME ": Invalid EXIF header magic.");
587 is_fatal(gbfgetint16(ftmp) != 0, MYNAME ": Error in EXIF header.");
588 endianess = gbfgetint16(ftmp);
589
590 #ifdef EXIF_DBG
591 printf(MYNAME ": endianess = 0x%04X\n", endianess);
592 #endif
593 if (endianess == 0x4949) {
594 ftmp->big_endian = 0;
595 } else if (endianess == 0x4D4D) {
596 ftmp->big_endian = 1;
597 } else {
598 fatal(MYNAME ": Invalid endianess identifier 0x%04X!\n", endianess);
599 }
600
601 gbfseek(ftmp, 6, SEEK_SET);
602 app->fexif = gbfopen(NULL, "wb", MYNAME);
603 app->fexif->big_endian = ftmp->big_endian;
604 i = gbfcopyfrom(app->fexif, ftmp, 0x7FFFFFFF);
605
606 exif_read_app(exif_app);
607 }
608
609 static exif_ifd_t*
exif_find_ifd(exif_app_t * app,const gbuint16 ifd_nr)610 exif_find_ifd(exif_app_t* app, const gbuint16 ifd_nr)
611 {
612 queue* e0, *t0;
613
614 QUEUE_FOR_EACH(&app->ifds, e0, t0) {
615 exif_ifd_t* ifd = (exif_ifd_t*)e0;
616
617 if (ifd->nr == ifd_nr) {
618 return ifd;
619 }
620 }
621 return NULL;
622 }
623
624 static exif_tag_t*
exif_find_tag(exif_app_t * app,const gbuint16 ifd_nr,const gbuint16 tag_id)625 exif_find_tag(exif_app_t* app, const gbuint16 ifd_nr, const gbuint16 tag_id)
626 {
627 exif_ifd_t* ifd = exif_find_ifd(app, ifd_nr);
628 if (ifd != NULL) {
629 queue* elem, *tmp;
630 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
631 exif_tag_t* tag = (exif_tag_t*)elem;
632 if (tag->id == tag_id) {
633 return tag;
634 }
635 }
636 }
637 return NULL;
638 }
639
640 static time_t
exif_get_exif_time(exif_app_t * app)641 exif_get_exif_time(exif_app_t* app)
642 {
643 exif_tag_t* tag;
644 time_t res = 0;
645
646 tag = exif_find_tag(app, EXIF_IFD, 0x9003); /* DateTimeOriginal from EXIF */
647 if (! tag) {
648 tag = exif_find_tag(app, IFD0, 0x0132); /* DateTime from IFD0 */
649 }
650 if (! tag) {
651 tag = exif_find_tag(app, EXIF_IFD, 0x9004); /* DateTimeDigitized from EXIF */
652 }
653 if (tag) {
654 struct tm tm;
655 char* c, *str;
656
657 memset(&tm, 0, sizeof(tm));
658 str = exif_read_str(tag);
659 c = strptime(str, "%Y:%m:%d %H:%M:%S", &tm);
660 if (c && (*c == '\0')) {
661 res = mklocaltime(&tm);
662 }
663
664 xfree(str);
665 }
666 return res;
667 }
668
669 static waypoint*
exif_waypt_from_exif_app(exif_app_t * app)670 exif_waypt_from_exif_app(exif_app_t* app)
671 {
672 waypoint* wpt;
673 queue* elem, *tmp;
674 exif_ifd_t* ifd;
675 exif_tag_t* tag;
676 char lat_ref = '\0';
677 char lon_ref = '\0';
678 char alt_ref = 0;
679 char speed_ref = '\0';
680 char* datum = NULL;
681 char mode = '\0';
682 double gpsdop = unknown_alt;
683 double alt = unknown_alt;
684 time_t timestamp = UNKNOWN_TIMESTAMP;
685 time_t datestamp = UNKNOWN_TIMESTAMP;
686
687 ifd = exif_find_ifd(app, GPS_IFD);
688 if (ifd == NULL) {
689 return NULL;
690 }
691
692 wpt = waypt_new();
693
694 wpt->latitude = unknown_alt;
695 wpt->longitude = unknown_alt;
696
697 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
698 tag = (exif_tag_t*)elem;
699
700 switch (tag->id) {
701 case GPS_IFD_TAG_VERSION:
702 break;
703 case GPS_IFD_TAG_LATREF:
704 lat_ref = *(char*)tag->data;
705 break;
706 case GPS_IFD_TAG_LAT:
707 wpt->latitude = exif_read_coord(tag);
708 break;
709 case GPS_IFD_TAG_LONREF:
710 lon_ref = *(char*)tag->data;
711 break;
712 case GPS_IFD_TAG_LON:
713 wpt->longitude = exif_read_coord(tag);
714 break;
715 case GPS_IFD_TAG_ALTREF:
716 alt_ref = *(char*)tag->data;
717 break;
718 case GPS_IFD_TAG_ALT:
719 alt = exif_read_double(tag, 0);
720 break;
721 case GPS_IFD_TAG_TIMESTAMP:
722 timestamp = exif_read_timestamp(tag);
723 break;
724 case GPS_IFD_TAG_SAT:
725 wpt->sat = atoi((char*)tag->data);
726 break;
727 case GPS_IFD_TAG_MODE:
728 mode = *(char*)tag->data;
729 break;
730 case GPS_IFD_TAG_DOP:
731 gpsdop = exif_read_double(tag, 0);
732 break;
733 case GPS_IFD_TAG_SPEEDREF:
734 speed_ref = *(char*)tag->data;
735 break;
736 case GPS_IFD_TAG_SPEED:
737 WAYPT_SET(wpt, speed, exif_read_double(tag, 0));
738 break;
739 case GPS_IFD_TAG_DATUM:
740 datum = exif_read_str(tag);
741 break;
742 case GPS_IFD_TAG_DATESTAMP:
743 datestamp = exif_read_datestamp(tag);
744 break;
745 }
746 }
747
748 if ((wpt->latitude == unknown_alt) || (wpt->longitude == unknown_alt)) {
749 fatal(MYNAME ": Missing GPSLatitude and/or GPSLongitude!\n");
750 }
751
752 if (lat_ref == 'S') {
753 wpt->latitude *= -1;
754 } else if (lat_ref != 'N') {
755 warning(MYNAME ": GPSLatitudeRef not set! Using N(orth).\n");
756 }
757
758 if (lon_ref == 'W') {
759 wpt->longitude *= -1;
760 } else if (lon_ref != 'E') {
761 warning(MYNAME ": GPSLongitudeRef not set! Using E(east).\n");
762 }
763
764 #ifdef EXIF_DBG
765 printf(MYNAME "-GPSLatitude = %12.7f\n", wpt->latitude);
766 printf(MYNAME "-GPSLongitude = %12.7f\n", wpt->longitude);
767 #endif
768 if (datum) {
769 int idatum = gt_lookup_datum_index(datum, MYNAME);
770 if (idatum < 0) {
771 fatal(MYNAME ": Unknown GPSMapDatum \"%s\"!\n", datum);
772 }
773 if (idatum != DATUM_WGS84) {
774 double alt;
775 GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0,
776 &wpt->latitude, &wpt->longitude, &alt, idatum);
777 }
778 xfree(datum);
779 }
780
781 if (alt != unknown_alt) {
782 double sign;
783 switch (alt_ref != 0) {
784 case 0:
785 sign = 1.0;
786 break;
787
788 case 1:
789 sign = -1.0;
790 break;
791
792 default:
793 warning(MYNAME ": Invalid GPSAltitudeRef (%d)! Using 0 (= Sea level).\n", alt_ref);
794 sign = 1.0;
795 }
796 wpt->altitude = sign * alt;
797 #ifdef EXIF_DBG
798 printf(MYNAME "-GPSAltitude = %12.7f m\n", wpt->altitude);
799 #endif
800 }
801
802 if WAYPT_HAS(wpt, speed) {
803 switch (speed_ref) {
804 case 'K':
805 wpt->speed = KPH_TO_MPS(wpt->speed);
806 break;
807 case 'M':
808 wpt->speed = MPH_TO_MPS(wpt->speed);
809 break;
810 case 'N':
811 wpt->speed = KNOTS_TO_MPS(wpt->speed);
812 break;
813 default:
814 wpt->speed = 0;
815 WAYPT_UNSET(wpt, speed);
816 warning(MYNAME ": Unknown GPSSpeedRef unit %c (0x%02x)!\n", speed_ref, speed_ref);
817 }
818 #ifdef EXIF_DBG
819 if WAYPT_HAS(wpt, speed) {
820 printf(MYNAME "-GPSSpeed = %12.2f m/s\n", wpt->speed);
821 }
822 #endif
823 }
824
825 if (mode == '2') {
826 wpt->fix = fix_2d;
827 if (gpsdop != unknown_alt) {
828 wpt->hdop = gpsdop;
829 }
830 } else if (mode == '3') {
831 wpt->fix = fix_3d;
832 if (gpsdop != unknown_alt) {
833 wpt->pdop = gpsdop;
834 }
835 }
836
837 if (timestamp != UNKNOWN_TIMESTAMP) {
838 if (datestamp != UNKNOWN_TIMESTAMP) {
839 timestamp += datestamp;
840 }
841 } else {
842 timestamp = datestamp;
843 }
844 if (timestamp != UNKNOWN_TIMESTAMP) {
845 #ifdef EXIF_DBG
846 char* str = exif_time_str(timestamp);
847 printf(MYNAME "-GPSTimeStamp = %s\n", str);
848 xfree(str);
849 #endif
850 wpt->creation_time = timestamp;
851 } else {
852 wpt->creation_time = exif_get_exif_time(app);
853 }
854
855 tag = exif_find_tag(app, EXIF_IFD, EXIF_IFD_TAG_USER_CMT); /* UserComment */
856 if (tag && (tag->size > 8)) {
857 char* str = NULL;
858 if (memcmp(tag->data, "ASCII\0\0\0", 8) == 0) {
859 str = xstrndup((char*)tag->data + 8, tag->size - 8);
860 } else if (memcmp(tag->data, "UNICODE\0", 8) == 0) {
861 int i, len = (tag->size - 8) / 2;
862 gbint16* s = (gbint16*)((char*)tag->data + 8);
863 for (i = 0; i < len; i++) {
864 s[i] = be_read16(&s[i]); /* always BE ? */
865 }
866 str = cet_str_uni_to_any(s, len, global_opts.charset);
867 }
868 if (str != NULL) {
869 wpt->notes = str;
870 }
871 }
872
873 if (opt_filename) {
874 char* c, *cx;
875 char* str = xstrdup(fin->name);
876
877 cx = str;
878 if ((c = strrchr(cx, ':'))) {
879 cx = c + 1;
880 }
881 if ((c = strrchr(cx, '\\'))) {
882 cx = c + 1;
883 }
884 if ((c = strrchr(cx, '/'))) {
885 cx = c + 1;
886 }
887 if (((c = strchr(cx, '.'))) && (c != cx)) {
888 *c = '\0';
889 }
890
891 if (wpt->shortname) {
892 xfree(wpt->shortname);
893 }
894 wpt->shortname = xstrdup(cx);
895 xfree(str);
896 }
897
898 return wpt;
899 }
900
901 static void
exif_dec2frac(double val,gbint32 * num,gbint32 * den)902 exif_dec2frac(double val, gbint32* num, gbint32* den)
903 {
904 char sval[16], snum[16];
905 char dot = 0;
906 int den1 = 1;
907 int num1, num2, den2, rem;
908 char* cx;
909 double vx;
910
911 if (val < 0.000000001) {
912 val = 0.0;
913 } else if (val > 999999999.0) {
914 fatal(MYNAME ": Value (%f) to big for a rational representation!\n", val);
915 }
916
917 num1 = 0;
918 vx = fabs(val);
919 while (vx > 1) {
920 num1++;
921 vx = vx / 10;
922 }
923
924 snprintf(sval, sizeof(sval), "%*.*f", 9, 9 - num1, fabs(val));
925 snum[0] = '\0';
926
927 cx = sval;
928 while (*cx) {
929 if (dot) {
930 den1 *= 10;
931 }
932 if (*cx == '.') {
933 dot = 1;
934 } else {
935 strncat(snum, cx, 1);
936 }
937 cx++;
938 }
939
940 num1 = atoi(snum);
941 if (den1 == 1) {
942 *num = num1;
943 *den = den1;
944 }
945
946 num2 = num1;
947 den2 = den1;
948 rem = 1;
949
950 /* Euclid's Algorithm to find the gcd */
951 while (num2 % den2) {
952 rem = num2 % den2;
953 num2 = den2;
954 den2 = rem;
955 }
956 if (den2 != den1) {
957 rem = den2;
958 }
959
960 *num = num1 / rem;
961 *den = den1 / rem;
962 }
963
964 static exif_tag_t*
exif_put_value(const int ifd_nr,const gbuint16 tag_id,const gbuint16 type,const gbuint32 count,const int index,const void * data)965 exif_put_value(const int ifd_nr, const gbuint16 tag_id, const gbuint16 type, const gbuint32 count, const int index, const void* data)
966 {
967 exif_tag_t* tag = NULL;
968 exif_ifd_t* ifd;
969 gbuint16 item_size, size;
970
971 ifd = exif_find_ifd(exif_app, ifd_nr);
972 if (ifd == NULL) {
973 ifd = (exif_ifd_t*) xcalloc(sizeof(*ifd), 1);
974 ifd->nr = ifd_nr;
975 QUEUE_INIT(&ifd->tags);
976 ENQUEUE_TAIL(&exif_app->ifds, &ifd->Q);
977 } else {
978 tag = exif_find_tag(exif_app, ifd_nr, tag_id);
979 }
980
981 item_size = exif_type_size(type);
982
983 if ((data == NULL) || (count < 1) || (index < 0)) {
984 size = 0;
985 } else {
986 size = (index + count) * item_size;
987 }
988
989 if (tag == NULL) {
990 if (size == 0) {
991 return NULL;
992 }
993
994 tag = (exif_tag_t*) xcalloc(sizeof(*tag), 1);
995
996 tag->id = tag_id;
997 tag->type = type;
998 tag->count = index + count;
999 tag->size = size;
1000 tag->data = xcalloc((size < 4) ? 4 : size, 1);
1001 tag->data_is_dynamic = 1;
1002 ifd->count++;
1003
1004 ENQUEUE_TAIL(&ifd->tags, &tag->Q);
1005 } else {
1006 if (size == 0) { /* remove this element */
1007 ifd->count--;
1008 exif_release_tag(tag);
1009 return NULL;
1010 }
1011 if (tag->count < (index + count)) {
1012 if (! tag->data_is_dynamic) {
1013 void* tmp = xmalloc(tag->size < 4 ? 4 : tag->size);
1014 memcpy(tmp, tag->data, tag->size);
1015 tag->data = tmp;
1016 tag->data_is_dynamic = 1;
1017 }
1018 tag->size = size;
1019 tag->count = index + count;
1020 tag->data = xrealloc(tag->data, size < 4 ? 4 : size);
1021 }
1022 }
1023
1024 switch (type) {
1025 case EXIF_TYPE_RAT:
1026 case EXIF_TYPE_SRAT: {
1027 double val = *(double*)data;
1028 gbuint32* dest = (gbuint32*) tag->data;
1029
1030 if ((int)val == val) {
1031 dest[index * 2] = (int)val;
1032 dest[(index * 2) + 1] = 1;
1033 } else {
1034 gbint32 Nom, Den;
1035 exif_dec2frac(val, &Nom, &Den);
1036 if ((type == EXIF_TYPE_SRAT) && (val < 0.0)) {
1037 Nom *= -1;
1038 }
1039 dest[index * 2] = Nom;
1040 dest[(index * 2) + 1] = Den;
1041 }
1042 }
1043 break;
1044 default: {
1045 char* dest = (char*) tag->data;
1046 memcpy(&dest[index * item_size], data, count * item_size);
1047 }
1048 }
1049 return tag;
1050 }
1051
1052
1053 static void
exif_put_double(const int ifd_nr,const int tag_id,const int index,const double val)1054 exif_put_double(const int ifd_nr, const int tag_id, const int index, const double val)
1055 {
1056 double d = fabs(val);
1057 exif_put_value(ifd_nr, tag_id, EXIF_TYPE_RAT, 1, index, &d);
1058 }
1059
1060
1061 static void
exif_put_str(const int ifd_nr,const int tag_id,const char * val)1062 exif_put_str(const int ifd_nr, const int tag_id, const char* val)
1063 {
1064 int len = (val) ? strlen(val) + 1 : 0;
1065 exif_put_value(ifd_nr, tag_id, EXIF_TYPE_ASCII, len, 0, val);
1066 }
1067
1068 static void
exif_put_coord(const int ifd_nr,const int tag_id,const double val)1069 exif_put_coord(const int ifd_nr, const int tag_id, const double val)
1070 {
1071 double vmin, vsec;
1072 int vint;
1073
1074 vint = abs((int) val);
1075 vmin = 60.0 * (fabs(val) - vint);
1076 vsec = 60.0 * (vmin - floor(vmin));
1077 vmin = floor(vmin);
1078
1079 exif_put_double(ifd_nr, tag_id, 0, (double)vint);
1080 exif_put_double(ifd_nr, tag_id, 1, (double)vmin);
1081 exif_put_double(ifd_nr, tag_id, 2, (double)vsec);
1082 }
1083
1084 static void
exif_put_long(const int ifd_nr,const int tag_id,const int index,const gbint32 val)1085 exif_put_long(const int ifd_nr, const int tag_id, const int index, const gbint32 val)
1086 {
1087 exif_put_value(ifd_nr, tag_id, EXIF_TYPE_LONG, 1, index, &val);
1088 }
1089
1090 static void
exif_remove_tag(const int ifd_nr,const int tag_id)1091 exif_remove_tag(const int ifd_nr, const int tag_id)
1092 {
1093 exif_put_value(ifd_nr, tag_id, EXIF_TYPE_BYTE, 0, 0, NULL);
1094 }
1095
1096 static void
exif_find_wpt_by_time(const waypoint * wpt)1097 exif_find_wpt_by_time(const waypoint* wpt)
1098 {
1099 if (wpt->creation_time <= 0) {
1100 return;
1101 }
1102
1103 if (exif_wpt_ref == NULL) {
1104 exif_wpt_ref = wpt;
1105 } else if (abs(exif_time_ref - wpt->creation_time) < abs(exif_time_ref - exif_wpt_ref->creation_time)) {
1106 exif_wpt_ref = wpt;
1107 }
1108 }
1109
1110 static void
exif_find_wpt_by_name(const waypoint * wpt)1111 exif_find_wpt_by_name(const waypoint* wpt)
1112 {
1113 if (exif_wpt_ref != NULL) {
1114 return;
1115 } else if ((wpt->shortname != NULL) && (case_ignore_strcmp(wpt->shortname, opt_name) == 0)) {
1116 exif_wpt_ref = wpt;
1117 }
1118 }
1119
1120
1121 static int
exif_sort_tags_cb(const queue * A,const queue * B)1122 exif_sort_tags_cb(const queue* A, const queue* B)
1123 {
1124 exif_tag_t* ta = (exif_tag_t*)A;
1125 exif_tag_t* tb = (exif_tag_t*)B;
1126
1127 return ta->id - tb->id;
1128 }
1129
1130 static int
exif_sort_ifds_cb(const queue * A,const queue * B)1131 exif_sort_ifds_cb(const queue* A, const queue* B)
1132 {
1133 exif_ifd_t* ia = (exif_ifd_t*)A;
1134 exif_ifd_t* ib = (exif_ifd_t*)B;
1135
1136 return ia->nr - ib->nr;
1137 }
1138
1139 static void
exif_write_value(exif_tag_t * tag,gbfile * fout)1140 exif_write_value(exif_tag_t* tag, gbfile* fout)
1141 {
1142 if (tag->size > 4) {
1143 gbfputuint32(tag->value, fout); /* offset to data */
1144 } else {
1145 char* data = (char*) tag->data;
1146
1147 if BYTE_TYPE(tag->type) {
1148 gbfwrite(data, 4, 1, fout);
1149 } else if WORD_TYPE(tag->type) {
1150 gbfputuint16(*(gbuint16*)data, fout);
1151 gbfputuint16(*(gbuint16*)(data+2), fout);
1152 } else if LONG_TYPE(tag->type) {
1153 gbfputuint32(*(gbuint32*)data, fout);
1154 } else if (tag->type == EXIF_TYPE_FLOAT) {
1155 gbfputflt(*(float*)data, fout);
1156 } else {
1157 fatal(MYNAME ": Unknown data type %d!\n", tag->type);
1158 }
1159 }
1160 }
1161
1162 static void
exif_write_ifd(const exif_ifd_t * ifd,const char next,gbfile * fout)1163 exif_write_ifd(const exif_ifd_t* ifd, const char next, gbfile* fout)
1164 {
1165 gbsize_t offs;
1166 queue* elem, *tmp;
1167
1168 gbfputuint16(ifd->count, fout);
1169 offs = gbftell(fout) + (ifd->count * 12) + 4;
1170
1171 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
1172 exif_tag_t* tag = (exif_tag_t*)elem;
1173
1174 gbfputuint16(tag->id, fout);
1175 gbfputuint16(tag->type, fout);
1176 gbfputuint32(tag->count, fout);
1177 if (tag->size > 4) {
1178 tag->value = offs;
1179 offs += tag->size;
1180 if (offs & 1) {
1181 offs++;
1182 }
1183 gbfputuint32(tag->value, fout);
1184 } else {
1185 exif_write_value(tag, fout);
1186 }
1187 }
1188
1189 if (next) {
1190 gbfputuint32(offs, fout);
1191 } else {
1192 gbfputuint32(0, fout);
1193 }
1194
1195 QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
1196 exif_tag_t* tag = (exif_tag_t*)elem;
1197
1198 if (tag->size > 4) {
1199 gbuint16 i;
1200 char* ptr = (char*) tag->data;
1201
1202 if BYTE_TYPE(tag->type) {
1203 gbfwrite(tag->data, tag->size, 1, fout);
1204 } else for (i = 0; i < tag->count; i++) {
1205 switch (tag->type) {
1206 case EXIF_TYPE_SHORT:
1207 case EXIF_TYPE_SSHORT:
1208 gbfputuint16(*(gbint16*)ptr, fout);
1209 break;
1210 case EXIF_TYPE_LONG:
1211 case EXIF_TYPE_SLONG:
1212 case EXIF_TYPE_IFD:
1213 gbfputuint32(*(gbint32*)ptr, fout);
1214 break;
1215 case EXIF_TYPE_RAT:
1216 case EXIF_TYPE_SRAT:
1217 gbfputuint32(*(gbint32*)ptr, fout);
1218 gbfputuint32(*(gbint32*)(ptr+4), fout);
1219 break;
1220 case EXIF_TYPE_FLOAT:
1221 gbfputflt(*(float*)ptr, fout);
1222 break;
1223 case EXIF_TYPE_DOUBLE:
1224 gbfputdbl(*(double*)ptr, fout);
1225 break;
1226 default:
1227 gbfwrite(ptr, exif_type_size(tag->type), 1, fin);
1228 break;
1229 }
1230 ptr += (tag->size / tag->count);
1231 }
1232 if (gbftell(fout) & 1) {
1233 gbfputc(0, fout);
1234 }
1235 }
1236 }
1237 }
1238
1239 static void
exif_write_apps(void)1240 exif_write_apps(void)
1241 {
1242 queue* e0, *t0;
1243
1244 gbfputuint16(0xFFD8, fout);
1245
1246 QUEUE_FOR_EACH(&exif_apps, e0, t0) {
1247 exif_app_t* app = (exif_app_t*)e0;
1248
1249 gbfputuint16(app->marker, fout);
1250
1251 if (app == exif_app) {
1252 queue* e1, *t1;
1253 gbuint16 len = 8;
1254 gbfile* ftmp;
1255 exif_tag_t* tag;
1256
1257 exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, 0);
1258 exif_put_long(GPS_IFD, GPS_IFD_TAG_VERSION, 0, 2);
1259
1260 sortqueue(&exif_app->ifds, exif_sort_ifds_cb);
1261
1262 QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1263 exif_ifd_t* ifd = (exif_ifd_t*)e1;
1264
1265 if (ifd->nr == GPS_IFD) {
1266 exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, len);
1267 } else if (ifd->nr == EXIF_IFD) {
1268 exif_put_long(IFD0, IFD0_TAG_EXIF_IFD_OFFS, 0, len);
1269 } else if (ifd->nr == INTER_IFD) {
1270 exif_put_long(EXIF_IFD, EXIF_IFD_TAG_INTER_IFD_OFFS, 0, len);
1271 }
1272
1273 len += exif_ifd_size(ifd);
1274 }
1275
1276 len += 4; /* DWORD(0) after last ifd */
1277
1278 if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_OFFS))) {
1279 exif_put_long(IFD1, IFD1_TAG_JPEG_OFFS, 0, len);
1280 }
1281
1282 QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1283 exif_ifd_t* ifd = (exif_ifd_t*)e1;
1284 sortqueue(&ifd->tags, exif_sort_tags_cb);
1285 }
1286
1287 ftmp = gbfopen_be(NULL, "wb", MYNAME);
1288 ftmp->big_endian = app->fcache->big_endian;
1289
1290 gbfwrite((ftmp->big_endian) ? "MM" : "II", 2, 1, ftmp);
1291 gbfputuint16(0x2A, ftmp);
1292 gbfputuint32(0x08, ftmp); /* offset to first IFD */
1293
1294 QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1295 exif_ifd_t* ifd = (exif_ifd_t*)e1;
1296 exif_ifd_t* ifd_next = (exif_ifd_t*)t1;
1297 char next;
1298
1299 if ((ifd->nr == IFD0) && (ifd_next->nr == IFD1)) {
1300 next = 1;
1301 } else {
1302 next = 0;
1303 }
1304
1305 exif_write_ifd(ifd, next, ftmp);
1306 len = gbftell(ftmp);
1307 }
1308
1309 gbfputuint32(0, ftmp); /* DWORD(0) after last ifd */
1310
1311 if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_OFFS))) {
1312 gbsize_t offs = tag->origin;
1313 if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_SIZE))) {
1314 gbfseek(app->fexif, offs, SEEK_SET);
1315 gbfcopyfrom(ftmp, app->fexif, tag->value);
1316 }
1317 }
1318
1319 len = gbftell(ftmp);
1320 gbfrewind(ftmp);
1321 gbfputuint16(len + 8, fout);
1322 gbfwrite("Exif\0\0", 6, 1, fout);
1323 gbfcopyfrom(fout, ftmp, len);
1324
1325 gbfclose(ftmp);
1326 } else {
1327 gbfputuint16(app->len, fout);
1328 gbfrewind(app->fcache);
1329 gbfcopyfrom(fout, app->fcache, 0x7FFFFFFF);
1330 }
1331 }
1332 }
1333
1334 /*******************************************************************************
1335 * %%% global callbacks called by gpsbabel main process %%% *
1336 *******************************************************************************/
1337
1338 static void
exif_rd_init(const char * fname)1339 exif_rd_init(const char* fname)
1340 {
1341 fin = gbfopen_be(fname, "rb", MYNAME);
1342 QUEUE_INIT(&exif_apps);
1343 }
1344
1345 static void
exif_rd_deinit(void)1346 exif_rd_deinit(void)
1347 {
1348 exif_release_apps();
1349 gbfclose(fin);
1350 }
1351
1352 static void
exif_read(void)1353 exif_read(void)
1354 {
1355 gbuint16 soi;
1356 waypoint* wpt;
1357
1358 soi = gbfgetuint16(fin);
1359 is_fatal(soi != 0xFFD8, MYNAME ": Unknown image file."); /* only jpeg for now */
1360
1361 exif_app = exif_load_apps();
1362 is_fatal(exif_app == NULL, MYNAME ": No EXIF header in source file \"%s\".", fin->name);
1363
1364 exif_examine_app(exif_app);
1365 wpt = exif_waypt_from_exif_app(exif_app);
1366 if (wpt) {
1367 waypt_add(wpt);
1368 }
1369 }
1370
1371 static void
exif_wr_init(const char * fname)1372 exif_wr_init(const char* fname)
1373 {
1374 gbuint16 soi;
1375 char* tmpname;
1376
1377 exif_success = 0;
1378 exif_fout_name = xstrdup(fname);
1379
1380 QUEUE_INIT(&exif_apps);
1381
1382 fin = gbfopen_be(fname, "rb", MYNAME);
1383 is_fatal(fin->is_pipe, MYNAME ": Sorry, this format cannot be used with pipes!");
1384
1385 soi = gbfgetuint16(fin);
1386 is_fatal(soi != 0xFFD8, MYNAME ": Unknown image file.");
1387 exif_app = exif_load_apps();
1388 is_fatal(exif_app == NULL, MYNAME ": No EXIF header found in source file \"%s\".", fin->name);
1389 exif_examine_app(exif_app);
1390 gbfclose(fin);
1391
1392 exif_time_ref = exif_get_exif_time(exif_app);
1393 if (exif_time_ref == 0) {
1394 fatal(MYNAME ": No valid timestamp found in picture!\n");
1395 }
1396
1397 xasprintf(&tmpname, "%s.jpg", fname);
1398 fout = gbfopen_be(tmpname, "wb", MYNAME);
1399 xfree(tmpname);
1400 }
1401
1402 static void
exif_wr_deinit(void)1403 exif_wr_deinit(void)
1404 {
1405 char* tmpname;
1406
1407 exif_release_apps();
1408 tmpname = xstrdup(fout->name);
1409 gbfclose(fout);
1410
1411 if (exif_success) {
1412 if (*opt_overwrite == '1') {
1413 remove(exif_fout_name);
1414 rename(tmpname, exif_fout_name);
1415 }
1416 } else {
1417 remove(tmpname);
1418 }
1419
1420 xfree(exif_fout_name);
1421 xfree(tmpname);
1422 }
1423
1424 static void
exif_write(void)1425 exif_write(void)
1426 {
1427 char alt_ref = 0;
1428 time_t frame;
1429
1430 exif_wpt_ref = NULL;
1431
1432 if (opt_name) {
1433 waypt_disp_all(exif_find_wpt_by_name);
1434 if (exif_wpt_ref == NULL) {
1435 route_disp_all(NULL, NULL, exif_find_wpt_by_name);
1436 }
1437 if (exif_wpt_ref == NULL) {
1438 track_disp_all(NULL, NULL, exif_find_wpt_by_name);
1439 }
1440 if (exif_wpt_ref == NULL) {
1441 warning(MYNAME ": No matching point with name \"%s\" found.\n", opt_name);
1442 }
1443 } else {
1444 char* str = exif_time_str(exif_time_ref);
1445
1446 track_disp_all(NULL, NULL, exif_find_wpt_by_time);
1447 route_disp_all(NULL, NULL, exif_find_wpt_by_time);
1448 waypt_disp_all(exif_find_wpt_by_time);
1449
1450 frame = atoi(opt_frame);
1451
1452 if (exif_wpt_ref == NULL) {
1453 warning(MYNAME ": No point with a valid timestamp found.\n");
1454 } else if (abs(exif_time_ref - exif_wpt_ref->creation_time) > frame) {
1455 warning(MYNAME ": No matching point found for image date %s!\n", str);
1456 if (exif_wpt_ref != NULL) {
1457 char* str = exif_time_str(exif_wpt_ref->creation_time);
1458 warning(MYNAME ": Best is from %s, %d second(s) away.\n",
1459 str, abs(exif_time_ref - exif_wpt_ref->creation_time));
1460 xfree(str);
1461 }
1462 exif_wpt_ref = NULL;
1463 }
1464 xfree(str);
1465 }
1466
1467 if (exif_wpt_ref != NULL) {
1468 const waypoint* wpt = exif_wpt_ref;
1469
1470 exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, 0);
1471 exif_put_long(GPS_IFD, GPS_IFD_TAG_VERSION, 0, 2);
1472 exif_put_str(GPS_IFD, GPS_IFD_TAG_DATUM, "WGS-84");
1473
1474 exif_put_str(GPS_IFD, GPS_IFD_TAG_LATREF, wpt->latitude < 0 ? "S" : "N");
1475 exif_put_coord(GPS_IFD, GPS_IFD_TAG_LAT, fabs(wpt->latitude));
1476 exif_put_str(GPS_IFD, GPS_IFD_TAG_LONREF, wpt->longitude < 0 ? "W" : "E");
1477 exif_put_coord(GPS_IFD, GPS_IFD_TAG_LON, fabs(wpt->longitude));
1478
1479 if (wpt->altitude == unknown_alt) {
1480 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_ALT);
1481 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_ALTREF);
1482 } else {
1483 exif_put_value(GPS_IFD, GPS_IFD_TAG_ALTREF, EXIF_TYPE_BYTE, 1, 0, &alt_ref);
1484 exif_put_double(GPS_IFD, GPS_IFD_TAG_ALT, 0, wpt->altitude);
1485 }
1486
1487 if (wpt->creation_time) {
1488 struct tm tm;
1489 char buf[32];
1490
1491 tm = *gmtime(&wpt->creation_time);
1492 tm.tm_year += 1900;
1493 tm.tm_mon += 1;
1494
1495 exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 0, tm.tm_hour);
1496 exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 1, tm.tm_min);
1497 exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 2, tm.tm_sec);
1498
1499 snprintf(buf, sizeof(buf), "%04d:%02d:%02d", tm.tm_year, tm.tm_mon, tm.tm_mday);
1500 exif_put_str(GPS_IFD, GPS_IFD_TAG_DATESTAMP, buf);
1501 } else {
1502 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_TIMESTAMP);
1503 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_DATESTAMP);
1504 }
1505
1506 if (wpt->sat > 0) {
1507 char buf[16];
1508 snprintf(buf, sizeof(buf), "%d", wpt->sat);
1509 exif_put_str(GPS_IFD, GPS_IFD_TAG_SAT, buf);
1510 } else {
1511 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SAT);
1512 }
1513
1514 if (wpt->fix == fix_2d) {
1515 exif_put_str(GPS_IFD, GPS_IFD_TAG_MODE, "2");
1516 } else if (wpt->fix == fix_3d) {
1517 exif_put_str(GPS_IFD, GPS_IFD_TAG_MODE, "3");
1518 } else {
1519 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_MODE);
1520 }
1521
1522 if (wpt->hdop > 0) {
1523 exif_put_double(GPS_IFD, GPS_IFD_TAG_DOP, 0, wpt->hdop);
1524 } else {
1525 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_DOP);
1526 }
1527
1528 if WAYPT_HAS(wpt, speed) {
1529 exif_put_str(GPS_IFD, GPS_IFD_TAG_SPEEDREF, "K");
1530 exif_put_double(GPS_IFD, GPS_IFD_TAG_SPEED, 0, MPS_TO_KPH(wpt->speed));
1531 } else {
1532 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SPEEDREF);
1533 exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SPEED);
1534 }
1535
1536 exif_write_apps(); /* Success, write the new file */
1537
1538 exif_success = 1;
1539 }
1540
1541 }
1542
1543 /**************************************************************************/
1544
1545 ff_vecs_t exif_vecs = {
1546 ff_type_file,
1547 {
1548 (ff_cap)(ff_cap_read | ff_cap_write) /* waypoints */,
1549 ff_cap_none /* tracks */,
1550 ff_cap_none /* routes */
1551 },
1552 exif_rd_init,
1553 exif_wr_init,
1554 exif_rd_deinit,
1555 exif_wr_deinit,
1556 exif_read,
1557 exif_write,
1558 NULL,
1559 exif_args,
1560 CET_CHARSET_UTF8, 0
1561 };
1562
1563 /**************************************************************************/
1564