Exemplo n.º 1
0
metadata_t *
getMetadata(const char *fileName)
{
	metadata_t	*mdata;

	if (metadataFromProgram) {
		if ((mdata = metadata_program(fileName, nFlag)) == NULL)
			return (NULL);

		if (!metadata_program_update(mdata, METADATA_ALL)) {
			metadata_free(&mdata);
			return (NULL);
		}
	} else {
		if ((mdata = metadata_file(fileName, nFlag)) == NULL)
			return (NULL);

		if (!metadata_file_update(mdata)) {
			metadata_free(&mdata);
			return (NULL);
		}
	}

	return (mdata);
}
Exemplo n.º 2
0
/**
 * a_geotag_get_exif_date_from_file:
 * @filename: The image file to process
 * @has_GPS_info: Returns whether the file has existing GPS information
 *
 * Returns: An allocated string with the date and time in EXIF_DATE_FORMAT, otherwise NULL if some kind of failure
 *
 *  Here EXIF processing is used to get time information
 *
 */
gchar* a_geotag_get_exif_date_from_file ( const gchar *filename, gboolean *has_GPS_info )
{
	gchar* datetime = NULL;
	*has_GPS_info = FALSE;

#ifdef HAVE_LIBGEXIV2
	GExiv2Metadata *gemd = gexiv2_metadata_new ();
	if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
		gdouble lat, lon;
		*has_GPS_info = ( gexiv2_metadata_get_gps_longitude(gemd,&lon) && gexiv2_metadata_get_gps_latitude(gemd,&lat) );

		// Prefer 'Photo' version over 'Image'
		if ( gexiv2_metadata_has_tag ( gemd, "Exif.Photo.DateTimeOriginal" ) )
			datetime = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Photo.DateTimeOriginal" ) );
		else
			datetime = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.DateTimeOriginal" ) );
	}
	metadata_free ( gemd );
#else
#ifdef HAVE_LIBEXIF
	ExifData *ed = exif_data_new_from_file ( filename );

	// Detect EXIF load failure
	if ( !ed )
		return datetime;

	gchar str[128];
	ExifEntry *ee;

	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL);
	if ( ee ) {
		exif_entry_get_value ( ee, str, 128 );
		datetime = g_strdup ( str );
	}

	// Check GPS Info

	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_VERSION_ID);
	// Confirm this has a GPS Id - normally "2.0.0.0" or "2.2.0.0"
	if ( ee && ee->components == 4 )
		*has_GPS_info = TRUE;

	// Check other basic GPS fields exist too
	// I have encountered some images which have just the EXIF_TAG_GPS_VERSION_ID but nothing else
	// So to confirm check more EXIF GPS TAGS:
	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LATITUDE);
	if ( !ee )
		*has_GPS_info = FALSE;
	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LONGITUDE);
	if ( !ee )
		*has_GPS_info = FALSE;

	exif_data_free ( ed );
#endif
#endif
	return datetime;
}
Exemplo n.º 3
0
static void handle_set_parameter_metadata(rtsp_conn_info *conn,
                                          rtsp_message *req, rtsp_message *resp) {
    char *cp = req->content;
    int cl = req->contentlength;

    metadata *meta = metadata_init();

    unsigned int off = 8;

    while (off < cl) {
        char tag[5];
        strncpy(tag, cp+off, 4);
        tag[4] = '\0';
        off += 4;

        uint32_t vl = ntohl(*(uint32_t *)(cp+off));
        off += sizeof(uint32_t);

        char *val = malloc(vl+1);
        strncpy(val, cp+off, vl);
        val[vl] = '\0';
        off += vl;

        debug(2, "Tag: %s   Content: %s\n", tag, val);
		#if 0 
        if (!strncmp(tag, "asal ", 4) && meta->album == NULL) {
            debug(1, "META Album: %s\n", val);
            meta->album = strdup(val);
			setAlbumConfig(meta->album);
			
        } else if (!strncmp(tag, "asar ", 4) && meta->artist == NULL) {
            debug(1, "META Artist: %s\n", val);
            meta->artist = strdup(val);
			setCreatorConfig(meta->artist);
        } else if (!strncmp(tag, "ascm ", 4) && meta->comment == NULL) {
            debug(1, "META Comment: %s\n", val);
            meta->comment = strdup(val);
        } else if (!strncmp(tag, "asgn ", 4) && meta->genre == NULL) {
            debug(1, "META Genre: %s\n", val);
            meta->genre = strdup(val);
        } else if (!strncmp(tag, "minm ", 4) && meta->title == NULL) {
            debug(1, "META Title: %s\n", val);
            meta->title = strdup(val);
			setTitleConfig(meta->title);
        }
		#endif
        free(val);    
    }

//    player_metadata(meta);
     metadata_free(meta);
}
Exemplo n.º 4
0
void
metafile_key_unset (MetaFile *metafile,
		    const char *key)
{
  MetaData *data;

  data = metafile_key_lookup (metafile, key, FALSE);
  if (data)
    {
      metafile->data = g_list_remove (metafile->data, data);
      metadata_free (data);
    }
}
Exemplo n.º 5
0
/**
 * a_geotag_waypoint_positioned:
 * @filename: The image file to process
 * @coord:    The location for positioning the Waypoint
 * @name:     Returns a name for the Waypoint (can be NULL)
 * @waypoint: An existing waypoint to update (can be NULL to generate a new waypoint)
 *
 * Returns: An allocated waypoint if the input waypoint is NULL,
 *  otherwise the passed in waypoint is updated
 *
 *  Here EXIF processing is used to get non position related information (i.e. just the comment)
 *
 */
