<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>