<div dir="ltr">Hi, <br><br>I tried your patch but had a SEGFAULT. I used a file I quickly geotagged with Picassa, so I guess it must be problematic. I'm attaching it for reference. I was using exiv2 0.17 on Gentoo.<br>
<br>Could you please put somewhere working track/jpg that I can test further?<br>I don't have any.<br><br>Some remarks already:<br><br>1) As a rule of thumb, features needing external libraries should be optional, so please be sure to adapt the Merkaartor.pro accordingly (i.e. à la OSMARENDER)<br>
2) Merkaartor being a multi-platform project, please be sure that exiv2 is available/compilable on windows under mingw; I don't know about Mac. Bart?<br>3) Would it be possible before the final patch to format the sources to avoid the 1-line IFs? I somewhat find them unreadable.<br>
<br>Thanks already<br>- Chris -<br><br><div class="gmail_quote">2008/8/19 Timo Schlüßler <span dir="ltr"><<a href="mailto:timo@schluessler.org">timo@schluessler.org</a>></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">



  

<div bgcolor="#ffffff" text="#000000">
For all who want to test my implementation, here is the patch. It's not
ready at all but you can give it a try and send me bugs.<br>
<br>
You have to apply the patch and then add the files to the directory Map.<br>
<br>
regards<br>
<br>
Timo Schlüßler wrote:
<blockquote type="cite"><div><div></div><div class="Wj3C7c">
  
Hello,<br>
  <br>
I think this would be a very great feature for merkaartor and I would <br>
like to implement it.<br>
  <br>
But before starting with that, I want to ask you if you are (still) <br>
interested in a "geotagged images"-feature or if there's yet a plugin
for <br>
merkaartor doing this.<br>
  <br>
best regards,<br>
timo<br>
  <br>
  <br>
Hanno Böck wrote:
  <blockquote type="cite">
    <pre>Hi,

I'm glad merkaartor seems to get better, as I don't really like josm (and I 
even less like potlach).

However, there's one thing that I'm using for all my mapping activity and that 
is using geotagged images. That's the single reason I'm stuck with josm.
I want a feature to show locations of jpeg images (by their exif gps tags) and 
show then on a click. josm has two plugins for that, I like the interface of 
AfPifoJ better than geotagged.