VikWaypoint* a_geotag_waypoint_positioned ( const gchar *filename, VikCoord coord, gdouble alt, gchar **name, VikWaypoint *wp )
{
	*name = NULL;
	if ( wp == NULL ) {
		// Need to create waypoint
		wp = vik_waypoint_new();
		wp->visible = TRUE;
	}
	wp->coord = coord;
	wp->altitude = alt;

#ifdef HAVE_LIBGEXIV2
	GExiv2Metadata *gemd = gexiv2_metadata_new ();
	if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
			wp->comment = geotag_get_exif_comment ( gemd );
			if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPTitle" ) )
				*name = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPTitle" ) );
	}
	metadata_free ( gemd );
#else
#ifdef HAVE_LIBEXIF
	ExifData *ed = exif_data_new_from_file ( filename );

	// Set info from exif values
	if ( ed ) {
		wp->comment = geotag_get_exif_comment ( ed );

		gchar str[128];
		ExifEntry *ee;
		// Name
		ee = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_XP_TITLE);
		if ( ee ) {
			exif_entry_get_value ( ee, str, 128 );
			*name = g_strdup ( str );
		}

		// Finished with EXIF
		exif_data_free ( ed );
	}
#endif
#endif

	vik_waypoint_set_image ( wp, filename );

	return wp;
}
Exemplo n.º 6
0
/**
 * a_geotag_get_position:
 *
 * @filename: The (JPG) file with EXIF information in it
 *
 * Returns: The position in LatLon format.
 *  It will be 0,0 if some kind of failure occurs.
 */
struct LatLon a_geotag_get_position ( const gchar *filename )
{
	struct LatLon ll = { 0.0, 0.0 };

#ifdef HAVE_LIBGEXIV2
	GExiv2Metadata *gemd = gexiv2_metadata_new ();
	if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
		gdouble lat;
		gdouble lon;
		gdouble alt;
		if ( gexiv2_metadata_get_gps_info ( gemd, &lon, &lat, &alt ) ) {
			ll.lat = lat;
			ll.lon = lon;
		}
	}
	metadata_free  ( gemd );
#else
#ifdef HAVE_LIBEXIF
	// open image with libexif
	ExifData *ed = exif_data_new_from_file ( filename );

	// Detect EXIF load failure
	if ( !ed )
		return ll;

	ExifEntry *ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_VERSION_ID);
	// Confirm this has a GPS Id - normally "2.0.0.0" or "2.2.0.0"
	if ( ! ( ee && ee->components == 4 ) )
		goto MyReturn0;

	ll = get_latlon ( ed );

MyReturn0:
	// Finished with EXIF
	exif_data_free ( ed );
