Locating geotagged images with Google Earth

Aurélien Gâteau agateau at kde.org
Mon Jun 1 07:42:37 BST 2020


Hi Jan,

This looks interesting, but I think there aren't any active developer subscribed to this mailing-list these days :( (I used to be one, but I no longer work on Gwenview). You can try reaching out others on https://forum.kde.org or on the #kde-devel IRC channel (on Freenode).

Aurélien

On Sun, May 24, 2020, at 22:13, Jan Depner wrote:
> Hi,
> 
>  Apologies in advance for a very long post.
> 
>  A few days ago I decided that I needed to be able to see the location of my geotagged images from within gwenview. I've got thousands of geotagged images and I randomly display them as my wallpaper. Half the time I can't remember where the pictures were taken so I was "Opening Wallpaper Image" (Kubuntu 18.04) with gwenview, starting geotag, finding the file based on the truncated name showing in the title bar of gwenview, then, from within geotag, opening the browser with the location tagged. Well, that got real tedious real fast so I decided to write my own little application that I could start from gwenview and then maybe later, look into incorporating it into gwenview. The application works great and allows me to open Google Earth (not in the browser) with the image location tagged with a "pushpin". Just for grins I also added a fallback to tagging the location in Google maps in the browser if you don't happen to have Google Earth installed.
> 
>  I looked into trying to incorporate the code into gwenview (it's C++ and Qt5) but building gwenview was an absolute nightmare. Way too many dependencies. At any rate, the code works as is and, if you add it to your "K" menu (using kmenuedit), you can start it from the File->Open With... in gwenview. So, I'm still using my little command line app out of gwenview for the present (because it works ;-) I threw the thing together in a couple of hours (I had already done something similar in my LiDAR processing software so it wasn't that difficult). It's not elegant but I thought you guys might be interested. I don't think that attaching the code as a file is the best idea (because some people don't like attachments) so here it is in it's entirety (dependencies are Qt5 and libexif-dev):
> 
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <errno.h>
> #include <math.h>
> #include <string.h>
> #include <getopt.h>
> #include <sys/types.h>
> #include <unistd.h>
> #include <libexif/exif-data.h>
> #include <QtCore>
> #include <QtWidgets>
> #include <QStandardPaths>
> 
> void usage (char *string)
> {
>   fprintf (stderr, "Program: %s\n", string);
>   fprintf (stderr, "Purpose: Reads EXIF data from image file and\n");
>   fprintf (stderr, "opens GoogleEarth (or browser in Google Maps)\n");
>   fprintf (stderr, "with pushpin at picture location.\n");
>   fprintf (stderr, "Usage: %s IMAGE_FILE_NAME\n\n", string);
>   fprintf (stderr, "Caveats:\n");
>   fprintf (stderr, "\tThe image file must contain GPS position data.\n\n");
>   exit (-1);
> }
> 
> int32_t main (int32_t argc, char **argv)
> {
>   char              img_name[1024], lat[64], latref[2], lon[64], lonref[2], c;
>   extern int        optind;
>   QProcess          *googleEarthProc = NULL;
> 
>   QApplication a (argc, argv);
>   
>   while ((c = getopt (argc, argv, "w")) != EOF)
>     {
>       switch (c)
>         {
>         case 'w':
>           // Placeholder in case you want to add a command line option
>           usage (argv[0]);
>           break;
>         default:
>           usage (argv[0]);
>           break;
>         }
>     }
> 
>   //  Make sure we got the mandatory filename argument.
>   if (optind >= argc) usage (argv[0]);
> 
>   strcpy (img_name, argv[optind]);
>   
>   ExifData *exif = exif_data_new_from_file (img_name);
> 
>   ExifEntry *entry_lat = exif_data_get_entry (exif, (ExifTag) EXIF_TAG_GPS_LATITUDE);
>   if (exif_entry_get_value (entry_lat, lat, sizeof (lat)))
>     {
>       if (QString (lat).isEmpty ()) return (-1);
>     }
>   ExifEntry *entry_latref = exif_data_get_entry (exif, (ExifTag) EXIF_TAG_GPS_LATITUDE_REF);
>   if (exif_entry_get_value (entry_latref, latref, sizeof (latref)))
>     {
>       if (QString (latref).isEmpty ()) return (-1);
>     }
>   ExifEntry *entry_lon = exif_data_get_entry (exif, (ExifTag) EXIF_TAG_GPS_LONGITUDE);
>   
>   if (exif_entry_get_value (entry_lon, lon, sizeof (lon)))
>     {
>       if (QString (lon).isEmpty ()) return (-1);
>     }
>   ExifEntry *entry_lonref = exif_data_get_entry (exif, (ExifTag) EXIF_TAG_GPS_LONGITUDE_REF);
>   
>   if (exif_entry_get_value (entry_lonref, lonref, sizeof (lonref)))
>     {
>       if (QString (lonref).isEmpty ()) return (-1);
>     }
>   
>   QString arg, temp_folder, ge_tmp_name;
>   QStringList arguments;
>   int8_t process_id;
>   double pushpin_lat, pushpin_lon, pos[3];
>   
>   QString ImageBaseName = QFileInfo (QString (img_name)).baseName ();
>   
>   
>   sscanf (lon, "%lf, %lf, %lf", &pos[0], &pos[1], &pos[2]);
>   pos[2] /= 3600.0;
>   pos[1] /= 60.0;
>   pushpin_lon = pos[0] + pos[1] + pos[2];
>   if (QString (lonref).contains ("W")) pushpin_lon = -pushpin_lon;
>   
>   sscanf (lat, "%lf, %lf, %lf", &pos[0], &pos[1], &pos[2]);
>   pos[2] /= 3600.0;
>   pos[1] /= 60.0;
>   pushpin_lat = pos[0] + pos[1] + pos[2];
>   if (QString (latref).contains ("S")) pushpin_lat = -pushpin_lat;
>   
>   exif_data_unref (exif);
> 
>   //  Check for google-earth or googleearth or google-earth-pro.
>   QString command;
>   command = QStandardPaths::findExecutable ("google-earth-pro");
>   if (command.isEmpty ())
>     {
>       command = QStandardPaths::findExecutable ("google-earth");
>       if (command.isEmpty ())
>         {
>           command = QStandardPaths::findExecutable ("googleearth");
>           if (command.isEmpty ())
>             {
>               //  If we couldn't find Google Earth open Google maps in browser with sat background and marker...
>   
>               QString browser_string = QString ("http://www.google.com/maps/place/%1,%2/@%1,%2,17z/data=!3m1!1e3").arg (pushpin_lat, 0, 'f', 11).arg (pushpin_lon, 0, 'f', 11);
>               QDesktopServices::openUrl (QUrl (browser_string, QUrl::TolerantMode));
>               return (0);
>             }
>         }
>     }
>   
>     
>   arguments.clear ();
>   
>   temp_folder = QStandardPaths::writableLocation (QStandardPaths::TempLocation);
>       
>       
>   process_id = getpid ();
>   ge_tmp_name = temp_folder + QString ("/gePic_GE_%1_tmp.kml").arg (process_id);
>   QFile file (ge_tmp_name);
>   if (!file.open (QIODevice::WriteOnly | QIODevice::Text)) return (-1);
>       
>   QTextStream ts (&file);
> 
>   ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
>   ts << "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n";
>   ts << "  <Document>\n";
>   ts << "    <Placemark>\n";
>   ts << QString ("      <name>%1</name>\n").arg (ImageBaseName);
>   ts << "      <Point>\n";
>   ts << "        <altitudeMode>relativeToGround</altitudeMode>\n";
>   ts << "        <coordinates>\n";
>   ts << QString ("          %1,%2\n").arg (pushpin_lon, 0, 'f', 11).arg (pushpin_lat, 0, 'f', 11);
>   ts << "        </coordinates>\n";
>   ts << "      </Point>\n";
>   ts << "    </Placemark>\n";
>   ts << "  </Document>\n";
>   ts << "</kml>\n";
>       
>   file.close ();
>   arguments << ge_tmp_name;
>   googleEarthProc = new QProcess (0);
>   googleEarthProc->start (command, arguments);
>   googleEarthProc->waitForFinished ();
>   file.remove ();
>   
>   return (0);
> }
> 
> 
> I wrote a silly little script to build a Makefile and make the app:
> 
> 
> #!/bin/bash
> 
> # Building the .pro file using qmake
> rm -f xyPic.pro Makefile
> qmake -project -o xyPic.tmp
> cat >xyPic.pro <<EOF
> RC_FILE = xyPic.rc
> LIBS += -lexif
> QT += widgets
> CONFIG += console
> EOF
> 
> cat xyPic.tmp >>xyPic.pro
> rm xyPic.tmp
> 
> # Building the Makefile file using qmake
> qmake -o Makefile
> 
> make
> 
> 
> All of the above is in the public domain (as is all of my software). My LiDAR (and sonar) processing code does something a bit more interesting. It builds a link file and makes Google Earth monitor it for changes every "N" seconds to update the viewed area and change the pushpin location but that would probably be overkill for an image viewer. This program doesn't have any real error handling, if you don't have GPS in the image it just doesn't come up.
> 
>  Again, sorry for the long post. If there is a dev out there that is interested in adding this to gwenview, go for it.
> 
>  V/r,
>  Jan Depner
> 
> 
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/gwenview-devel/attachments/20200601/352ab954/attachment.htm>


More information about the Gwenview-devel mailing list