Is this feature planned (or even still possible and I didn't find it)?

  </pre>
    <pre><hr size="4" width="90%">
_______________________________________________
Merkaartor mailing list
<a href="mailto:Merkaartor@openstreetmap.org" target="_blank">Merkaartor@openstreetmap.org</a>
<a href="http://lists.openstreetmap.org/cgi-bin/mailman/listinfo/merkaartor" target="_blank">http://lists.openstreetmap.org/cgi-bin/mailman/listinfo/merkaartor</a>
  </pre>
  </blockquote>
  </div></div><pre><div><div></div><div class="Wj3C7c">
<hr size="4" width="90%">
_______________________________________________
Merkaartor mailing list
<a href="mailto:Merkaartor@openstreetmap.org" target="_blank">Merkaartor@openstreetmap.org</a>
</div></div><a href="http://lists.openstreetmap.org/listinfo/merkaartor" target="_blank">http://lists.openstreetmap.org/listinfo/merkaartor</a>
  </pre>
</blockquote>
</div>

<br>Index: MainWindow.h<br>
===================================================================<br>
--- MainWindow.h        (revision 9959)<br>
+++ MainWindow.h        (working copy)<br>
@@ -8,6 +8,7 @@<br>
 #include <QProgressBar><br>
 #include <QLabel><br>
<br>
+<br>
 class LayerDock;<br>
 class MapDocument;<br>
 class MapLayer;<br>
@@ -18,6 +19,7 @@<br>
 class DirtyDock;<br>
 class QGPS;<br>
 class FeaturePainter;<br>
+class GeoImage;<br>
<br>
 class MainWindow : public QMainWindow, public Ui::MainWindow<br>
 {<br>
Index: MainWindow.cpp<br>
===================================================================<br>
--- MainWindow.cpp      (revision 9959)<br>
+++ MainWindow.cpp      (working copy)<br>
@@ -31,6 +31,7 @@<br>
 #include "Map/Road.h"<br>
 #include "Map/RoadManipulations.h"<br>
 #include "Map/TrackPoint.h"<br>
+#include "Map/GeoImage.h"<br>
 #include "PaintStyle/EditPaintStyle.h"<br>
 #include "PaintStyle/PaintStyleEditor.h"<br>
 #include "Sync/SyncOSM.h"<br>
@@ -391,6 +392,7 @@<br>
        "OpenStreetMap binary format (*.osb)\n" \<br>
        "Noni GPSPlot format (*.ngt)\n" \<br>
        "NMEA GPS log format (*.nmea *.nme)\n" \<br>
+       "Geotagged images (*.jpg)\n" \<br>
        "All Files (*)")<br>
 #define FILTER_IMPORT_SUPPORTED \<br>
        tr("Supported formats (*.gpx *.osm *.osb *.ngt *.nmea *.nme)\n" \<br>
@@ -538,7 +540,16 @@<br>
                return;<br>
<br>
        QStringList fileNames(fileList);<br>
+<br>
+       QStringList images = fileNames.filter(".jpg", Qt::CaseInsensitive);<br>
+       if (!images.isEmpty()) {<br>
+               GeoImage::loadImages(images, theDocument, theView);<br>
+               QString cur;<br>
+               foreach (cur, images) fileNames.removeAll(cur);<br>
+       }<br>
<br>
+       if (fileNames.isEmpty()) return;<br>
+<br>
        QApplication::setOverrideCursor(Qt::BusyCursor);<br>
        theLayers->setUpdatesEnabled(false);<br>
        view()->setUpdatesEnabled(false);<br>
@@ -549,6 +560,7 @@<br>
        while (it.hasNext())<br>
        {<br>
                const QString & fn = it.next();<br>
+<br>
                if (fn.endsWith(".mdc") == false)<br>
                        continue;<br>
<br>
Index: Merkaartor.pri<br>
===================================================================<br>
--- Merkaartor.pri      (revision 9959)<br>
+++ Merkaartor.pri      (working copy)<br>
@@ -36,6 +36,7 @@<br>
 ./Map/Road.h \<br>
 ./Map/RoadManipulations.h \<br>
 ./Map/TrackPoint.h \<br>
+./Map/GeoImage.h \<br>
 ./Map/TrackSegment.h \<br>
 ./MapView.h \<br>
 ./PaintStyle/EditPaintStyle.h \<br>
@@ -84,6 +85,7 @@<br>
 ./Map/Road.cpp \<br>
 ./Map/RoadManipulations.cpp \<br>
 ./Map/TrackPoint.cpp \<br>
+./Map/GeoImage.cpp \<br>
 ./Map/TrackSegment.cpp \<br>
 ./MapView.cpp \<br>
 ./Interaction/CreateAreaInteraction.cpp \<br>
Index: Merkaartor.pro<br>
===================================================================<br>
--- Merkaartor.pro      (revision 9959)<br>
+++ Merkaartor.pro      (working copy)<br>
@@ -109,3 +109,5 @@<br>
     }<br>
     QT += webkit<br>
 }<br>
+<br>
+LIBS += -lexiv2<br>
Index: Map/ImportGPX.cpp<br>
===================================================================<br>
--- Map/ImportGPX.cpp   (revision 9959)<br>
+++ Map/ImportGPX.cpp   (working copy)<br>
@@ -88,6 +88,7 @@<br>
                if (!t.isNull() && t.tagName() == "trkpt")<br>
                {<br>
                        TrackPoint* Pt = importTrkPt(t,theDocument, theLayer, theList);<br>
+                       Pt->setParent(S);<br>
                        if (MakeSegment)<br>
                                S->add(Pt);<br>
                        progress.setValue(progress.value()+1);<br>
Index: Map/MapDocument.cpp<br>
===================================================================<br>
--- Map/MapDocument.cpp (revision 9959)<br>
+++ Map/MapDocument.cpp (working copy)<br>
@@ -372,8 +372,8 @@<br>
        QVector<MapFeature*> theFeatures;<br>
        for (VisibleFeatureIterator i(this); !i.isEnd(); ++i) {<br>
                if (!layerType)<br>
-                       theFeatures.append(i.get());<br>
-               else<br>
+                       qDebug() << "append :)";<br>
+               else<br>
                        if (i.get()->layer()->className() == *layerType)<br>
                                theFeatures.append(i.get());<br>
        }<br>
<br>#include "GeoImage.h"<br>
<br>
#include "Command/DocumentCommands.h"<br>
<br>
/*#include <QtGui/QStandardItemModel><br>
#include <QtGui/QDialog><br>
#include <QtGui/QListView><br>
#include <QtGui/QDialogButtonBox>*/<br>
#include <QtGui/QInputDialog><br>
#include <QtGui/QMessageBox><br>
<br>
class TrackSegment;<br>
<br>
GeoImage::GeoImage(TrackPoint * Pt, QImage img)<br>
: TrackPoint(*Pt), Image(img)<br>
{<br>
}<br>
<br>
GeoImage::~GeoImage()<br>
{<br>
}<br>
<br>
void GeoImage::draw(QPainter& P, const Projection& theProjection)<br>
{<br>
<br>
        QPointF me = theProjection.project(position());<br>
        P.setPen(QPen(QColor(0, 0, 0), 2));<br>
        QRectF box(me - QPointF(10, 6), me + QPointF(10, 6));<br>
        P.drawRect(box);<br>
        bound = CoordBox(theProjection.inverse(box.topLeft()), theProjection.inverse(box.bottomRight()));<br>
}<br>
void GeoImage::drawFocus(QPainter& P, const Projection& theProjection)<br>
{<br>
        QPointF me = theProjection.project(position());<br>
        double aspect = (double)Image.height() / (double)Image.width();<br>
        QPointF middle(P.device()->width()*0.2, aspect * P.device()->width()*0.2);<br>
        P.drawImage(QRectF(me - middle, me + middle), Image);<br>
}<br>
<br>
/*CoordBox GeoImage::boundingBox(void)<br>
{<br>
        qDebug() << bound.topLeft().lat() << bound.topLeft().lon() << bound.bottomRight().lat();<br>
        if (bound.isNull()) return TrackPoint::boundingBox();<br>
        else return bound;<br>
}*/<br>
<br>
<br>
void GeoImage::loadImages(QStringList fileNames, MapDocument *theDocument, MapView *theView)<br>
{<br>
        QString file;<br>
        QImage img;<br>
        QDateTime time;<br>
        bool foundTime;<br>
<br>
        Exiv2::Image::AutoPtr image;<br>
        Exiv2::ExifData *exifData;<br>
        Exiv2::ExifData::const_iterator i, end;<br>
<br>
        MapLayer *theLayer;<br>
        {<br>
                QStringList layers;<br>
                unsigned int i;<br>
                for (i=0;i<theDocument->layerSize();i++) layers.append(theDocument->getLayer(i)->name());<br>
<br>
                bool ok;<br>
                QString layer = QInputDialog::getItem(NULL, MainWindow::tr("Load geotagged Images"),<br>
                 MainWindow::tr("Select the layer to which the images belong:"), layers, 0, false, &ok);<br>
                if (ok && !layer.isEmpty())<br>
                        theLayer = theDocument->getLayer(layers.indexOf(layer));<br>
                else return;<br>
<br>
                /*<br>
                QDialog dlg;<br>
<br>
        QVBoxLayout layout(&dlg);<br>
           QLabel text("Select the layer the images belong to.");<br>
                QListView list(&dlg);<br>
                QStandardItemModel *model = new QStandardItemModel(&list);<br>
                list.setModel(model);<br>
                list.setSelectionMode(QAbstractItemView::SingleSelection);<br>
                QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);<br>
                layout.addWidget(&text, 0);<br>
                layout.addWidget(&list, 1);<br>
                layout.addWidget(&buttons, 2, Qt::AlignRight);<br>
<br>
                dlg.setWindowTitle("Load geotagged Images");<br>
<br>
                unsigned int i;<br>
                qDebug() << theDocument->layerSize();<br>
                for (i=0;i<theDocument->layerSize();i++) model->appendRow(new QStandardItem(theDocument->getLayer(i)->name()));<br>
<br>
                dlg.connect(&buttons, SIGNAL(accepted()), &dlg, SLOT(accept()));<br>
                dlg.connect(&buttons, SIGNAL(rejected()), &dlg, SLOT(reject()));<br>
                if (dlg.exec() != QDialog::Accepted) return;<br>
<br>
                QModelIndexList selection = list.selectionModel()->selectedRows();<br>
                if (selection.size() != 1) return;<br>
                theLayer = theDocument->getLayer(selection.first().row());<br>
<br>
                delete model;<br>
                */<br>
        }<br>
<br>
        CommandList * theList = new CommandList(MainWindow::tr("Loading Images"));<br>
<br>
        bool ok;<br>
        int offset = QInputDialog::getInteger( NULL, MainWindow::tr("Set offset"),<br>
         MainWindow::tr("Specify an offset\n(positive values will position the images more to the end of the track):"),<br>
         0, 0, (int) ((unsigned int)-1 / 2), 1, &ok);<br>
        qDebug() << (unsigned int)-1 << (int)((unsigned int)-1 /2);<br>
        if (!ok) offset = 0;<br>
<br>
        foreach(file, fileNames) {<br>
                if (!img.load(file)) { if (warning(MainWindow::tr("Image broken"), MainWindow::tr("Cannot open image %1.").arg(file))) continue; else return;}<br>
                if (img.isNull()) continue;<br>
<br>
        image = Exiv2::ImageFactory::open(file.toAscii().constData());<br>
                if (image.get() == 0) { qWarning("Error with exiv2 in %s.\n", file.toAscii().constData()); continue; }<br>
                image->readMetadata();<br>
<br>
                exifData = &  image->exifData();<br>
                if (exifData->empty()) {<br>
                        qWarning("No exif data. Skipping.\n"); continue;<br>
                }<br>
                end = exifData->end();<br>
                foundTime = false;<br>
                for (i = exifData->begin(); i != end; i++) {<br>
                        if (i->key() == "Exif.Image.DateTime") {<br>
                                time = QDateTime::fromString(i->value().toString().c_str(), "yyyy:MM:dd hh:mm:ss");<br>
                                qDebug() << "time is" << time;<br>
                                foundTime = true;<br>
                        }<br>
                }<br>
                if (!foundTime) { if (warning(MainWindow::tr("No timestamp"), MainWindow::tr("Image doesn't provide any time information."))) continue; else return; }<br>
<br>
<br>
                time = time.addSecs(offset);<br>
<br>
                qDebug() << theLayer;<br>
                qDebug() << "theLayer" << theLayer->size();<br>
                MapFeature *feature = NULL, *bestFeature = NULL;<br>
                TrackPoint *Pt;<br>
                unsigned int secondsTo = (unsigned int)-1, a;<br>
                unsigned int u;<br>
                for (u=0; u<theLayer->size(); feature = theLayer->get(u++)) {<br>
                        if (!feature) { qDebug() << "is this a bug???"; continue; } // TODO<br>
                        if (!(Pt = dynamic_cast<TrackPoint*>(feature))) continue;<br>
                        a = time.secsTo(Pt->time());<br>
                        if (a < secondsTo) { secondsTo = a; bestFeature = feature; }<br>
                }<br>
                if (!bestFeature) { qDebug() << "no features found"; continue; }<br>
<br>
                if (secondsTo >= 15)<br>
                        if ( QMessageBox::question(NULL, MainWindow::tr("Wrong image?"),<br>
                         MainWindow::tr("Image \"%1\" was taken %2 seconds before the next trackpoint was recorded.\n" \<br>
                         "Do you still want to use it?").arg(file).arg(secondsTo), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes) continue;<br>
<br>
                TrackSegment *S;<br>
                int idx;<br>
                if (bestFeature->sizeParents() == 1 &&<br>
                 (Pt = dynamic_cast<TrackPoint*>(bestFeature)) &&<br>
                 (S = dynamic_cast<TrackSegment*>(bestFeature->getParent(0))) )<br>
                        idx = S->find(Pt);<br>
                else { qWarning() << "Can't access TrackPoint or it's parent or the parent is not a TrackSegment!\n"; continue; }<br>
<br>
                if (bestFeature->deleteChildren(theDocument, theList)) {<br>
                        std::vector<MapFeature*> Alternatives;<br>
                        theList->add(new RemoveFeatureCommand(theDocument, Pt, Alternatives));<br>
                }<br>
<br>
                GeoImage * GeoPoint = new GeoImage(Pt, QImage(file));<br>
                theList->add(new AddFeatureCommand(theLayer, GeoPoint, false));<br>
<br>
                S->add(GeoPoint, idx);<br>
        }<br>
        if (theList->size()) {<br>
                theDocument->addHistory(theList);<br>
                theView->invalidate(true, false);<br>
        }<br>
        else delete theList;<br>
<br>
}<br>
<br>
bool GeoImage::warning(QString title, QString message)<br>
{<br>
        if ( QMessageBox::warning ( NULL, title, message, QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Ignore ) == QMessageBox::Ignore) return true;<br>
        else return false;<br>
}<br>
<br>
<br>#include "Map/TrackPoint.h"<br>
#include "Map/TrackSegment.h"<br>
#include "Map/Projection.h"<br>
#include "MapView.h"<br>
#include <QtGui/QPainter><br>
#include <exiv2/image.hpp><br>
#include <exiv2/exif.hpp><br>
#include "TrackPoint.h"<br>
<br>
class GeoImage : public TrackPoint<br>
{<br>
public:<br>
        GeoImage(TrackPoint *Pt, QImage img);<br>
        virtual ~GeoImage();<br>
<br>
        static void loadImages(QStringList fileNames, MapDocument *theDocument, MapView *theView);<br>
<br>
        virtual void draw(QPainter& P, const Projection& theProjection);<br>
        virtual void drawFocus(QPainter& P, const Projection& theProjection);<br>
        //virtual CoordBox boundingBox(void);<br>
<br>
private:<br>
        QImage Image;<br>
        CoordBox bound;<br>
<br>
        static bool warning(QString title, QString message);<br>
};<br>
<br>
<br>_______________________________________________<br>
Merkaartor mailing list<br>
<a href="mailto:Merkaartor@openstreetmap.org">Merkaartor@openstreetmap.org</a><br>
<a href="http://lists.openstreetmap.org/listinfo/merkaartor" target="_blank">http://lists.openstreetmap.org/listinfo/merkaartor</a><br>
<br></blockquote></div><br></div>