#endif
#endif

	return ll;
}
Exemplo n.º 7
0
int
streamFile(shout_t *shout, const char *fileName)
{
	FILE		*filepstream = NULL;
	int		 popenFlag = 0;
	char		*songLenStr = NULL;
	int		 isStdin = 0;
	int		 ret, retval = 0;
	long		 songLen;
	metadata_t	*mdata;
	struct timeval	 startTime;

	if ((filepstream = openResource(shout, fileName, &popenFlag,
					&mdata, &isStdin, &songLen))
	    == NULL) {
		if (++resource_errors > 100) {
			printf("%s: Too many errors -- giving up.\n", __progname);
			return (0);
		}
		/* Continue with next resource on failure: */
		return (1);
	}
	resource_errors = 0;

	if (mdata != NULL) {
		char	*tmp, *metaData;

		tmp = metadata_assemble_string(mdata);
		if ((metaData = UTF8toCHAR(tmp, ICONV_REPLACE)) == NULL)
			metaData = xstrdup("(unknown title)");
		xfree(tmp);
		printf("%s: Streaming ``%s''", __progname, metaData);
		if (vFlag)
			printf(" (file: %s)\n", fileName);
		else
			printf("\n");
		xfree(metaData);

		/* MP3 streams are special, so set the metadata explicitly: */
		if (strcmp(pezConfig->format, MP3_FORMAT) == 0)
			setMetadata(shout, mdata, NULL);

		metadata_free(&mdata);
	} else if (isStdin)
		printf("%s: Streaming from standard input\n", __progname);

	if (songLen > 0)
		songLenStr = xstrdup(getTimeString(songLen));
	ez_gettimeofday((void *)&startTime);
	do {
		ret = sendStream(shout, filepstream, fileName, isStdin,
				 songLenStr, &startTime);
		if (quit)
			break;
		if (ret != STREAM_DONE) {
			if ((skipTrack && rereadPlaylist) ||
			    (skipTrack && queryMetadata)) {
				skipTrack = 0;
				ret = STREAM_CONT;
			}
			if (queryMetadata && rereadPlaylist) {
				queryMetadata = 0;
				ret = STREAM_CONT;
			}
			if (ret == STREAM_SKIP || skipTrack) {
				skipTrack = 0;
				if (!isStdin && vFlag)
					printf("%s: SIGUSR1 signal received, skipping current track\n",
					       __progname);
				retval = 1;
				ret = STREAM_DONE;
			}
			if (ret == STREAM_UPDMDATA || queryMetadata) {
				queryMetadata = 0;
				if (mFlag)
					continue;
				if (metadataFromProgram) {
					char		*mdataStr = NULL;
					metadata_t	*prog_mdata;

					if (vFlag > 1)
						printf("%s: Querying '%s' for fresh metadata\n",
						       __progname, pezConfig->metadataProgram);
					if ((prog_mdata = getMetadata(pezConfig->metadataProgram)) == NULL) {
						retval = 0;
						ret = STREAM_DONE;
						continue;
					}
					if (setMetadata(shout, prog_mdata, &mdataStr) != SHOUTERR_SUCCESS) {
						retval = 0;
						ret = STREAM_DONE;
						continue;
					}
					metadata_free(&prog_mdata);
					if (vFlag > 1)
						printf("%s: New metadata: ``%s''\n",
						       __progname, mdataStr);
					xfree(mdataStr);
				}
			}
			if (ret == STREAM_SERVERR) {
				retval = 0;
				ret = STREAM_DONE;
			}
		} else
			retval = 1;
	} while (ret != STREAM_DONE);

	if (popenFlag)
		pclose(filepstream);
	else if (!isStdin)
		fclose(filepstream);

	if (songLenStr != NULL)
		xfree(songLenStr);

	return (retval);
}
Exemplo n.º 8
0
FILE *
openResource(shout_t *shout, const char *fileName, int *popenFlag,
	     metadata_t **mdata_p, int *isStdin, long *songLen)
{
	FILE		*filep = NULL;
	char		 extension[25];
	char		*p = NULL;
	char		*pCommandString = NULL;
	metadata_t	*mdata;

	if (mdata_p != NULL)
		*mdata_p = NULL;
	if (songLen != NULL)
		*songLen = 0;

	if (strcmp(fileName, "stdin") == 0) {
		if (metadataFromProgram) {
			if ((mdata = getMetadata(pezConfig->metadataProgram)) == NULL)
				return (NULL);
			if (setMetadata(shout, mdata, NULL) != SHOUTERR_SUCCESS) {
				metadata_free(&mdata);
				return (NULL);
			}
			if (mdata_p != NULL)
				*mdata_p = mdata;
			else
				metadata_free(&mdata);
		}

		if (isStdin != NULL)
			*isStdin = 1;
#ifdef WIN32
		_setmode(_fileno(stdin), _O_BINARY);
#endif
		filep = stdin;
		return (filep);
	}

	if (isStdin != NULL)
		*isStdin = 0;

	extension[0] = '\0';
	p = strrchr(fileName, '.');
	if (p != NULL)
		strlcpy(extension, p, sizeof(extension));
	for (p = extension; *p != '\0'; p++)
		*p = tolower((int)*p);

	if (strlen(extension) == 0) {
		printf("%s: Error: Cannot determine file type of '%s'\n",
		       __progname, fileName);
		return (filep);
	}

	if (metadataFromProgram) {
		if ((mdata = getMetadata(pezConfig->metadataProgram)) == NULL)
			return (NULL);
	} else {
		if ((mdata = getMetadata(fileName)) == NULL)
			return (NULL);
	}
	if (songLen != NULL)
		*songLen = metadata_get_length(mdata);

	*popenFlag = 0;
	if (pezConfig->reencode) {
		int	stderr_fd = -1;

		pCommandString = buildCommandString(extension, fileName, mdata);
		if (mdata_p != NULL)
			*mdata_p = mdata;
		else
			metadata_free(&mdata);
		if (vFlag > 1)
			printf("%s: Running command `%s`\n", __progname,
			       pCommandString);

		if (qFlag) {
			int fd;

			stderr_fd = dup(fileno(stderr));
			if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) {
				printf("%s: Cannot open %s for redirecting STDERR output: %s\n",
				       __progname, _PATH_DEVNULL, strerror(errno));
				exit(1);
			}

			dup2(fd, fileno(stderr));
			if (fd > 2)
				close(fd);
		}

		fflush(NULL);
		errno = 0;
		if ((filep = popen(pCommandString, "r")) == NULL) {
			printf("%s: popen(): Error while executing '%s'",
			       __progname, pCommandString);
			/* popen() does not set errno reliably ... */
			if (errno)
				printf(": %s\n", strerror(errno));
			else
				printf("\n");
		} else {
			*popenFlag = 1;
#ifdef WIN32
			_setmode(_fileno(filep), _O_BINARY );
#endif
		}
		xfree(pCommandString);

		if (qFlag)
			dup2(stderr_fd, fileno(stderr));

		if (stderr_fd > 2)
			close(stderr_fd);

		return (filep);
	}

	if (mdata_p != NULL)
		*mdata_p = mdata;
	else
		metadata_free(&mdata);

	if ((filep = fopen(fileName, "rb")) == NULL)
		printf("%s: %s: %s\n", __progname, fileName,
		       strerror(errno));

	return (filep);
}
Exemplo n.º 9
0
/**
 * a_geotag_write_exif_gps:
 * @filename: The image file to save information in
 * @coord:    The location
 * @alt:      The elevation
 * @direction:     The image direction (if NAN then these direction fields are not written)
 * @direction_ref: The image direction value type
 *
 * Returns: A value indicating success: 0, or some other value for failure
 *
 */
gint a_geotag_write_exif_gps ( const gchar *filename, VikCoord coord, gdouble alt,
                               gdouble direction, VikWaypointImageDirectionRef direction_ref,
                               gboolean no_change_mtime )
{
	gint result = 0; // OK so far...

	// Save mtime for later use
	struct stat stat_save;
	if ( no_change_mtime )
		if ( stat ( filename, &stat_save ) != 0 )
			g_warning ( "%s couldn't read: %s", __FUNCTION__, filename );

#ifdef HAVE_LIBGEXIV2
	GExiv2Metadata *gemd = gexiv2_metadata_new ();
	if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
		struct LatLon ll;
		vik_coord_to_latlon ( &coord, &ll );
		if ( ! gexiv2_metadata_set_gps_info ( gemd, ll.lon, ll.lat, alt ) ) {
			result = 1; // Failed
		}
		else {
			if ( !isnan(direction) ) {
				gint nom = (gint)round(direction * 10.0);
				gboolean set_d = gexiv2_metadata_set_exif_tag_rational ( gemd, EXIF_GPS_IMGDIR, nom, 10 );
				if ( !set_d ) result = 1; // Failed
				gboolean set_r = gexiv2_metadata_set_tag_string ( gemd, EXIF_GPS_IMGDIR_REF, direction_ref == WP_IMAGE_DIRECTION_REF_TRUE ? "T" : "M" );
				if ( !set_r ) result = 1; // Failed
			}
			// Still OK to save - no fails yet
			if ( result == 0 ) {
				GError *error = NULL;
				if ( ! gexiv2_metadata_save_file ( gemd, filename, &error ) ) {
					result = 2;
					g_warning ( "Write EXIF failure:%s" , error->message );
					g_error_free ( error );
				}
			}
		}
	}
	metadata_free ( gemd );
#else
#ifdef HAVE_LIBEXIF
	/*
	  Appears libexif doesn't actually support writing EXIF data directly to files
	  Thus embed command line exif writing method within Viking
	  (for example this is done by Enlightment - http://www.enlightenment.org/ )
	  This appears to be JPEG only, but is probably 99% of our use case
	  Alternatively consider using libexiv2 and C++...
	*/

	// Actual EXIF settings here...
	JPEGData *jdata;

	/* Parse the JPEG file. */
	jdata = jpeg_data_new ();
	jpeg_data_load_file (jdata, filename);

	// Get current values
	ExifData *ed = exif_data_new_from_file ( filename );
	if ( !ed )
		ed = exif_data_new ();

	// Update ExifData with our new settings
	ExifEntry *ee;
	//
	// I don't understand it, but when saving the 'ed' nothing gets set after putting in the GPS ID tag - so it must come last
	// (unless of course there is some bug in the setting of the ID, that prevents subsequent tags)
	//

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE, EXIF_IFD_GPS);
	convert_to_entry ( NULL, alt, ee, exif_data_get_byte_order(ed) );

	// byte 0 meaning "sea level" or 1 if the value is negative.
	ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_IFD_GPS);
	convert_to_entry ( alt < 0.0 ? "1" : "0", 0.0, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_IFD_GPS);
	// see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html
	convert_to_entry ( "MANUAL", 0.0, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_MAP_DATUM, EXIF_IFD_GPS);
	convert_to_entry ( "WGS-84", 0.0, ee, exif_data_get_byte_order(ed) );

	struct LatLon ll;
    vik_coord_to_latlon ( &coord, &ll );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE_REF, EXIF_IFD_GPS);
	// N or S
	convert_to_entry ( ll.lat < 0.0 ? "S" : "N", 0.0, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE, EXIF_IFD_GPS);
	convert_to_entry ( NULL, ll.lat, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_IFD_GPS);
	// E or W
	convert_to_entry ( ll.lon < 0.0 ? "W" : "E", 0.0, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE, EXIF_IFD_GPS);
	convert_to_entry ( NULL, ll.lon, ee, exif_data_get_byte_order(ed) );

	ee = my_exif_create_value (ed, EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_GPS);
	//convert_to_entry ( "2 0 0 0", 0.0, ee, exif_data_get_byte_order(ed) );
	convert_to_entry ( "2 2 0 0", 0.0, ee, exif_data_get_byte_order(ed) );

	jpeg_data_set_exif_data (jdata, ed);

	if ( jdata ) {
		/* Save the modified image. */
		result = jpeg_data_save_file (jdata, filename);

		// Convert result from 1 for success, 0 for failure into our scheme
		result = !result;
		
		jpeg_data_unref (jdata);
	}
	else {
		// Epic fail - file probably not a JPEG
		result = 2;
	}

	exif_data_free ( ed );
#endif
#endif

	if ( no_change_mtime ) {
		// Restore mtime, using the saved value
		struct stat stat_tmp;
		struct utimbuf utb;
		(void)stat ( filename, &stat_tmp );
		utb.actime = stat_tmp.st_atime;
		utb.modtime = stat_save.st_mtime;
		// Not security critical, thus potential Time of Check Time of Use race condition is not bad
		// coverity[toctou]
		if ( g_utime ( filename, &utb ) != 0 )
			g_warning ( "%s couldn't set time on: %s", __FUNCTION__, filename );
	}

	return result;
}
Exemplo n.º 10
0
/**
 * a_geotag_create_waypoint_from_file:
 * @filename: The image file to process
 * @vcmode:   The current location mode to use in the positioning of Waypoint
 * @name:     Returns a name for the Waypoint (can be NULL)
 *
 * Returns: An allocated Waypoint or NULL if Waypoint could not be generated (e.g. no EXIF info)
 *
 */
VikWaypoint* a_geotag_create_waypoint_from_file ( const gchar *filename, VikCoordMode vcmode, gchar **name )
{
	// Default return values (for failures)
	*name = NULL;
	VikWaypoint *wp = NULL;

#ifdef HAVE_LIBGEXIV2
	GExiv2Metadata *gemd = gexiv2_metadata_new ();
	if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
		gdouble lat;
		gdouble lon;
		gdouble alt;
		if ( gexiv2_metadata_get_gps_info ( gemd, &lon, &lat, &alt ) ) {
			struct LatLon ll;
			ll.lat = lat;
			ll.lon = lon;

			//
			// Now create Waypoint with acquired information
			//
			wp = vik_waypoint_new();
			wp->visible = TRUE;
			// Set info from exif values
			// Location
			vik_coord_load_from_latlon ( &(wp->coord), vcmode, &ll );
			// Altitude
			wp->altitude = alt;

			if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPTitle" ) )
				*name = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPTitle" ) );
			wp->comment = geotag_get_exif_comment ( gemd );

			// Direction
			VikWaypointImageDirectionRef ref = WP_IMAGE_DIRECTION_REF_TRUE;
			if ( gexiv2_metadata_has_tag ( gemd, EXIF_GPS_IMGDIR_REF ) ) {
				gchar* ref_str = gexiv2_metadata_get_tag_interpreted_string(gemd, EXIF_GPS_IMGDIR_REF);
				if ( ref_str && g_ascii_strncasecmp ("M", ref_str, 1) == 0 )
					ref = WP_IMAGE_DIRECTION_REF_MAGNETIC;
				g_free ( ref_str );
			}
			if ( gexiv2_metadata_has_tag ( gemd, EXIF_GPS_IMGDIR ) ) {
				gint nom;
				gint den;
				gdouble direction = NAN;
				if ( gexiv2_metadata_get_exif_tag_rational (gemd, EXIF_GPS_IMGDIR, &nom, &den) )
					if ( den != 0 )
						direction = (gdouble)nom/(gdouble)den;

				if ( !isnan(direction) )
					vik_waypoint_set_image_direction_info ( wp, direction, ref );
			}

			vik_waypoint_set_image ( wp, filename );
		}
	}
	metadata_free ( gemd );
#else
#ifdef HAVE_LIBEXIF
	// TODO use log?
	//ExifLog *log = NULL;

	// open image with libexif
	ExifData *ed = exif_data_new_from_file ( filename );

	// Detect EXIF load failure
	if ( !ed )
		// return with no Waypoint
		return wp;

	struct LatLon ll;

	gchar str[128];
	ExifEntry *ee;

	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_VERSION_ID);
	// Confirm this has a GPS Id - normally "2.0.0.0" or "2.2.0.0"
	if ( ! ( ee && ee->components == 4 ) )
		goto MyReturn;
	// Could test for these versions explicitly but may have byte order issues...
	//if ( ! ( ee->data[0] == 2 && ee->data[2] == 0 && ee->data[3] == 0 ) )
	//	goto MyReturn;

	ll = get_latlon ( ed );

	// Hopefully won't have valid images at 0,0!
	if ( ll.lat == 0.0 && ll.lon == 0.0 )
		goto MyReturn;

	//
	// Not worried if none of the other fields exist, as can default the values to something
	//

	gdouble alt = VIK_DEFAULT_ALTITUDE;
	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_ALTITUDE);
	if ( ee && ee->components == 1 && ee->format == EXIF_FORMAT_RATIONAL ) {
		alt = Rational2Double ( ee->data,
								0,
								exif_data_get_byte_order(ed) );

		ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_ALTITUDE_REF);
		if ( ee && ee->components == 1 && ee->format == EXIF_FORMAT_BYTE && ee->data[0] == 1 )
			alt = -alt;
	}

	// Name
	ee = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_XP_TITLE);
	if ( ee ) {
		exif_entry_get_value ( ee, str, 128 );
		*name = g_strdup ( str );
	}

	//
	// Now create Waypoint with acquired information
	//
	wp = vik_waypoint_new();
	wp->visible = TRUE;
	// Set info from exif values
	// Location
	vik_coord_load_from_latlon ( &(wp->coord), vcmode, &ll );
	// Altitude
	wp->altitude = alt;

	wp->comment = geotag_get_exif_comment ( ed );

	vik_waypoint_set_image ( wp, filename );

MyReturn:
	// Finished with EXIF
	exif_data_free ( ed );
#endif
#endif

	return wp;
}